aboutsummaryrefslogtreecommitdiffstats
path: root/extras/recipes-kernel/linux/linux-omap
diff options
context:
space:
mode:
Diffstat (limited to 'extras/recipes-kernel/linux/linux-omap')
-rw-r--r--extras/recipes-kernel/linux/linux-omap/0001-BeagleBoard-Adjust-USER-button-pin-for-xM.patch29
-rw-r--r--extras/recipes-kernel/linux/linux-omap/0001-beagleboard-hack-in-support-from-xM-rev-C.patch94
-rw-r--r--extras/recipes-kernel/linux/linux-omap/0001-board-omap3beagle-whitespace-cleanup.patch91
-rw-r--r--extras/recipes-kernel/linux/linux-omap/0001-omap3-allow-1GHz-mpurates.patch26
-rw-r--r--extras/recipes-kernel/linux/linux-omap/0001-xM-audio-fix-from-Ashok.patch27
-rw-r--r--extras/recipes-kernel/linux/linux-omap/0002-board-omap3beagle-allow-for-building-without-wl1271.patch42
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0001-omap3-beaglexm-fix-EHCI-power-up-GPIO-dir.patch44
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0002-omap3-beaglexm-fix-DVI-reset-GPIO.patch48
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0003-omap3-beaglexm-fix-power-on-of-DVI.patch94
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0004-omap-Beagle-detect-new-xM-revision-B.patch43
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0005-ARM-OMAP-beagleboard-Add-infrastructure-to-do-fixups.patch219
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0006-ARM-OMAP-beagleboard-pre-export-GPIOs-to-userspace-w.patch57
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0007-modedb.c-add-proper-720p60-mode.patch28
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0008-mmc-don-t-display-single-block-read-console-messages.patch28
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0009-MTD-silence-ecc-errors-on-mtdblock0.patch63
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0010-Miracle-patch.patch504
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0011-ARM-OMAP-add-omap_rev_-macros.patch81
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0012-OMAP-DSS2-enable-hsclk-in-dsi_pll_init-for-OMAP36XX.patch31
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0013-omap3-beagleboard-add-WIP-support-for-beagleboardtoy.patch128
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0014-drivers-net-smsc911x-return-ENODEV-if-device-is-not-.patch29
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0015-drivers-input-touchscreen-ads7846-return-ENODEV-if-d.patch47
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0016-ASoC-enable-audio-capture-by-default-for-twl4030.patch27
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0017-MFD-enable-madc-clock.patch51
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0018-MFD-add-twl4030-madc-driver.patch740
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0019-ARM-OMAP-Add-twl4030-madc-support-to-Overo.patch32
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0020-ARM-OMAP-Add-twl4030-madc-support-to-Beagle.patch35
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0021-OMAP-DSS2-Add-support-for-Samsung-LTE430WQ-F0C-panel.patch173
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0022-OMAP-DSS2-Add-support-for-LG-Philips-LB035Q02-panel.patch299
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0023-OMAP-DSS2-add-bootarg-for-selecting-svideo-or-compos.patch75
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0024-ARM-OMAP2-mmc-twl4030-move-clock-input-selection-pri.patch39
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0025-RTC-add-support-for-backup-battery-recharge.patch55
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0026-ARM-OMAP-automatically-set-musb-mode-in-platform-dat.patch49
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0027-OMAP-DSS2-check-for-both-cpu-type-and-revision-rathe.patch34
-rw-r--r--extras/recipes-kernel/linux/linux-omap/base/0028-OMAP-DSS2-Add-DSS2-support-for-Overo.patch355
-rw-r--r--extras/recipes-kernel/linux/linux-omap/beagleboard/defconfig3361
-rw-r--r--extras/recipes-kernel/linux/linux-omap/beagleboard/logo_linux_clut224.ppm73147
-rw-r--r--extras/recipes-kernel/linux/linux-omap/dvfs/0001-OMAP3-PM-Adding-T2-enabling-of-smartreflex.patch60
-rw-r--r--extras/recipes-kernel/linux/linux-omap/dvfs/0002-OMAP-CPUfreq-ensure-driver-initializes-after-cpufreq.patch27
-rw-r--r--extras/recipes-kernel/linux/linux-omap/dvfs/0003-OMAP-CPUfreq-ensure-policy-is-fully-initialized.patch31
-rw-r--r--extras/recipes-kernel/linux/linux-omap/dvfs/0004-OMAP3-PM-CPUFreq-driver-for-OMAP3.patch269
-rw-r--r--extras/recipes-kernel/linux/linux-omap/dvfs/0005-OMAP-PM-CPUFREQ-Fix-conditional-compilation.patch32
-rw-r--r--extras/recipes-kernel/linux/linux-omap/dvfs/0006-OMAP-Introduce-a-user-list-for-each-voltage-domain-i.patch199
-rw-r--r--extras/recipes-kernel/linux/linux-omap/dvfs/0007-OMAP-Introduce-API-in-the-OPP-layer-to-find-the-opp-.patch82
-rw-r--r--extras/recipes-kernel/linux/linux-omap/dvfs/0008-OMAP-Introduce-API-to-register-a-device-with-a-volta.patch182
-rw-r--r--extras/recipes-kernel/linux/linux-omap/dvfs/0009-OMAP-Introduce-device-specific-set-rate-and-get-rate.patch120
-rw-r--r--extras/recipes-kernel/linux/linux-omap/dvfs/0010-OMAP-Voltage-layer-changes-to-support-DVFS.patch134
-rw-r--r--extras/recipes-kernel/linux/linux-omap/dvfs/0011-OMAP-Introduce-dependent-voltage-domain-support.patch195
-rw-r--r--extras/recipes-kernel/linux/linux-omap/dvfs/0012-OMAP-Introduce-device-scale.patch134
-rw-r--r--extras/recipes-kernel/linux/linux-omap/dvfs/0013-OMAP-Disable-smartreflex-across-DVFS.patch50
-rw-r--r--extras/recipes-kernel/linux/linux-omap/dvfs/0014-OMAP3-Introduce-custom-set-rate-and-get-rate-APIs-fo.patch176
-rw-r--r--extras/recipes-kernel/linux/linux-omap/dvfs/0015-OMAP3-Update-cpufreq-driver-to-use-the-new-set_rate-.patch54
-rw-r--r--extras/recipes-kernel/linux/linux-omap/dvfs/0016-OMAP3-Introduce-voltage-domain-info-in-the-hwmod-str.patch45
-rw-r--r--extras/recipes-kernel/linux/linux-omap/dvfs/0017-OMAP3-Add-voltage-dependency-table-for-VDD1.patch61
-rw-r--r--extras/recipes-kernel/linux/linux-omap/dvfs/0018-omap3-4-opp-make-omapx_opp_init-non-static.patch62
-rw-r--r--extras/recipes-kernel/linux/linux-omap/dvfs/0019-OMAP3-beagle-xm-enable-upto-1GHz-OPP.patch107
-rw-r--r--extras/recipes-kernel/linux/linux-omap/dvfs/0020-omap3-Add-basic-support-for-720MHz-part.patch202
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0001-ARM-pxa-PXA_ESERIES-depends-on-FB_W100.patch29
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0002-ARM-smp-avoid-incrementing-mm_users-on-CPU-startup.patch32
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0003-ARM-get-rid-of-kmap_high_l1_vipt.patch186
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0004-ARM-fix-cache-xsc3l2-after-stack-based-kmap_atomic.patch189
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0005-ARM-fix-cache-feroceon-l2-after-stack-based-kmap_ato.patch119
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0006-drm-i915-Set-the-required-VFMUNIT-clock-gating-disab.patch45
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0007-drm-i915-sdvo-Add-hdmi-connector-properties-after-in.patch38
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0008-drm-i915-intel_ips-When-i915-loads-after-IPS-make-IP.patch190
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0009-drm-i915-Verify-Ironlake-eDP-presence-on-DP_A-using-.patch69
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0010-ARM-6536-1-Add-missing-SZ_-32-64-128.patch42
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0011-ARM-6537-1-update-Nomadik-U300-and-Ux500-maintainers.patch65
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0012-ARM-6540-1-Stop-irqsoff-trace-on-return-to-user.patch44
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0013-ueagle-atm-fix-PHY-signal-initialization-race.patch100
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0014-ehea-Avoid-changing-vlan-flags.patch34
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0015-ppp-allow-disabling-multilink-protocol-ID-compressio.patch64
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0016-skfp-testing-the-wrong-variable-in-skfp_driver_init.patch31
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0017-ASoC-codecs-Add-missing-control_type-initialization.patch84
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0018-ASoC-codecs-max98088-Fix-register-cache-incoherency.patch72
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0019-ASoC-codecs-wm8523-Fix-register-cache-incoherency.patch74
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0020-ASoC-codecs-wm8741-Fix-register-cache-incoherency.patch61
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0021-ASoC-codecs-wm8904-Fix-register-cache-incoherency.patch131
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0022-ASoC-codecs-wm8955-Fix-register-cache-incoherency.patch107
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0023-ASoC-codecs-wm8962-Fix-register-cache-incoherency.patch151
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0024-ASoC-codecs-wm9090-Fix-register-cache-incoherency.patch75
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0025-ASoC-codecs-wm8753-Fix-register-cache-incoherency.patch514
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0026-KVM-MMU-Fix-incorrect-direct-gfn-for-unpaged-mode-sh.patch35
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0027-fix-freeing-user_struct-in-user-cache.patch34
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0028-spi-omap2_mcspi.c-Force-CS-to-be-in-inactive-state-a.patch111
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0029-kconfig-fix-undesirable-side-effect-of-adding-visibl.patch49
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0030-spi-m68knommu-Coldfire-QSPI-platform-support.patch33
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0031-sound-Prevent-buffer-overflow-in-OSS-load_mixer_volu.patch47
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0032-ALSA-hda-Use-LPIB-quirk-for-Dell-Inspiron-m101z-1120.patch32
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0033-Revert-drm-i915-bios-Reverse-order-of-100-120-Mhz-SS.patch33
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0034-drm-i915-dvo-Report-LVDS-attached-to-ch701x-as-conne.patch30
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0035-update-Documentation-filesystems-Locking.patch402
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0036-memcg-fix-wrong-VM_BUG_ON-in-try_charge-s-mm-owner-c.patch63
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0037-Revert-Staging-zram-work-around-oops-due-to-startup-.patch54
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0038-CAN-Use-inode-instead-of-kernel-address-for-proc-fil.patch43
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0039-ISDN-Gigaset-Fix-memory-leak-in-do_disconnect_req.patch56
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0040-Broadcom-CNIC-core-network-driver-fix-mem-leak-on-al.patch58
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0041-tg3-fix-return-value-check-in-tg3_read_vpd.patch35
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0042-starfire-Fix-dma_addr_t-size-test-for-MIPS.patch37
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0043-drivers-atm-atmtcp.c-add-missing-atm_dev_put.patch50
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0044-KVM-i8259-initialize-isr_ack.patch32
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0045-hwmon-s3c-hwmon-Fix-compilation.patch37
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0046-watchdog-Improve-initialisation-error-message-and-do.patch58
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0047-ARM-6605-1-Add-missing-include-asm-memory.h.patch42
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0048-mv_xor-fix-race-in-tasklet-function.patch31
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0049-dmaengine-provide-dummy-functions-for-DMA_ENGINE-n.patch55
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0050-cx25840-Prevent-device-probe-failure-due-to-volume-c.patch52
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0051-wm8775-Revert-changeset-fcb9757333-to-avoid-a-regres.patch518
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0052-em28xx-radio_fops-should-also-use-unlocked_ioctl.patch31
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0053-arch-x86-oprofile-op_model_amd.c-Perform-initialisat.patch81
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0054-perf-Fix-callchain-hit-bad-cast-on-ascii-display.patch39
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0055-ARM-it8152-add-IT8152_LAST_IRQ-definition-to-fix-bui.patch40
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0056-ARM-pxa-fix-page-table-corruption-on-resume.patch46
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0057-atl1-fix-oops-when-changing-tx-rx-ring-params.patch63
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0058-bridge-fix-br_multicast_ipv6_rcv-for-paged-skbs.patch157
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0059-name_to_dev_t-must-not-call-__init-code.patch31
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0060-bridge-stp-ensure-mac-header-is-set.patch38
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0061-ima-fix-add-LSM-rule-bug.patch64
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0062-arch-mn10300-kernel-irq.c-fix-build.patch31
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0063-remove-trim_fs-method-from-Documentation-filesystems.patch38
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0064-ipv4-route.c-respect-prefsrc-for-local-routes.patch57
-rw-r--r--extras/recipes-kernel/linux/linux-omap/linus/0065-Linux-2.6.37.patch25
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0001-v4l-Share-code-between-video_usercopy-and-video_ioct.patch297
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0002-v4l-subdev-Don-t-require-core-operations.patch31
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0003-v4l-subdev-Merge-v4l2_i2c_new_subdev_cfg-and-v4l2_i2.patch132
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0004-v4l-subdev-Add-device-node-support.patch615
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0005-v4l-subdev-Uninline-the-v4l2_subdev_init-function.patch103
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0006-v4l-subdev-Control-ioctls-support.patch88
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0007-v4l-subdev-Events-support.patch223
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0008-media-Media-device-node-support.patch500
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0009-media-Media-device.patch398
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0010-media-Entities-pads-and-links.patch690
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0011-media-Entity-graph-traversal.patch228
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0012-media-Entity-use-count.patch176
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0013-media-Media-device-information-query.patch659
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0014-media-Entities-pads-and-links-enumeration.patch889
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0015-media-Links-setup.patch517
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0016-media-Pipelines-and-media-streams.patch259
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0017-v4l-Add-a-media_device-pointer-to-the-v4l2_device-st.patch115
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0018-v4l-Make-video_device-inherit-from-media_entity.patch234
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0019-v4l-Make-v4l2_subdev-inherit-from-media_entity.patch265
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0020-v4l-Move-the-media-v4l2-mediabus.h-header-to-include.patch205
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0021-v4l-Replace-enums-with-fixed-sized-fields-in-public-.patch50
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0022-v4l-Rename-V4L2_MBUS_FMT_GREY8_1X8-to-V4L2_MBUS_FMT_.patch154
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0023-v4l-Group-media-bus-pixel-codes-by-types-and-sort-th.patch112
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0024-v4l-Create-v4l2-subdev-file-handle-structure.patch243
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0025-v4l-subdev-Add-a-new-file-operations-class.patch93
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0026-v4l-v4l2_subdev-pad-level-operations.patch49
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0028-v4l-v4l2_subdev-userspace-format-API.patch3546
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0029-v4l-v4l2_subdev-userspace-frame-interval-API.patch479
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0030-v4l-v4l2_subdev-userspace-crop-API.patch350
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0031-v4l-subdev-Generic-ioctl-support.patch46
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0032-v4l-Add-subdev-sensor-g_skip_frames-operation.patch35
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0033-v4l-Include-linux-videodev2.h-in-media-v4l2-ctrls.h.patch27
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0034-v4l-Fix-a-use-before-set-in-the-control-framework.patch32
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0035-v4l-Add-8-bit-YUYV-on-16-bit-bus-and-SGRBG10-media-b.patch60
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0036-v4l-Add-remaining-RAW10-patterns-w-DPCM-pixel-code-v.patch48
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0037-v4l-Add-missing-12-bits-bayer-media-bus-formats.patch105
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0038-v4l-Add-12-bits-bayer-pixel-formats.patch35
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0039-ARM-OMAP3-Update-Camera-ISP-definitions-for-OMAP3630.patch99
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0040-omap3-Remove-unusued-ISP-CBUFF-resource.patch32
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0041-omap3-Add-function-to-register-omap3isp-platform-dev.patch91
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0042-omap2-Fix-camera-resources-for-multiomap.patch70
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0043-OMAP3-ISP-driver.patch21513
-rw-r--r--extras/recipes-kernel/linux/linux-omap/new/0001-OMAP-Enable-Magic-SysRq-on-serial-console-ttyOx.patch35
l---------extras/recipes-kernel/linux/linux-omap/omap3-touchbook/defconfig1
l---------extras/recipes-kernel/linux/linux-omap/omap3evm/defconfig1
l---------extras/recipes-kernel/linux/linux-omap/overo/defconfig1
l---------extras/recipes-kernel/linux/linux-omap/usrp-e1xx/defconfig1
-rw-r--r--extras/recipes-kernel/linux/linux-omap/usrp/0001-Add-defines-to-set-config-options-in-GPMC-per-CS-con.patch80
-rw-r--r--extras/recipes-kernel/linux/linux-omap/usrp/0002-Add-functions-to-dma.c-to-set-address-and-length-for.patch83
-rw-r--r--extras/recipes-kernel/linux/linux-omap/usrp/0003-usrp-embedded-Add-driver-for-USRP-Embedded-FPGA-inte.patch1889
-rw-r--r--extras/recipes-kernel/linux/linux-omap/wl1271/0001-wl12xx-Read-MAC-address-from-NVS-file-on-HW-startup.patch41
-rw-r--r--extras/recipes-kernel/linux/linux-omap/wl1271/0002-wl1271-11n-Support-Add-Definitions.patch165
-rw-r--r--extras/recipes-kernel/linux/linux-omap/wl1271/0003-wl1271-11n-Support-ACX-Commands.patch128
-rw-r--r--extras/recipes-kernel/linux/linux-omap/wl1271/0004-wl1271-11n-Support-functionality-and-configuration-a.patch249
-rw-r--r--extras/recipes-kernel/linux/linux-omap/wl1271/0005-wl1271-set-wl-vif-only-if-add_interface-succeeded.patch86
-rw-r--r--extras/recipes-kernel/linux/linux-omap/wl1271/0006-wl12xx-Unset-bssid-filter-ssid-and-bssid-from-firmwa.patch44
-rw-r--r--extras/recipes-kernel/linux/linux-omap/wl1271/0007-drivers-media-radio-wl128x-FM-Driver-common-header-f.patch268
-rw-r--r--extras/recipes-kernel/linux/linux-omap/wl1271/0008-drivers-media-radio-wl128x-FM-Driver-V4L2-sources.patch645
-rw-r--r--extras/recipes-kernel/linux/linux-omap/wl1271/0009-drivers-media-radio-wl128x-FM-Driver-Common-sources.patch2114
-rw-r--r--extras/recipes-kernel/linux/linux-omap/wl1271/0010-drivers-media-radio-wl128x-FM-driver-RX-sources.patch938
-rw-r--r--extras/recipes-kernel/linux/linux-omap/wl1271/0011-drivers-media-radio-wl128x-FM-driver-TX-sources.patch494
-rw-r--r--extras/recipes-kernel/linux/linux-omap/wl1271/0012-drivers-media-radio-wl128x-Kconfig-Makefile-for-wl12.patch52
-rw-r--r--extras/recipes-kernel/linux/linux-omap/wl1271/0013-drivers-media-radio-Update-Kconfig-and-Makefile-for-.patch38
-rw-r--r--extras/recipes-kernel/linux/linux-omap/wl1271/0014-drivers-misc-ti-st-change-protocol-parse-logic.patch900
-rw-r--r--extras/recipes-kernel/linux/linux-omap/wl1271/0015-Bluetooth-btwilink-driver.patch463
186 files changed, 130370 insertions, 0 deletions
diff --git a/extras/recipes-kernel/linux/linux-omap/0001-BeagleBoard-Adjust-USER-button-pin-for-xM.patch b/extras/recipes-kernel/linux/linux-omap/0001-BeagleBoard-Adjust-USER-button-pin-for-xM.patch
new file mode 100644
index 00000000..44397d4a
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/0001-BeagleBoard-Adjust-USER-button-pin-for-xM.patch
@@ -0,0 +1,29 @@
+From 3b1dc08ab568d1fdbc2a3731d7643cfeb48023e8 Mon Sep 17 00:00:00 2001
+From: Koen Kooi <koen@dominion.thruhere.net>
+Date: Thu, 10 Mar 2011 14:16:08 +0100
+Subject: [PATCH] BeagleBoard: Adjust USER button pin for xM
+
+Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c | 5 +++++
+ 1 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 731f4b5..fae3104 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -949,6 +949,11 @@ static void __init omap3_beagle_init(void)
+ omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+ omap3_beagle_init_rev();
+ omap3_beagle_i2c_init();
++
++ if (cpu_is_omap3630()) {
++ gpio_buttons[0].gpio = 4;
++ }
++
+ platform_add_devices(omap3_beagle_devices,
+ ARRAY_SIZE(omap3_beagle_devices));
+ omap_serial_init();
+--
+1.7.0
+
diff --git a/extras/recipes-kernel/linux/linux-omap/0001-beagleboard-hack-in-support-from-xM-rev-C.patch b/extras/recipes-kernel/linux/linux-omap/0001-beagleboard-hack-in-support-from-xM-rev-C.patch
new file mode 100644
index 00000000..77c29281
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/0001-beagleboard-hack-in-support-from-xM-rev-C.patch
@@ -0,0 +1,94 @@
+From d9c289c5f98bb109aa7a9e5a802638ba89639e70 Mon Sep 17 00:00:00 2001
+From: Koen Kooi <koen@dominion.thruhere.net>
+Date: Thu, 10 Mar 2011 13:15:38 +0100
+Subject: [PATCH] beagleboard: hack in support from xM rev C
+
+Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c | 20 +++++++++++++-------
+ 1 files changed, 13 insertions(+), 7 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 6abb79a..731f4b5 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -64,6 +64,7 @@
+ * C4 = GPIO173, GPIO172, GPIO171: 1 0 1
+ * XMA = GPIO173, GPIO172, GPIO171: 0 0 0
+ * XMB = GPIO173, GPIO172, GPIO171: 0 0 1
++ * XMC = GPIO173, GPIO172, GPIO171: 0 1 0
+ */
+ enum {
+ OMAP3BEAGLE_BOARD_UNKN = 0,
+@@ -71,6 +72,7 @@ enum {
+ OMAP3BEAGLE_BOARD_C1_3,
+ OMAP3BEAGLE_BOARD_C4,
+ OMAP3BEAGLE_BOARD_XM,
++ OMAP3BEAGLE_BOARD_XMC,
+ };
+
+ static u8 omap3_beagle_version;
+@@ -129,9 +131,13 @@ static void __init omap3_beagle_init_rev(void)
+ printk(KERN_INFO "OMAP3 Beagle Rev: xM B\n");
+ omap3_beagle_version = OMAP3BEAGLE_BOARD_XM;
+ break;
++ case 2:
++ printk(KERN_INFO "OMAP3 Beagle Rev: xM C\n");
++ omap3_beagle_version = OMAP3BEAGLE_BOARD_XMC;
++ break;
+ default:
+- printk(KERN_INFO "OMAP3 Beagle Rev: unknown %hd\n", beagle_rev);
+- omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN;
++ printk(KERN_INFO "OMAP3 Beagle Rev: unknown %hd, assuming xM C or newer\n", beagle_rev);
++ omap3_beagle_version = OMAP3BEAGLE_BOARD_XMC;
+ }
+
+ return;
+@@ -484,7 +490,7 @@ static int beagle_twl_gpio_setup(struct device *dev,
+ {
+ int r;
+
+- if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
++ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM || omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XMC) {
+ mmc[0].gpio_wp = -EINVAL;
+ } else if ((omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C1_3) ||
+ (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C4)) {
+@@ -517,7 +523,7 @@ static int beagle_twl_gpio_setup(struct device *dev,
+ /* REVISIT: need ehci-omap hooks for external VBUS
+ * power switch and overcurrent detect
+ */
+- if (omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XM) {
++ if (omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XM && omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XMC) {
+ r = gpio_request(gpio + 1, "EHCI_nOC");
+ if (!r) {
+ r = gpio_direction_input(gpio + 1);
+@@ -539,7 +545,7 @@ static int beagle_twl_gpio_setup(struct device *dev,
+ gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
+
+ /* DVI reset GPIO is different between beagle revisions */
+- if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM)
++ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM || omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XMC)
+ beagle_dvi_device.reset_gpio = 129;
+ else
+ beagle_dvi_device.reset_gpio = 170;
+@@ -553,7 +559,7 @@ static int beagle_twl_gpio_setup(struct device *dev,
+ * P7/P8 revisions(prototype): Camera EN
+ * A2+ revisions (production): LDO (supplies DVI, serial, led blocks)
+ */
+- if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
++ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM || omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XMC) {
+ r = gpio_request(gpio + 1, "nDVI_PWR_EN");
+ if (!r) {
+ r = gpio_direction_output(gpio + 1, 0);
+@@ -899,7 +905,7 @@ static void __init beagle_opp_init(void)
+ }
+
+ /* Custom OPP enabled for XM */
+- if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
++ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM || omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XMC) {
+ struct omap_hwmod *mh = omap_hwmod_lookup("mpu");
+ struct omap_hwmod *dh = omap_hwmod_lookup("iva");
+ struct device *dev;
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/0001-board-omap3beagle-whitespace-cleanup.patch b/extras/recipes-kernel/linux/linux-omap/0001-board-omap3beagle-whitespace-cleanup.patch
new file mode 100644
index 00000000..69105575
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/0001-board-omap3beagle-whitespace-cleanup.patch
@@ -0,0 +1,91 @@
+From e5e52482147151aaaafbd388d1e5978268e51d24 Mon Sep 17 00:00:00 2001
+Message-Id: <e5e52482147151aaaafbd388d1e5978268e51d24.1307392642.git.dvhart@linux.intel.com>
+From: Darren Hart <dvhart@linux.intel.com>
+Date: Mon, 6 Jun 2011 10:17:56 -0700
+Subject: [PATCH 1/2] board-omap3beagle: whitespace cleanup
+
+Eliminate leading and trailing whitespace.
+Indent with tabs.
+
+Signed-off-by: Darren Hart <dvhart@linux.intel.com>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c | 28 ++++++++++++++--------------
+ 1 files changed, 14 insertions(+), 14 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index b035bb5..b618cb6 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -167,12 +167,12 @@ struct wl12xx_platform_data omap_beagle_wlan_data __initdata = {
+ .board_ref_clock = 2, /* 38.4 MHz */
+ };
+
+- static struct omap2_hsmmc_info mmcbbt[] = {
+- {
+- .mmc = 1,
+- .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+- .gpio_wp = 29,
+- },
++static struct omap2_hsmmc_info mmcbbt[] = {
++ {
++ .mmc = 1,
++ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
++ .gpio_wp = 29,
++ },
+ {
+ .name = "wl1271",
+ .mmc = 2,
+@@ -181,8 +181,8 @@ struct wl12xx_platform_data omap_beagle_wlan_data __initdata = {
+ .gpio_cd = -EINVAL,
+ .nonremovable = true,
+ },
+- {} /* Terminator */
+- };
++ {} /* Terminator */
++};
+
+ static struct regulator_consumer_supply beagle_vmmc2_supply = {
+ .supply = "vmmc",
+@@ -455,7 +455,7 @@ static int beagle_twl_gpio_setup(struct device *dev,
+ /* gpio + 0 is "mmc0_cd" (input/IRQ) */
+ mmc[0].gpio_cd = gpio + 0;
+ #if defined(CONFIG_WL1271) || defined(CONFIG_WL1271_MODULE)
+- if(!strcmp(expansionboard_name, "bbtoys-wifi")) {
++ if(!strcmp(expansionboard_name, "bbtoys-wifi")) {
+ omap2_hsmmc_init(mmcbbt);
+ /* link regulators to MMC adapters */
+ beagle_vmmc1_supply.dev = mmcbbt[0].dev;
+@@ -648,9 +648,9 @@ static struct i2c_board_info __initdata beagle_i2c1_boardinfo[] = {
+ };
+
+ static struct i2c_board_info __initdata beagle_i2c_eeprom[] = {
+- {
+- I2C_BOARD_INFO("eeprom", 0x50),
+- },
++ {
++ I2C_BOARD_INFO("eeprom", 0x50),
++ },
+ };
+
+ #if defined(CONFIG_RTC_DRV_DS1307) || \
+@@ -888,7 +888,7 @@ static void __init omap3_beagle_init(void)
+ /* REVISIT leave DVI powered down until it's needed ... */
+ gpio_direction_output(170, true);
+
+- if(!strcmp(expansionboard_name, "zippy"))
++ if(!strcmp(expansionboard_name, "zippy"))
+ {
+ printk(KERN_INFO "Beagle expansionboard: initializing enc28j60\n");
+ omap3beagle_enc28j60_init();
+@@ -897,7 +897,7 @@ static void __init omap3_beagle_init(void)
+ mmc[1].gpio_cd = 162;
+ }
+
+- if(!strcmp(expansionboard_name, "zippy2"))
++ if(!strcmp(expansionboard_name, "zippy2"))
+ {
+ printk(KERN_INFO "Beagle expansionboard: initializing ks_8851\n");
+ omap3beagle_ks8851_init();
+--
+1.7.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/0001-omap3-allow-1GHz-mpurates.patch b/extras/recipes-kernel/linux/linux-omap/0001-omap3-allow-1GHz-mpurates.patch
new file mode 100644
index 00000000..f84163cd
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/0001-omap3-allow-1GHz-mpurates.patch
@@ -0,0 +1,26 @@
+From 095749d8941257799eaf5b2509918373f1a08152 Mon Sep 17 00:00:00 2001
+From: Koen Kooi <koen@dominion.thruhere.net>
+Date: Thu, 10 Mar 2011 14:03:08 +0100
+Subject: [PATCH] omap3: allow 1GHz mpurates
+
+Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
+---
+ arch/arm/plat-omap/clock.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
+index fc62fb5..f3e3d29 100644
+--- a/arch/arm/plat-omap/clock.c
++++ b/arch/arm/plat-omap/clock.c
+@@ -181,7 +181,7 @@ static int __init omap_clk_setup(char *str)
+ if (!mpurate)
+ return 1;
+
+- if (mpurate < 1000)
++ if (mpurate < 2000)
+ mpurate *= 1000000;
+
+ return 1;
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/0001-xM-audio-fix-from-Ashok.patch b/extras/recipes-kernel/linux/linux-omap/0001-xM-audio-fix-from-Ashok.patch
new file mode 100644
index 00000000..1254c804
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/0001-xM-audio-fix-from-Ashok.patch
@@ -0,0 +1,27 @@
+From d53f988fc10fe22ec7e64457eac22f264bb72491 Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Thu, 13 Jan 2011 11:37:56 -0600
+Subject: [PATCH] xM audio fix from Ashok
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ sound/soc/omap/omap-mcbsp.c | 3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
+index 7e84f24..1038686 100644
+--- a/sound/soc/omap/omap-mcbsp.c
++++ b/sound/soc/omap/omap-mcbsp.c
+@@ -332,6 +332,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
+ } else if (cpu_is_omap343x()) {
+ dma = omap24xx_dma_reqs[bus_id][substream->stream];
+ port = omap34xx_mcbsp_port[bus_id][substream->stream];
++ } else if (cpu_is_omap3630()) {
++ dma = omap24xx_dma_reqs[bus_id][substream->stream];
++ port = omap34xx_mcbsp_port[bus_id][substream->stream];
+ } else {
+ return -ENODEV;
+ }
+--
+1.7.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/0002-board-omap3beagle-allow-for-building-without-wl1271.patch b/extras/recipes-kernel/linux/linux-omap/0002-board-omap3beagle-allow-for-building-without-wl1271.patch
new file mode 100644
index 00000000..51978e2b
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/0002-board-omap3beagle-allow-for-building-without-wl1271.patch
@@ -0,0 +1,42 @@
+From 1b9bc1583d882866d64420df39bf5df4bce22bd6 Mon Sep 17 00:00:00 2001
+Message-Id: <1b9bc1583d882866d64420df39bf5df4bce22bd6.1307392642.git.dvhart@linux.intel.com>
+In-Reply-To: <e5e52482147151aaaafbd388d1e5978268e51d24.1307392642.git.dvhart@linux.intel.com>
+References: <e5e52482147151aaaafbd388d1e5978268e51d24.1307392642.git.dvhart@linux.intel.com>
+From: Darren Hart <dvhart@linux.intel.com>
+Date: Mon, 6 Jun 2011 10:19:00 -0700
+Subject: [PATCH 2/2] board-omap3beagle: allow for building without wl1271
+
+While the header file wl12xx.h is ifdef'd to include if the wl1271 driver is
+built, the init routine calls into it regardless. Ideally, the module would
+perform its own initialization at load time and we wouldn't need to ifdef these
+calls in the general board initialization. For now, follow the existing practice
+in this file and ifdef the wl1271 init block.
+
+Signed-off-by: Darren Hart <dvhart@linux.intel.com>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index b618cb6..caaed82 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -937,6 +937,7 @@ static void __init omap3_beagle_init(void)
+ gpio_export(162, 1);
+ }
+
++#if defined(CONFIG_WL1271) || defined(CONFIG_WL1271_MODULE)
+ if(!strcmp(expansionboard_name, "bbtoys-wifi"))
+ {
+ if (wl12xx_set_platform_data(&omap_beagle_wlan_data))
+@@ -944,6 +945,7 @@ static void __init omap3_beagle_init(void)
+ printk(KERN_INFO "Beagle expansionboard: registering wl12xx platform device\n");
+ platform_device_register(&omap_vwlan_device);
+ }
++#endif
+
+ usb_musb_init(&musb_board_data);
+ usb_ehci_init(&ehci_pdata);
+--
+1.7.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0001-omap3-beaglexm-fix-EHCI-power-up-GPIO-dir.patch b/extras/recipes-kernel/linux/linux-omap/base/0001-omap3-beaglexm-fix-EHCI-power-up-GPIO-dir.patch
new file mode 100644
index 00000000..42bfa4e2
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0001-omap3-beaglexm-fix-EHCI-power-up-GPIO-dir.patch
@@ -0,0 +1,44 @@
+From 3d2f0e2f29320d9c6a6e4d8d5aeff9127a2106cb Mon Sep 17 00:00:00 2001
+From: Koen Kooi <koen@beagleboard.org>
+Date: Tue, 11 Jan 2011 17:13:35 +0000
+Subject: [PATCH 01/28] omap3: beaglexm: fix EHCI power up GPIO dir
+
+EHCI enable power pin is inverted (active high) in comparison
+to vanilla beagle which is active low. Handle this case conditionally.
+
+Without this fix, Beagle XM 4 port EHCI will not function and no
+networking will be available
+
+[nm@ti.com: split up, added descriptive changelogs]
+Signed-off-by: Nishanth Menon <nm@ti.com>
+Signed-off-by: Koen Kooi <koen@beagleboard.org>
+Signed-off-by: Tony Lindgren <tony@atomide.com>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c | 10 ++++++++--
+ 1 files changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 6c12760..af1166b 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -297,9 +297,15 @@ static int beagle_twl_gpio_setup(struct device *dev,
+ gpio_request(gpio + 1, "EHCI_nOC");
+ gpio_direction_input(gpio + 1);
+
+- /* TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, active low) */
++ /*
++ * TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, XM active
++ * high / others active low)
++ */
+ gpio_request(gpio + TWL4030_GPIO_MAX, "nEN_USB_PWR");
+- gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
++ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM)
++ gpio_direction_output(gpio + TWL4030_GPIO_MAX, 1);
++ else
++ gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
+
+ /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
+ gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0002-omap3-beaglexm-fix-DVI-reset-GPIO.patch b/extras/recipes-kernel/linux/linux-omap/base/0002-omap3-beaglexm-fix-DVI-reset-GPIO.patch
new file mode 100644
index 00000000..1808a861
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0002-omap3-beaglexm-fix-DVI-reset-GPIO.patch
@@ -0,0 +1,48 @@
+From e1dd1afba99853083da545f632a1f7c6899ae379 Mon Sep 17 00:00:00 2001
+From: Koen Kooi <koen@beagleboard.org>
+Date: Tue, 11 Jan 2011 17:13:36 +0000
+Subject: [PATCH 02/28] omap3: beaglexm: fix DVI reset GPIO
+
+GPIO reset line for Beagle XM is different from vanilla beagle
+so we populate it as part of gpio update routine.
+
+This in part fixes the issue of display not functioning on beagle XM
+platform.
+
+[nm@ti.com: split up, added descriptive changelogs]
+Signed-off-by: Nishanth Menon <nm@ti.com>
+Signed-off-by: Koen Kooi <koen@beagleboard.org>
+Signed-off-by: Tony Lindgren <tony@atomide.com>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c | 8 +++++++-
+ 1 files changed, 7 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index af1166b..673deb9 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -199,7 +199,7 @@ static struct omap_dss_device beagle_dvi_device = {
+ .name = "dvi",
+ .driver_name = "generic_panel",
+ .phy.dpi.data_lines = 24,
+- .reset_gpio = 170,
++ .reset_gpio = -EINVAL,
+ .platform_enable = beagle_enable_dvi,
+ .platform_disable = beagle_disable_dvi,
+ };
+@@ -307,6 +307,12 @@ static int beagle_twl_gpio_setup(struct device *dev,
+ else
+ gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
+
++ /* DVI reset GPIO is different between beagle revisions */
++ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM)
++ beagle_dvi_device.reset_gpio = 129;
++ else
++ beagle_dvi_device.reset_gpio = 170;
++
+ /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
+ gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0003-omap3-beaglexm-fix-power-on-of-DVI.patch b/extras/recipes-kernel/linux/linux-omap/base/0003-omap3-beaglexm-fix-power-on-of-DVI.patch
new file mode 100644
index 00000000..90446e40
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0003-omap3-beaglexm-fix-power-on-of-DVI.patch
@@ -0,0 +1,94 @@
+From 4004c3e68b973f4cb736048b1e90ee3b511f5865 Mon Sep 17 00:00:00 2001
+From: Koen Kooi <koen@beagleboard.org>
+Date: Wed, 12 Jan 2011 00:23:29 +0000
+Subject: [PATCH 03/28] omap3: beaglexm: fix power on of DVI
+
+TFP410 DVI chip is used to provide display out.
+This chip is controlled by 2 lines:
+LDO which supplies the power is controlled over gpio + 2
+and the enable of the chip itself is done over gpio + 1
+NOTE: the LDO is necessary for LED, serial blocks as well.
+
+gpio + 1 was used to sense USB overcurrent in vanilla beagle.
+
+Without this fix, the display would not function as the LDO
+remains shut down.
+
+[nm@ti.com: split up, added descriptive changelogs]
+Signed-off-by: Nishanth Menon <nm@ti.com>
+Signed-off-by: Koen Kooi <koen@beagleboard.org>
+Signed-off-by: Tony Lindgren <tony@atomide.com>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c | 42 ++++++++++++++++++++++++++++--
+ 1 files changed, 39 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 673deb9..2ed8040 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -273,6 +273,8 @@ static struct gpio_led gpio_leds[];
+ static int beagle_twl_gpio_setup(struct device *dev,
+ unsigned gpio, unsigned ngpio)
+ {
++ int r;
++
+ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
+ mmc[0].gpio_wp = -EINVAL;
+ } else if ((omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C1_3) ||
+@@ -293,9 +295,16 @@ static int beagle_twl_gpio_setup(struct device *dev,
+ /* REVISIT: need ehci-omap hooks for external VBUS
+ * power switch and overcurrent detect
+ */
+-
+- gpio_request(gpio + 1, "EHCI_nOC");
+- gpio_direction_input(gpio + 1);
++ if (omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XM) {
++ r = gpio_request(gpio + 1, "EHCI_nOC");
++ if (!r) {
++ r = gpio_direction_input(gpio + 1);
++ if (r)
++ gpio_free(gpio + 1);
++ }
++ if (r)
++ pr_err("%s: unable to configure EHCI_nOC\n", __func__);
++ }
+
+ /*
+ * TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, XM active
+@@ -316,6 +325,33 @@ static int beagle_twl_gpio_setup(struct device *dev,
+ /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
+ gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
+
++ /*
++ * gpio + 1 on Xm controls the TFP410's enable line (active low)
++ * gpio + 2 control varies depending on the board rev as follows:
++ * P7/P8 revisions(prototype): Camera EN
++ * A2+ revisions (production): LDO (supplies DVI, serial, led blocks)
++ */
++ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
++ r = gpio_request(gpio + 1, "nDVI_PWR_EN");
++ if (!r) {
++ r = gpio_direction_output(gpio + 1, 0);
++ if (r)
++ gpio_free(gpio + 1);
++ }
++ if (r)
++ pr_err("%s: unable to configure nDVI_PWR_EN\n",
++ __func__);
++ r = gpio_request(gpio + 2, "DVI_LDO_EN");
++ if (!r) {
++ r = gpio_direction_output(gpio + 2, 1);
++ if (r)
++ gpio_free(gpio + 2);
++ }
++ if (r)
++ pr_err("%s: unable to configure DVI_LDO_EN\n",
++ __func__);
++ }
++
+ return 0;
+ }
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0004-omap-Beagle-detect-new-xM-revision-B.patch b/extras/recipes-kernel/linux/linux-omap/base/0004-omap-Beagle-detect-new-xM-revision-B.patch
new file mode 100644
index 00000000..43371618
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0004-omap-Beagle-detect-new-xM-revision-B.patch
@@ -0,0 +1,43 @@
+From 24b7a742b27ed2c05c6bc7800b0299a77af37a82 Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Tue, 9 Nov 2010 08:34:55 -0600
+Subject: [PATCH 04/28] omap: Beagle: detect new xM revision B
+
+The xM B uses a DM3730 ES1.1 over the ES1.0 on xM A's, no other board changes.
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+Signed-off-by: Koen Kooi <koen@beagleboard.org>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c | 9 +++++++--
+ 1 files changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 2ed8040..f9fb64b 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -58,7 +58,8 @@
+ * AXBX = GPIO173, GPIO172, GPIO171: 1 1 1
+ * C1_3 = GPIO173, GPIO172, GPIO171: 1 1 0
+ * C4 = GPIO173, GPIO172, GPIO171: 1 0 1
+- * XM = GPIO173, GPIO172, GPIO171: 0 0 0
++ * XMA = GPIO173, GPIO172, GPIO171: 0 0 0
++ * XMB = GPIO173, GPIO172, GPIO171: 0 0 1
+ */
+ enum {
+ OMAP3BEAGLE_BOARD_UNKN = 0,
+@@ -117,7 +118,11 @@ static void __init omap3_beagle_init_rev(void)
+ omap3_beagle_version = OMAP3BEAGLE_BOARD_C4;
+ break;
+ case 0:
+- printk(KERN_INFO "OMAP3 Beagle Rev: xM\n");
++ printk(KERN_INFO "OMAP3 Beagle Rev: xM A\n");
++ omap3_beagle_version = OMAP3BEAGLE_BOARD_XM;
++ break;
++ case 1:
++ printk(KERN_INFO "OMAP3 Beagle Rev: xM B\n");
+ omap3_beagle_version = OMAP3BEAGLE_BOARD_XM;
+ break;
+ default:
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0005-ARM-OMAP-beagleboard-Add-infrastructure-to-do-fixups.patch b/extras/recipes-kernel/linux/linux-omap/base/0005-ARM-OMAP-beagleboard-Add-infrastructure-to-do-fixups.patch
new file mode 100644
index 00000000..21d8d8fe
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0005-ARM-OMAP-beagleboard-Add-infrastructure-to-do-fixups.patch
@@ -0,0 +1,219 @@
+From a564ca287c115928a9e7febf7c99bbab582290e6 Mon Sep 17 00:00:00 2001
+From: Koen Kooi <koen@dominion.thruhere.net>
+Date: Wed, 6 Oct 2010 10:19:34 +0200
+Subject: [PATCH 05/28] ARM: OMAP: beagleboard: Add infrastructure to do fixups based on expansionboard name passed by u-boot
+
+Add support for Tincantools Zippy and Zippy2 expansionboards as well
+
+Signed-off-by: Koen Kooi <koen@beagleboard.org>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c | 142 ++++++++++++++++++++++++++++++-
+ 1 files changed, 139 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index f9fb64b..d777b3b 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -21,6 +21,7 @@
+ #include <linux/io.h>
+ #include <linux/leds.h>
+ #include <linux/gpio.h>
++#include <linux/irq.h>
+ #include <linux/input.h>
+ #include <linux/gpio_keys.h>
+
+@@ -143,6 +144,92 @@ fail0:
+ return;
+ }
+
++char expansionboard_name[16];
++
++#if defined(CONFIG_ENC28J60) || defined(CONFIG_ENC28J60_MODULE)
++
++#include <plat/mcspi.h>
++#include <linux/spi/spi.h>
++
++#define OMAP3BEAGLE_GPIO_ENC28J60_IRQ 157
++
++static struct omap2_mcspi_device_config enc28j60_spi_chip_info = {
++ .turbo_mode = 0,
++ .single_channel = 1, /* 0: slave, 1: master */
++};
++
++static struct spi_board_info omap3beagle_zippy_spi_board_info[] __initdata = {
++ {
++ .modalias = "enc28j60",
++ .bus_num = 4,
++ .chip_select = 0,
++ .max_speed_hz = 20000000,
++ .controller_data = &enc28j60_spi_chip_info,
++ },
++};
++
++static void __init omap3beagle_enc28j60_init(void)
++{
++ if ((gpio_request(OMAP3BEAGLE_GPIO_ENC28J60_IRQ, "ENC28J60_IRQ") == 0) &&
++ (gpio_direction_input(OMAP3BEAGLE_GPIO_ENC28J60_IRQ) == 0)) {
++ gpio_export(OMAP3BEAGLE_GPIO_ENC28J60_IRQ, 0);
++ omap3beagle_zippy_spi_board_info[0].irq = OMAP_GPIO_IRQ(OMAP3BEAGLE_GPIO_ENC28J60_IRQ);
++ set_irq_type(omap3beagle_zippy_spi_board_info[0].irq, IRQ_TYPE_EDGE_FALLING);
++ } else {
++ printk(KERN_ERR "could not obtain gpio for ENC28J60_IRQ\n");
++ return;
++ }
++
++ spi_register_board_info(omap3beagle_zippy_spi_board_info,
++ ARRAY_SIZE(omap3beagle_zippy_spi_board_info));
++}
++
++#else
++static inline void __init omap3beagle_enc28j60_init(void) { return; }
++#endif
++
++#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
++
++#include <plat/mcspi.h>
++#include <linux/spi/spi.h>
++
++#define OMAP3BEAGLE_GPIO_KS8851_IRQ 157
++
++static struct omap2_mcspi_device_config ks8851_spi_chip_info = {
++ .turbo_mode = 0,
++ .single_channel = 1, /* 0: slave, 1: master */
++};
++
++static struct spi_board_info omap3beagle_zippy2_spi_board_info[] __initdata = {
++ {
++ .modalias = "ks8851",
++ .bus_num = 4,
++ .chip_select = 0,
++ .max_speed_hz = 36000000,
++ .controller_data = &ks8851_spi_chip_info,
++ },
++};
++
++static void __init omap3beagle_ks8851_init(void)
++{
++ if ((gpio_request(OMAP3BEAGLE_GPIO_KS8851_IRQ, "KS8851_IRQ") == 0) &&
++ (gpio_direction_input(OMAP3BEAGLE_GPIO_KS8851_IRQ) == 0)) {
++ gpio_export(OMAP3BEAGLE_GPIO_KS8851_IRQ, 0);
++ omap3beagle_zippy2_spi_board_info[0].irq = OMAP_GPIO_IRQ(OMAP3BEAGLE_GPIO_KS8851_IRQ);
++ set_irq_type(omap3beagle_zippy2_spi_board_info[0].irq, IRQ_TYPE_EDGE_FALLING);
++ } else {
++ printk(KERN_ERR "could not obtain gpio for KS8851_IRQ\n");
++ return;
++ }
++
++ spi_register_board_info(omap3beagle_zippy2_spi_board_info,
++ ARRAY_SIZE(omap3beagle_zippy2_spi_board_info));
++}
++
++#else
++static inline void __init omap3beagle_ks8851_init(void) { return; }
++#endif
++
+ static struct mtd_partition omap3beagle_nand_partitions[] = {
+ /* All the partition sizes are listed in terms of NAND block size */
+ {
+@@ -262,6 +349,12 @@ static struct omap2_hsmmc_info mmc[] = {
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+ .gpio_wp = 29,
+ },
++ {
++ .mmc = 2,
++ .caps = MMC_CAP_4_BIT_DATA,
++ .transceiver = true,
++ .ocr_mask = 0x00100000, /* 3.3V */
++ },
+ {} /* Terminator */
+ };
+
+@@ -457,7 +550,7 @@ static struct twl4030_platform_data beagle_twldata = {
+ .vpll2 = &beagle_vpll2,
+ };
+
+-static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = {
++static struct i2c_board_info __initdata beagle_i2c1_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("twl4030", 0x48),
+ .flags = I2C_CLIENT_WAKE,
+@@ -472,10 +565,24 @@ static struct i2c_board_info __initdata beagle_i2c_eeprom[] = {
+ },
+ };
+
++#if defined(CONFIG_RTC_DRV_DS1307) || \
++ defined(CONFIG_RTC_DRV_DS1307_MODULE)
++
++static struct i2c_board_info __initdata beagle_i2c2_boardinfo[] = {
++ {
++ I2C_BOARD_INFO("ds1307", 0x68),
++ },
++};
++#else
++static struct i2c_board_info __initdata beagle_i2c2_boardinfo[] = {};
++#endif
++
+ static int __init omap3_beagle_i2c_init(void)
+ {
+- omap_register_i2c_bus(1, 2600, beagle_i2c_boardinfo,
+- ARRAY_SIZE(beagle_i2c_boardinfo));
++ omap_register_i2c_bus(1, 2600, beagle_i2c1_boardinfo,
++ ARRAY_SIZE(beagle_i2c1_boardinfo));
++ omap_register_i2c_bus(2, 400, beagle_i2c2_boardinfo,
++ ARRAY_SIZE(beagle_i2c2_boardinfo));
+ /* Bus 3 is attached to the DVI port where devices like the pico DLP
+ * projector don't work reliably with 400kHz */
+ omap_register_i2c_bus(3, 100, beagle_i2c_eeprom, ARRAY_SIZE(beagle_i2c_eeprom));
+@@ -609,6 +716,15 @@ static struct omap_musb_board_data musb_board_data = {
+ .power = 100,
+ };
+
++static int __init expansionboard_setup(char *str)
++{
++ if (!str)
++ return -EINVAL;
++ strncpy(expansionboard_name, str, 16);
++ printk(KERN_INFO "Beagle expansionboard: %s\n", expansionboard_name);
++ return 0;
++}
++
+ static void __init omap3_beagle_init(void)
+ {
+ omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+@@ -623,6 +739,24 @@ static void __init omap3_beagle_init(void)
+ /* REVISIT leave DVI powered down until it's needed ... */
+ gpio_direction_output(170, true);
+
++ if(!strcmp(expansionboard_name, "zippy"))
++ {
++ printk(KERN_INFO "Beagle expansionboard: initializing enc28j60\n");
++ omap3beagle_enc28j60_init();
++ printk(KERN_INFO "Beagle expansionboard: assigning GPIO 141 and 162 to MMC1\n");
++ mmc[1].gpio_wp = 141;
++ mmc[1].gpio_cd = 162;
++ }
++
++ if(!strcmp(expansionboard_name, "zippy2"))
++ {
++ printk(KERN_INFO "Beagle expansionboard: initializing ks_8851\n");
++ omap3beagle_ks8851_init();
++ printk(KERN_INFO "Beagle expansionboard: assigning GPIO 141 and 162 to MMC1\n");
++ mmc[1].gpio_wp = 141;
++ mmc[1].gpio_cd = 162;
++ }
++
+ usb_musb_init(&musb_board_data);
+ usb_ehci_init(&ehci_pdata);
+ omap3beagle_flash_init();
+@@ -634,6 +768,8 @@ static void __init omap3_beagle_init(void)
+ beagle_display_init();
+ }
+
++early_param("buddy", expansionboard_setup);
++
+ MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
+ /* Maintainer: Syed Mohammed Khasim - http://beagleboard.org */
+ .boot_params = 0x80000100,
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0006-ARM-OMAP-beagleboard-pre-export-GPIOs-to-userspace-w.patch b/extras/recipes-kernel/linux/linux-omap/base/0006-ARM-OMAP-beagleboard-pre-export-GPIOs-to-userspace-w.patch
new file mode 100644
index 00000000..3c8547a1
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0006-ARM-OMAP-beagleboard-pre-export-GPIOs-to-userspace-w.patch
@@ -0,0 +1,57 @@
+From 0c2c9a4d7fd299444b66e08aa34acc868261003f Mon Sep 17 00:00:00 2001
+From: Koen Kooi <koen@dominion.thruhere.net>
+Date: Sun, 5 Dec 2010 13:25:00 +0100
+Subject: [PATCH 06/28] ARM: OMAP: beagleboard: pre-export GPIOs to userspace when using a Tincantools trainerboard
+
+This really needs a for loop, patches welcome
+
+Signed-off-by: Koen Kooi <koen@beagleboard.org>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c | 31 +++++++++++++++++++++++++++++++
+ 1 files changed, 31 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index d777b3b..64a181e 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -757,6 +757,37 @@ static void __init omap3_beagle_init(void)
+ mmc[1].gpio_cd = 162;
+ }
+
++ if(!strcmp(expansionboard_name, "trainer"))
++ {
++ printk(KERN_INFO "Beagle expansionboard: exporting GPIOs 130-141,162 to userspace\n");
++ gpio_request(130, "sysfs");
++ gpio_export(130, 1);
++ gpio_request(131, "sysfs");
++ gpio_export(131, 1);
++ gpio_request(132, "sysfs");
++ gpio_export(132, 1);
++ gpio_request(133, "sysfs");
++ gpio_export(133, 1);
++ gpio_request(134, "sysfs");
++ gpio_export(134, 1);
++ gpio_request(135, "sysfs");
++ gpio_export(135, 1);
++ gpio_request(136, "sysfs");
++ gpio_export(136, 1);
++ gpio_request(137, "sysfs");
++ gpio_export(137, 1);
++ gpio_request(138, "sysfs");
++ gpio_export(138, 1);
++ gpio_request(139, "sysfs");
++ gpio_export(139, 1);
++ gpio_request(140, "sysfs");
++ gpio_export(140, 1);
++ gpio_request(141, "sysfs");
++ gpio_export(141, 1);
++ gpio_request(162, "sysfs");
++ gpio_export(162, 1);
++ }
++
+ usb_musb_init(&musb_board_data);
+ usb_ehci_init(&ehci_pdata);
+ omap3beagle_flash_init();
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0007-modedb.c-add-proper-720p60-mode.patch b/extras/recipes-kernel/linux/linux-omap/base/0007-modedb.c-add-proper-720p60-mode.patch
new file mode 100644
index 00000000..575ee6f5
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0007-modedb.c-add-proper-720p60-mode.patch
@@ -0,0 +1,28 @@
+From ed12d865de851c5aed3ae7685337551b831bb045 Mon Sep 17 00:00:00 2001
+From: Koen Kooi <koen@dominion.thruhere.net>
+Date: Mon, 8 Mar 2010 14:38:31 +0100
+Subject: [PATCH 07/28] modedb.c: add proper 720p60 mode
+
+Signed-off-by: Koen Kooi <koen@beagleboard.org>
+---
+ drivers/video/modedb.c | 4 ++++
+ 1 files changed, 4 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
+index de450c1..1cd8153 100644
+--- a/drivers/video/modedb.c
++++ b/drivers/video/modedb.c
+@@ -46,6 +46,10 @@ static const struct fb_videomode modedb[] = {
+ NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2,
+ 0, FB_VMODE_NONINTERLACED
+ }, {
++ /* 1280x720 @ 60 Hz, 45 kHz hsync, CEA 681-E Format 4 */
++ "hd720", 60, 1280, 720, 13468, 220, 110, 20, 5, 40, 5,
++ 0, FB_VMODE_NONINTERLACED
++ }, {
+ /* 800x600 @ 56 Hz, 35.15 kHz hsync */
+ NULL, 56, 800, 600, 27777, 128, 24, 22, 1, 72, 2,
+ 0, FB_VMODE_NONINTERLACED
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0008-mmc-don-t-display-single-block-read-console-messages.patch b/extras/recipes-kernel/linux/linux-omap/base/0008-mmc-don-t-display-single-block-read-console-messages.patch
new file mode 100644
index 00000000..7e776412
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0008-mmc-don-t-display-single-block-read-console-messages.patch
@@ -0,0 +1,28 @@
+From 13235700be3729d183143bdb75ee58742372d6aa Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Mon, 4 Jan 2010 19:20:25 -0800
+Subject: [PATCH 08/28] mmc: don't display single block read console messages
+
+mmc: don't display single block read console messages
+---
+ drivers/mmc/card/block.c | 4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
+index 217f820..b0b68cc 100644
+--- a/drivers/mmc/card/block.c
++++ b/drivers/mmc/card/block.c
+@@ -434,8 +434,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
+ if (brq.cmd.error || brq.data.error || brq.stop.error) {
+ if (brq.data.blocks > 1 && rq_data_dir(req) == READ) {
+ /* Redo read one sector at a time */
+- printk(KERN_WARNING "%s: retrying using single "
+- "block read\n", req->rq_disk->disk_name);
++ /* printk(KERN_WARNING "%s: retrying using single "
++ "block read\n", req->rq_disk->disk_name); */
+ disable_multi = 1;
+ continue;
+ }
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0009-MTD-silence-ecc-errors-on-mtdblock0.patch b/extras/recipes-kernel/linux/linux-omap/base/0009-MTD-silence-ecc-errors-on-mtdblock0.patch
new file mode 100644
index 00000000..e665e23a
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0009-MTD-silence-ecc-errors-on-mtdblock0.patch
@@ -0,0 +1,63 @@
+From 8b0c56b910811acd23c15bed273b3dbd959ef96a Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Mon, 26 Apr 2010 11:17:26 -0700
+Subject: [PATCH 09/28] MTD: silence ecc errors on mtdblock0
+
+mtdblock0 is the x-load partition, which uses hw ecc
+this confuses linux, which uses sw ecc
+this patch silences ecc error messages when linux peeks into mtdblock0
+* not for upstream submission *
+---
+ block/blk-core.c | 7 ++++---
+ drivers/mtd/nand/nand_ecc.c | 2 +-
+ fs/buffer.c | 3 ++-
+ 3 files changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/block/blk-core.c b/block/blk-core.c
+index 4ce953f..1ef9a01 100644
+--- a/block/blk-core.c
++++ b/block/blk-core.c
+@@ -2028,9 +2028,10 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes)
+
+ if (error && req->cmd_type == REQ_TYPE_FS &&
+ !(req->cmd_flags & REQ_QUIET)) {
+- printk(KERN_ERR "end_request: I/O error, dev %s, sector %llu\n",
+- req->rq_disk ? req->rq_disk->disk_name : "?",
+- (unsigned long long)blk_rq_pos(req));
++ if (req->rq_disk && (strcmp(req->rq_disk->disk_name, "mtdblock0") != 0))
++ printk(KERN_ERR "end_request: I/O error, dev %s, sector %llu\n",
++ req->rq_disk ? req->rq_disk->disk_name : "?",
++ (unsigned long long)blk_rq_pos(req));
+ }
+
+ blk_account_io_completion(req, nr_bytes);
+diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
+index 271b8e7..5924ba7 100644
+--- a/drivers/mtd/nand/nand_ecc.c
++++ b/drivers/mtd/nand/nand_ecc.c
+@@ -507,7 +507,7 @@ int __nand_correct_data(unsigned char *buf,
+ if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1)
+ return 1; /* error in ecc data; no action needed */
+
+- printk(KERN_ERR "uncorrectable error : ");
++// printk(KERN_ERR "uncorrectable error : ");
+ return -1;
+ }
+ EXPORT_SYMBOL(__nand_correct_data);
+diff --git a/fs/buffer.c b/fs/buffer.c
+index 5930e38..06a00d5 100644
+--- a/fs/buffer.c
++++ b/fs/buffer.c
+@@ -114,7 +114,8 @@ static int quiet_error(struct buffer_head *bh)
+ static void buffer_io_error(struct buffer_head *bh)
+ {
+ char b[BDEVNAME_SIZE];
+- printk(KERN_ERR "Buffer I/O error on device %s, logical block %Lu\n",
++ if (strcmp(bdevname(bh->b_bdev, b), "mtdblock0") != 0)
++ printk(KERN_ERR "Buffer I/O error on device %s, logical block %Lu\n",
+ bdevname(bh->b_bdev, b),
+ (unsigned long long)bh->b_blocknr);
+ }
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0010-Miracle-patch.patch b/extras/recipes-kernel/linux/linux-omap/base/0010-Miracle-patch.patch
new file mode 100644
index 00000000..c5eba83d
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0010-Miracle-patch.patch
@@ -0,0 +1,504 @@
+From ce4f1f734efd638af01f1849ffffdc2746ad4a55 Mon Sep 17 00:00:00 2001
+From: Mike Galbraith <efault@gmx.de>
+Date: Fri, 19 Nov 2010 12:52:42 +0100
+Subject: [PATCH 10/28] Miracle patch
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+On Sun, 2010-11-14 at 16:26 -0800, Linus Torvalds wrote:
+> On Sun, Nov 14, 2010 at 4:15 PM, Linus Torvalds
+> <torvalds@linux-foundation.org> wrote:
+> >
+> > THAT is why I think it's so silly to try to be so strict and walk over
+> > all processes while holding a couple of spinlocks.
+>
+> Btw, let me say that I think the patch is great even with that thing
+> in. It looks clean, the thing I'm complaining about is not a big deal,
+> and it seems to perform very much as advertized. The difference with
+> autogroup scheduling is very noticeable with a simple "make -j64"
+> kernel compile.
+>
+> So I really don't think it's a big deal. The sysctl handler isn't even
+> complicated. But boy does it hurt my eyes to see a spinlock held
+> around a "do_each_thread()". And I do get the feeling that the
+> simplest way to fix it would be to just remove the code entirely, and
+> just say that "enabling/disabling may be delayed for old processes
+> with existing autogroups".
+
+Which is what I just did. If the oddball case isn't a big deal, the
+patch shrinks, which is a good thing. I just wanted to cover all bases.
+
+Patchlet with handler whacked:
+
+A recurring complaint from CFS users is that parallel kbuild has a negative
+impact on desktop interactivity. This patch implements an idea from Linus,
+to automatically create task groups. This patch only implements Linus' per
+tty task group suggestion, and only for fair class tasks, but leaves the way
+open for enhancement.
+
+Implementation: each task's signal struct contains an inherited pointer to a
+refcounted autogroup struct containing a task group pointer, the default for
+all tasks pointing to the init_task_group. When a task calls __proc_set_tty(),
+the process wide reference to the default group is dropped, a new task group is
+created, and the process is moved into the new task group. Children thereafter
+inherit this task group, and increase it's refcount. On exit, a reference to the
+current task group is dropped when the last reference to each signal struct is
+dropped. The task group is destroyed when the last signal struct referencing
+it is freed. At runqueue selection time, IFF a task has no cgroup assignment,
+it's current autogroup is used.
+
+The feature is enabled from boot by default if CONFIG_SCHED_AUTOGROUP is
+selected, but can be disabled via the boot option noautogroup, and can be
+also be turned on/off on the fly via..
+ echo [01] > /proc/sys/kernel/sched_autogroup_enabled.
+..which will automatically move tasks to/from the root task group.
+
+Some numbers.
+
+A 100% hog overhead measurement proggy pinned to the same CPU as a make -j10
+
+About measurement proggy:
+ pert/sec = perturbations/sec
+ min/max/avg = scheduler service latencies in usecs
+ sum/s = time accrued by the competition per sample period (1 sec here)
+ overhead = %CPU received by the competition per sample period
+
+pert/s: 31 >40475.37us: 3 min: 0.37 max:48103.60 avg:29573.74 sum/s:916786us overhead:90.24%
+pert/s: 23 >41237.70us: 12 min: 0.36 max:56010.39 avg:40187.01 sum/s:924301us overhead:91.99%
+pert/s: 24 >42150.22us: 12 min: 8.86 max:61265.91 avg:39459.91 sum/s:947038us overhead:92.20%
+pert/s: 26 >42344.91us: 11 min: 3.83 max:52029.60 avg:36164.70 sum/s:940282us overhead:91.12%
+pert/s: 24 >44262.90us: 14 min: 5.05 max:82735.15 avg:40314.33 sum/s:967544us overhead:92.22%
+
+Same load with this patch applied.
+
+pert/s: 229 >5484.43us: 41 min: 0.15 max:12069.42 avg:2193.81 sum/s:502382us overhead:50.24%
+pert/s: 222 >5652.28us: 43 min: 0.46 max:12077.31 avg:2248.56 sum/s:499181us overhead:49.92%
+pert/s: 211 >5809.38us: 43 min: 0.16 max:12064.78 avg:2381.70 sum/s:502538us overhead:50.25%
+pert/s: 223 >6147.92us: 43 min: 0.15 max:16107.46 avg:2282.17 sum/s:508925us overhead:50.49%
+pert/s: 218 >6252.64us: 43 min: 0.16 max:12066.13 avg:2324.11 sum/s:506656us overhead:50.27%
+
+Average service latency is an order of magnitude better with autogroup.
+(Imagine that pert were Xorg or whatnot instead)
+
+Using Mathieu Desnoyers' wakeup-latency testcase:
+
+With taskset -c 3 make -j 10 running..
+
+taskset -c 3 ./wakeup-latency& sleep 30;killall wakeup-latency
+
+without:
+maximum latency: 42963.2 µs
+average latency: 9077.0 µs
+missed timer events: 0
+
+with:
+maximum latency: 4160.7 µs
+average latency: 149.4 µs
+missed timer events: 0
+
+Signed-off-by: Mike Galbraith <efault@gmx.de>
+---
+ Documentation/kernel-parameters.txt | 2 +
+ drivers/tty/tty_io.c | 1 +
+ include/linux/sched.h | 19 +++++
+ init/Kconfig | 12 +++
+ kernel/fork.c | 5 +-
+ kernel/sched.c | 25 ++++--
+ kernel/sched_autogroup.c | 140 +++++++++++++++++++++++++++++++++++
+ kernel/sched_autogroup.h | 18 +++++
+ kernel/sysctl.c | 11 +++
+ 9 files changed, 224 insertions(+), 9 deletions(-)
+ create mode 100644 kernel/sched_autogroup.c
+ create mode 100644 kernel/sched_autogroup.h
+
+diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
+index 01ece1b..1031923 100644
+--- a/Documentation/kernel-parameters.txt
++++ b/Documentation/kernel-parameters.txt
+@@ -1622,6 +1622,8 @@ and is between 256 and 4096 characters. It is defined in the file
+ noapic [SMP,APIC] Tells the kernel to not make use of any
+ IOAPICs that may be present in the system.
+
++ noautogroup Disable scheduler automatic task group creation.
++
+ nobats [PPC] Do not use BATs for mapping kernel lowmem
+ on "Classic" PPC cores.
+
+diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
+index 35480dd..1849f4a 100644
+--- a/drivers/tty/tty_io.c
++++ b/drivers/tty/tty_io.c
+@@ -3169,6 +3169,7 @@ static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+ put_pid(tsk->signal->tty_old_pgrp);
+ tsk->signal->tty = tty_kref_get(tty);
+ tsk->signal->tty_old_pgrp = NULL;
++ sched_autogroup_create_attach(tsk);
+ }
+
+ static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+diff --git a/include/linux/sched.h b/include/linux/sched.h
+index 2238745..3a775e3 100644
+--- a/include/linux/sched.h
++++ b/include/linux/sched.h
+@@ -509,6 +509,8 @@ struct thread_group_cputimer {
+ spinlock_t lock;
+ };
+
++struct autogroup;
++
+ /*
+ * NOTE! "signal_struct" does not have it's own
+ * locking, because a shared signal_struct always
+@@ -576,6 +578,9 @@ struct signal_struct {
+
+ struct tty_struct *tty; /* NULL if no tty */
+
++#ifdef CONFIG_SCHED_AUTOGROUP
++ struct autogroup *autogroup;
++#endif
+ /*
+ * Cumulative resource counters for dead threads in the group,
+ * and for reaped dead child processes forked by this group.
+@@ -1931,6 +1936,20 @@ int sched_rt_handler(struct ctl_table *table, int write,
+
+ extern unsigned int sysctl_sched_compat_yield;
+
++#ifdef CONFIG_SCHED_AUTOGROUP
++extern unsigned int sysctl_sched_autogroup_enabled;
++
++extern void sched_autogroup_create_attach(struct task_struct *p);
++extern void sched_autogroup_detach(struct task_struct *p);
++extern void sched_autogroup_fork(struct signal_struct *sig);
++extern void sched_autogroup_exit(struct signal_struct *sig);
++#else
++static inline void sched_autogroup_create_attach(struct task_struct *p) { }
++static inline void sched_autogroup_detach(struct task_struct *p) { }
++static inline void sched_autogroup_fork(struct signal_struct *sig) { }
++static inline void sched_autogroup_exit(struct signal_struct *sig) { }
++#endif
++
+ #ifdef CONFIG_RT_MUTEXES
+ extern int rt_mutex_getprio(struct task_struct *p);
+ extern void rt_mutex_setprio(struct task_struct *p, int prio);
+diff --git a/init/Kconfig b/init/Kconfig
+index c972899..a4985d9 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -741,6 +741,18 @@ config NET_NS
+
+ endif # NAMESPACES
+
++config SCHED_AUTOGROUP
++ bool "Automatic process group scheduling"
++ select CGROUPS
++ select CGROUP_SCHED
++ select FAIR_GROUP_SCHED
++ help
++ This option optimizes the scheduler for common desktop workloads by
++ automatically creating and populating task groups. This separation
++ of workloads isolates aggressive CPU burners (like build jobs) from
++ desktop applications. Task group autogeneration is currently based
++ upon task tty association.
++
+ config MM_OWNER
+ bool
+
+diff --git a/kernel/fork.c b/kernel/fork.c
+index 5447dc7..70ea75f 100644
+--- a/kernel/fork.c
++++ b/kernel/fork.c
+@@ -174,8 +174,10 @@ static inline void free_signal_struct(struct signal_struct *sig)
+
+ static inline void put_signal_struct(struct signal_struct *sig)
+ {
+- if (atomic_dec_and_test(&sig->sigcnt))
++ if (atomic_dec_and_test(&sig->sigcnt)) {
++ sched_autogroup_exit(sig);
+ free_signal_struct(sig);
++ }
+ }
+
+ void __put_task_struct(struct task_struct *tsk)
+@@ -905,6 +907,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
+ posix_cpu_timers_init_group(sig);
+
+ tty_audit_fork(sig);
++ sched_autogroup_fork(sig);
+
+ sig->oom_adj = current->signal->oom_adj;
+ sig->oom_score_adj = current->signal->oom_score_adj;
+diff --git a/kernel/sched.c b/kernel/sched.c
+index 297d1a0..53ff9a1 100644
+--- a/kernel/sched.c
++++ b/kernel/sched.c
+@@ -78,6 +78,7 @@
+
+ #include "sched_cpupri.h"
+ #include "workqueue_sched.h"
++#include "sched_autogroup.h"
+
+ #define CREATE_TRACE_POINTS
+ #include <trace/events/sched.h>
+@@ -605,11 +606,14 @@ static inline int cpu_of(struct rq *rq)
+ */
+ static inline struct task_group *task_group(struct task_struct *p)
+ {
++ struct task_group *tg;
+ struct cgroup_subsys_state *css;
+
+ css = task_subsys_state_check(p, cpu_cgroup_subsys_id,
+ lockdep_is_held(&task_rq(p)->lock));
+- return container_of(css, struct task_group, css);
++ tg = container_of(css, struct task_group, css);
++
++ return autogroup_task_group(p, tg);
+ }
+
+ /* Change a task's cfs_rq and parent entity if it moves across CPUs/groups */
+@@ -2063,6 +2067,7 @@ static void update_rq_clock_task(struct rq *rq, s64 delta)
+ #include "sched_idletask.c"
+ #include "sched_fair.c"
+ #include "sched_rt.c"
++#include "sched_autogroup.c"
+ #include "sched_stoptask.c"
+ #ifdef CONFIG_SCHED_DEBUG
+ # include "sched_debug.c"
+@@ -8164,7 +8169,7 @@ void __init sched_init(void)
+ #ifdef CONFIG_CGROUP_SCHED
+ list_add(&init_task_group.list, &task_groups);
+ INIT_LIST_HEAD(&init_task_group.children);
+-
++ autogroup_init(&init_task);
+ #endif /* CONFIG_CGROUP_SCHED */
+
+ #if defined CONFIG_FAIR_GROUP_SCHED && defined CONFIG_SMP
+@@ -8694,15 +8699,11 @@ void sched_destroy_group(struct task_group *tg)
+ /* change task's runqueue when it moves between groups.
+ * The caller of this function should have put the task in its new group
+ * by now. This function just updates tsk->se.cfs_rq and tsk->se.parent to
+- * reflect its new group.
++ * reflect its new group. Called with the runqueue lock held.
+ */
+-void sched_move_task(struct task_struct *tsk)
++void __sched_move_task(struct task_struct *tsk, struct rq *rq)
+ {
+ int on_rq, running;
+- unsigned long flags;
+- struct rq *rq;
+-
+- rq = task_rq_lock(tsk, &flags);
+
+ running = task_current(rq, tsk);
+ on_rq = tsk->se.on_rq;
+@@ -8723,7 +8724,15 @@ void sched_move_task(struct task_struct *tsk)
+ tsk->sched_class->set_curr_task(rq);
+ if (on_rq)
+ enqueue_task(rq, tsk, 0);
++}
+
++void sched_move_task(struct task_struct *tsk)
++{
++ struct rq *rq;
++ unsigned long flags;
++
++ rq = task_rq_lock(tsk, &flags);
++ __sched_move_task(tsk, rq);
+ task_rq_unlock(rq, &flags);
+ }
+ #endif /* CONFIG_CGROUP_SCHED */
+diff --git a/kernel/sched_autogroup.c b/kernel/sched_autogroup.c
+new file mode 100644
+index 0000000..62f1d0e
+--- /dev/null
++++ b/kernel/sched_autogroup.c
+@@ -0,0 +1,140 @@
++#ifdef CONFIG_SCHED_AUTOGROUP
++
++unsigned int __read_mostly sysctl_sched_autogroup_enabled = 1;
++
++struct autogroup {
++ struct kref kref;
++ struct task_group *tg;
++};
++
++static struct autogroup autogroup_default;
++
++static void autogroup_init(struct task_struct *init_task)
++{
++ autogroup_default.tg = &init_task_group;
++ kref_init(&autogroup_default.kref);
++ init_task->signal->autogroup = &autogroup_default;
++}
++
++static inline void autogroup_destroy(struct kref *kref)
++{
++ struct autogroup *ag = container_of(kref, struct autogroup, kref);
++ struct task_group *tg = ag->tg;
++
++ kfree(ag);
++ sched_destroy_group(tg);
++}
++
++static inline void autogroup_kref_put(struct autogroup *ag)
++{
++ kref_put(&ag->kref, autogroup_destroy);
++}
++
++static inline struct autogroup *autogroup_kref_get(struct autogroup *ag)
++{
++ kref_get(&ag->kref);
++ return ag;
++}
++
++static inline struct autogroup *autogroup_create(void)
++{
++ struct autogroup *ag = kmalloc(sizeof(*ag), GFP_KERNEL);
++
++ if (!ag)
++ goto out_fail;
++
++ ag->tg = sched_create_group(&init_task_group);
++ kref_init(&ag->kref);
++
++ if (!(IS_ERR(ag->tg)))
++ return ag;
++
++out_fail:
++ if (ag) {
++ kfree(ag);
++ WARN_ON(1);
++ } else
++ WARN_ON(1);
++
++ return autogroup_kref_get(&autogroup_default);
++}
++
++static inline struct task_group *
++autogroup_task_group(struct task_struct *p, struct task_group *tg)
++{
++ int enabled = ACCESS_ONCE(sysctl_sched_autogroup_enabled);
++
++ enabled &= (tg == &root_task_group);
++ enabled &= (p->sched_class == &fair_sched_class);
++ enabled &= (!(p->flags & PF_EXITING));
++
++ if (enabled)
++ return p->signal->autogroup->tg;
++
++ return tg;
++}
++
++static void
++autogroup_move_group(struct task_struct *p, struct autogroup *ag)
++{
++ struct autogroup *prev;
++ struct task_struct *t;
++ struct rq *rq;
++ unsigned long flags;
++
++ rq = task_rq_lock(p, &flags);
++ prev = p->signal->autogroup;
++ if (prev == ag) {
++ task_rq_unlock(rq, &flags);
++ return;
++ }
++
++ p->signal->autogroup = autogroup_kref_get(ag);
++ __sched_move_task(p, rq);
++ task_rq_unlock(rq, &flags);
++
++ rcu_read_lock();
++ list_for_each_entry_rcu(t, &p->thread_group, thread_group) {
++ sched_move_task(t);
++ }
++ rcu_read_unlock();
++
++ autogroup_kref_put(prev);
++}
++
++void sched_autogroup_create_attach(struct task_struct *p)
++{
++ struct autogroup *ag = autogroup_create();
++
++ autogroup_move_group(p, ag);
++ /* drop extra refrence added by autogroup_create() */
++ autogroup_kref_put(ag);
++}
++EXPORT_SYMBOL(sched_autogroup_create_attach);
++
++/* currently has no users */
++void sched_autogroup_detach(struct task_struct *p)
++{
++ autogroup_move_group(p, &autogroup_default);
++}
++EXPORT_SYMBOL(sched_autogroup_detach);
++
++void sched_autogroup_fork(struct signal_struct *sig)
++{
++ sig->autogroup = autogroup_kref_get(current->signal->autogroup);
++}
++
++void sched_autogroup_exit(struct signal_struct *sig)
++{
++ autogroup_kref_put(sig->autogroup);
++}
++
++static int __init setup_autogroup(char *str)
++{
++ sysctl_sched_autogroup_enabled = 0;
++
++ return 1;
++}
++
++__setup("noautogroup", setup_autogroup);
++#endif
+diff --git a/kernel/sched_autogroup.h b/kernel/sched_autogroup.h
+new file mode 100644
+index 0000000..6048f5d
+--- /dev/null
++++ b/kernel/sched_autogroup.h
+@@ -0,0 +1,18 @@
++#ifdef CONFIG_SCHED_AUTOGROUP
++
++static void __sched_move_task(struct task_struct *tsk, struct rq *rq);
++
++static inline struct task_group *
++autogroup_task_group(struct task_struct *p, struct task_group *tg);
++
++#else /* !CONFIG_SCHED_AUTOGROUP */
++
++static inline void autogroup_init(struct task_struct *init_task) { }
++
++static inline struct task_group *
++autogroup_task_group(struct task_struct *p, struct task_group *tg)
++{
++ return tg;
++}
++
++#endif /* CONFIG_SCHED_AUTOGROUP */
+diff --git a/kernel/sysctl.c b/kernel/sysctl.c
+index 5abfa15..b162f65 100644
+--- a/kernel/sysctl.c
++++ b/kernel/sysctl.c
+@@ -382,6 +382,17 @@ static struct ctl_table kern_table[] = {
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
++#ifdef CONFIG_SCHED_AUTOGROUP
++ {
++ .procname = "sched_autogroup_enabled",
++ .data = &sysctl_sched_autogroup_enabled,
++ .maxlen = sizeof(unsigned int),
++ .mode = 0644,
++ .proc_handler = proc_dointvec,
++ .extra1 = &zero,
++ .extra2 = &one,
++ },
++#endif
+ #ifdef CONFIG_PROVE_LOCKING
+ {
+ .procname = "prove_locking",
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0011-ARM-OMAP-add-omap_rev_-macros.patch b/extras/recipes-kernel/linux/linux-omap/base/0011-ARM-OMAP-add-omap_rev_-macros.patch
new file mode 100644
index 00000000..b89302bc
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0011-ARM-OMAP-add-omap_rev_-macros.patch
@@ -0,0 +1,81 @@
+From 8b34449d7eb89e1ae1c1c84f90ef5ea1e397787e Mon Sep 17 00:00:00 2001
+From: Koen Kooi <koen@dominion.thruhere.net>
+Date: Tue, 23 Nov 2010 11:40:20 +0100
+Subject: [PATCH 11/28] ARM: OMAP: add omap_rev_* macros
+
+This is just to make the SGX modules build that depend on omap_rev_lt_3_0
+
+Signed-off-by: Koen Kooi <koen@beagleboard.org>
+---
+ arch/arm/plat-omap/include/plat/cpu.h | 55 +++++++++++++++++++++++++++++++++
+ 1 files changed, 55 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/plat-omap/include/plat/cpu.h b/arch/arm/plat-omap/include/plat/cpu.h
+index 3fd8b40..1a8c347 100644
+--- a/arch/arm/plat-omap/include/plat/cpu.h
++++ b/arch/arm/plat-omap/include/plat/cpu.h
+@@ -394,6 +394,61 @@ IS_OMAP_TYPE(3517, 0x3517)
+ #define OMAP4430_REV_ES2_0 0x44301044
+
+ /*
++ * Silicon revisions
++ */
++#define OMAP_ES_1_0 0x00
++#define OMAP_ES_2_0 0x10
++#define OMAP_ES_2_1 0x20
++#define OMAP_ES_3_0 0x30
++#define OMAP_ES_3_1 0x40
++
++#define OMAP_REV_MASK 0x0000ff00
++#define OMAP_REV_BITS ((omap_rev() & OMAP_REV_MASK) >> 8)
++
++#define OMAP_REV_IS(revid) \
++static inline u8 omap_rev_is_ ##revid (void) \
++{ \
++ return (OMAP_REV_BITS == OMAP_ES_ ##revid) ? 1 : 0; \
++}
++
++#define OMAP_REV_LT(revid) \
++static inline u8 omap_rev_lt_ ##revid (void) \
++{ \
++ return (OMAP_REV_BITS < OMAP_ES_ ##revid) ? 1 : 0; \
++}
++
++#define OMAP_REV_LE(revid) \
++static inline u8 omap_rev_le_ ##revid (void) \
++{ \
++ return (OMAP_REV_BITS <= OMAP_ES_ ##revid) ? 1 : 0; \
++}
++
++#define OMAP_REV_GT(revid) \
++static inline u8 omap_rev_gt_ ##revid (void) \
++{ \
++ return (OMAP_REV_BITS > OMAP_ES_ ##revid) ? 1 : 0; \
++}
++
++#define OMAP_REV_GE(revid) \
++static inline u8 omap_rev_ge_ ##revid (void) \
++{ \
++ return (OMAP_REV_BITS >= OMAP_ES_ ##revid) ? 1 : 0; \
++}
++
++#define OMAP_REV_FUNCTIONS(revid) \
++ OMAP_REV_IS(revid) \
++ OMAP_REV_LT(revid) \
++ OMAP_REV_LE(revid) \
++ OMAP_REV_GT(revid) \
++ OMAP_REV_GE(revid)
++
++OMAP_REV_FUNCTIONS(1_0)
++OMAP_REV_FUNCTIONS(2_0)
++OMAP_REV_FUNCTIONS(2_1)
++OMAP_REV_FUNCTIONS(3_0)
++OMAP_REV_FUNCTIONS(3_1)
++
++/*
+ * omap_chip bits
+ *
+ * CHIP_IS_OMAP{2420,2430,3430} indicate that a particular structure is
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0012-OMAP-DSS2-enable-hsclk-in-dsi_pll_init-for-OMAP36XX.patch b/extras/recipes-kernel/linux/linux-omap/base/0012-OMAP-DSS2-enable-hsclk-in-dsi_pll_init-for-OMAP36XX.patch
new file mode 100644
index 00000000..7413b5f8
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0012-OMAP-DSS2-enable-hsclk-in-dsi_pll_init-for-OMAP36XX.patch
@@ -0,0 +1,31 @@
+From cd8a01e55dc674bba0030b99bff4f58d587aaecd Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Mon, 10 May 2010 20:44:09 -0700
+Subject: [PATCH 12/28] OMAP: DSS2: enable hsclk in dsi_pll_init for OMAP36XX
+
+Signed-off-by: Koen Kooi <koen@beagleboard.org>
+---
+ drivers/video/omap2/dss/dpi.c | 7 ++++++-
+ 1 files changed, 6 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
+index 960e977..23047b6 100644
+--- a/drivers/video/omap2/dss/dpi.c
++++ b/drivers/video/omap2/dss/dpi.c
+@@ -177,7 +177,12 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
+
+ #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+ dss_clk_enable(DSS_CLK_FCK2);
+- r = dsi_pll_init(dssdev, 0, 1);
++
++ if (cpu_is_omap3630())
++ r = dsi_pll_init(dssdev, 1, 1);
++ else
++ r = dsi_pll_init(dssdev, 0, 1);
++
+ if (r)
+ goto err3;
+ #endif
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0013-omap3-beagleboard-add-WIP-support-for-beagleboardtoy.patch b/extras/recipes-kernel/linux/linux-omap/base/0013-omap3-beagleboard-add-WIP-support-for-beagleboardtoy.patch
new file mode 100644
index 00000000..af12b2c9
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0013-omap3-beagleboard-add-WIP-support-for-beagleboardtoy.patch
@@ -0,0 +1,128 @@
+From f7d71be36165002251727019b1a03a19938bfa64 Mon Sep 17 00:00:00 2001
+From: Koen Kooi <koen@beagleboard.org>
+Date: Mon, 20 Dec 2010 11:57:56 +0100
+Subject: [PATCH 13/28] omap3: beagleboard: add WIP support for beagleboardtoys WL12xx board
+
+Based on a patch by Luciano Coelho <luciano.coelho@nokia.com>
+
+Signed-off-by: Koen Kooi <koen@beagleboard.org>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c | 84 ++++++++++++++++++++++++++++++-
+ 1 files changed, 83 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 64a181e..59b26da 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -146,6 +146,67 @@ fail0:
+
+ char expansionboard_name[16];
+
++#if defined(CONFIG_WL1271) || defined(CONFIG_WL1271_MODULE)
++#include <linux/regulator/fixed.h>
++#include <linux/wl12xx.h>
++
++#define OMAP_BEAGLE_WLAN_EN_GPIO (139)
++#define OMAP_BEAGLE_WLAN_IRQ_GPIO (137)
++
++struct wl12xx_platform_data omap_beagle_wlan_data __initdata = {
++ .irq = OMAP_GPIO_IRQ(OMAP_BEAGLE_WLAN_IRQ_GPIO),
++ .board_ref_clock = 2, /* 38.4 MHz */
++};
++
++ static struct omap2_hsmmc_info mmcbbt[] = {
++ {
++ .mmc = 1,
++ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
++ .gpio_wp = 29,
++ },
++ {
++ .name = "wl1271",
++ .mmc = 2,
++ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD,
++ .gpio_wp = -EINVAL,
++ .gpio_cd = -EINVAL,
++ .nonremovable = true,
++ },
++ {} /* Terminator */
++ };
++
++static struct regulator_consumer_supply beagle_vmmc2_supply = {
++ .supply = "vmmc",
++ .dev_name = "mmci-omap-hs.1",
++};
++
++static struct regulator_init_data beagle_vmmc2 = {
++ .constraints = {
++ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
++ },
++ .num_consumer_supplies = 1,
++ .consumer_supplies = &beagle_vmmc2_supply,
++};
++
++static struct fixed_voltage_config beagle_vwlan = {
++ .supply_name = "vwl1271",
++ .microvolts = 1800000, /* 1.8V */
++ .gpio = OMAP_BEAGLE_WLAN_EN_GPIO,
++ .startup_delay = 70000, /* 70ms */
++ .enable_high = 1,
++ .enabled_at_boot = 0,
++ .init_data = &beagle_vmmc2,
++};
++
++static struct platform_device omap_vwlan_device = {
++ .name = "reg-fixed-voltage",
++ .id = 1,
++ .dev = {
++ .platform_data = &beagle_vwlan,
++ },
++};
++#endif
++
+ #if defined(CONFIG_ENC28J60) || defined(CONFIG_ENC28J60_MODULE)
+
+ #include <plat/mcspi.h>
+@@ -384,11 +445,24 @@ static int beagle_twl_gpio_setup(struct device *dev,
+ }
+ /* gpio + 0 is "mmc0_cd" (input/IRQ) */
+ mmc[0].gpio_cd = gpio + 0;
++#if defined(CONFIG_WL1271) || defined(CONFIG_WL1271_MODULE)
++ if(!strcmp(expansionboard_name, "bbtoys-wifi")) {
++ omap2_hsmmc_init(mmcbbt);
++ /* link regulators to MMC adapters */
++ beagle_vmmc1_supply.dev = mmcbbt[0].dev;
++ beagle_vsim_supply.dev = mmcbbt[0].dev;
++ } else {
++ omap2_hsmmc_init(mmc);
++ /* link regulators to MMC adapters */
++ beagle_vmmc1_supply.dev = mmc[0].dev;
++ beagle_vsim_supply.dev = mmc[0].dev;
++ }
++#else
+ omap2_hsmmc_init(mmc);
+-
+ /* link regulators to MMC adapters */
+ beagle_vmmc1_supply.dev = mmc[0].dev;
+ beagle_vsim_supply.dev = mmc[0].dev;
++#endif
+
+ /* REVISIT: need ehci-omap hooks for external VBUS
+ * power switch and overcurrent detect
+@@ -788,6 +862,14 @@ static void __init omap3_beagle_init(void)
+ gpio_export(162, 1);
+ }
+
++ if(!strcmp(expansionboard_name, "bbtoys-wifi"))
++ {
++ if (wl12xx_set_platform_data(&omap_beagle_wlan_data))
++ pr_err("error setting wl12xx data\n");
++ printk(KERN_INFO "Beagle expansionboard: registering wl12xx platform device\n");
++ platform_device_register(&omap_vwlan_device);
++ }
++
+ usb_musb_init(&musb_board_data);
+ usb_ehci_init(&ehci_pdata);
+ omap3beagle_flash_init();
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0014-drivers-net-smsc911x-return-ENODEV-if-device-is-not-.patch b/extras/recipes-kernel/linux/linux-omap/base/0014-drivers-net-smsc911x-return-ENODEV-if-device-is-not-.patch
new file mode 100644
index 00000000..2eac323b
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0014-drivers-net-smsc911x-return-ENODEV-if-device-is-not-.patch
@@ -0,0 +1,29 @@
+From a47bbc5c9742e4ce250ee3bfba62732f3fea40b7 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <sakoman@gmail.com>
+Date: Tue, 15 Dec 2009 15:17:44 -0800
+Subject: [PATCH 14/28] drivers: net: smsc911x: return ENODEV if device is not found
+
+Signed-off-by: Steve Sakoman <sakoman@gmail.com>
+---
+ drivers/net/smsc911x.c | 4 +++-
+ 1 files changed, 3 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
+index 64bfdae..ba2a00e 100644
+--- a/drivers/net/smsc911x.c
++++ b/drivers/net/smsc911x.c
+@@ -2019,8 +2019,10 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
+ }
+
+ retval = smsc911x_init(dev);
+- if (retval < 0)
++ if (retval < 0) {
++ retval = -ENODEV;
+ goto out_unmap_io_3;
++ }
+
+ /* configure irq polarity and type before connecting isr */
+ if (pdata->config.irq_polarity == SMSC911X_IRQ_POLARITY_ACTIVE_HIGH)
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0015-drivers-input-touchscreen-ads7846-return-ENODEV-if-d.patch b/extras/recipes-kernel/linux/linux-omap/base/0015-drivers-input-touchscreen-ads7846-return-ENODEV-if-d.patch
new file mode 100644
index 00000000..74691ab8
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0015-drivers-input-touchscreen-ads7846-return-ENODEV-if-d.patch
@@ -0,0 +1,47 @@
+From 713eb96dd137e1436198aa07094049ae0e0f9f1f Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <sakoman@gmail.com>
+Date: Tue, 15 Dec 2009 15:24:10 -0800
+Subject: [PATCH 15/28] drivers: input: touchscreen: ads7846: return ENODEV if device is not found
+
+Signed-off-by: Steve Sakoman <sakoman@gmail.com>
+---
+ drivers/input/touchscreen/ads7846.c | 13 ++++++++++---
+ 1 files changed, 10 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
+index 14ea54b..c775e38 100644
+--- a/drivers/input/touchscreen/ads7846.c
++++ b/drivers/input/touchscreen/ads7846.c
+@@ -1325,11 +1325,18 @@ static int __devinit ads7846_probe(struct spi_device *spi)
+ * the touchscreen, in case it's not connected.
+ */
+ if (ts->model == 7845)
+- ads7845_read12_ser(&spi->dev, PWRDOWN);
++ err = ads7845_read12_ser(&spi->dev, PWRDOWN);
+ else
+- (void) ads7846_read12_ser(&spi->dev,
++ err = ads7846_read12_ser(&spi->dev,
+ READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
+
++ /* if sample is all 0's or all 1's then there is no device on spi */
++ if ( (err == 0x000) || (err == 0xfff)) {
++ dev_info(&spi->dev, "no device detected, test read result was 0x%08X\n", err);
++ err = -ENODEV;
++ goto err_free_irq;
++ }
++
+ err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);
+ if (err)
+ goto err_remove_hwmon;
+@@ -1353,7 +1360,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
+ err_put_regulator:
+ regulator_put(ts->reg);
+ err_free_gpio:
+- if (ts->gpio_pendown != -1)
++ if (!ts->get_pendown_state && ts->gpio_pendown != -1)
+ gpio_free(ts->gpio_pendown);
+ err_cleanup_filter:
+ if (ts->filter_cleanup)
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0016-ASoC-enable-audio-capture-by-default-for-twl4030.patch b/extras/recipes-kernel/linux/linux-omap/base/0016-ASoC-enable-audio-capture-by-default-for-twl4030.patch
new file mode 100644
index 00000000..081aa5b9
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0016-ASoC-enable-audio-capture-by-default-for-twl4030.patch
@@ -0,0 +1,27 @@
+From de63bf4fdf6c64e543c207792cb2d8ebcd089342 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Thu, 17 Dec 2009 12:45:20 -0800
+Subject: [PATCH 16/28] ASoC: enable audio capture by default for twl4030
+
+---
+ sound/soc/codecs/twl4030.c | 4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
+index cbebec6..430cd10 100644
+--- a/sound/soc/codecs/twl4030.c
++++ b/sound/soc/codecs/twl4030.c
+@@ -56,8 +56,8 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
+ 0x00, /* REG_OPTION (0x2) */
+ 0x00, /* REG_UNKNOWN (0x3) */
+ 0x00, /* REG_MICBIAS_CTL (0x4) */
+- 0x00, /* REG_ANAMICL (0x5) */
+- 0x00, /* REG_ANAMICR (0x6) */
++ 0x34, /* REG_ANAMICL (0x5) */
++ 0x14, /* REG_ANAMICR (0x6) */
+ 0x00, /* REG_AVADC_CTL (0x7) */
+ 0x00, /* REG_ADCMICSEL (0x8) */
+ 0x00, /* REG_DIGMIXING (0x9) */
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0017-MFD-enable-madc-clock.patch b/extras/recipes-kernel/linux/linux-omap/base/0017-MFD-enable-madc-clock.patch
new file mode 100644
index 00000000..2f3d1a43
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0017-MFD-enable-madc-clock.patch
@@ -0,0 +1,51 @@
+From 18934b05f81025c1254d64c1774832e95187cbd9 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Sat, 23 Jan 2010 06:26:54 -0800
+Subject: [PATCH 17/28] MFD: enable madc clock
+
+---
+ drivers/mfd/twl-core.c | 8 ++++++++
+ include/linux/i2c/twl.h | 1 +
+ 2 files changed, 9 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
+index 35275ba..5aa7358 100644
+--- a/drivers/mfd/twl-core.c
++++ b/drivers/mfd/twl-core.c
+@@ -208,6 +208,11 @@
+
+ /* Few power values */
+ #define R_CFG_BOOT 0x05
++#define R_GPBR1 0x0C
++
++/* MADC clock values for R_GPBR1 */
++#define MADC_HFCLK_EN 0x80
++#define DEFAULT_MADC_CLK_EN 0x10
+
+ /* some fields in R_CFG_BOOT */
+ #define HFCLK_FREQ_19p2_MHZ (1 << 0)
+@@ -929,6 +934,9 @@ static void clocks_init(struct device *dev,
+
+ e |= unprotect_pm_master();
+ /* effect->MADC+USB ck en */
++ if (twl_has_madc())
++ e |= twl_i2c_write_u8(TWL_MODULE_INTBR,
++ MADC_HFCLK_EN | DEFAULT_MADC_CLK_EN, R_GPBR1);
+ e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, ctrl, R_CFG_BOOT);
+ e |= protect_pm_master();
+
+diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
+index c760991..cfdfdd3 100644
+--- a/include/linux/i2c/twl.h
++++ b/include/linux/i2c/twl.h
+@@ -74,6 +74,7 @@
+
+ #define TWL_MODULE_USB TWL4030_MODULE_USB
+ #define TWL_MODULE_AUDIO_VOICE TWL4030_MODULE_AUDIO_VOICE
++#define TWL_MODULE_INTBR TWL4030_MODULE_INTBR
+ #define TWL_MODULE_PIH TWL4030_MODULE_PIH
+ #define TWL_MODULE_MADC TWL4030_MODULE_MADC
+ #define TWL_MODULE_MAIN_CHARGE TWL4030_MODULE_MAIN_CHARGE
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0018-MFD-add-twl4030-madc-driver.patch b/extras/recipes-kernel/linux/linux-omap/base/0018-MFD-add-twl4030-madc-driver.patch
new file mode 100644
index 00000000..a55136db
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0018-MFD-add-twl4030-madc-driver.patch
@@ -0,0 +1,740 @@
+From 562dc52ebe3df1e5d23416e78306db7c568dc427 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Thu, 17 Dec 2009 14:19:34 -0800
+Subject: [PATCH 18/28] MFD: add twl4030 madc driver
+
+---
+ drivers/mfd/Kconfig | 21 ++
+ drivers/mfd/Makefile | 1 +
+ drivers/mfd/twl4030-madc.c | 537 ++++++++++++++++++++++++++++++++++++++
+ include/linux/i2c/twl4030-madc.h | 130 +++++++++
+ 4 files changed, 689 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/mfd/twl4030-madc.c
+ create mode 100644 include/linux/i2c/twl4030-madc.h
+
+diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
+index 3a1493b..26ca160 100644
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -186,6 +186,27 @@ config TWL4030_CODEC
+ select MFD_CORE
+ default n
+
++config TWL4030_MADC
++ tristate "TWL4030 MADC Driver"
++ depends on TWL4030_CORE
++ help
++ The TWL4030 Monitoring ADC driver enables the host
++ processor to monitor analog signals using analog-to-digital
++ conversions on the input source. TWL4030 MADC provides the
++ following features:
++ - Single 10-bit ADC with successive approximation register (SAR) conversion;
++ - Analog multiplexer for 16 inputs;
++ - Seven (of the 16) inputs are freely available;
++ - Battery voltage monitoring;
++ - Concurrent conversion request management;
++ - Interrupt signal to Primary Interrupt Handler;
++ - Averaging feature;
++ - Selective enable/disable of the averaging feature.
++
++ Say 'y' here to statically link this module into the kernel or 'm'
++ to build it as a dinamically loadable module. The module will be
++ called twl4030-madc.ko
++
+ config TWL6030_PWM
+ tristate "TWL6030 PWM (Pulse Width Modulator) Support"
+ depends on TWL4030_CORE
+diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
+index f54b365..8c4ccb2 100644
+--- a/drivers/mfd/Makefile
++++ b/drivers/mfd/Makefile
+@@ -39,6 +39,7 @@ obj-$(CONFIG_MENELAUS) += menelaus.o
+ obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o
+ obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o
+ obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o
++obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
+ obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o
+
+ obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o
+diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c
+new file mode 100644
+index 0000000..4adf880
+--- /dev/null
++++ b/drivers/mfd/twl4030-madc.c
+@@ -0,0 +1,537 @@
++/*
++ * TWL4030 MADC module driver
++ *
++ * Copyright (C) 2008 Nokia Corporation
++ * Mikko Ylinen <mikko.k.ylinen@nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ *
++ */
++
++#include <linux/delay.h>
++#include <linux/fs.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/miscdevice.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/i2c/twl.h>
++#include <linux/i2c/twl4030-madc.h>
++
++#include <asm/uaccess.h>
++
++#define TWL4030_MADC_PFX "twl4030-madc: "
++
++struct twl4030_madc_data {
++ struct device *dev;
++ struct mutex lock;
++ struct work_struct ws;
++ struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS];
++ int imr;
++ int isr;
++};
++
++static struct twl4030_madc_data *the_madc;
++
++static
++const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
++ [TWL4030_MADC_RT] = {
++ .sel = TWL4030_MADC_RTSELECT_LSB,
++ .avg = TWL4030_MADC_RTAVERAGE_LSB,
++ .rbase = TWL4030_MADC_RTCH0_LSB,
++ },
++ [TWL4030_MADC_SW1] = {
++ .sel = TWL4030_MADC_SW1SELECT_LSB,
++ .avg = TWL4030_MADC_SW1AVERAGE_LSB,
++ .rbase = TWL4030_MADC_GPCH0_LSB,
++ .ctrl = TWL4030_MADC_CTRL_SW1,
++ },
++ [TWL4030_MADC_SW2] = {
++ .sel = TWL4030_MADC_SW2SELECT_LSB,
++ .avg = TWL4030_MADC_SW2AVERAGE_LSB,
++ .rbase = TWL4030_MADC_GPCH0_LSB,
++ .ctrl = TWL4030_MADC_CTRL_SW2,
++ },
++};
++
++static int twl4030_madc_read(struct twl4030_madc_data *madc, u8 reg)
++{
++ int ret;
++ u8 val;
++
++ ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, reg);
++ if (ret) {
++ dev_dbg(madc->dev, "unable to read register 0x%X\n", reg);
++ return ret;
++ }
++
++ return val;
++}
++
++static void twl4030_madc_write(struct twl4030_madc_data *madc, u8 reg, u8 val)
++{
++ int ret;
++
++ ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, reg);
++ if (ret)
++ dev_err(madc->dev, "unable to write register 0x%X\n", reg);
++}
++
++static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
++{
++ u8 msb, lsb;
++
++ /* For each ADC channel, we have MSB and LSB register pair. MSB address
++ * is always LSB address+1. reg parameter is the addr of LSB register */
++ msb = twl4030_madc_read(madc, reg + 1);
++ lsb = twl4030_madc_read(madc, reg);
++
++ return (int)(((msb << 8) | lsb) >> 6);
++}
++
++static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
++ u8 reg_base, u16 channels, int *buf)
++{
++ int count = 0;
++ u8 reg, i;
++
++ if (unlikely(!buf))
++ return 0;
++
++ for (i = 0; i < TWL4030_MADC_MAX_CHANNELS; i++) {
++ if (channels & (1<<i)) {
++ reg = reg_base + 2*i;
++ buf[i] = twl4030_madc_channel_raw_read(madc, reg);
++ count++;
++ }
++ }
++ return count;
++}
++
++static void twl4030_madc_enable_irq(struct twl4030_madc_data *madc, int id)
++{
++ u8 val;
++
++ val = twl4030_madc_read(madc, madc->imr);
++ val &= ~(1 << id);
++ twl4030_madc_write(madc, madc->imr, val);
++}
++
++static void twl4030_madc_disable_irq(struct twl4030_madc_data *madc, int id)
++{
++ u8 val;
++
++ val = twl4030_madc_read(madc, madc->imr);
++ val |= (1 << id);
++ twl4030_madc_write(madc, madc->imr, val);
++}
++
++static irqreturn_t twl4030_madc_irq_handler(int irq, void *_madc)
++{
++ struct twl4030_madc_data *madc = _madc;
++ u8 isr_val, imr_val;
++ int i;
++
++#ifdef CONFIG_LOCKDEP
++ /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
++ * we don't want and can't tolerate. Although it might be
++ * friendlier not to borrow this thread context...
++ */
++ local_irq_enable();
++#endif
++
++ /* Use COR to ack interrupts since we have no shared IRQs in ISRx */
++ isr_val = twl4030_madc_read(madc, madc->isr);
++ imr_val = twl4030_madc_read(madc, madc->imr);
++
++ isr_val &= ~imr_val;
++
++ for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
++
++ if (!(isr_val & (1<<i)))
++ continue;
++
++ twl4030_madc_disable_irq(madc, i);
++ madc->requests[i].result_pending = 1;
++ }
++
++ schedule_work(&madc->ws);
++
++ return IRQ_HANDLED;
++}
++
++static void twl4030_madc_work(struct work_struct *ws)
++{
++ const struct twl4030_madc_conversion_method *method;
++ struct twl4030_madc_data *madc;
++ struct twl4030_madc_request *r;
++ int len, i;
++
++ madc = container_of(ws, struct twl4030_madc_data, ws);
++ mutex_lock(&madc->lock);
++
++ for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
++
++ r = &madc->requests[i];
++
++ /* No pending results for this method, move to next one */
++ if (!r->result_pending)
++ continue;
++
++ method = &twl4030_conversion_methods[r->method];
++
++ /* Read results */
++ len = twl4030_madc_read_channels(madc, method->rbase,
++ r->channels, r->rbuf);
++
++ /* Return results to caller */
++ if (r->func_cb != NULL) {
++ r->func_cb(len, r->channels, r->rbuf);
++ r->func_cb = NULL;
++ }
++
++ /* Free request */
++ r->result_pending = 0;
++ r->active = 0;
++ }
++
++ mutex_unlock(&madc->lock);
++}
++
++static int twl4030_madc_set_irq(struct twl4030_madc_data *madc,
++ struct twl4030_madc_request *req)
++{
++ struct twl4030_madc_request *p;
++
++ p = &madc->requests[req->method];
++
++ memcpy(p, req, sizeof *req);
++
++ twl4030_madc_enable_irq(madc, req->method);
++
++ return 0;
++}
++
++static inline void twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
++ int conv_method)
++{
++ const struct twl4030_madc_conversion_method *method;
++
++ method = &twl4030_conversion_methods[conv_method];
++
++ switch (conv_method) {
++ case TWL4030_MADC_SW1:
++ case TWL4030_MADC_SW2:
++ twl4030_madc_write(madc, method->ctrl, TWL4030_MADC_SW_START);
++ break;
++ case TWL4030_MADC_RT:
++ default:
++ break;
++ }
++}
++
++static int twl4030_madc_wait_conversion_ready(
++ struct twl4030_madc_data *madc,
++ unsigned int timeout_ms, u8 status_reg)
++{
++ unsigned long timeout;
++
++ timeout = jiffies + msecs_to_jiffies(timeout_ms);
++ do {
++ u8 reg;
++
++ reg = twl4030_madc_read(madc, status_reg);
++ if (!(reg & TWL4030_MADC_BUSY) && (reg & TWL4030_MADC_EOC_SW))
++ return 0;
++ } while (!time_after(jiffies, timeout));
++
++ return -EAGAIN;
++}
++
++int twl4030_madc_conversion(struct twl4030_madc_request *req)
++{
++ const struct twl4030_madc_conversion_method *method;
++ u8 ch_msb, ch_lsb;
++ int ret;
++
++ if (unlikely(!req))
++ return -EINVAL;
++
++ mutex_lock(&the_madc->lock);
++
++ /* Do we have a conversion request ongoing */
++ if (the_madc->requests[req->method].active) {
++ ret = -EBUSY;
++ goto out;
++ }
++
++ ch_msb = (req->channels >> 8) & 0xff;
++ ch_lsb = req->channels & 0xff;
++
++ method = &twl4030_conversion_methods[req->method];
++
++ /* Select channels to be converted */
++ twl4030_madc_write(the_madc, method->sel + 1, ch_msb);
++ twl4030_madc_write(the_madc, method->sel, ch_lsb);
++
++ /* Select averaging for all channels if do_avg is set */
++ if (req->do_avg) {
++ twl4030_madc_write(the_madc, method->avg + 1, ch_msb);
++ twl4030_madc_write(the_madc, method->avg, ch_lsb);
++ }
++
++ if ((req->type == TWL4030_MADC_IRQ_ONESHOT) && (req->func_cb != NULL)) {
++ twl4030_madc_set_irq(the_madc, req);
++ twl4030_madc_start_conversion(the_madc, req->method);
++ the_madc->requests[req->method].active = 1;
++ ret = 0;
++ goto out;
++ }
++
++ /* With RT method we should not be here anymore */
++ if (req->method == TWL4030_MADC_RT) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ twl4030_madc_start_conversion(the_madc, req->method);
++ the_madc->requests[req->method].active = 1;
++
++ /* Wait until conversion is ready (ctrl register returns EOC) */
++ ret = twl4030_madc_wait_conversion_ready(the_madc, 5, method->ctrl);
++ if (ret) {
++ dev_dbg(the_madc->dev, "conversion timeout!\n");
++ the_madc->requests[req->method].active = 0;
++ goto out;
++ }
++
++ ret = twl4030_madc_read_channels(the_madc, method->rbase, req->channels,
++ req->rbuf);
++
++ the_madc->requests[req->method].active = 0;
++
++out:
++ mutex_unlock(&the_madc->lock);
++
++ return ret;
++}
++EXPORT_SYMBOL(twl4030_madc_conversion);
++
++static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
++ int chan, int on)
++{
++ int ret;
++ u8 regval;
++
++ /* Current generator is only available for ADCIN0 and ADCIN1. NB:
++ * ADCIN1 current generator only works when AC or VBUS is present */
++ if (chan > 1)
++ return EINVAL;
++
++ ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
++ &regval, TWL4030_BCI_BCICTL1);
++ if (on)
++ regval |= (chan) ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
++ else
++ regval &= (chan) ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN;
++ ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
++ regval, TWL4030_BCI_BCICTL1);
++
++ return ret;
++}
++
++static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
++{
++ u8 regval;
++
++ regval = twl4030_madc_read(madc, TWL4030_MADC_CTRL1);
++ if (on)
++ regval |= TWL4030_MADC_MADCON;
++ else
++ regval &= ~TWL4030_MADC_MADCON;
++ twl4030_madc_write(madc, TWL4030_MADC_CTRL1, regval);
++
++ return 0;
++}
++
++static long twl4030_madc_ioctl(struct file *filp, unsigned int cmd,
++ unsigned long arg)
++{
++ struct twl4030_madc_user_parms par;
++ int val, ret;
++
++ ret = copy_from_user(&par, (void __user *) arg, sizeof(par));
++ if (ret) {
++ dev_dbg(the_madc->dev, "copy_from_user: %d\n", ret);
++ return -EACCES;
++ }
++
++ switch (cmd) {
++ case TWL4030_MADC_IOCX_ADC_RAW_READ: {
++ struct twl4030_madc_request req;
++ if (par.channel >= TWL4030_MADC_MAX_CHANNELS)
++ return -EINVAL;
++
++ req.channels = (1 << par.channel);
++ req.do_avg = par.average;
++ req.method = TWL4030_MADC_SW1;
++ req.func_cb = NULL;
++
++ val = twl4030_madc_conversion(&req);
++ if (val <= 0) {
++ par.status = -1;
++ } else {
++ par.status = 0;
++ par.result = (u16)req.rbuf[par.channel];
++ }
++ break;
++ }
++ default:
++ return -EINVAL;
++ }
++
++ ret = copy_to_user((void __user *) arg, &par, sizeof(par));
++ if (ret) {
++ dev_dbg(the_madc->dev, "copy_to_user: %d\n", ret);
++ return -EACCES;
++ }
++
++ return 0;
++}
++
++static struct file_operations twl4030_madc_fileops = {
++ .owner = THIS_MODULE,
++ .unlocked_ioctl = twl4030_madc_ioctl
++};
++
++static struct miscdevice twl4030_madc_device = {
++ .minor = MISC_DYNAMIC_MINOR,
++ .name = "twl4030-madc",
++ .fops = &twl4030_madc_fileops
++};
++
++static int __init twl4030_madc_probe(struct platform_device *pdev)
++{
++ struct twl4030_madc_data *madc;
++ struct twl4030_madc_platform_data *pdata = pdev->dev.platform_data;
++ int ret;
++ u8 regval;
++
++ madc = kzalloc(sizeof *madc, GFP_KERNEL);
++ if (!madc)
++ return -ENOMEM;
++
++ if (!pdata) {
++ dev_dbg(&pdev->dev, "platform_data not available\n");
++ ret = -EINVAL;
++ goto err_pdata;
++ }
++
++ madc->imr = (pdata->irq_line == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
++ madc->isr = (pdata->irq_line == 1) ? TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
++
++ ret = misc_register(&twl4030_madc_device);
++ if (ret) {
++ dev_dbg(&pdev->dev, "could not register misc_device\n");
++ goto err_misc;
++ }
++ twl4030_madc_set_power(madc, 1);
++ twl4030_madc_set_current_generator(madc, 0, 1);
++
++ /* Enable ADCIN3 through 6 */
++ ret = twl_i2c_read_u8(TWL4030_MODULE_USB,
++ &regval, TWL4030_USB_CARKIT_ANA_CTRL);
++
++ regval |= TWL4030_USB_SEL_MADC_MCPC;
++
++ ret = twl_i2c_write_u8(TWL4030_MODULE_USB,
++ regval, TWL4030_USB_CARKIT_ANA_CTRL);
++
++
++ ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
++ &regval, TWL4030_BCI_BCICTL1);
++
++ regval |= TWL4030_BCI_MESBAT;
++
++ ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
++ regval, TWL4030_BCI_BCICTL1);
++
++ ret = request_irq(platform_get_irq(pdev, 0), twl4030_madc_irq_handler,
++ 0, "twl4030_madc", madc);
++ if (ret) {
++ dev_dbg(&pdev->dev, "could not request irq\n");
++ goto err_irq;
++ }
++
++ platform_set_drvdata(pdev, madc);
++ mutex_init(&madc->lock);
++ INIT_WORK(&madc->ws, twl4030_madc_work);
++
++ the_madc = madc;
++
++ return 0;
++
++err_irq:
++ misc_deregister(&twl4030_madc_device);
++
++err_misc:
++err_pdata:
++ kfree(madc);
++
++ return ret;
++}
++
++static int __exit twl4030_madc_remove(struct platform_device *pdev)
++{
++ struct twl4030_madc_data *madc = platform_get_drvdata(pdev);
++
++ twl4030_madc_set_power(madc, 0);
++ twl4030_madc_set_current_generator(madc, 0, 0);
++ free_irq(platform_get_irq(pdev, 0), madc);
++ cancel_work_sync(&madc->ws);
++ misc_deregister(&twl4030_madc_device);
++
++ return 0;
++}
++
++static struct platform_driver twl4030_madc_driver = {
++ .probe = twl4030_madc_probe,
++ .remove = __exit_p(twl4030_madc_remove),
++ .driver = {
++ .name = "twl4030_madc",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init twl4030_madc_init(void)
++{
++ return platform_driver_register(&twl4030_madc_driver);
++}
++module_init(twl4030_madc_init);
++
++static void __exit twl4030_madc_exit(void)
++{
++ platform_driver_unregister(&twl4030_madc_driver);
++}
++module_exit(twl4030_madc_exit);
++
++MODULE_ALIAS("platform:twl4030-madc");
++MODULE_AUTHOR("Nokia Corporation");
++MODULE_DESCRIPTION("twl4030 ADC driver");
++MODULE_LICENSE("GPL");
++
+diff --git a/include/linux/i2c/twl4030-madc.h b/include/linux/i2c/twl4030-madc.h
+new file mode 100644
+index 0000000..341a665
+--- /dev/null
++++ b/include/linux/i2c/twl4030-madc.h
+@@ -0,0 +1,130 @@
++/*
++ * include/linux/i2c/twl4030-madc.h
++ *
++ * TWL4030 MADC module driver header
++ *
++ * Copyright (C) 2008 Nokia Corporation
++ * Mikko Ylinen <mikko.k.ylinen@nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ *
++ */
++
++#ifndef _TWL4030_MADC_H
++#define _TWL4030_MADC_H
++
++struct twl4030_madc_conversion_method {
++ u8 sel;
++ u8 avg;
++ u8 rbase;
++ u8 ctrl;
++};
++
++#define TWL4030_MADC_MAX_CHANNELS 16
++
++struct twl4030_madc_request {
++ u16 channels;
++ u16 do_avg;
++ u16 method;
++ u16 type;
++ int active;
++ int result_pending;
++ int rbuf[TWL4030_MADC_MAX_CHANNELS];
++ void (*func_cb)(int len, int channels, int *buf);
++};
++
++enum conversion_methods {
++ TWL4030_MADC_RT,
++ TWL4030_MADC_SW1,
++ TWL4030_MADC_SW2,
++ TWL4030_MADC_NUM_METHODS
++};
++
++enum sample_type {
++ TWL4030_MADC_WAIT,
++ TWL4030_MADC_IRQ_ONESHOT,
++ TWL4030_MADC_IRQ_REARM
++};
++
++#define TWL4030_MADC_CTRL1 0x00
++#define TWL4030_MADC_CTRL2 0x01
++
++#define TWL4030_MADC_RTSELECT_LSB 0x02
++#define TWL4030_MADC_SW1SELECT_LSB 0x06
++#define TWL4030_MADC_SW2SELECT_LSB 0x0A
++
++#define TWL4030_MADC_RTAVERAGE_LSB 0x04
++#define TWL4030_MADC_SW1AVERAGE_LSB 0x08
++#define TWL4030_MADC_SW2AVERAGE_LSB 0x0C
++
++#define TWL4030_MADC_CTRL_SW1 0x12
++#define TWL4030_MADC_CTRL_SW2 0x13
++
++#define TWL4030_MADC_RTCH0_LSB 0x17
++#define TWL4030_MADC_GPCH0_LSB 0x37
++
++#define TWL4030_MADC_MADCON (1<<0) /* MADC power on */
++#define TWL4030_MADC_BUSY (1<<0) /* MADC busy */
++#define TWL4030_MADC_EOC_SW (1<<1) /* MADC conversion completion */
++#define TWL4030_MADC_SW_START (1<<5) /* MADC SWx start conversion */
++
++#define TWL4030_MADC_ADCIN0 (1<<0)
++#define TWL4030_MADC_ADCIN1 (1<<1)
++#define TWL4030_MADC_ADCIN2 (1<<2)
++#define TWL4030_MADC_ADCIN3 (1<<3)
++#define TWL4030_MADC_ADCIN4 (1<<4)
++#define TWL4030_MADC_ADCIN5 (1<<5)
++#define TWL4030_MADC_ADCIN6 (1<<6)
++#define TWL4030_MADC_ADCIN7 (1<<7)
++#define TWL4030_MADC_ADCIN8 (1<<8)
++#define TWL4030_MADC_ADCIN9 (1<<9)
++#define TWL4030_MADC_ADCIN10 (1<<10)
++#define TWL4030_MADC_ADCIN11 (1<<11)
++#define TWL4030_MADC_ADCIN12 (1<<12)
++#define TWL4030_MADC_ADCIN13 (1<<13)
++#define TWL4030_MADC_ADCIN14 (1<<14)
++#define TWL4030_MADC_ADCIN15 (1<<15)
++
++/* Fixed channels */
++#define TWL4030_MADC_BTEMP TWL4030_MADC_ADCIN1
++#define TWL4030_MADC_VBUS TWL4030_MADC_ADCIN8
++#define TWL4030_MADC_VBKB TWL4030_MADC_ADCIN9
++#define TWL4030_MADC_ICHG TWL4030_MADC_ADCIN10
++#define TWL4030_MADC_VCHG TWL4030_MADC_ADCIN11
++#define TWL4030_MADC_VBAT TWL4030_MADC_ADCIN12
++
++/* BCI related - XXX To be moved elsewhere */
++#define TWL4030_BCI_BCICTL1 0x23
++#define TWL4030_BCI_MESBAT (1<<1)
++#define TWL4030_BCI_TYPEN (1<<4)
++#define TWL4030_BCI_ITHEN (1<<3)
++
++/* USB related - XXX To be moved elsewhere */
++#define TWL4030_USB_CARKIT_ANA_CTRL 0xBB
++#define TWL4030_USB_SEL_MADC_MCPC (1<<3)
++
++#define TWL4030_MADC_IOC_MAGIC '`'
++#define TWL4030_MADC_IOCX_ADC_RAW_READ _IO(TWL4030_MADC_IOC_MAGIC, 0)
++
++struct twl4030_madc_user_parms {
++ int channel;
++ int average;
++ int status;
++ u16 result;
++};
++
++int twl4030_madc_conversion(struct twl4030_madc_request *conv);
++
++#endif
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0019-ARM-OMAP-Add-twl4030-madc-support-to-Overo.patch b/extras/recipes-kernel/linux/linux-omap/base/0019-ARM-OMAP-Add-twl4030-madc-support-to-Overo.patch
new file mode 100644
index 00000000..b24e4dd2
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0019-ARM-OMAP-Add-twl4030-madc-support-to-Overo.patch
@@ -0,0 +1,32 @@
+From a33c4e0fb917ca059e900c2851849ba604758ff9 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Thu, 17 Dec 2009 14:27:15 -0800
+Subject: [PATCH 19/28] ARM: OMAP: Add twl4030 madc support to Overo
+
+---
+ arch/arm/mach-omap2/board-overo.c | 5 +++++
+ 1 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
+index cb26e5d..17f066a 100644
+--- a/arch/arm/mach-omap2/board-overo.c
++++ b/arch/arm/mach-omap2/board-overo.c
+@@ -369,10 +369,15 @@ static struct twl4030_codec_data overo_codec_data = {
+
+ /* mmc2 (WLAN) and Bluetooth don't use twl4030 regulators */
+
++static struct twl4030_madc_platform_data overo_madc_data = {
++ .irq_line = 1,
++};
++
+ static struct twl4030_platform_data overo_twldata = {
+ .irq_base = TWL4030_IRQ_BASE,
+ .irq_end = TWL4030_IRQ_END,
+ .gpio = &overo_gpio_data,
++ .madc = &overo_madc_data,
+ .usb = &overo_usb_data,
+ .codec = &overo_codec_data,
+ .vmmc1 = &overo_vmmc1,
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0020-ARM-OMAP-Add-twl4030-madc-support-to-Beagle.patch b/extras/recipes-kernel/linux/linux-omap/base/0020-ARM-OMAP-Add-twl4030-madc-support-to-Beagle.patch
new file mode 100644
index 00000000..7028c17b
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0020-ARM-OMAP-Add-twl4030-madc-support-to-Beagle.patch
@@ -0,0 +1,35 @@
+From fe51c97f26f8d6798909b1f22a5fb4ca84684f36 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Thu, 17 Dec 2009 14:32:36 -0800
+Subject: [PATCH 20/28] ARM: OMAP: Add twl4030 madc support to Beagle
+
+---
+ arch/arm/mach-omap2/board-omap3beagle.c | 5 +++++
+ 1 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index f699701..9259780 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -604,6 +604,10 @@ static struct twl4030_codec_data beagle_codec_data = {
+ .audio = &beagle_audio_data,
+ };
+
++static struct twl4030_madc_platform_data beagle_madc_data = {
++ .irq_line = 1,
++};
++
+ static struct twl4030_platform_data beagle_twldata = {
+ .irq_base = TWL4030_IRQ_BASE,
+ .irq_end = TWL4030_IRQ_END,
+@@ -612,6 +616,7 @@ static struct twl4030_platform_data beagle_twldata = {
+ .usb = &beagle_usb_data,
+ .gpio = &beagle_gpio_data,
+ .codec = &beagle_codec_data,
++ .madc = &beagle_madc_data,
+ .vmmc1 = &beagle_vmmc1,
+ .vsim = &beagle_vsim,
+ .vdac = &beagle_vdac,
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0021-OMAP-DSS2-Add-support-for-Samsung-LTE430WQ-F0C-panel.patch b/extras/recipes-kernel/linux/linux-omap/base/0021-OMAP-DSS2-Add-support-for-Samsung-LTE430WQ-F0C-panel.patch
new file mode 100644
index 00000000..823ab9f3
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0021-OMAP-DSS2-Add-support-for-Samsung-LTE430WQ-F0C-panel.patch
@@ -0,0 +1,173 @@
+From f8049ce6302904c1d08d8813f8a60b10b8a476e7 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Tue, 23 Feb 2010 14:40:27 -0800
+Subject: [PATCH 21/28] OMAP: DSS2: Add support for Samsung LTE430WQ-F0C panel
+
+---
+ .../omap2/displays/panel-samsung-lte430wq-f0c.c | 154 ++++++++++++++++++++
+ 1 files changed, 154 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/video/omap2/displays/panel-samsung-lte430wq-f0c.c
+
+diff --git a/drivers/video/omap2/displays/panel-samsung-lte430wq-f0c.c b/drivers/video/omap2/displays/panel-samsung-lte430wq-f0c.c
+new file mode 100644
+index 0000000..6a29f9c
+--- /dev/null
++++ b/drivers/video/omap2/displays/panel-samsung-lte430wq-f0c.c
+@@ -0,0 +1,154 @@
++/*
++ * LCD panel driver for Samsung LTE430WQ-F0C
++ *
++ * Author: Steve Sakoman <steve@sakoman.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published by
++ * the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/module.h>
++#include <linux/delay.h>
++
++#include <plat/display.h>
++
++static struct omap_video_timings samsung_lte_timings = {
++ .x_res = 480,
++ .y_res = 272,
++
++ .pixel_clock = 9200,
++
++ .hsw = 41,
++ .hfp = 8,
++ .hbp = 45-41,
++
++ .vsw = 10,
++ .vfp = 4,
++ .vbp = 12-10,
++};
++
++static int samsung_lte_panel_power_on(struct omap_dss_device *dssdev)
++{
++ int r;
++
++ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
++ return 0;
++
++ r = omapdss_dpi_display_enable(dssdev);
++ if (r)
++ goto err0;
++
++ if (dssdev->platform_enable) {
++ r = dssdev->platform_enable(dssdev);
++ if (r)
++ goto err1;
++ }
++
++ return 0;
++err1:
++ omapdss_dpi_display_disable(dssdev);
++err0:
++ return r;
++}
++
++static void samsung_lte_panel_power_off(struct omap_dss_device *dssdev)
++{
++ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
++ return;
++
++ if (dssdev->platform_disable)
++ dssdev->platform_disable(dssdev);
++
++ omapdss_dpi_display_disable(dssdev);
++}
++
++static int samsung_lte_panel_probe(struct omap_dss_device *dssdev)
++{
++ dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
++ OMAP_DSS_LCD_IHS;
++ dssdev->panel.timings = samsung_lte_timings;
++
++ return 0;
++}
++
++static void samsung_lte_panel_remove(struct omap_dss_device *dssdev)
++{
++}
++
++static int samsung_lte_panel_enable(struct omap_dss_device *dssdev)
++{
++ int r = 0;
++
++ r = samsung_lte_panel_power_on(dssdev);
++ if (r)
++ return r;
++
++ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
++
++ return 0;
++}
++
++static void samsung_lte_panel_disable(struct omap_dss_device *dssdev)
++{
++ samsung_lte_panel_power_off(dssdev);
++
++ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
++}
++
++static int samsung_lte_panel_suspend(struct omap_dss_device *dssdev)
++{
++ samsung_lte_panel_disable(dssdev);
++ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
++ return 0;
++}
++
++static int samsung_lte_panel_resume(struct omap_dss_device *dssdev)
++{
++ int r;
++
++ r = samsung_lte_panel_enable(dssdev);
++ if (r)
++ return r;
++
++ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
++
++ return 0;
++}
++
++static struct omap_dss_driver samsung_lte_driver = {
++ .probe = samsung_lte_panel_probe,
++ .remove = samsung_lte_panel_remove,
++
++ .enable = samsung_lte_panel_enable,
++ .disable = samsung_lte_panel_disable,
++ .suspend = samsung_lte_panel_suspend,
++ .resume = samsung_lte_panel_resume,
++
++ .driver = {
++ .name = "samsung_lte_panel",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init samsung_lte_panel_drv_init(void)
++{
++ return omap_dss_register_driver(&samsung_lte_driver);
++}
++
++static void __exit samsung_lte_panel_drv_exit(void)
++{
++ omap_dss_unregister_driver(&samsung_lte_driver);
++}
++
++module_init(samsung_lte_panel_drv_init);
++module_exit(samsung_lte_panel_drv_exit);
++MODULE_LICENSE("GPL");
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0022-OMAP-DSS2-Add-support-for-LG-Philips-LB035Q02-panel.patch b/extras/recipes-kernel/linux/linux-omap/base/0022-OMAP-DSS2-Add-support-for-LG-Philips-LB035Q02-panel.patch
new file mode 100644
index 00000000..c3029423
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0022-OMAP-DSS2-Add-support-for-LG-Philips-LB035Q02-panel.patch
@@ -0,0 +1,299 @@
+From 93032782a4803072d7ab1e22da029325f8f3cf44 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Thu, 17 Dec 2009 15:05:30 -0800
+Subject: [PATCH 22/28] OMAP: DSS2: Add support for LG Philips LB035Q02 panel
+
+---
+ drivers/video/omap2/displays/Kconfig | 12 +
+ drivers/video/omap2/displays/Makefile | 2 +
+ .../omap2/displays/panel-lgphilips-lb035q02.c | 244 ++++++++++++++++++++
+ 3 files changed, 258 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
+
+diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
+index 12327bb..48e872f 100644
+--- a/drivers/video/omap2/displays/Kconfig
++++ b/drivers/video/omap2/displays/Kconfig
+@@ -7,6 +7,18 @@ config PANEL_GENERIC
+ Generic panel driver.
+ Used for DVI output for Beagle and OMAP3 SDP.
+
++config PANEL_LGPHILIPS_LB035Q02
++ tristate "LG.Philips LB035Q02 LCD Panel"
++ depends on OMAP2_DSS
++ help
++ LCD Panel used on Overo Palo35
++
++config PANEL_SAMSUNG_LTE430WQ_F0C
++ tristate "Samsung LTE430WQ-F0C LCD Panel"
++ depends on OMAP2_DSS
++ help
++ LCD Panel used on Overo Palo43
++
+ config PANEL_SHARP_LS037V7DW01
+ tristate "Sharp LS037V7DW01 LCD Panel"
+ depends on OMAP2_DSS
+diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
+index aa38609..2fb1a57 100644
+--- a/drivers/video/omap2/displays/Makefile
++++ b/drivers/video/omap2/displays/Makefile
+@@ -1,4 +1,6 @@
+ obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o
++obj-$(CONFIG_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o
++obj-$(CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C) += panel-samsung-lte430wq-f0c.o
+ obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
+ obj-$(CONFIG_PANEL_SHARP_LQ043T1DG01) += panel-sharp-lq043t1dg01.o
+
+diff --git a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
+new file mode 100644
+index 0000000..4ad709d
+--- /dev/null
++++ b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
+@@ -0,0 +1,244 @@
++/*
++ * LCD panel driver for LG.Philips LB035Q02
++ *
++ * Author: Steve Sakoman <steve@sakoman.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published by
++ * the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/spi/spi.h>
++
++#include <plat/display.h>
++
++static struct spi_device *spidev;
++
++static struct omap_video_timings lb035q02_timings = {
++ .x_res = 320,
++ .y_res = 240,
++
++ .pixel_clock = 6500,
++
++ .hsw = 2,
++ .hfp = 20,
++ .hbp = 68,
++
++ .vsw = 2,
++ .vfp = 4,
++ .vbp = 18,
++};
++
++static int lb035q02_write_reg(u8 reg, u16 val)
++{
++ struct spi_message msg;
++ struct spi_transfer index_xfer = {
++ .len = 3,
++ .cs_change = 1,
++ };
++ struct spi_transfer value_xfer = {
++ .len = 3,
++ };
++ u8 buffer[16];
++
++ spi_message_init(&msg);
++
++ /* register index */
++ buffer[0] = 0x70;
++ buffer[1] = 0x00;
++ buffer[2] = reg & 0x7f;
++ index_xfer.tx_buf = buffer;
++ spi_message_add_tail(&index_xfer, &msg);
++
++ /* register value */
++ buffer[4] = 0x72;
++ buffer[5] = val >> 8;
++ buffer[6] = val;
++ value_xfer.tx_buf = buffer + 4;
++ spi_message_add_tail(&value_xfer, &msg);
++
++ return spi_sync(spidev, &msg);
++}
++
++static int lb035q02_panel_power_on(struct omap_dss_device *dssdev)
++{
++ int r;
++
++ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
++ return 0;
++
++ r = omapdss_dpi_display_enable(dssdev);
++ if (r)
++ goto err0;
++
++ if (dssdev->platform_enable) {
++ r = dssdev->platform_enable(dssdev);
++ if (r)
++ goto err1;
++ }
++
++ /* Panel init sequence from page 28 of the spec */
++ lb035q02_write_reg(0x01, 0x6300);
++ lb035q02_write_reg(0x02, 0x0200);
++ lb035q02_write_reg(0x03, 0x0177);
++ lb035q02_write_reg(0x04, 0x04c7);
++ lb035q02_write_reg(0x05, 0xffc0);
++ lb035q02_write_reg(0x06, 0xe806);
++ lb035q02_write_reg(0x0a, 0x4008);
++ lb035q02_write_reg(0x0b, 0x0000);
++ lb035q02_write_reg(0x0d, 0x0030);
++ lb035q02_write_reg(0x0e, 0x2800);
++ lb035q02_write_reg(0x0f, 0x0000);
++ lb035q02_write_reg(0x16, 0x9f80);
++ lb035q02_write_reg(0x17, 0x0a0f);
++ lb035q02_write_reg(0x1e, 0x00c1);
++ lb035q02_write_reg(0x30, 0x0300);
++ lb035q02_write_reg(0x31, 0x0007);
++ lb035q02_write_reg(0x32, 0x0000);
++ lb035q02_write_reg(0x33, 0x0000);
++ lb035q02_write_reg(0x34, 0x0707);
++ lb035q02_write_reg(0x35, 0x0004);
++ lb035q02_write_reg(0x36, 0x0302);
++ lb035q02_write_reg(0x37, 0x0202);
++ lb035q02_write_reg(0x3a, 0x0a0d);
++ lb035q02_write_reg(0x3b, 0x0806);
++
++ return 0;
++err1:
++ omapdss_dpi_display_disable(dssdev);
++err0:
++ return r;
++}
++
++static void lb035q02_panel_power_off(struct omap_dss_device *dssdev)
++{
++ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
++ return;
++
++ if (dssdev->platform_disable)
++ dssdev->platform_disable(dssdev);
++
++ omapdss_dpi_display_disable(dssdev);
++}
++
++static int lb035q02_panel_probe(struct omap_dss_device *dssdev)
++{
++ dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
++ OMAP_DSS_LCD_IHS;
++ dssdev->panel.timings = lb035q02_timings;
++
++ return 0;
++}
++
++static void lb035q02_panel_remove(struct omap_dss_device *dssdev)
++{
++}
++
++static int lb035q02_panel_enable(struct omap_dss_device *dssdev)
++{
++ int r = 0;
++
++ r = lb035q02_panel_power_on(dssdev);
++ if (r)
++ return r;
++
++ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
++
++ return 0;
++}
++
++static void lb035q02_panel_disable(struct omap_dss_device *dssdev)
++{
++ lb035q02_panel_power_off(dssdev);
++
++ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
++}
++
++static int lb035q02_panel_suspend(struct omap_dss_device *dssdev)
++{
++ lb035q02_panel_disable(dssdev);
++ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
++ return 0;
++}
++
++static int lb035q02_panel_resume(struct omap_dss_device *dssdev)
++{
++ int r;
++
++ r = lb035q02_panel_power_on(dssdev);
++ if (r)
++ return r;
++
++ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
++
++ return 0;
++}
++
++static struct omap_dss_driver lb035q02_driver = {
++ .probe = lb035q02_panel_probe,
++ .remove = lb035q02_panel_remove,
++
++ .enable = lb035q02_panel_enable,
++ .disable = lb035q02_panel_disable,
++ .suspend = lb035q02_panel_suspend,
++ .resume = lb035q02_panel_resume,
++
++ .driver = {
++ .name = "lgphilips_lb035q02_panel",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __devinit lb035q02_panel_spi_probe(struct spi_device *spi)
++{
++ spidev = spi;
++ return 0;
++}
++
++static int __devexit lb035q02_panel_spi_remove(struct spi_device *spi)
++{
++ return 0;
++}
++
++static struct spi_driver lb035q02_spi_driver = {
++ .driver = {
++ .name = "lgphilips_lb035q02_panel-spi",
++ .owner = THIS_MODULE,
++ },
++ .probe = lb035q02_panel_spi_probe,
++ .remove = __devexit_p (lb035q02_panel_spi_remove),
++};
++
++static int __init lb035q02_panel_drv_init(void)
++{
++ int r;
++ r = spi_register_driver(&lb035q02_spi_driver);
++ if (r != 0)
++ pr_err("lgphilips_lb035q02: Unable to register SPI driver: %d\n", r);
++
++ r = omap_dss_register_driver(&lb035q02_driver);
++ if (r != 0)
++ pr_err("lgphilips_lb035q02: Unable to register panel driver: %d\n", r);
++
++ return r;
++}
++
++static void __exit lb035q02_panel_drv_exit(void)
++{
++ spi_unregister_driver(&lb035q02_spi_driver);
++ omap_dss_unregister_driver(&lb035q02_driver);
++}
++
++module_init(lb035q02_panel_drv_init);
++module_exit(lb035q02_panel_drv_exit);
++MODULE_LICENSE("GPL");
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0023-OMAP-DSS2-add-bootarg-for-selecting-svideo-or-compos.patch b/extras/recipes-kernel/linux/linux-omap/base/0023-OMAP-DSS2-add-bootarg-for-selecting-svideo-or-compos.patch
new file mode 100644
index 00000000..12f7d7b0
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0023-OMAP-DSS2-add-bootarg-for-selecting-svideo-or-compos.patch
@@ -0,0 +1,75 @@
+From f046a207183e3e338c7e851085265f0df95f4cc2 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Tue, 19 Jan 2010 21:19:15 -0800
+Subject: [PATCH 23/28] OMAP: DSS2: add bootarg for selecting svideo or composite for tv output
+
+also add pal-16 and ntsc-16 omapfb.mode settings for 16bpp
+---
+ drivers/video/omap2/dss/venc.c | 22 ++++++++++++++++++++++
+ drivers/video/omap2/omapfb/omapfb-main.c | 10 +++++++++-
+ 2 files changed, 31 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
+index eff3505..e1f4aab 100644
+--- a/drivers/video/omap2/dss/venc.c
++++ b/drivers/video/omap2/dss/venc.c
+@@ -87,6 +87,11 @@
+ #define VENC_OUTPUT_TEST 0xC8
+ #define VENC_DAC_B__DAC_C 0xC8
+
++static char *tv_connection;
++
++module_param_named(tvcable, tv_connection, charp, 0);
++MODULE_PARM_DESC(tvcable, "TV connection type (svideo, composite)");
++
+ struct venc_config {
+ u32 f_control;
+ u32 vidout_ctrl;
+@@ -459,6 +464,23 @@ static int venc_panel_probe(struct omap_dss_device *dssdev)
+ {
+ dssdev->panel.timings = omap_dss_pal_timings;
+
++ /* Allow the TV output to be overriden */
++ if (tv_connection) {
++ if (strcmp(tv_connection, "svideo") == 0) {
++ printk(KERN_INFO
++ "omapdss: tv output is svideo.\n");
++ dssdev->phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO;
++ } else if (strcmp(tv_connection, "composite") == 0) {
++ printk(KERN_INFO
++ "omapdss: tv output is composite.\n");
++ dssdev->phy.venc.type = OMAP_DSS_VENC_TYPE_COMPOSITE;
++ } else {
++ printk(KERN_INFO
++ "omapdss: unsupported output type'%s'.\n",
++ tv_connection);
++ }
++ }
++
+ return 0;
+ }
+
+diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
+index 6a704f1..7ee833f 100644
+--- a/drivers/video/omap2/omapfb/omapfb-main.c
++++ b/drivers/video/omap2/omapfb/omapfb-main.c
+@@ -2036,7 +2036,15 @@ static int omapfb_mode_to_timings(const char *mode_str,
+ int r;
+
+ #ifdef CONFIG_OMAP2_DSS_VENC
+- if (strcmp(mode_str, "pal") == 0) {
++ if (strcmp(mode_str, "pal-16") == 0) {
++ *timings = omap_dss_pal_timings;
++ *bpp = 16;
++ return 0;
++ } else if (strcmp(mode_str, "ntsc-16") == 0) {
++ *timings = omap_dss_ntsc_timings;
++ *bpp = 16;
++ return 0;
++ } else if (strcmp(mode_str, "pal") == 0) {
+ *timings = omap_dss_pal_timings;
+ *bpp = 24;
+ return 0;
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0024-ARM-OMAP2-mmc-twl4030-move-clock-input-selection-pri.patch b/extras/recipes-kernel/linux/linux-omap/base/0024-ARM-OMAP2-mmc-twl4030-move-clock-input-selection-pri.patch
new file mode 100644
index 00000000..f012a91a
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0024-ARM-OMAP2-mmc-twl4030-move-clock-input-selection-pri.patch
@@ -0,0 +1,39 @@
+From 66bba5baf225a1420c734aa0268e7dd37fc3f73b Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Sun, 24 Jan 2010 09:33:56 -0800
+Subject: [PATCH 24/28] ARM: OMAP2: mmc-twl4030: move clock input selection prior to vcc test
+
+otherwise it is not executed on systems that use non-twl regulators
+---
+ arch/arm/mach-omap2/hsmmc.c | 14 ++++++--------
+ 1 files changed, 6 insertions(+), 8 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
+index 34272e4..a74631d 100644
+--- a/arch/arm/mach-omap2/hsmmc.c
++++ b/arch/arm/mach-omap2/hsmmc.c
+@@ -186,15 +186,13 @@ static void hsmmc23_before_set_reg(struct device *dev, int slot,
+ if (mmc->slots[0].remux)
+ mmc->slots[0].remux(dev, slot, power_on);
+
+- if (power_on) {
+- /* Only MMC2 supports a CLKIN */
+- if (mmc->slots[0].internal_clock) {
+- u32 reg;
++ /* Only MMC2 supports a CLKIN */
++ if (mmc->slots[0].internal_clock) {
++ u32 reg;
+
+- reg = omap_ctrl_readl(control_devconf1_offset);
+- reg |= OMAP2_MMCSDIO2ADPCLKISEL;
+- omap_ctrl_writel(reg, control_devconf1_offset);
+- }
++ reg = omap_ctrl_readl(control_devconf1_offset);
++ reg |= OMAP2_MMCSDIO2ADPCLKISEL;
++ omap_ctrl_writel(reg, control_devconf1_offset);
+ }
+ }
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0025-RTC-add-support-for-backup-battery-recharge.patch b/extras/recipes-kernel/linux/linux-omap/base/0025-RTC-add-support-for-backup-battery-recharge.patch
new file mode 100644
index 00000000..419e7648
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0025-RTC-add-support-for-backup-battery-recharge.patch
@@ -0,0 +1,55 @@
+From ae08111e55d17183382dd06d161066adf9f80f3c Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Thu, 4 Feb 2010 12:26:22 -0800
+Subject: [PATCH 25/28] RTC: add support for backup battery recharge
+
+---
+ drivers/rtc/rtc-twl.c | 25 +++++++++++++++++++++++++
+ 1 files changed, 25 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c
+index ed1b868..33a8598 100644
+--- a/drivers/rtc/rtc-twl.c
++++ b/drivers/rtc/rtc-twl.c
+@@ -30,6 +30,23 @@
+
+ #include <linux/i2c/twl.h>
+
++/*
++ * PM_RECEIVER block register offsets (use TWL4030_MODULE_PM_RECEIVER)
++ */
++#define REG_BB_CFG 0x12
++
++/* PM_RECEIVER BB_CFG bitfields */
++#define BIT_PM_RECEIVER_BB_CFG_BBCHEN 0x10
++#define BIT_PM_RECEIVER_BB_CFG_BBSEL 0x0C
++#define BIT_PM_RECEIVER_BB_CFG_BBSEL_2V5 0x00
++#define BIT_PM_RECEIVER_BB_CFG_BBSEL_3V0 0x04
++#define BIT_PM_RECEIVER_BB_CFG_BBSEL_3V1 0x08
++#define BIT_PM_RECEIVER_BB_CFG_BBSEL_3v2 0x0c
++#define BIT_PM_RECEIVER_BB_CFG_BBISEL 0x03
++#define BIT_PM_RECEIVER_BB_CFG_BBISEL_25UA 0x00
++#define BIT_PM_RECEIVER_BB_CFG_BBISEL_150UA 0x01
++#define BIT_PM_RECEIVER_BB_CFG_BBISEL_500UA 0x02
++#define BIT_PM_RECEIVER_BB_CFG_BBISEL_1MA 0x03
+
+ /*
+ * RTC block register offsets (use TWL_MODULE_RTC)
+@@ -508,6 +525,14 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev)
+ if (ret < 0)
+ goto out2;
+
++ /* enable backup battery charging */
++ /* use a conservative 25uA @ 3.1V */
++ ret = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
++ BIT_PM_RECEIVER_BB_CFG_BBCHEN |
++ BIT_PM_RECEIVER_BB_CFG_BBSEL_3V1 |
++ BIT_PM_RECEIVER_BB_CFG_BBISEL_25UA,
++ REG_BB_CFG);
++
+ return ret;
+
+ out2:
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0026-ARM-OMAP-automatically-set-musb-mode-in-platform-dat.patch b/extras/recipes-kernel/linux/linux-omap/base/0026-ARM-OMAP-automatically-set-musb-mode-in-platform-dat.patch
new file mode 100644
index 00000000..b002f288
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0026-ARM-OMAP-automatically-set-musb-mode-in-platform-dat.patch
@@ -0,0 +1,49 @@
+From dd53a7c1ab8addfd2a943ea44b5ccc5700648323 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Wed, 24 Feb 2010 10:37:22 -0800
+Subject: [PATCH 26/28] ARM: OMAP: automatically set musb mode in platform data based on CONFIG options
+
+---
+ arch/arm/mach-omap2/board-omap3beagle.c | 6 ++++++
+ arch/arm/mach-omap2/board-overo.c | 6 ++++++
+ 2 files changed, 12 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 9259780..ad0c1d8 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -785,7 +785,13 @@ static struct omap_board_mux board_mux[] __initdata = {
+
+ static struct omap_musb_board_data musb_board_data = {
+ .interface_type = MUSB_INTERFACE_ULPI,
++#if defined(CONFIG_USB_MUSB_OTG)
+ .mode = MUSB_OTG,
++#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
++ .mode = MUSB_PERIPHERAL,
++#else
++ .mode = MUSB_HOST,
++#endif
+ .power = 100,
+ };
+
+diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
+index 17f066a..b28a9d5 100644
+--- a/arch/arm/mach-omap2/board-overo.c
++++ b/arch/arm/mach-omap2/board-overo.c
+@@ -447,7 +447,13 @@ static struct omap_board_mux board_mux[] __initdata = {
+
+ static struct omap_musb_board_data musb_board_data = {
+ .interface_type = MUSB_INTERFACE_ULPI,
++#if defined(CONFIG_USB_MUSB_OTG)
+ .mode = MUSB_OTG,
++#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
++ .mode = MUSB_PERIPHERAL,
++#else
++ .mode = MUSB_HOST,
++#endif
+ .power = 100,
+ };
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0027-OMAP-DSS2-check-for-both-cpu-type-and-revision-rathe.patch b/extras/recipes-kernel/linux/linux-omap/base/0027-OMAP-DSS2-check-for-both-cpu-type-and-revision-rathe.patch
new file mode 100644
index 00000000..8f672d9a
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0027-OMAP-DSS2-check-for-both-cpu-type-and-revision-rathe.patch
@@ -0,0 +1,34 @@
+From ec3e66ef2e222feb0408f16a3498be1ea9b6a9c0 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Mon, 10 May 2010 13:59:14 -0700
+Subject: [PATCH 27/28] OMAP: DSS2: check for both cpu type and revision, rather than just revision
+
+---
+ drivers/video/omap2/dss/dispc.c | 4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
+index fa40fa5..133916a 100644
+--- a/drivers/video/omap2/dss/dispc.c
++++ b/drivers/video/omap2/dss/dispc.c
+@@ -2101,7 +2101,7 @@ void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode)
+ static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
+ int vsw, int vfp, int vbp)
+ {
+- if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
++ if (cpu_is_omap24xx() || (cpu_is_omap34xx() && omap_rev_lt_3_0())) {
+ if (hsw < 1 || hsw > 64 ||
+ hfp < 1 || hfp > 256 ||
+ hbp < 1 || hbp > 256 ||
+@@ -2134,7 +2134,7 @@ static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp,
+ {
+ u32 timing_h, timing_v;
+
+- if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
++ if (cpu_is_omap24xx() || (cpu_is_omap34xx() && omap_rev_lt_3_0())) {
+ timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) |
+ FLD_VAL(hbp-1, 27, 20);
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/base/0028-OMAP-DSS2-Add-DSS2-support-for-Overo.patch b/extras/recipes-kernel/linux/linux-omap/base/0028-OMAP-DSS2-Add-DSS2-support-for-Overo.patch
new file mode 100644
index 00000000..ff2ab556
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/base/0028-OMAP-DSS2-Add-DSS2-support-for-Overo.patch
@@ -0,0 +1,355 @@
+From 9b2bfa418f2e1b7ed3e210cb7cba3cdd67f9925f Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Fri, 18 Dec 2009 06:39:24 -0800
+Subject: [PATCH 28/28] OMAP: DSS2: Add DSS2 support for Overo
+
+---
+ arch/arm/mach-omap2/board-overo.c | 238 +++++++++++++++++++++++++++++++------
+ 1 files changed, 204 insertions(+), 34 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
+index b28a9d5..8a44c17 100644
+--- a/arch/arm/mach-omap2/board-overo.c
++++ b/arch/arm/mach-omap2/board-overo.c
+@@ -28,6 +28,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/i2c/twl.h>
+ #include <linux/regulator/machine.h>
++#include <linux/spi/spi.h>
+
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/nand.h>
+@@ -41,10 +42,13 @@
+
+ #include <plat/board.h>
+ #include <plat/common.h>
++#include <plat/display.h>
+ #include <mach/gpio.h>
+ #include <plat/gpmc.h>
+ #include <mach/hardware.h>
+ #include <plat/nand.h>
++#include <plat/mcspi.h>
++#include <plat/mux.h>
+ #include <plat/usb.h>
+
+ #include "mux.h"
+@@ -68,8 +72,6 @@
+ #if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
+ defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+
+-#include <plat/mcspi.h>
+-#include <linux/spi/spi.h>
+ #include <linux/spi/ads7846.h>
+
+ static struct omap2_mcspi_device_config ads7846_mcspi_config = {
+@@ -94,18 +96,6 @@ static struct ads7846_platform_data ads7846_config = {
+ .keep_vref_on = 1,
+ };
+
+-static struct spi_board_info overo_spi_board_info[] __initdata = {
+- {
+- .modalias = "ads7846",
+- .bus_num = 1,
+- .chip_select = 0,
+- .max_speed_hz = 1500000,
+- .controller_data = &ads7846_mcspi_config,
+- .irq = OMAP_GPIO_IRQ(OVERO_GPIO_PENDOWN),
+- .platform_data = &ads7846_config,
+- }
+-};
+-
+ static void __init overo_ads7846_init(void)
+ {
+ if ((gpio_request(OVERO_GPIO_PENDOWN, "ADS7846_PENDOWN") == 0) &&
+@@ -115,9 +105,6 @@ static void __init overo_ads7846_init(void)
+ printk(KERN_ERR "could not obtain gpio for ADS7846_PENDOWN\n");
+ return;
+ }
+-
+- spi_register_board_info(overo_spi_board_info,
+- ARRAY_SIZE(overo_spi_board_info));
+ }
+
+ #else
+@@ -233,6 +220,139 @@ static inline void __init overo_init_smsc911x(void)
+ static inline void __init overo_init_smsc911x(void) { return; }
+ #endif
+
++/* DSS */
++static int lcd_enabled;
++static int dvi_enabled;
++
++#define OVERO_GPIO_LCD_EN 144
++#define OVERO_GPIO_LCD_BL 145
++
++static void __init overo_display_init(void)
++{
++ if ((gpio_request(OVERO_GPIO_LCD_EN, "OVERO_GPIO_LCD_EN") == 0) &&
++ (gpio_direction_output(OVERO_GPIO_LCD_EN, 1) == 0))
++ gpio_export(OVERO_GPIO_LCD_EN, 0);
++ else
++ printk(KERN_ERR "could not obtain gpio for "
++ "OVERO_GPIO_LCD_EN\n");
++
++ if ((gpio_request(OVERO_GPIO_LCD_BL, "OVERO_GPIO_LCD_BL") == 0) &&
++ (gpio_direction_output(OVERO_GPIO_LCD_BL, 1) == 0))
++ gpio_export(OVERO_GPIO_LCD_BL, 0);
++ else
++ printk(KERN_ERR "could not obtain gpio for "
++ "OVERO_GPIO_LCD_BL\n");
++}
++
++static int overo_panel_enable_dvi(struct omap_dss_device *dssdev)
++{
++ if (lcd_enabled) {
++ printk(KERN_ERR "cannot enable DVI, LCD is enabled\n");
++ return -EINVAL;
++ }
++ dvi_enabled = 1;
++
++ return 0;
++}
++
++static void overo_panel_disable_dvi(struct omap_dss_device *dssdev)
++{
++ dvi_enabled = 0;
++}
++
++static struct omap_dss_device overo_dvi_device = {
++ .type = OMAP_DISPLAY_TYPE_DPI,
++ .name = "dvi",
++ .driver_name = "generic_panel",
++ .phy.dpi.data_lines = 24,
++ .platform_enable = overo_panel_enable_dvi,
++ .platform_disable = overo_panel_disable_dvi,
++};
++
++static struct omap_dss_device overo_tv_device = {
++ .name = "tv",
++ .driver_name = "venc",
++ .type = OMAP_DISPLAY_TYPE_VENC,
++ .phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO,
++};
++
++static int overo_panel_enable_lcd(struct omap_dss_device *dssdev)
++{
++ if (dvi_enabled) {
++ printk(KERN_ERR "cannot enable LCD, DVI is enabled\n");
++ return -EINVAL;
++ }
++
++ gpio_set_value(OVERO_GPIO_LCD_EN, 1);
++ gpio_set_value(OVERO_GPIO_LCD_BL, 1);
++ lcd_enabled = 1;
++ return 0;
++}
++
++static void overo_panel_disable_lcd(struct omap_dss_device *dssdev)
++{
++ gpio_set_value(OVERO_GPIO_LCD_EN, 0);
++ gpio_set_value(OVERO_GPIO_LCD_BL, 0);
++ lcd_enabled = 0;
++}
++
++#if defined(CONFIG_PANEL_LGPHILIPS_LB035Q02) || \
++ defined(CONFIG_PANEL_LGPHILIPS_LB035Q02_MODULE)
++static struct omap_dss_device overo_lcd35_device = {
++ .type = OMAP_DISPLAY_TYPE_DPI,
++ .name = "lcd35",
++ .driver_name = "lgphilips_lb035q02_panel",
++ .phy.dpi.data_lines = 24,
++ .platform_enable = overo_panel_enable_lcd,
++ .platform_disable = overo_panel_disable_lcd,
++};
++#endif
++
++#if defined(CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C) || \
++ defined(CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C_MODULE)
++static struct omap_dss_device overo_lcd43_device = {
++ .type = OMAP_DISPLAY_TYPE_DPI,
++ .name = "lcd43",
++ .driver_name = "samsung_lte_panel",
++ .phy.dpi.data_lines = 24,
++ .platform_enable = overo_panel_enable_lcd,
++ .platform_disable = overo_panel_disable_lcd,
++};
++#endif
++
++static struct omap_dss_device *overo_dss_devices[] = {
++ &overo_dvi_device,
++ &overo_tv_device,
++#if defined(CONFIG_PANEL_LGPHILIPS_LB035Q02) || \
++ defined(CONFIG_PANEL_LGPHILIPS_LB035Q02_MODULE)
++ &overo_lcd35_device,
++#endif
++#if defined(CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C) || \
++ defined(CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C_MODULE)
++ &overo_lcd43_device,
++#endif
++};
++
++static struct omap_dss_board_info overo_dss_data = {
++ .num_devices = ARRAY_SIZE(overo_dss_devices),
++ .devices = overo_dss_devices,
++ .default_device = &overo_dvi_device,
++};
++
++static struct platform_device overo_dss_device = {
++ .name = "omapdss",
++ .id = -1,
++ .dev = {
++ .platform_data = &overo_dss_data,
++ },
++};
++
++static struct regulator_consumer_supply overo_vdda_dac_supply =
++ REGULATOR_SUPPLY("vdda_dac", "omapdss");
++
++static struct regulator_consumer_supply overo_vdds_dsi_supply =
++ REGULATOR_SUPPLY("vdds_dsi", "omapdss");
++
+ static struct mtd_partition overo_nand_partitions[] = {
+ {
+ .name = "xloader",
+@@ -358,6 +478,37 @@ static struct regulator_init_data overo_vmmc1 = {
+ .consumer_supplies = &overo_vmmc1_supply,
+ };
+
++/* VDAC for DSS driving S-Video (8 mA unloaded, max 65 mA) */
++static struct regulator_init_data overo_vdac = {
++ .constraints = {
++ .min_uV = 1800000,
++ .max_uV = 1800000,
++ .valid_modes_mask = REGULATOR_MODE_NORMAL
++ | REGULATOR_MODE_STANDBY,
++ .valid_ops_mask = REGULATOR_CHANGE_MODE
++ | REGULATOR_CHANGE_STATUS,
++ },
++ .num_consumer_supplies = 1,
++ .consumer_supplies = &overo_vdda_dac_supply,
++};
++
++/* VPLL2 for digital video outputs */
++static struct regulator_init_data overo_vpll2 = {
++ .constraints = {
++ .name = "VDVI",
++ .min_uV = 1800000,
++ .max_uV = 1800000,
++ .valid_modes_mask = REGULATOR_MODE_NORMAL
++ | REGULATOR_MODE_STANDBY,
++ .valid_ops_mask = REGULATOR_CHANGE_MODE
++ | REGULATOR_CHANGE_STATUS,
++ },
++ .num_consumer_supplies = 1,
++ .consumer_supplies = &overo_vdds_dsi_supply,
++};
++
++/* mmc2 (WLAN) and Bluetooth don't use twl4030 regulators */
++
+ static struct twl4030_codec_audio_data overo_audio_data = {
+ .audio_mclk = 26000000,
+ };
+@@ -367,8 +518,6 @@ static struct twl4030_codec_data overo_codec_data = {
+ .audio = &overo_audio_data,
+ };
+
+-/* mmc2 (WLAN) and Bluetooth don't use twl4030 regulators */
+-
+ static struct twl4030_madc_platform_data overo_madc_data = {
+ .irq_line = 1,
+ };
+@@ -381,6 +530,8 @@ static struct twl4030_platform_data overo_twldata = {
+ .usb = &overo_usb_data,
+ .codec = &overo_codec_data,
+ .vmmc1 = &overo_vmmc1,
++ .vdac = &overo_vdac,
++ .vpll2 = &overo_vpll2,
+ };
+
+ static struct i2c_board_info __initdata overo_i2c_boardinfo[] = {
+@@ -401,23 +552,41 @@ static int __init overo_i2c_init(void)
+ return 0;
+ }
+
+-static struct platform_device overo_lcd_device = {
+- .name = "overo_lcd",
+- .id = -1,
+-};
+-
+-static struct omap_lcd_config overo_lcd_config __initdata = {
+- .ctrl_name = "internal",
++static struct spi_board_info overo_spi_board_info[] __initdata = {
++#if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
++ defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
++ {
++ .modalias = "ads7846",
++ .bus_num = 1,
++ .chip_select = 0,
++ .max_speed_hz = 1500000,
++ .controller_data = &ads7846_mcspi_config,
++ .irq = OMAP_GPIO_IRQ(OVERO_GPIO_PENDOWN),
++ .platform_data = &ads7846_config,
++ },
++#endif
++#if defined(CONFIG_PANEL_LGPHILIPS_LB035Q02) || \
++ defined(CONFIG_PANEL_LGPHILIPS_LB035Q02_MODULE)
++ {
++ .modalias = "lgphilips_lb035q02_panel-spi",
++ .bus_num = 1,
++ .chip_select = 1,
++ .max_speed_hz = 500000,
++ .mode = SPI_MODE_3,
++ },
++#endif
+ };
+
+-static struct omap_board_config_kernel overo_config[] __initdata = {
+- { OMAP_TAG_LCD, &overo_lcd_config },
+-};
++static int __init overo_spi_init(void)
++{
++ overo_ads7846_init();
++ spi_register_board_info(overo_spi_board_info,
++ ARRAY_SIZE(overo_spi_board_info));
++ return 0;
++}
+
+ static void __init overo_init_irq(void)
+ {
+- omap_board_config = overo_config;
+- omap_board_config_size = ARRAY_SIZE(overo_config);
+ omap2_init_common_infrastructure();
+ omap2_init_common_devices(mt46h32m32lf6_sdrc_params,
+ mt46h32m32lf6_sdrc_params);
+@@ -425,7 +594,7 @@ static void __init overo_init_irq(void)
+ }
+
+ static struct platform_device *overo_devices[] __initdata = {
+- &overo_lcd_device,
++ &overo_dss_device,
+ };
+
+ static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+@@ -466,8 +635,9 @@ static void __init overo_init(void)
+ overo_flash_init();
+ usb_musb_init(&musb_board_data);
+ usb_ehci_init(&ehci_pdata);
+- overo_ads7846_init();
++ overo_spi_init();
+ overo_init_smsc911x();
++ overo_display_init();
+
+ /* Ensure SDRC pins are mux'd for self-refresh */
+ omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
+@@ -510,7 +680,7 @@ static void __init overo_init(void)
+ "OVERO_GPIO_USBH_CPEN\n");
+ }
+
+-MACHINE_START(OVERO, "Gumstix Overo")
++MACHINE_START(OVERO, "Gumstsix Overo")
+ .boot_params = 0x80000100,
+ .map_io = omap3_map_io,
+ .reserve = omap_reserve,
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/beagleboard/defconfig b/extras/recipes-kernel/linux/linux-omap/beagleboard/defconfig
new file mode 100644
index 00000000..738d8949
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/beagleboard/defconfig
@@ -0,0 +1,3361 @@
+#
+# Automatically generated make config: don't edit
+# Linux/arm 2.6.37 Kernel Configuration
+# Thu Jan 27 16:18:14 2011
+#
+CONFIG_ARM=y
+CONFIG_HAVE_PWM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_ARM_L1_CACHE_SHIFT_6=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+CONFIG_HAVE_IRQ_WORK=y
+CONFIG_IRQ_WORK=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+# CONFIG_AUDIT is not set
+# CONFIG_HAVE_GENERIC_HARDIRQS is not set
+# CONFIG_SPARSE_IRQ is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_PREEMPT_RCU=y
+# CONFIG_TINY_RCU is not set
+# CONFIG_TINY_PREEMPT_RCU is not set
+CONFIG_PREEMPT_RCU=y
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+CONFIG_CGROUP_NS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_MEM_RES_CTLR=y
+CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y
+CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+# CONFIG_BLK_CGROUP is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_MM_OWNER=y
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+CONFIG_RD_LZO=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_PERF_EVENTS=y
+# CONFIG_PERF_COUNTERS is not set
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_HW_BREAKPOINT=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+CONFIG_BLK_DEV_BSG=y
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_SPIN_UNLOCK is not set
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_READ_UNLOCK is not set
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_WRITE_UNLOCK is not set
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_VEXPRESS is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_LPC32XX is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_NUC93X is not set
+# CONFIG_ARCH_TEGRA is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5P64X0 is not set
+# CONFIG_ARCH_S5P6442 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_S5PV310 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_TCC_926 is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_PLAT_SPEAR is not set
+
+#
+# TI OMAP Common Features
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2PLUS=y
+
+#
+# OMAP Feature Selections
+#
+CONFIG_OMAP_SMARTREFLEX=y
+CONFIG_OMAP_SMARTREFLEX_CLASS3=y
+CONFIG_OMAP_RESET_CLOCKS=y
+# CONFIG_OMAP_MUX is not set
+CONFIG_OMAP_MCBSP=y
+CONFIG_OMAP_MBOX_FWK=m
+CONFIG_OMAP_MBOX_KFIFO_SIZE=256
+CONFIG_OMAP_IOMMU=m
+CONFIG_OMAP_IOMMU_DEBUG=m
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+# CONFIG_OMAP3_L2_AUX_SECURE_SAVE_RESTORE is not set
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_PM_NONE is not set
+CONFIG_OMAP_PM_NOOP=y
+
+#
+# TI OMAP2/3/4 Specific Features
+#
+CONFIG_ARCH_OMAP2PLUS_TYPICAL=y
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+# CONFIG_ARCH_OMAP4 is not set
+CONFIG_ARCH_OMAP3430=y
+CONFIG_OMAP_PACKAGE_CBB=y
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_OMAP3_BEAGLE=y
+# CONFIG_MACH_DEVKIT8000 is not set
+# CONFIG_MACH_OMAP_LDP is not set
+# CONFIG_MACH_OMAP3530_LV_SOM is not set
+# CONFIG_MACH_OMAP3_TORPEDO is not set
+CONFIG_MACH_OVERO=y
+CONFIG_MACH_OMAP3EVM=y
+# CONFIG_MACH_OMAP3517EVM is not set
+# CONFIG_MACH_CRANEBOARD is not set
+# CONFIG_MACH_OMAP3_PANDORA is not set
+CONFIG_MACH_OMAP3_TOUCHBOOK=y
+# CONFIG_MACH_OMAP_3430SDP is not set
+# CONFIG_MACH_NOKIA_RM680 is not set
+# CONFIG_MACH_NOKIA_RX51 is not set
+CONFIG_MACH_OMAP_ZOOM2=y
+# CONFIG_MACH_OMAP_ZOOM3 is not set
+# CONFIG_MACH_CM_T35 is not set
+# CONFIG_MACH_CM_T3517 is not set
+# CONFIG_MACH_IGEP0020 is not set
+# CONFIG_MACH_IGEP0030 is not set
+# CONFIG_MACH_SBC3530 is not set
+# CONFIG_MACH_OMAP_3630SDP is not set
+# CONFIG_OMAP3_EMU is not set
+# CONFIG_OMAP3_SDRC_AC_TIMING is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+CONFIG_ARM_THUMBEE=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_ARM_L1_CACHE_SHIFT=6
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_ARM_ERRATA_430973=y
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+# CONFIG_ARM_ERRATA_743622 is not set
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=128
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_LEDS=y
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_CC_STACKPROTECTOR is not set
+# CONFIG_DEPRECATED_PARAM_STRUCT is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=" debug "
+# CONFIG_CMDLINE_FORCE is not set
+# CONFIG_XIP_KERNEL is not set
+CONFIG_KEXEC=y
+CONFIG_ATAGS_PROC=y
+# CONFIG_AUTO_ZRELADDR is not set
+
+#
+# CPU Power Management
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+CONFIG_CPU_FREQ_DEBUG=y
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+CONFIG_PM=y
+CONFIG_PM_DEBUG=y
+# CONFIG_PM_ADVANCED_DEBUG is not set
+# CONFIG_PM_VERBOSE is not set
+CONFIG_CAN_PM_TRACE=y
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_NVS=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_PM_OPS=y
+CONFIG_ARCH_HAS_OPP=y
+CONFIG_PM_OPP=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_XFRM_IPCOMP=m
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE_DEMUX=m
+CONFIG_NET_IPGRE=m
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_LRO=y
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BIC=m
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+CONFIG_TCP_CONG_LP=m
+CONFIG_TCP_CONG_VENO=m
+CONFIG_TCP_CONG_YEAH=m
+CONFIG_TCP_CONG_ILLINOIS=m
+CONFIG_DEFAULT_CUBIC=y
+# CONFIG_DEFAULT_RENO is not set
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_MIP6=m
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_SIT=m
+# CONFIG_IPV6_SIT_6RD is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_IPV6_TUNNEL=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
+# CONFIG_IPV6_PIMSM_V2 is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETWORK_PHY_TIMESTAMPING=y
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_ZONES=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=m
+CONFIG_NF_CT_PROTO_GRE=m
+CONFIG_NF_CT_PROTO_SCTP=m
+CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+# CONFIG_NETFILTER_TPROXY is not set
+CONFIG_NETFILTER_XTABLES=m
+
+#
+# Xtables combined modules
+#
+CONFIG_NETFILTER_XT_MARK=m
+CONFIG_NETFILTER_XT_CONNMARK=m
+
+#
+# Xtables targets
+#
+CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CT=m
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+CONFIG_NETFILTER_XT_TARGET_HL=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+# CONFIG_NETFILTER_XT_TARGET_LED is not set
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
+CONFIG_NETFILTER_XT_TARGET_RATEEST=m
+CONFIG_NETFILTER_XT_TARGET_TEE=m
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
+
+#
+# Xtables matches
+#
+# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_CPU=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_HL=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_IPVS=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+# CONFIG_NETFILTER_XT_MATCH_OSF is not set
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+CONFIG_IP_VS=m
+CONFIG_IP_VS_IPV6=y
+CONFIG_IP_VS_DEBUG=y
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS transport protocol load balancing support
+#
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_AH_ESP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+# CONFIG_IP_VS_PROTO_SCTP is not set
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+
+#
+# IPVS application helper
+#
+CONFIG_IP_VS_FTP=m
+CONFIG_IP_VS_NFCT=y
+CONFIG_IP_VS_PE_SIP=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=m
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_NF_NAT=m
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_NF_NAT_SNMP_BASIC=m
+CONFIG_NF_NAT_PROTO_DCCP=m
+CONFIG_NF_NAT_PROTO_GRE=m
+CONFIG_NF_NAT_PROTO_UDPLITE=m
+CONFIG_NF_NAT_PROTO_SCTP=m
+CONFIG_NF_NAT_FTP=m
+CONFIG_NF_NAT_IRC=m
+CONFIG_NF_NAT_TFTP=m
+CONFIG_NF_NAT_AMANDA=m
+CONFIG_NF_NAT_PPTP=m
+CONFIG_NF_NAT_H323=m
+CONFIG_NF_NAT_SIP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV6=m
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+CONFIG_IP_DCCP=m
+CONFIG_INET_DCCP_DIAG=m
+
+#
+# DCCP CCIDs Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP_CCID2_DEBUG is not set
+CONFIG_IP_DCCP_CCID3=y
+# CONFIG_IP_DCCP_CCID3_DEBUG is not set
+CONFIG_IP_DCCP_TFRC_LIB=y
+
+#
+# DCCP Kernel Hacking
+#
+# CONFIG_IP_DCCP_DEBUG is not set
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+# CONFIG_RDS is not set
+CONFIG_TIPC=m
+# CONFIG_TIPC_ADVANCED is not set
+# CONFIG_TIPC_DEBUG is not set
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+# CONFIG_ATM_CLIP_NO_ICMP is not set
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+# CONFIG_ATM_BR2684_IPFILTER is not set
+CONFIG_L2TP=m
+CONFIG_L2TP_DEBUGFS=m
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=m
+CONFIG_L2TP_ETH=m
+CONFIG_STP=m
+CONFIG_GARP=m
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+# CONFIG_NET_DSA is not set
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+CONFIG_WAN_ROUTER=m
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_DRR=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_CLS_CGROUP=m
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_DCB is not set
+CONFIG_DNS_RESOLVER=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_CAN=m
+CONFIG_CAN_RAW=m
+CONFIG_CAN_BCM=m
+
+#
+# CAN Device Drivers
+#
+CONFIG_CAN_VCAN=m
+# CONFIG_CAN_DEV is not set
+# CONFIG_CAN_DEBUG_DEVICES is not set
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+CONFIG_IRDA_ULTRA=y
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+
+#
+# Dongle support
+#
+CONFIG_DONGLE=y
+CONFIG_ESI_DONGLE=m
+CONFIG_ACTISYS_DONGLE=m
+CONFIG_TEKRAM_DONGLE=m
+CONFIG_TOIM3232_DONGLE=m
+CONFIG_LITELINK_DONGLE=m
+CONFIG_MA600_DONGLE=m
+CONFIG_GIRBIL_DONGLE=m
+CONFIG_MCP2120_DONGLE=m
+CONFIG_OLD_BELKIN_DONGLE=m
+# CONFIG_ACT200L_DONGLE is not set
+CONFIG_KINGSUN_DONGLE=m
+CONFIG_KSDAZZLE_DONGLE=m
+CONFIG_KS959_DONGLE=m
+
+#
+# FIR device drivers
+#
+CONFIG_USB_IRDA=m
+CONFIG_SIGMATEL_FIR=m
+CONFIG_MCS_FIR=m
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIBTSDIO=m
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_ATH3K=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_BT_MRVL is not set
+CONFIG_BT_ATH3K=m
+CONFIG_BT_WILINK=m
+CONFIG_AF_RXRPC=m
+# CONFIG_AF_RXRPC_DEBUG is not set
+# CONFIG_RXKAD is not set
+CONFIG_FIB_RULES=y
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_SPY=y
+CONFIG_WEXT_PRIV=y
+CONFIG_CFG80211=m
+CONFIG_NL80211_TESTMODE=y
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_DEBUGFS is not set
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+CONFIG_CFG80211_WEXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+CONFIG_LIB80211=y
+CONFIG_LIB80211_CRYPT_WEP=m
+CONFIG_LIB80211_CRYPT_CCMP=m
+CONFIG_LIB80211_CRYPT_TKIP=m
+# CONFIG_LIB80211_DEBUG is not set
+CONFIG_MAC80211=m
+CONFIG_MAC80211_HAS_RC=y
+CONFIG_MAC80211_RC_PID=y
+# CONFIG_MAC80211_RC_MINSTREL is not set
+CONFIG_MAC80211_RC_DEFAULT_PID=y
+CONFIG_MAC80211_RC_DEFAULT="pid"
+# CONFIG_MAC80211_MESH is not set
+CONFIG_MAC80211_LEDS=y
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+CONFIG_WIMAX=m
+CONFIG_WIMAX_DEBUG_LEVEL=8
+CONFIG_RFKILL=m
+CONFIG_RFKILL_LEDS=y
+CONFIG_RFKILL_INPUT=y
+CONFIG_NET_9P=m
+# CONFIG_NET_9P_DEBUG is not set
+# CONFIG_CAIF is not set
+CONFIG_CEPH_LIB=m
+# CONFIG_CEPH_LIB_PRETTYDEBUG is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH=""
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+CONFIG_SM_FTL=m
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND_ECC=y
+# CONFIG_MTD_NAND_ECC_SMC is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_SM_COMMON is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_OMAP2=y
+CONFIG_MTD_NAND_OMAP_PREFETCH=y
+# CONFIG_MTD_NAND_OMAP_PREFETCH_DMA is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+CONFIG_MTD_NAND_PLATFORM=y
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+# CONFIG_MTD_UBI_GLUEBI is not set
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
+# CONFIG_BLK_DEV_RBD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_APDS9802ALS is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_ISL29020 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+CONFIG_SENSORS_BH1780=m
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_APDS990X is not set
+CONFIG_HMC6352=m
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+CONFIG_BMP085=m
+CONFIG_USRP_E=m
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+CONFIG_EEPROM_AT24=m
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+CONFIG_EEPROM_93CX6=y
+CONFIG_IWMC3200TOP=m
+# CONFIG_IWMC3200TOP_DEBUG is not set
+# CONFIG_IWMC3200TOP_DEBUGFS is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+CONFIG_TI_ST=m
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=m
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+CONFIG_SCSI_ISCSI_ATTRS=m
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+CONFIG_ISCSI_TCP=m
+CONFIG_ISCSI_BOOT_SYSFS=m
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID456=m
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+# CONFIG_DM_DEBUG is not set
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+# CONFIG_DM_LOG_USERSPACE is not set
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+# CONFIG_DM_MULTIPATH_QL is not set
+# CONFIG_DM_MULTIPATH_ST is not set
+CONFIG_DM_DELAY=m
+# CONFIG_DM_UEVENT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_MACVLAN=m
+CONFIG_MACVTAP=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+CONFIG_VETH=m
+CONFIG_MII=y
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+CONFIG_BCM63XX_PHY=m
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+CONFIG_MICREL_PHY=m
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_AX88796 is not set
+CONFIG_SMC91X=y
+# CONFIG_TI_DAVINCI_EMAC is not set
+CONFIG_TI_DAVINCI_MDIO=m
+CONFIG_TI_DAVINCI_CPDMA=m
+# CONFIG_DM9000 is not set
+CONFIG_ENC28J60=y
+# CONFIG_ENC28J60_WRITEVERIFY is not set
+# CONFIG_ETHOC is not set
+CONFIG_SMC911X=y
+CONFIG_SMSC911X=y
+# CONFIG_SMSC911X_ARCH_HOOKS is not set
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+CONFIG_KS8851=y
+# CONFIG_KS8851_MLL is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+CONFIG_WLAN=y
+# CONFIG_LIBERTAS_THINFIRM is not set
+CONFIG_AT76C50X_USB=m
+CONFIG_USB_ZD1201=m
+CONFIG_USB_NET_RNDIS_WLAN=m
+CONFIG_RTL8187=m
+CONFIG_RTL8187_LEDS=y
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_ATH_COMMON is not set
+CONFIG_B43=m
+# CONFIG_B43_SDIO is not set
+CONFIG_B43_PIO=y
+CONFIG_B43_PHY_LP=y
+CONFIG_B43_LEDS=y
+CONFIG_B43_HWRNG=y
+# CONFIG_B43_DEBUG is not set
+# CONFIG_B43LEGACY is not set
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_HOSTAP_FIRMWARE_NVRAM=y
+# CONFIG_IWM is not set
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+# CONFIG_LIBERTAS_SDIO is not set
+# CONFIG_LIBERTAS_SPI is not set
+# CONFIG_LIBERTAS_DEBUG is not set
+# CONFIG_LIBERTAS_MESH is not set
+CONFIG_P54_COMMON=m
+CONFIG_P54_USB=m
+# CONFIG_P54_SPI is not set
+CONFIG_P54_LEDS=y
+CONFIG_RT2X00=m
+CONFIG_RT2500USB=m
+CONFIG_RT73USB=m
+# CONFIG_RT2800USB is not set
+CONFIG_RT2X00_LIB_USB=m
+CONFIG_RT2X00_LIB=m
+CONFIG_RT2X00_LIB_FIRMWARE=y
+CONFIG_RT2X00_LIB_CRYPTO=y
+CONFIG_RT2X00_LIB_LEDS=y
+# CONFIG_RT2X00_DEBUG is not set
+CONFIG_WL1251=m
+CONFIG_WL1251_SPI=m
+CONFIG_WL1251_SDIO=m
+CONFIG_WL12XX=m
+CONFIG_WL1271=m
+CONFIG_WL1271_HT=y
+CONFIG_WL1271_SPI=m
+CONFIG_WL1271_SDIO=m
+CONFIG_WL12XX_PLATFORM_DATA=y
+CONFIG_ZD1211RW=m
+# CONFIG_ZD1211RW_DEBUG is not set
+
+#
+# WiMAX Wireless Broadband devices
+#
+CONFIG_WIMAX_I2400M=m
+CONFIG_WIMAX_I2400M_USB=m
+CONFIG_WIMAX_I2400M_SDIO=m
+CONFIG_WIMAX_IWMC3200_SDIO=y
+CONFIG_WIMAX_I2400M_DEBUG_LEVEL=8
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_CATC=y
+CONFIG_USB_KAWETH=y
+CONFIG_USB_PEGASUS=y
+CONFIG_USB_RTL8150=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_CDC_EEM is not set
+CONFIG_USB_NET_DM9601=y
+CONFIG_USB_NET_SMSC75XX=m
+CONFIG_USB_NET_SMSC95XX=y
+CONFIG_USB_NET_GL620A=y
+CONFIG_USB_NET_NET1080=y
+CONFIG_USB_NET_PLUSB=y
+CONFIG_USB_NET_MCS7830=y
+CONFIG_USB_NET_RNDIS_HOST=y
+CONFIG_USB_NET_CDC_SUBSET=y
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_NET_ZAURUS=y
+CONFIG_USB_NET_CX82310_ETH=m
+CONFIG_USB_HSO=m
+CONFIG_USB_NET_INT51X1=m
+CONFIG_USB_IPHETH=m
+CONFIG_USB_SIERRA_NET=m
+# CONFIG_WAN is not set
+CONFIG_ATM_DRIVERS=y
+# CONFIG_ATM_DUMMY is not set
+# CONFIG_ATM_TCP is not set
+
+#
+# CAIF transport drivers
+#
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_PPTP=m
+# CONFIG_PPPOATM is not set
+CONFIG_PPPOL2TP=m
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+CONFIG_NETCONSOLE=m
+CONFIG_NETCONSOLE_DYNAMIC=y
+CONFIG_NETPOLL=y
+CONFIG_NETPOLL_TRAP=y
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_FF_MEMLESS=y
+CONFIG_INPUT_POLLDEV=y
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_QT2160=m
+# CONFIG_KEYBOARD_LKKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_KEYBOARD_GPIO_POLLED is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+CONFIG_KEYBOARD_MCS=m
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_TWL4030 is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_GPIO is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_AD714X=m
+CONFIG_INPUT_AD714X_I2C=m
+CONFIG_INPUT_AD714X_SPI=m
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+CONFIG_INPUT_TWL4030_PWRBUTTON=y
+CONFIG_INPUT_TWL4030_VIBRA=m
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_PCF8574=m
+CONFIG_INPUT_PWM_BEEPER=m
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+CONFIG_INPUT_ADXL34X=m
+CONFIG_INPUT_ADXL34X_I2C=m
+CONFIG_INPUT_ADXL34X_SPI=m
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_SERIO_PS2MULT is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_N_GSM=m
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+# CONFIG_SERIAL_MAX3107 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_OMAP=y
+CONFIG_SERIAL_OMAP_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_TTY_PRINTK=y
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_RAMOOPS is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MUX=m
+
+#
+# Multiplexer I2C Chip support
+#
+# CONFIG_I2C_MUX_PCA9541 is not set
+# CONFIG_I2C_MUX_PCA954x is not set
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOBIT=m
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+CONFIG_SPI_OMAP24XX=y
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+CONFIG_SPI_SPIDEV=y
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_MAX730X=m
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_BASIC_MMIO is not set
+# CONFIG_GPIO_IT8761E is not set
+# CONFIG_GPIO_VX855 is not set
+
+#
+# I2C GPIO expanders:
+#
+CONFIG_GPIO_MAX7300=m
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_SX150X is not set
+CONFIG_GPIO_TWL4030=y
+CONFIG_GPIO_ADP5588=m
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+# CONFIG_GPIO_74X164 is not set
+
+#
+# AC97 GPIO expanders:
+#
+
+#
+# MODULbus GPIO expanders:
+#
+# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=m
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+CONFIG_TEST_POWER=m
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_BQ20Z75 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_MAX17040 is not set
+CONFIG_CHARGER_ISP1704=m
+CONFIG_CHARGER_TWL4030=m
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADCXX is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+CONFIG_SENSORS_ADT7411=m
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+CONFIG_SENSORS_ASC7621=m
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+CONFIG_SENSORS_GPIO_FAN=m
+# CONFIG_SENSORS_IT87 is not set
+CONFIG_SENSORS_JC42=m
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM73 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LTC4261 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_SHT15 is not set
+CONFIG_SENSORS_SMM665=m
+# CONFIG_SENSORS_DME1737 is not set
+CONFIG_SENSORS_EMC1403=m
+CONFIG_SENSORS_EMC2103=m
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+CONFIG_SENSORS_ADS7871=m
+CONFIG_SENSORS_AMC6821=m
+# CONFIG_SENSORS_THMC50 is not set
+CONFIG_SENSORS_TMP102=m
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83795 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_LIS3_SPI is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
+CONFIG_THERMAL=y
+CONFIG_THERMAL_HWMON=y
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+# CONFIG_TWL4030_WATCHDOG is not set
+# CONFIG_MAX63XX_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB=y
+CONFIG_SSB_BLOCKIO=y
+CONFIG_SSB_SDIOHOST_POSSIBLE=y
+# CONFIG_SSB_SDIOHOST is not set
+# CONFIG_SSB_SILENT is not set
+# CONFIG_SSB_DEBUG is not set
+CONFIG_MFD_SUPPORT=y
+CONFIG_MFD_CORE=y
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_HTC_I2CPLD is not set
+# CONFIG_TPS65010 is not set
+CONFIG_TPS6507X=m
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_POWER=y
+CONFIG_TWL4030_CODEC=y
+CONFIG_TWL4030_MADC=m
+CONFIG_TWL6030_PWM=m
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC35892 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM831X_SPI is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13XXX is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_EZX_PCAP is not set
+CONFIG_MFD_TPS6586X=y
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+CONFIG_REGULATOR_DUMMY=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_MAX8649 is not set
+# CONFIG_REGULATOR_MAX8660 is not set
+# CONFIG_REGULATOR_MAX8952 is not set
+CONFIG_REGULATOR_TWL4030=y
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_LP3972 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+# CONFIG_REGULATOR_ISL6271A is not set
+# CONFIG_REGULATOR_AD5398 is not set
+CONFIG_REGULATOR_TPS6586X=m
+CONFIG_MEDIA_SUPPORT=y
+
+#
+# Multimedia core support
+#
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+CONFIG_VIDEO_ALLOW_V4L1=y
+CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_DVB_CORE=m
+CONFIG_VIDEO_MEDIA=m
+
+#
+# Multimedia drivers
+#
+CONFIG_IR_CORE=m
+CONFIG_VIDEO_IR=m
+CONFIG_LIRC=m
+CONFIG_RC_MAP=m
+CONFIG_IR_NEC_DECODER=m
+CONFIG_IR_RC5_DECODER=m
+CONFIG_IR_RC6_DECODER=m
+CONFIG_IR_JVC_DECODER=m
+CONFIG_IR_SONY_DECODER=m
+CONFIG_IR_RC5_SZ_DECODER=m
+CONFIG_IR_LIRC_CODEC=m
+# CONFIG_IR_IMON is not set
+# CONFIG_IR_MCEUSB is not set
+# CONFIG_IR_STREAMZAP is not set
+CONFIG_MEDIA_ATTACH=y
+CONFIG_MEDIA_TUNER=m
+CONFIG_MEDIA_TUNER_CUSTOMISE=y
+
+#
+# Customize TV tuners
+#
+CONFIG_MEDIA_TUNER_SIMPLE=m
+CONFIG_MEDIA_TUNER_TDA8290=m
+CONFIG_MEDIA_TUNER_TDA827X=m
+CONFIG_MEDIA_TUNER_TDA18271=m
+CONFIG_MEDIA_TUNER_TDA9887=m
+CONFIG_MEDIA_TUNER_TEA5761=m
+CONFIG_MEDIA_TUNER_TEA5767=m
+CONFIG_MEDIA_TUNER_MT20XX=m
+CONFIG_MEDIA_TUNER_MT2060=m
+CONFIG_MEDIA_TUNER_MT2266=m
+CONFIG_MEDIA_TUNER_MT2131=m
+CONFIG_MEDIA_TUNER_QT1010=m
+CONFIG_MEDIA_TUNER_XC2028=m
+CONFIG_MEDIA_TUNER_XC5000=m
+CONFIG_MEDIA_TUNER_MXL5005S=m
+CONFIG_MEDIA_TUNER_MXL5007T=m
+CONFIG_MEDIA_TUNER_MC44S803=m
+CONFIG_MEDIA_TUNER_MAX2165=m
+CONFIG_MEDIA_TUNER_TDA18218=m
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_V4L1=y
+CONFIG_VIDEOBUF_GEN=y
+CONFIG_VIDEOBUF_VMALLOC=m
+CONFIG_VIDEOBUF_DMA_CONTIG=y
+CONFIG_VIDEOBUF_DVB=m
+CONFIG_VIDEO_TVEEPROM=m
+CONFIG_VIDEO_TUNER=m
+CONFIG_V4L2_MEM2MEM_DEV=m
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
+CONFIG_VIDEO_IR_I2C=m
+
+#
+# Encoders/decoders and other helper chips
+#
+
+#
+# Audio decoders
+#
+# CONFIG_VIDEO_TVAUDIO is not set
+# CONFIG_VIDEO_TDA7432 is not set
+# CONFIG_VIDEO_TDA9840 is not set
+# CONFIG_VIDEO_TDA9875 is not set
+# CONFIG_VIDEO_TEA6415C is not set
+# CONFIG_VIDEO_TEA6420 is not set
+CONFIG_VIDEO_MSP3400=m
+# CONFIG_VIDEO_CS5345 is not set
+CONFIG_VIDEO_CS53L32A=m
+# CONFIG_VIDEO_M52790 is not set
+# CONFIG_VIDEO_TLV320AIC23B is not set
+CONFIG_VIDEO_WM8775=m
+# CONFIG_VIDEO_WM8739 is not set
+# CONFIG_VIDEO_VP27SMPX is not set
+
+#
+# RDS decoders
+#
+# CONFIG_VIDEO_SAA6588 is not set
+
+#
+# Video decoders
+#
+# CONFIG_VIDEO_ADV7180 is not set
+# CONFIG_VIDEO_BT819 is not set
+# CONFIG_VIDEO_BT856 is not set
+# CONFIG_VIDEO_BT866 is not set
+# CONFIG_VIDEO_KS0127 is not set
+# CONFIG_VIDEO_OV7670 is not set
+CONFIG_VIDEO_MT9V011=m
+# CONFIG_VIDEO_TCM825X is not set
+# CONFIG_VIDEO_SAA7110 is not set
+CONFIG_VIDEO_SAA711X=m
+# CONFIG_VIDEO_SAA717X is not set
+# CONFIG_VIDEO_SAA7191 is not set
+# CONFIG_VIDEO_TVP514X is not set
+# CONFIG_VIDEO_TVP5150 is not set
+# CONFIG_VIDEO_TVP7002 is not set
+# CONFIG_VIDEO_VPX3220 is not set
+
+#
+# Video and audio decoders
+#
+CONFIG_VIDEO_CX25840=m
+
+#
+# MPEG video encoders
+#
+CONFIG_VIDEO_CX2341X=m
+
+#
+# Video encoders
+#
+# CONFIG_VIDEO_SAA7127 is not set
+# CONFIG_VIDEO_SAA7185 is not set
+# CONFIG_VIDEO_ADV7170 is not set
+# CONFIG_VIDEO_ADV7175 is not set
+# CONFIG_VIDEO_THS7303 is not set
+# CONFIG_VIDEO_ADV7343 is not set
+# CONFIG_VIDEO_AK881X is not set
+
+#
+# Video improvement chips
+#
+# CONFIG_VIDEO_UPD64031A is not set
+# CONFIG_VIDEO_UPD64083 is not set
+CONFIG_VIDEO_VIVI=m
+CONFIG_VIDEO_VPFE_CAPTURE=y
+# CONFIG_VIDEO_DM6446_CCDC is not set
+CONFIG_VIDEO_OMAP2_VOUT=y
+# CONFIG_VIDEO_CPIA2 is not set
+# CONFIG_VIDEO_AU0828 is not set
+CONFIG_VIDEO_SR030PC30=m
+CONFIG_VIDEO_OMAP3=y
+# CONFIG_VIDEO_OMAP3_DEBUG is not set
+# CONFIG_SOC_CAMERA is not set
+CONFIG_V4L_USB_DRIVERS=y
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
+CONFIG_USB_GSPCA=m
+CONFIG_USB_M5602=m
+CONFIG_USB_STV06XX=m
+# CONFIG_USB_GL860 is not set
+CONFIG_USB_GSPCA_BENQ=m
+CONFIG_USB_GSPCA_CONEX=m
+CONFIG_USB_GSPCA_CPIA1=m
+CONFIG_USB_GSPCA_ETOMS=m
+CONFIG_USB_GSPCA_FINEPIX=m
+# CONFIG_USB_GSPCA_JEILINJ is not set
+CONFIG_USB_GSPCA_KONICA=m
+CONFIG_USB_GSPCA_MARS=m
+# CONFIG_USB_GSPCA_MR97310A is not set
+CONFIG_USB_GSPCA_OV519=m
+CONFIG_USB_GSPCA_OV534=m
+CONFIG_USB_GSPCA_OV534_9=m
+CONFIG_USB_GSPCA_PAC207=m
+# CONFIG_USB_GSPCA_PAC7302 is not set
+CONFIG_USB_GSPCA_PAC7311=m
+CONFIG_USB_GSPCA_SN9C2028=m
+# CONFIG_USB_GSPCA_SN9C20X is not set
+CONFIG_USB_GSPCA_SONIXB=m
+CONFIG_USB_GSPCA_SONIXJ=m
+CONFIG_USB_GSPCA_SPCA500=m
+CONFIG_USB_GSPCA_SPCA501=m
+CONFIG_USB_GSPCA_SPCA505=m
+CONFIG_USB_GSPCA_SPCA506=m
+CONFIG_USB_GSPCA_SPCA508=m
+CONFIG_USB_GSPCA_SPCA561=m
+CONFIG_USB_GSPCA_SPCA1528=m
+# CONFIG_USB_GSPCA_SQ905 is not set
+# CONFIG_USB_GSPCA_SQ905C is not set
+CONFIG_USB_GSPCA_SQ930X=m
+CONFIG_USB_GSPCA_STK014=m
+# CONFIG_USB_GSPCA_STV0680 is not set
+CONFIG_USB_GSPCA_SUNPLUS=m
+CONFIG_USB_GSPCA_T613=m
+CONFIG_USB_GSPCA_TV8532=m
+CONFIG_USB_GSPCA_VC032X=m
+CONFIG_USB_GSPCA_XIRLINK_CIT=m
+CONFIG_USB_GSPCA_ZC3XX=m
+CONFIG_VIDEO_PVRUSB2=m
+CONFIG_VIDEO_PVRUSB2_SYSFS=y
+CONFIG_VIDEO_PVRUSB2_DVB=y
+# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set
+CONFIG_VIDEO_HDPVR=m
+CONFIG_VIDEO_EM28XX=m
+CONFIG_VIDEO_EM28XX_ALSA=m
+CONFIG_VIDEO_EM28XX_DVB=m
+CONFIG_VIDEO_TLG2300=m
+CONFIG_VIDEO_CX231XX=m
+# CONFIG_VIDEO_CX231XX_ALSA is not set
+CONFIG_VIDEO_CX231XX_DVB=m
+CONFIG_VIDEO_USBVISION=m
+CONFIG_VIDEO_USBVIDEO=m
+CONFIG_USB_VICAM=m
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_KONICAWC=m
+CONFIG_USB_ET61X251=m
+CONFIG_USB_SE401=m
+CONFIG_USB_SN9C102=m
+CONFIG_USB_PWC=m
+# CONFIG_USB_PWC_DEBUG is not set
+CONFIG_USB_PWC_INPUT_EVDEV=y
+CONFIG_USB_ZR364XX=m
+CONFIG_USB_STKWEBCAM=m
+CONFIG_USB_S2255=m
+CONFIG_V4L_MEM2MEM_DRIVERS=y
+CONFIG_VIDEO_MEM2MEM_TESTDEV=m
+CONFIG_RADIO_ADAPTERS=y
+# CONFIG_I2C_SI4713 is not set
+# CONFIG_RADIO_SI4713 is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_RADIO_SI470X is not set
+# CONFIG_USB_MR800 is not set
+# CONFIG_RADIO_TEA5764 is not set
+CONFIG_RADIO_SAA7706H=m
+# CONFIG_RADIO_TEF6862 is not set
+
+#
+# Texas Instruments WL128x FM driver (ST based)
+#
+CONFIG_RADIO_WL128X=m
+CONFIG_DVB_MAX_ADAPTERS=8
+CONFIG_DVB_DYNAMIC_MINORS=y
+CONFIG_DVB_CAPTURE_DRIVERS=y
+# CONFIG_TTPCI_EEPROM is not set
+
+#
+# Supported USB Adapters
+#
+CONFIG_DVB_USB=m
+# CONFIG_DVB_USB_DEBUG is not set
+CONFIG_DVB_USB_A800=m
+CONFIG_DVB_USB_DIBUSB_MB=m
+# CONFIG_DVB_USB_DIBUSB_MB_FAULTY is not set
+CONFIG_DVB_USB_DIBUSB_MC=m
+CONFIG_DVB_USB_DIB0700=m
+CONFIG_DVB_USB_UMT_010=m
+CONFIG_DVB_USB_CXUSB=m
+CONFIG_DVB_USB_M920X=m
+CONFIG_DVB_USB_GL861=m
+CONFIG_DVB_USB_AU6610=m
+CONFIG_DVB_USB_DIGITV=m
+CONFIG_DVB_USB_VP7045=m
+CONFIG_DVB_USB_VP702X=m
+CONFIG_DVB_USB_GP8PSK=m
+CONFIG_DVB_USB_NOVA_T_USB2=m
+CONFIG_DVB_USB_TTUSB2=m
+CONFIG_DVB_USB_DTT200U=m
+CONFIG_DVB_USB_OPERA1=m
+CONFIG_DVB_USB_AF9005=m
+CONFIG_DVB_USB_AF9005_REMOTE=m
+CONFIG_DVB_USB_DW2102=m
+CONFIG_DVB_USB_CINERGY_T2=m
+CONFIG_DVB_USB_ANYSEE=m
+CONFIG_DVB_USB_DTV5100=m
+CONFIG_DVB_USB_AF9015=m
+# CONFIG_DVB_USB_CE6230 is not set
+# CONFIG_DVB_USB_FRIIO is not set
+# CONFIG_DVB_USB_EC168 is not set
+CONFIG_DVB_USB_AZ6027=m
+CONFIG_DVB_USB_LME2510=m
+# CONFIG_SMS_SIANO_MDTV is not set
+
+#
+# Supported FlexCopII (B2C2) Adapters
+#
+CONFIG_DVB_B2C2_FLEXCOP=m
+CONFIG_DVB_B2C2_FLEXCOP_USB=m
+# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set
+
+#
+# Supported DVB Frontends
+#
+# CONFIG_DVB_FE_CUSTOMISE is not set
+
+#
+# Multistandard (satellite) frontends
+#
+CONFIG_DVB_STB0899=m
+CONFIG_DVB_STB6100=m
+
+#
+# DVB-S (satellite) frontends
+#
+CONFIG_DVB_CX24123=m
+CONFIG_DVB_MT312=m
+CONFIG_DVB_ZL10039=m
+CONFIG_DVB_S5H1420=m
+CONFIG_DVB_STV0288=m
+CONFIG_DVB_STB6000=m
+CONFIG_DVB_STV0299=m
+CONFIG_DVB_STV6110=m
+CONFIG_DVB_STV0900=m
+CONFIG_DVB_TDA10086=m
+CONFIG_DVB_TUNER_ITD1000=m
+CONFIG_DVB_TUNER_CX24113=m
+CONFIG_DVB_TDA826X=m
+CONFIG_DVB_CX24116=m
+CONFIG_DVB_SI21XX=m
+CONFIG_DVB_DS3000=m
+
+#
+# DVB-T (terrestrial) frontends
+#
+CONFIG_DVB_CX22702=m
+CONFIG_DVB_TDA1004X=m
+CONFIG_DVB_NXT6000=m
+CONFIG_DVB_MT352=m
+CONFIG_DVB_ZL10353=m
+CONFIG_DVB_DIB3000MB=m
+CONFIG_DVB_DIB3000MC=m
+CONFIG_DVB_DIB7000M=m
+CONFIG_DVB_DIB7000P=m
+CONFIG_DVB_TDA10048=m
+CONFIG_DVB_AF9013=m
+
+#
+# DVB-C (cable) frontends
+#
+CONFIG_DVB_TDA10023=m
+CONFIG_DVB_STV0297=m
+
+#
+# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
+#
+CONFIG_DVB_NXT200X=m
+CONFIG_DVB_BCM3510=m
+CONFIG_DVB_LGDT330X=m
+CONFIG_DVB_LGDT3305=m
+CONFIG_DVB_S5H1409=m
+CONFIG_DVB_S5H1411=m
+
+#
+# ISDB-T (terrestrial) frontends
+#
+CONFIG_DVB_DIB8000=m
+
+#
+# Digital terrestrial only tuners/PLL
+#
+CONFIG_DVB_PLL=m
+CONFIG_DVB_TUNER_DIB0070=m
+CONFIG_DVB_TUNER_DIB0090=m
+
+#
+# SEC control devices for DVB-S
+#
+CONFIG_DVB_LNBP21=m
+CONFIG_DVB_ISL6421=m
+CONFIG_DVB_LGS8GXX=m
+CONFIG_DVB_ATBM8830=m
+CONFIG_DVB_IX2505V=m
+
+#
+# Tools to develop new frontends
+#
+# CONFIG_DVB_DUMMY_FE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+CONFIG_DRM=m
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+CONFIG_FB_SYS_FILLRECT=m
+CONFIG_FB_SYS_COPYAREA=m
+CONFIG_FB_SYS_IMAGEBLIT=m
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+CONFIG_FB_SYS_FOPS=m
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_TMIO is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_OMAP2_VRAM=y
+CONFIG_OMAP2_VRFB=y
+CONFIG_OMAP2_DSS=y
+CONFIG_OMAP2_VRAM_SIZE=14
+CONFIG_OMAP2_DSS_DEBUG_SUPPORT=y
+# CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS is not set
+CONFIG_OMAP2_DSS_DPI=y
+# CONFIG_OMAP2_DSS_RFBI is not set
+CONFIG_OMAP2_DSS_VENC=y
+# CONFIG_OMAP2_DSS_SDI is not set
+CONFIG_OMAP2_DSS_DSI=y
+CONFIG_OMAP2_DSS_USE_DSI_PLL=y
+# CONFIG_OMAP2_DSS_FAKE_VSYNC is not set
+CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0
+CONFIG_FB_OMAP2=y
+CONFIG_FB_OMAP2_DEBUG_SUPPORT=y
+CONFIG_FB_OMAP2_NUM_FBS=2
+
+#
+# OMAP2/3 Display Device Drivers
+#
+CONFIG_PANEL_GENERIC=y
+# CONFIG_PANEL_LGPHILIPS_LB035Q02 is not set
+# CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C is not set
+CONFIG_PANEL_SHARP_LS037V7DW01=y
+# CONFIG_PANEL_SHARP_LQ043T1DG01 is not set
+# CONFIG_PANEL_TAAL is not set
+CONFIG_PANEL_TOPPOLY_TDO35S=m
+CONFIG_PANEL_TPO_TD043MTEA1=m
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+
+#
+# Display device support
+#
+CONFIG_DISPLAY_SUPPORT=y
+
+#
+# Display hardware drivers
+#
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_HWDEP=y
+CONFIG_SND_RAWMIDI=y
+CONFIG_SND_JACK=y
+CONFIG_SND_SEQUENCER=m
+# CONFIG_SND_SEQ_DUMMY is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_HRTIMER=m
+CONFIG_SND_SEQ_HRTIMER_DEFAULT=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_RAWMIDI_SEQ=m
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+CONFIG_SND_ALOOP=m
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+# CONFIG_SND_ARM is not set
+CONFIG_SND_SPI=y
+CONFIG_SND_USB=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_USB_UA101=m
+CONFIG_SND_USB_CAIAQ=m
+CONFIG_SND_USB_CAIAQ_INPUT=y
+CONFIG_SND_SOC=y
+CONFIG_SND_OMAP_SOC=y
+CONFIG_SND_OMAP_SOC_MCBSP=y
+CONFIG_SND_OMAP_SOC_OVERO=y
+CONFIG_SND_OMAP_SOC_OMAP3EVM=y
+CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE=y
+CONFIG_SND_OMAP_SOC_ZOOM2=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+CONFIG_SND_SOC_TWL4030=y
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_3M_PCT is not set
+CONFIG_HID_A4TECH=y
+# CONFIG_HID_ACRUX_FF is not set
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+# CONFIG_HID_CANDO is not set
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+# CONFIG_HID_PRODIKEYS is not set
+CONFIG_HID_CYPRESS=y
+# CONFIG_HID_DRAGONRISE is not set
+CONFIG_HID_EGALAX=m
+# CONFIG_HID_ELECOM is not set
+CONFIG_HID_EZKEY=y
+# CONFIG_HID_KYE is not set
+CONFIG_HID_UCLOGIC=m
+CONFIG_HID_WALTOP=m
+CONFIG_HID_GYRATION=y
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+CONFIG_HID_LOGITECH=y
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+# CONFIG_LOGIG940_FF is not set
+# CONFIG_LOGIWII_FF is not set
+CONFIG_HID_MAGICMOUSE=m
+CONFIG_HID_MICROSOFT=y
+# CONFIG_HID_MOSART is not set
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_NTRIG=y
+# CONFIG_HID_ORTEK is not set
+CONFIG_HID_PANTHERLORD=y
+# CONFIG_PANTHERLORD_FF is not set
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_PICOLCD=m
+CONFIG_HID_PICOLCD_FB=y
+CONFIG_HID_PICOLCD_BACKLIGHT=y
+CONFIG_HID_PICOLCD_LEDS=y
+CONFIG_HID_QUANTA=m
+CONFIG_HID_ROCCAT=m
+CONFIG_HID_ROCCAT_KONE=m
+# CONFIG_HID_ROCCAT_PYRA is not set
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_STANTUM=m
+CONFIG_HID_SUNPLUS=y
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+CONFIG_HID_TOPSEED=y
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_WACOM is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_U132_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# OMAP 343x high speed USB support
+#
+# CONFIG_USB_MUSB_AM35X is not set
+# CONFIG_USB_MUSB_HOST is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
+# CONFIG_USB_MUSB_DEBUG is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_WDM=m
+CONFIG_USB_TMC=m
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+CONFIG_USB_UAS=m
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_EZUSB=y
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRCABLE=m
+CONFIG_USB_SERIAL_ARK3116=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_CH341=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+# CONFIG_USB_SERIAL_CP210X is not set
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_FUNSOFT=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_IUU=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_MOS7720=m
+CONFIG_USB_SERIAL_MOS7840=m
+CONFIG_USB_SERIAL_MOTOROLA=m
+CONFIG_USB_SERIAL_NAVMAN=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_OTI6858=m
+CONFIG_USB_SERIAL_QCAUX=m
+# CONFIG_USB_SERIAL_QUALCOMM is not set
+CONFIG_USB_SERIAL_SPCP8X5=m
+CONFIG_USB_SERIAL_HP4X=m
+CONFIG_USB_SERIAL_SAFE=m
+# CONFIG_USB_SERIAL_SAFE_PADDED is not set
+CONFIG_USB_SERIAL_SAMBA=m
+CONFIG_USB_SERIAL_SIEMENS_MPI=m
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+# CONFIG_USB_SERIAL_SYMBOL is not set
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+# CONFIG_USB_SERIAL_OPTION is not set
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_SERIAL_OPTICON=m
+CONFIG_USB_SERIAL_VIVOPAY_SERIAL=m
+CONFIG_USB_SERIAL_ZIO=m
+CONFIG_USB_SERIAL_SSU100=m
+CONFIG_USB_SERIAL_DEBUG=m
+
+#
+# USB Miscellaneous drivers
+#
+CONFIG_USB_EMI62=m
+CONFIG_USB_EMI26=m
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_LED=m
+CONFIG_USB_CYPRESS_CY7C63=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_FTDI_ELAN=m
+# CONFIG_USB_APPLEDISPLAY is not set
+CONFIG_USB_SISUSBVGA=m
+CONFIG_USB_SISUSBVGA_CON=y
+CONFIG_USB_LD=m
+CONFIG_USB_TRANCEVIBRATOR=m
+# CONFIG_USB_IOWARRIOR is not set
+CONFIG_USB_TEST=m
+# CONFIG_USB_ISIGHTFW is not set
+CONFIG_USB_YUREX=m
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+CONFIG_USB_CXACRU=m
+CONFIG_USB_UEAGLEATM=m
+CONFIG_USB_XUSBATM=m
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_GADGET_VBUS_DRAW=480
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_ETH_EEM is not set
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FUNCTIONFS=m
+# CONFIG_USB_FUNCTIONFS_ETH is not set
+CONFIG_USB_FUNCTIONFS_RNDIS=y
+# CONFIG_USB_FUNCTIONFS_GENERIC is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_MASS_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+# CONFIG_USB_G_MULTI is not set
+CONFIG_USB_G_HID=m
+CONFIG_USB_G_DBGP=m
+# CONFIG_USB_G_DBGP_PRINTK is not set
+CONFIG_USB_G_DBGP_SERIAL=y
+CONFIG_USB_G_WEBCAM=m
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+CONFIG_USB_GPIO_VBUS=y
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_USB_ULPI is not set
+CONFIG_TWL4030_USB=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_UNSAFE_RESUME=y
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_MINORS=8
+CONFIG_MMC_BLOCK_BOUNCE=y
+CONFIG_SDIO_UART=y
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_OMAP is not set
+CONFIG_MMC_OMAP_HS=y
+CONFIG_MMC_SPI=m
+CONFIG_MMC_USHC=m
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP3944 is not set
+CONFIG_LEDS_LP5521=m
+CONFIG_LEDS_LP5523=m
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+CONFIG_LEDS_PWM=m
+CONFIG_LEDS_REGULATOR=m
+# CONFIG_LEDS_BD2802 is not set
+# CONFIG_LEDS_LT3593 is not set
+CONFIG_LEDS_TRIGGERS=y
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGER_TIMER=m
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=m
+CONFIG_LEDS_TRIGGER_GPIO=m
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=m
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+CONFIG_RTC_DRV_DS1307=m
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS3232 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_ISL12022 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+CONFIG_RTC_DRV_BQ32K=m
+CONFIG_RTC_DRV_TWL4030=m
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+CONFIG_UIO=m
+CONFIG_UIO_PDRV=m
+CONFIG_UIO_PDRV_GENIRQ=m
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+# CONFIG_VIDEO_TM6000 is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_USB_IP_COMMON is not set
+CONFIG_W35UND=m
+CONFIG_PRISM2_USB=m
+CONFIG_ECHO=m
+CONFIG_BRCM80211=m
+CONFIG_BRCMFMAC=y
+CONFIG_RT2870=m
+# CONFIG_COMEDI is not set
+# CONFIG_ASUS_OLED is not set
+CONFIG_R8712U=m
+CONFIG_R8712_AP=y
+# CONFIG_TRANZPORT is not set
+# CONFIG_POHMELFS is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_LINE6_USB is not set
+# CONFIG_USB_SERIAL_QUATECH2 is not set
+# CONFIG_USB_SERIAL_QUATECH_USB2 is not set
+# CONFIG_VT6656 is not set
+CONFIG_FB_UDL=m
+# CONFIG_IIO is not set
+CONFIG_ZRAM=m
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_FB_SM7XX is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+CONFIG_ST_BT=m
+CONFIG_ADIS16255=m
+# CONFIG_LIRC_STAGING is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_EASYCAP is not set
+# CONFIG_TIDSPBRIDGE is not set
+# CONFIG_MACH_OMAP3_WESTBRIDGE_AST_PNAND_HAL is not set
+CONFIG_MACH_NO_WESTBRIDGE=y
+# CONFIG_ATH6K_LEGACY is not set
+CONFIG_USB_ENESTORAGE=m
+CONFIG_BCM_WIMAX=m
+CONFIG_FT1000=m
+CONFIG_FT1000_USB=m
+
+#
+# Speakup console speech
+#
+# CONFIG_SPEAKUP is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_XATTR=y
+# CONFIG_EXT4_FS_POSIX_ACL is not set
+# CONFIG_EXT4_FS_SECURITY is not set
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_JBD2=y
+# CONFIG_JBD2_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+CONFIG_REISERFS_PROC_INFO=y
+CONFIG_REISERFS_FS_XATTR=y
+# CONFIG_REISERFS_FS_POSIX_ACL is not set
+# CONFIG_REISERFS_FS_SECURITY is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_DEBUG is not set
+CONFIG_GFS2_FS=m
+# CONFIG_GFS2_FS_LOCKING_DLM is not set
+CONFIG_OCFS2_FS=m
+CONFIG_OCFS2_FS_O2CB=m
+CONFIG_OCFS2_FS_USERSPACE_CLUSTER=m
+CONFIG_OCFS2_FS_STATS=y
+CONFIG_OCFS2_DEBUG_MASKLOG=y
+# CONFIG_OCFS2_DEBUG_FS is not set
+CONFIG_BTRFS_FS=m
+# CONFIG_BTRFS_FS_POSIX_ACL is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_EXPORTFS=m
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_FANOTIFY=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QUOTA_DEBUG is not set
+CONFIG_QUOTA_TREE=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+# CONFIG_CUSE is not set
+CONFIG_GENERIC_ACL=y
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_CONFIGFS_FS=m
+CONFIG_MISC_FILESYSTEMS=y
+CONFIG_ADFS_FS=m
+# CONFIG_ADFS_FS_RW is not set
+CONFIG_AFFS_FS=m
+# CONFIG_ECRYPT_FS is not set
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_FS_POSIX_ACL=y
+CONFIG_JFFS2_FS_SECURITY=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RTIME=y
+CONFIG_JFFS2_RUBIN=y
+# CONFIG_JFFS2_CMODE_NONE is not set
+# CONFIG_JFFS2_CMODE_PRIORITY is not set
+# CONFIG_JFFS2_CMODE_SIZE is not set
+CONFIG_JFFS2_CMODE_FAVOURLZO=y
+CONFIG_UBIFS_FS=y
+CONFIG_UBIFS_FS_XATTR=y
+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
+CONFIG_LOGFS=m
+CONFIG_CRAMFS=m
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_XATTR is not set
+CONFIG_SQUASHFS_LZO=y
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+CONFIG_VXFS_FS=m
+CONFIG_MINIX_FS=m
+CONFIG_OMFS_FS=m
+CONFIG_HPFS_FS=m
+CONFIG_QNX4FS_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_ROMFS_BACKED_BY_BLOCK=y
+# CONFIG_ROMFS_BACKED_BY_MTD is not set
+# CONFIG_ROMFS_BACKED_BY_BOTH is not set
+CONFIG_ROMFS_ON_BLOCK=y
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_UFS_DEBUG is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFS_USE_LEGACY_DNS is not set
+CONFIG_NFS_USE_KERNEL_DNS=y
+# CONFIG_NFS_USE_NEW_IDMAPPER is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_DEPRECATED=y
+CONFIG_NFSD_V2_ACL=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+CONFIG_CEPH_FS=m
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+CONFIG_CIFS_STATS2=y
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+# CONFIG_CIFS_UPCALL is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_DFS_UPCALL is not set
+CONFIG_CIFS_EXPERIMENTAL=y
+CONFIG_NCP_FS=m
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_CODA_FS=m
+CONFIG_AFS_FS=m
+# CONFIG_AFS_DEBUG is not set
+CONFIG_9P_FS=m
+# CONFIG_9P_FS_POSIX_ACL is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+# CONFIG_UNIXWARE_DISKLABEL is not set
+CONFIG_LDM_PARTITION=y
+CONFIG_LDM_DEBUG=y
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=y
+CONFIG_DLM=m
+# CONFIG_DLM_DEBUG is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_LOCKUP_DETECTOR is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_BKL=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_RING_BUFFER=y
+CONFIG_RING_BUFFER_ALLOW_SWAP=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_ASYNC_RAID6_TEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_STRICT_DEVMEM is not set
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+# CONFIG_OC_ETM is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_XOR_BLOCKS=m
+CONFIG_ASYNC_CORE=m
+CONFIG_ASYNC_MEMCPY=m
+CONFIG_ASYNC_XOR=m
+CONFIG_ASYNC_PQ=m
+CONFIG_ASYNC_RAID6_RECOV=m
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+CONFIG_CRYPTO_GF128MUL=m
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_AUTHENC=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_SEQIV=m
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CTR=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=m
+CONFIG_CRYPTO_XCBC=m
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_GHASH=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+CONFIG_CRYPTO_RMD128=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_RMD256=m
+CONFIG_CRYPTO_RMD320=m
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SALSA20=m
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_DEV_OMAP_SHAM=m
+CONFIG_CRYPTO_DEV_OMAP_AES=m
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_RAID6_PQ=m
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+CONFIG_CRC7=y
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_LZO=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_BTREE=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/extras/recipes-kernel/linux/linux-omap/beagleboard/logo_linux_clut224.ppm b/extras/recipes-kernel/linux/linux-omap/beagleboard/logo_linux_clut224.ppm
new file mode 100644
index 00000000..d29fc1c5
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/beagleboard/logo_linux_clut224.ppm
@@ -0,0 +1,73147 @@
+P3
+# CREATOR: GIMP PNM Filter Version 1.1
+387 63
+255
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+116
+28
+246
+116
+28
+246
+116
+28
+246
+116
+28
+246
+116
+28
+246
+116
+28
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+111
+26
+246
+116
+28
+246
+116
+28
+247
+118
+39
+247
+118
+39
+247
+118
+39
+246
+116
+28
+247
+111
+26
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+247
+111
+26
+247
+111
+26
+246
+116
+28
+247
+118
+39
+247
+118
+39
+247
+118
+39
+246
+116
+28
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+247
+111
+26
+247
+111
+26
+246
+116
+28
+247
+118
+39
+247
+118
+39
+247
+118
+39
+246
+116
+28
+247
+111
+26
+247
+111
+26
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+247
+111
+26
+247
+111
+26
+246
+116
+28
+247
+118
+39
+247
+118
+39
+247
+118
+39
+246
+116
+28
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+118
+39
+247
+123
+41
+247
+123
+41
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+123
+41
+247
+123
+41
+247
+118
+39
+246
+116
+28
+247
+111
+26
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+246
+109
+10
+247
+111
+26
+246
+116
+28
+247
+118
+39
+247
+123
+41
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+123
+41
+247
+118
+39
+246
+116
+28
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+111
+26
+246
+116
+28
+247
+123
+41
+247
+123
+41
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+123
+41
+247
+118
+39
+247
+111
+26
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+118
+39
+247
+123
+41
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+123
+41
+247
+123
+41
+247
+118
+39
+247
+111
+26
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+111
+26
+246
+116
+28
+247
+123
+41
+247
+123
+41
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+123
+41
+247
+118
+39
+247
+111
+26
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+247
+111
+26
+246
+116
+28
+247
+118
+39
+247
+123
+41
+247
+130
+53
+248
+138
+64
+250
+139
+73
+247
+143
+74
+247
+143
+74
+249
+146
+83
+249
+146
+83
+249
+146
+83
+247
+143
+74
+250
+139
+73
+248
+138
+64
+247
+130
+53
+247
+123
+41
+247
+118
+39
+246
+116
+28
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+246
+109
+10
+247
+111
+26
+246
+116
+28
+247
+123
+41
+247
+130
+53
+248
+138
+64
+250
+139
+73
+247
+143
+74
+247
+143
+74
+250
+139
+73
+248
+138
+64
+247
+130
+53
+247
+123
+41
+246
+116
+28
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+118
+39
+247
+123
+41
+247
+130
+60
+248
+138
+64
+247
+143
+74
+247
+143
+74
+247
+143
+74
+250
+139
+73
+247
+130
+60
+247
+130
+53
+247
+123
+41
+246
+116
+28
+247
+111
+26
+246
+109
+10
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+118
+39
+247
+130
+53
+247
+130
+60
+250
+139
+73
+247
+143
+74
+247
+143
+74
+247
+143
+74
+248
+138
+64
+247
+130
+60
+247
+130
+53
+247
+118
+39
+247
+111
+26
+247
+111
+26
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+118
+39
+247
+123
+41
+247
+130
+60
+248
+138
+64
+247
+143
+74
+247
+143
+74
+247
+143
+74
+250
+139
+73
+247
+130
+60
+247
+130
+53
+247
+123
+41
+246
+116
+28
+247
+111
+26
+246
+109
+10
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+247
+111
+26
+246
+116
+28
+247
+118
+39
+247
+130
+53
+247
+130
+60
+250
+139
+73
+249
+146
+83
+249
+152
+92
+249
+159
+103
+249
+159
+103
+247
+165
+111
+251
+168
+115
+251
+168
+115
+247
+165
+111
+247
+165
+111
+249
+159
+103
+249
+152
+92
+249
+146
+83
+250
+139
+73
+247
+130
+60
+247
+123
+41
+247
+118
+39
+247
+111
+26
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+246
+116
+28
+247
+123
+41
+247
+130
+60
+247
+143
+74
+247
+150
+84
+246
+156
+93
+249
+159
+103
+249
+159
+103
+246
+156
+93
+247
+150
+84
+250
+139
+73
+247
+130
+60
+247
+123
+41
+246
+116
+28
+247
+111
+26
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+118
+39
+247
+123
+41
+248
+138
+64
+247
+143
+74
+249
+152
+92
+249
+159
+103
+249
+159
+103
+249
+159
+103
+246
+156
+93
+247
+150
+84
+250
+139
+73
+247
+130
+53
+247
+123
+41
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+118
+39
+247
+130
+53
+248
+138
+64
+249
+146
+83
+249
+152
+92
+249
+159
+103
+249
+159
+103
+249
+159
+103
+249
+152
+92
+249
+146
+83
+248
+138
+64
+247
+130
+53
+247
+118
+39
+247
+111
+26
+246
+109
+10
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+118
+39
+247
+130
+53
+248
+138
+64
+247
+143
+74
+249
+152
+92
+249
+159
+103
+249
+159
+103
+249
+159
+103
+246
+156
+93
+247
+150
+84
+250
+139
+73
+247
+130
+53
+247
+123
+41
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+118
+39
+247
+123
+41
+247
+130
+60
+250
+139
+73
+247
+150
+84
+249
+159
+103
+247
+165
+111
+249
+174
+124
+248
+180
+134
+252
+185
+144
+240
+181
+138
+219
+170
+138
+219
+170
+138
+230
+173
+136
+240
+181
+138
+248
+180
+134
+249
+174
+124
+247
+165
+111
+249
+159
+103
+249
+146
+83
+248
+138
+64
+247
+130
+53
+247
+123
+41
+247
+111
+26
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+123
+41
+247
+130
+60
+247
+143
+74
+249
+159
+103
+214
+151
+109
+121
+100
+85
+65
+67
+64
+74
+68
+68
+129
+102
+78
+214
+151
+109
+246
+156
+93
+247
+143
+74
+247
+130
+53
+247
+118
+39
+247
+111
+26
+246
+109
+10
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+111
+26
+246
+116
+28
+247
+123
+41
+248
+138
+64
+249
+146
+83
+249
+159
+103
+204
+141
+99
+102
+91
+75
+65
+67
+64
+81
+77
+76
+146
+111
+88
+238
+159
+107
+249
+152
+92
+250
+139
+73
+247
+130
+53
+247
+118
+39
+247
+111
+26
+246
+109
+10
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+118
+39
+247
+130
+53
+248
+138
+64
+247
+150
+84
+245
+162
+103
+162
+125
+96
+81
+77
+76
+55
+66
+67
+99
+90
+79
+187
+140
+108
+249
+159
+103
+247
+150
+84
+248
+138
+64
+247
+123
+41
+246
+116
+28
+247
+111
+26
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+111
+26
+246
+116
+28
+247
+123
+41
+248
+138
+64
+249
+146
+83
+249
+159
+103
+187
+140
+108
+102
+91
+75
+58
+69
+70
+76
+78
+76
+146
+111
+88
+238
+159
+107
+249
+152
+92
+250
+139
+73
+247
+130
+53
+247
+118
+39
+247
+111
+26
+246
+109
+10
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+246
+109
+10
+247
+111
+26
+246
+116
+28
+247
+123
+41
+247
+130
+53
+248
+138
+64
+249
+146
+83
+249
+159
+103
+251
+168
+115
+248
+180
+134
+239
+182
+144
+186
+157
+134
+124
+111
+99
+82
+69
+65
+65
+58
+56
+55
+48
+48
+65
+58
+56
+65
+58
+56
+65
+58
+56
+99
+90
+79
+158
+130
+108
+230
+173
+136
+250
+176
+132
+247
+165
+111
+249
+152
+92
+247
+143
+74
+247
+130
+53
+247
+123
+41
+246
+116
+28
+247
+111
+26
+246
+109
+10
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+111
+26
+247
+118
+39
+247
+130
+53
+250
+139
+73
+246
+156
+93
+214
+151
+109
+74
+68
+68
+56
+64
+60
+95
+87
+59
+88
+82
+59
+56
+64
+60
+81
+77
+76
+238
+159
+107
+249
+152
+92
+248
+138
+64
+247
+130
+53
+246
+116
+28
+247
+111
+26
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+118
+39
+247
+130
+53
+247
+143
+74
+249
+159
+103
+187
+140
+108
+51
+62
+63
+69
+69
+61
+95
+87
+59
+83
+78
+61
+48
+58
+59
+121
+100
+85
+247
+165
+111
+247
+150
+84
+248
+138
+64
+247
+123
+41
+246
+116
+28
+246
+109
+10
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+123
+41
+247
+130
+60
+247
+150
+84
+247
+165
+111
+139
+115
+96
+48
+58
+59
+95
+78
+64
+118
+86
+65
+81
+73
+62
+48
+58
+59
+162
+125
+96
+249
+159
+103
+249
+146
+83
+247
+130
+60
+247
+123
+41
+247
+111
+26
+246
+109
+10
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+118
+39
+247
+130
+53
+247
+143
+74
+249
+159
+103
+187
+140
+108
+48
+58
+59
+76
+70
+64
+118
+86
+65
+95
+78
+64
+51
+62
+63
+121
+100
+85
+247
+165
+111
+247
+150
+84
+248
+138
+64
+247
+123
+41
+247
+111
+26
+246
+109
+10
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+246
+109
+10
+247
+111
+26
+246
+116
+28
+247
+123
+41
+247
+130
+60
+247
+143
+74
+249
+152
+92
+247
+165
+111
+250
+176
+132
+251
+192
+154
+167
+142
+123
+65
+58
+56
+35
+31
+30
+71
+60
+43
+108
+87
+46
+129
+106
+52
+137
+110
+49
+156
+125
+62
+187
+166
+150
+129
+106
+52
+101
+83
+47
+59
+50
+39
+55
+48
+48
+139
+115
+96
+240
+181
+138
+249
+174
+124
+249
+159
+103
+247
+143
+74
+247
+130
+53
+247
+123
+41
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+123
+41
+247
+130
+60
+247
+150
+84
+247
+165
+111
+124
+111
+99
+56
+64
+60
+137
+110
+49
+171
+129
+45
+171
+129
+45
+129
+106
+52
+51
+62
+63
+162
+125
+96
+247
+165
+111
+249
+146
+83
+247
+130
+60
+247
+118
+39
+247
+111
+26
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+123
+41
+248
+138
+64
+249
+152
+92
+245
+169
+119
+81
+77
+76
+69
+69
+61
+152
+119
+47
+171
+129
+45
+171
+129
+45
+105
+93
+60
+48
+58
+59
+187
+140
+108
+249
+159
+103
+247
+143
+74
+247
+130
+53
+247
+118
+39
+247
+111
+26
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+111
+26
+246
+116
+28
+247
+130
+53
+250
+139
+73
+249
+159
+103
+210
+156
+119
+51
+62
+63
+112
+85
+63
+234
+126
+45
+234
+126
+45
+225
+124
+48
+95
+78
+64
+63
+74
+74
+234
+168
+124
+246
+156
+93
+250
+139
+73
+247
+123
+41
+246
+116
+28
+246
+109
+10
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+123
+41
+248
+138
+64
+249
+152
+92
+245
+169
+119
+81
+77
+76
+81
+73
+62
+212
+120
+56
+234
+126
+45
+234
+126
+45
+135
+94
+64
+41
+58
+57
+187
+140
+108
+249
+159
+103
+247
+143
+74
+247
+130
+53
+247
+118
+39
+247
+111
+26
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+246
+116
+28
+247
+123
+41
+247
+130
+60
+249
+146
+83
+249
+159
+103
+249
+174
+124
+249
+189
+146
+236
+186
+153
+99
+90
+79
+47
+40
+38
+85
+71
+43
+145
+114
+49
+171
+129
+45
+171
+129
+45
+171
+129
+45
+168
+127
+42
+160
+120
+43
+195
+167
+113
+216
+194
+154
+168
+127
+42
+168
+127
+42
+123
+102
+54
+59
+50
+39
+82
+69
+65
+230
+173
+136
+249
+174
+124
+249
+159
+103
+247
+143
+74
+247
+130
+53
+247
+118
+39
+247
+111
+26
+246
+109
+10
+247
+103
+7
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+123
+41
+248
+138
+64
+246
+156
+93
+245
+169
+119
+84
+85
+82
+83
+78
+61
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+75
+74
+61
+101
+100
+92
+249
+174
+124
+246
+156
+93
+248
+138
+64
+247
+123
+41
+246
+116
+28
+247
+111
+26
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+111
+26
+247
+118
+39
+247
+130
+53
+247
+143
+74
+249
+159
+103
+210
+156
+119
+48
+58
+59
+105
+93
+60
+171
+129
+45
+158
+125
+46
+161
+127
+40
+152
+119
+47
+62
+63
+61
+139
+115
+96
+251
+168
+115
+247
+150
+84
+247
+130
+60
+247
+123
+41
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+111
+26
+247
+118
+39
+247
+130
+53
+249
+146
+83
+247
+165
+111
+158
+130
+108
+51
+62
+63
+188
+112
+56
+234
+125
+52
+224
+123
+55
+234
+126
+45
+163
+104
+61
+48
+58
+59
+210
+156
+119
+247
+165
+111
+249
+146
+83
+247
+130
+60
+247
+118
+39
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+118
+39
+247
+130
+53
+247
+143
+74
+247
+165
+111
+210
+156
+119
+55
+66
+67
+146
+97
+64
+234
+126
+45
+224
+123
+55
+234
+125
+52
+199
+115
+54
+62
+63
+61
+139
+115
+96
+251
+168
+115
+247
+150
+84
+247
+130
+60
+247
+118
+39
+247
+111
+26
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+111
+26
+246
+116
+28
+247
+123
+41
+247
+130
+60
+249
+146
+83
+249
+159
+103
+250
+176
+132
+219
+170
+138
+150
+125
+114
+65
+58
+56
+24
+22
+23
+59
+50
+39
+152
+119
+47
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+160
+120
+43
+158
+125
+46
+227
+196
+175
+192
+155
+91
+160
+120
+43
+171
+129
+45
+158
+125
+46
+85
+71
+43
+65
+58
+56
+219
+170
+138
+249
+174
+124
+246
+156
+93
+250
+139
+73
+247
+130
+53
+247
+118
+39
+247
+111
+26
+246
+109
+10
+247
+103
+7
+246
+97
+3
+247
+103
+7
+246
+109
+10
+246
+116
+28
+247
+130
+53
+247
+143
+74
+249
+159
+103
+230
+173
+136
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+91
+92
+89
+252
+185
+144
+247
+165
+111
+249
+146
+83
+247
+130
+60
+247
+123
+41
+246
+116
+28
+247
+111
+26
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+111
+26
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+111
+26
+246
+116
+28
+247
+123
+41
+248
+138
+64
+249
+152
+92
+249
+174
+124
+203
+161
+131
+43
+57
+62
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+63
+69
+60
+133
+120
+107
+250
+176
+132
+246
+156
+93
+248
+138
+64
+247
+123
+41
+246
+116
+28
+247
+111
+26
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+111
+26
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+123
+41
+248
+138
+64
+249
+152
+92
+249
+174
+124
+154
+133
+118
+56
+64
+60
+199
+115
+54
+227
+126
+50
+224
+123
+55
+234
+125
+52
+183
+110
+59
+51
+62
+63
+186
+157
+134
+250
+176
+132
+246
+156
+93
+250
+139
+73
+247
+130
+53
+247
+118
+39
+247
+111
+26
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+111
+26
+247
+111
+26
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+111
+26
+247
+118
+39
+247
+130
+53
+250
+139
+73
+246
+156
+93
+249
+174
+124
+209
+171
+139
+51
+62
+63
+155
+100
+63
+234
+125
+52
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+133
+120
+107
+249
+174
+124
+246
+156
+93
+248
+138
+64
+247
+123
+41
+247
+111
+26
+246
+109
+10
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+111
+26
+247
+111
+26
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+118
+39
+247
+130
+53
+247
+143
+74
+249
+159
+103
+250
+176
+132
+158
+130
+108
+47
+40
+38
+59
+50
+39
+85
+71
+43
+85
+71
+43
+59
+50
+39
+35
+31
+30
+123
+102
+54
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+152
+119
+47
+192
+155
+91
+224
+207
+180
+158
+125
+46
+160
+120
+43
+168
+127
+42
+171
+129
+45
+71
+60
+43
+82
+69
+65
+239
+182
+144
+249
+174
+124
+249
+152
+92
+248
+138
+64
+247
+123
+41
+246
+116
+28
+247
+111
+26
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+111
+26
+247
+118
+39
+247
+130
+53
+249
+146
+83
+247
+165
+111
+239
+182
+144
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+91
+92
+89
+250
+197
+158
+250
+176
+132
+249
+159
+103
+247
+143
+74
+247
+130
+60
+247
+123
+41
+247
+118
+39
+246
+116
+28
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+116
+28
+247
+118
+39
+247
+118
+39
+247
+118
+39
+246
+116
+28
+246
+116
+28
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+247
+111
+26
+247
+111
+26
+246
+116
+28
+246
+116
+28
+246
+116
+28
+247
+118
+39
+247
+118
+39
+246
+116
+28
+246
+116
+28
+246
+116
+28
+246
+116
+28
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+116
+28
+246
+116
+28
+247
+118
+39
+247
+118
+39
+246
+116
+28
+246
+116
+28
+246
+116
+28
+246
+116
+28
+246
+116
+28
+247
+118
+39
+247
+123
+41
+247
+130
+60
+249
+146
+83
+249
+159
+103
+248
+180
+134
+212
+173
+150
+48
+58
+59
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+65
+67
+64
+137
+127
+115
+248
+180
+134
+249
+159
+103
+247
+143
+74
+247
+130
+53
+247
+118
+39
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+116
+28
+247
+118
+39
+247
+118
+39
+247
+118
+39
+246
+116
+28
+246
+116
+28
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+118
+39
+247
+130
+53
+250
+139
+73
+249
+159
+103
+250
+176
+132
+167
+142
+123
+56
+64
+60
+199
+115
+54
+227
+126
+50
+224
+123
+55
+234
+125
+52
+173
+106
+60
+48
+58
+59
+187
+166
+150
+249
+189
+146
+251
+168
+115
+249
+152
+92
+250
+139
+73
+247
+130
+53
+247
+123
+41
+246
+116
+28
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+116
+28
+246
+116
+28
+247
+118
+39
+247
+118
+39
+246
+116
+28
+246
+116
+28
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+116
+28
+246
+116
+28
+247
+118
+39
+247
+118
+39
+246
+116
+28
+246
+116
+28
+246
+116
+28
+246
+116
+28
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+116
+28
+247
+123
+41
+247
+130
+53
+248
+138
+64
+247
+150
+84
+247
+165
+111
+252
+185
+144
+212
+173
+150
+51
+62
+63
+155
+100
+63
+234
+125
+52
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+133
+120
+107
+248
+180
+134
+249
+159
+103
+250
+139
+73
+247
+123
+41
+247
+111
+26
+246
+109
+10
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+116
+28
+246
+116
+28
+247
+118
+39
+247
+118
+39
+247
+118
+39
+246
+116
+28
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+103
+7
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+116
+28
+246
+116
+28
+247
+118
+39
+247
+118
+39
+246
+116
+28
+246
+116
+28
+246
+116
+28
+246
+116
+28
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+111
+26
+247
+118
+39
+247
+130
+53
+250
+139
+73
+249
+159
+103
+250
+176
+132
+167
+142
+123
+24
+22
+23
+85
+71
+43
+158
+125
+46
+171
+129
+45
+171
+129
+45
+171
+129
+45
+85
+71
+43
+35
+31
+30
+145
+114
+49
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+152
+119
+47
+216
+194
+154
+195
+167
+113
+152
+119
+47
+158
+125
+46
+168
+127
+42
+158
+125
+46
+59
+50
+39
+139
+115
+96
+252
+185
+144
+247
+165
+111
+247
+150
+84
+247
+130
+60
+247
+123
+41
+247
+111
+26
+246
+109
+10
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+118
+39
+247
+130
+60
+247
+150
+84
+251
+168
+115
+236
+186
+153
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+91
+92
+89
+251
+209
+178
+249
+189
+146
+249
+174
+124
+249
+159
+103
+249
+146
+83
+248
+138
+64
+247
+130
+53
+247
+130
+53
+247
+123
+41
+247
+118
+39
+246
+116
+28
+247
+111
+26
+247
+111
+26
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+247
+111
+26
+246
+116
+28
+247
+118
+39
+247
+123
+41
+247
+123
+41
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+123
+41
+247
+123
+41
+246
+116
+28
+247
+111
+26
+247
+111
+26
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+111
+26
+246
+116
+28
+247
+118
+39
+247
+123
+41
+247
+123
+41
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+118
+39
+246
+116
+28
+246
+116
+28
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+116
+28
+247
+118
+39
+247
+123
+41
+247
+123
+41
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+248
+138
+64
+247
+143
+74
+246
+156
+93
+249
+174
+124
+251
+192
+154
+207
+178
+158
+48
+58
+59
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+63
+69
+60
+137
+127
+115
+249
+189
+146
+247
+165
+111
+247
+150
+84
+248
+138
+64
+247
+130
+53
+247
+123
+41
+247
+118
+39
+247
+123
+41
+247
+123
+41
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+123
+41
+247
+118
+39
+247
+118
+39
+247
+118
+39
+247
+123
+41
+247
+130
+60
+247
+143
+74
+249
+159
+103
+252
+185
+144
+167
+142
+123
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+234
+125
+52
+173
+106
+60
+51
+62
+63
+187
+166
+150
+250
+200
+166
+248
+180
+134
+247
+165
+111
+249
+152
+92
+247
+143
+74
+247
+130
+60
+247
+130
+53
+247
+123
+41
+247
+123
+41
+247
+118
+39
+247
+111
+26
+247
+111
+26
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+118
+39
+247
+123
+41
+247
+123
+41
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+123
+41
+247
+123
+41
+247
+118
+39
+247
+111
+26
+247
+111
+26
+246
+109
+10
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+118
+39
+247
+123
+41
+247
+123
+41
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+130
+53
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+118
+39
+247
+118
+39
+247
+118
+39
+247
+118
+39
+247
+118
+39
+247
+118
+39
+247
+118
+39
+247
+123
+41
+247
+123
+41
+247
+130
+53
+247
+130
+60
+250
+139
+73
+249
+152
+92
+247
+165
+111
+248
+180
+134
+250
+197
+158
+207
+178
+158
+51
+62
+63
+155
+100
+63
+234
+125
+52
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+252
+185
+144
+249
+159
+103
+247
+143
+74
+247
+130
+53
+246
+116
+28
+246
+109
+10
+247
+103
+7
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+118
+39
+247
+123
+41
+247
+123
+41
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+123
+41
+247
+123
+41
+247
+118
+39
+246
+116
+28
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+116
+28
+247
+118
+39
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+130
+53
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+118
+39
+247
+118
+39
+246
+116
+28
+246
+116
+28
+246
+116
+28
+247
+118
+39
+247
+118
+39
+247
+123
+41
+247
+123
+41
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+118
+39
+246
+116
+28
+247
+111
+26
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+123
+41
+248
+138
+64
+247
+150
+84
+251
+168
+115
+230
+173
+136
+47
+40
+38
+59
+50
+39
+168
+127
+42
+168
+127
+42
+158
+125
+46
+158
+125
+46
+161
+127
+40
+171
+129
+45
+59
+50
+39
+71
+60
+43
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+152
+119
+47
+170
+137
+67
+239
+227
+208
+170
+137
+67
+160
+120
+43
+158
+125
+46
+171
+129
+45
+123
+102
+54
+47
+40
+38
+209
+171
+139
+248
+180
+134
+247
+165
+111
+249
+146
+83
+247
+130
+60
+247
+123
+41
+247
+111
+26
+247
+111
+26
+246
+109
+10
+247
+111
+26
+247
+123
+41
+247
+130
+60
+247
+150
+84
+249
+174
+124
+236
+186
+153
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+91
+92
+89
+255
+215
+190
+253
+204
+176
+249
+189
+146
+249
+174
+124
+247
+165
+111
+246
+156
+93
+249
+146
+83
+247
+143
+74
+248
+138
+64
+247
+130
+60
+247
+130
+53
+247
+123
+41
+246
+116
+28
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+116
+28
+247
+118
+39
+247
+123
+41
+247
+130
+53
+248
+138
+64
+250
+139
+73
+247
+143
+74
+249
+146
+83
+247
+150
+84
+249
+146
+83
+249
+146
+83
+247
+143
+74
+248
+138
+64
+247
+130
+60
+247
+130
+53
+247
+123
+41
+247
+118
+39
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+109
+10
+247
+111
+26
+247
+111
+26
+246
+116
+28
+247
+118
+39
+247
+123
+41
+247
+130
+53
+248
+138
+64
+250
+139
+73
+247
+143
+74
+249
+146
+83
+249
+146
+83
+249
+146
+83
+249
+146
+83
+249
+146
+83
+247
+143
+74
+247
+143
+74
+250
+139
+73
+250
+139
+73
+248
+138
+64
+247
+130
+60
+247
+130
+53
+247
+130
+53
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+130
+53
+247
+130
+60
+250
+139
+73
+247
+143
+74
+249
+146
+83
+249
+146
+83
+249
+146
+83
+249
+146
+83
+249
+146
+83
+247
+143
+74
+247
+143
+74
+247
+143
+74
+247
+143
+74
+247
+150
+84
+249
+159
+103
+249
+174
+124
+252
+185
+144
+250
+200
+166
+217
+187
+166
+48
+58
+59
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+63
+69
+60
+137
+127
+115
+251
+192
+154
+249
+174
+124
+246
+156
+93
+247
+143
+74
+248
+138
+64
+247
+130
+60
+247
+130
+60
+248
+138
+64
+250
+139
+73
+247
+143
+74
+249
+146
+83
+247
+150
+84
+249
+146
+83
+249
+146
+83
+247
+143
+74
+248
+138
+64
+247
+130
+60
+247
+130
+53
+247
+130
+53
+247
+130
+60
+250
+139
+73
+247
+150
+84
+251
+168
+115
+249
+189
+146
+161
+144
+134
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+234
+125
+52
+173
+106
+60
+48
+58
+59
+187
+166
+150
+253
+212
+188
+250
+197
+158
+248
+180
+134
+251
+168
+115
+249
+159
+103
+247
+150
+84
+247
+143
+74
+250
+139
+73
+248
+138
+64
+247
+130
+53
+247
+123
+41
+247
+118
+39
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+111
+26
+247
+118
+39
+247
+123
+41
+247
+130
+53
+248
+138
+64
+250
+139
+73
+247
+143
+74
+249
+146
+83
+247
+150
+84
+247
+150
+84
+249
+146
+83
+247
+143
+74
+250
+139
+73
+247
+130
+60
+247
+130
+53
+247
+123
+41
+247
+118
+39
+247
+111
+26
+247
+111
+26
+246
+109
+10
+246
+109
+10
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+118
+39
+247
+123
+41
+247
+130
+53
+247
+130
+60
+248
+138
+64
+247
+143
+74
+249
+146
+83
+249
+146
+83
+249
+146
+83
+249
+146
+83
+249
+146
+83
+247
+143
+74
+247
+143
+74
+247
+143
+74
+250
+139
+73
+250
+139
+73
+250
+139
+73
+248
+138
+64
+248
+138
+64
+248
+138
+64
+248
+138
+64
+248
+138
+64
+248
+138
+64
+250
+139
+73
+250
+139
+73
+250
+139
+73
+250
+139
+73
+247
+143
+74
+247
+143
+74
+250
+139
+73
+250
+139
+73
+248
+138
+64
+248
+138
+64
+247
+130
+60
+247
+130
+60
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+60
+247
+130
+60
+248
+138
+64
+250
+139
+73
+247
+143
+74
+247
+150
+84
+249
+159
+103
+251
+168
+115
+248
+180
+134
+250
+197
+158
+253
+212
+188
+207
+178
+158
+51
+62
+63
+155
+100
+63
+234
+125
+52
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+249
+189
+146
+247
+165
+111
+247
+143
+74
+247
+130
+53
+246
+116
+28
+246
+109
+10
+247
+103
+7
+247
+103
+7
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+111
+26
+247
+118
+39
+247
+123
+41
+247
+130
+53
+247
+130
+60
+250
+139
+73
+247
+143
+74
+249
+146
+83
+247
+150
+84
+247
+150
+84
+249
+146
+83
+247
+143
+74
+250
+139
+73
+248
+138
+64
+247
+130
+53
+247
+123
+41
+247
+123
+41
+247
+118
+39
+247
+118
+39
+247
+118
+39
+247
+123
+41
+247
+123
+41
+247
+130
+53
+247
+130
+53
+248
+138
+64
+248
+138
+64
+250
+139
+73
+250
+139
+73
+247
+143
+74
+247
+143
+74
+250
+139
+73
+250
+139
+73
+248
+138
+64
+247
+130
+60
+247
+130
+60
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+60
+248
+138
+64
+250
+139
+73
+247
+143
+74
+249
+146
+83
+249
+146
+83
+249
+146
+83
+249
+146
+83
+249
+146
+83
+247
+143
+74
+247
+143
+74
+250
+139
+73
+250
+139
+73
+248
+138
+64
+247
+130
+60
+247
+130
+53
+247
+123
+41
+247
+123
+41
+246
+116
+28
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+111
+26
+247
+118
+39
+247
+130
+53
+247
+143
+74
+249
+159
+103
+252
+185
+144
+139
+115
+96
+35
+31
+30
+129
+106
+52
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+171
+129
+45
+117
+98
+55
+35
+31
+30
+152
+119
+47
+168
+127
+42
+168
+127
+42
+160
+120
+43
+168
+127
+42
+171
+129
+45
+152
+119
+47
+216
+194
+154
+224
+207
+180
+160
+120
+43
+160
+120
+43
+137
+110
+49
+102
+91
+75
+35
+31
+30
+115
+102
+92
+250
+200
+166
+250
+176
+132
+249
+159
+103
+249
+146
+83
+247
+130
+60
+247
+123
+41
+246
+116
+28
+247
+111
+26
+246
+116
+28
+247
+123
+41
+248
+138
+64
+249
+152
+92
+249
+174
+124
+236
+186
+153
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+91
+92
+89
+255
+215
+190
+255
+215
+190
+253
+204
+176
+250
+197
+158
+252
+185
+144
+249
+174
+124
+251
+168
+115
+249
+159
+103
+246
+156
+93
+247
+150
+84
+250
+139
+73
+247
+130
+60
+247
+130
+53
+247
+123
+41
+247
+118
+39
+246
+116
+28
+246
+116
+28
+247
+118
+39
+247
+123
+41
+247
+130
+53
+248
+138
+64
+249
+146
+83
+249
+152
+92
+249
+159
+103
+247
+165
+111
+251
+168
+115
+251
+168
+115
+251
+168
+115
+251
+168
+115
+247
+165
+111
+249
+159
+103
+247
+150
+84
+247
+143
+74
+248
+138
+64
+247
+130
+53
+247
+123
+41
+247
+118
+39
+246
+116
+28
+246
+116
+28
+246
+116
+28
+247
+118
+39
+247
+123
+41
+247
+130
+60
+250
+139
+73
+249
+146
+83
+249
+152
+92
+249
+159
+103
+247
+165
+111
+251
+168
+115
+251
+168
+115
+251
+168
+115
+251
+168
+115
+247
+165
+111
+247
+165
+111
+247
+165
+111
+249
+159
+103
+249
+159
+103
+246
+156
+93
+247
+150
+84
+249
+146
+83
+247
+143
+74
+248
+138
+64
+247
+130
+60
+247
+130
+60
+247
+130
+60
+248
+138
+64
+250
+139
+73
+249
+146
+83
+249
+152
+92
+249
+159
+103
+249
+159
+103
+247
+165
+111
+251
+168
+115
+251
+168
+115
+251
+168
+115
+251
+168
+115
+247
+165
+111
+247
+165
+111
+249
+159
+103
+247
+165
+111
+251
+168
+115
+250
+176
+132
+252
+185
+144
+250
+200
+166
+255
+215
+190
+217
+187
+166
+48
+58
+59
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+65
+67
+64
+137
+127
+115
+250
+200
+166
+250
+176
+132
+247
+165
+111
+249
+152
+92
+247
+150
+84
+249
+146
+83
+247
+150
+84
+249
+152
+92
+249
+159
+103
+247
+165
+111
+251
+168
+115
+251
+168
+115
+251
+168
+115
+247
+165
+111
+249
+159
+103
+246
+156
+93
+247
+150
+84
+247
+143
+74
+250
+139
+73
+247
+143
+74
+249
+146
+83
+249
+159
+103
+249
+174
+124
+251
+192
+154
+161
+144
+134
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+227
+126
+50
+173
+106
+60
+51
+62
+63
+187
+166
+150
+255
+215
+190
+253
+212
+188
+250
+200
+166
+249
+189
+146
+248
+180
+134
+249
+174
+124
+247
+165
+111
+249
+159
+103
+249
+152
+92
+247
+143
+74
+248
+138
+64
+247
+130
+53
+247
+123
+41
+247
+118
+39
+246
+116
+28
+247
+111
+26
+246
+116
+28
+247
+118
+39
+247
+123
+41
+247
+130
+53
+248
+138
+64
+247
+143
+74
+249
+152
+92
+249
+159
+103
+247
+165
+111
+251
+168
+115
+251
+168
+115
+251
+168
+115
+251
+168
+115
+247
+165
+111
+249
+159
+103
+249
+152
+92
+247
+143
+74
+248
+138
+64
+247
+130
+53
+247
+123
+41
+247
+118
+39
+247
+111
+26
+247
+111
+26
+247
+111
+26
+246
+116
+28
+247
+123
+41
+247
+130
+53
+248
+138
+64
+247
+143
+74
+247
+150
+84
+249
+159
+103
+249
+159
+103
+247
+165
+111
+251
+168
+115
+251
+168
+115
+251
+168
+115
+251
+168
+115
+247
+165
+111
+247
+165
+111
+249
+159
+103
+249
+159
+103
+249
+159
+103
+249
+159
+103
+249
+159
+103
+249
+159
+103
+246
+156
+93
+246
+156
+93
+246
+156
+93
+249
+159
+103
+249
+159
+103
+249
+159
+103
+249
+159
+103
+249
+159
+103
+249
+159
+103
+249
+159
+103
+249
+159
+103
+249
+159
+103
+249
+159
+103
+249
+152
+92
+249
+152
+92
+247
+150
+84
+249
+146
+83
+249
+146
+83
+249
+146
+83
+247
+150
+84
+249
+152
+92
+246
+156
+93
+249
+159
+103
+247
+165
+111
+249
+174
+124
+250
+176
+132
+249
+189
+146
+250
+200
+166
+253
+212
+188
+255
+215
+190
+207
+178
+158
+51
+62
+63
+155
+100
+63
+234
+125
+52
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+249
+189
+146
+247
+165
+111
+247
+143
+74
+247
+130
+53
+246
+116
+28
+246
+109
+10
+247
+103
+7
+247
+103
+7
+246
+109
+10
+247
+111
+26
+246
+116
+28
+247
+123
+41
+247
+130
+53
+248
+138
+64
+247
+143
+74
+247
+150
+84
+249
+159
+103
+247
+165
+111
+251
+168
+115
+251
+168
+115
+251
+168
+115
+251
+168
+115
+247
+165
+111
+249
+159
+103
+249
+152
+92
+249
+146
+83
+250
+139
+73
+247
+130
+60
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+60
+248
+138
+64
+247
+143
+74
+249
+146
+83
+249
+152
+92
+246
+156
+93
+249
+159
+103
+249
+159
+103
+249
+159
+103
+249
+159
+103
+249
+159
+103
+249
+159
+103
+246
+156
+93
+249
+152
+92
+247
+150
+84
+249
+146
+83
+247
+143
+74
+247
+143
+74
+247
+143
+74
+249
+146
+83
+247
+150
+84
+246
+156
+93
+249
+159
+103
+247
+165
+111
+247
+165
+111
+251
+168
+115
+251
+168
+115
+251
+168
+115
+247
+165
+111
+247
+165
+111
+247
+165
+111
+249
+159
+103
+249
+159
+103
+246
+156
+93
+247
+150
+84
+247
+143
+74
+248
+138
+64
+247
+130
+53
+247
+123
+41
+247
+118
+39
+247
+111
+26
+246
+109
+10
+247
+103
+7
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+123
+41
+248
+138
+64
+249
+152
+92
+249
+174
+124
+236
+186
+153
+47
+40
+38
+59
+50
+39
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+47
+40
+38
+108
+87
+46
+168
+127
+42
+111
+94
+57
+76
+70
+64
+59
+50
+39
+101
+83
+47
+160
+120
+43
+170
+137
+67
+253
+255
+252
+195
+167
+113
+145
+114
+49
+69
+69
+61
+120
+114
+108
+35
+31
+30
+47
+40
+38
+217
+187
+166
+250
+197
+158
+250
+176
+132
+249
+159
+103
+249
+146
+83
+248
+138
+64
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+130
+53
+250
+139
+73
+246
+156
+93
+250
+176
+132
+232
+190
+161
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+91
+92
+89
+255
+215
+190
+255
+215
+190
+245
+212
+186
+227
+196
+175
+212
+173
+150
+209
+171
+139
+219
+170
+138
+240
+181
+138
+250
+176
+132
+251
+168
+115
+249
+159
+103
+247
+150
+84
+250
+139
+73
+247
+130
+60
+247
+130
+53
+247
+130
+53
+247
+130
+53
+247
+130
+53
+248
+138
+64
+249
+146
+83
+246
+156
+93
+247
+165
+111
+249
+174
+124
+248
+180
+134
+240
+181
+138
+219
+170
+138
+203
+161
+131
+203
+161
+131
+219
+170
+138
+240
+181
+138
+250
+176
+132
+249
+174
+124
+249
+159
+103
+249
+152
+92
+247
+143
+74
+247
+130
+60
+247
+130
+53
+247
+123
+41
+247
+123
+41
+247
+130
+53
+247
+130
+53
+248
+138
+64
+249
+146
+83
+246
+156
+93
+247
+165
+111
+249
+174
+124
+245
+179
+138
+230
+173
+136
+203
+161
+131
+203
+161
+131
+219
+170
+138
+239
+182
+144
+251
+192
+154
+249
+189
+146
+252
+185
+144
+252
+185
+144
+248
+180
+134
+245
+169
+119
+234
+168
+124
+247
+165
+111
+249
+159
+103
+249
+152
+92
+247
+150
+84
+247
+150
+84
+247
+150
+84
+249
+152
+92
+249
+159
+103
+247
+165
+111
+249
+174
+124
+248
+180
+134
+230
+173
+136
+219
+170
+138
+203
+161
+131
+209
+171
+139
+239
+182
+144
+251
+192
+154
+249
+189
+146
+249
+189
+146
+252
+185
+144
+252
+185
+144
+249
+189
+146
+236
+186
+153
+250
+200
+166
+255
+215
+190
+255
+215
+190
+217
+187
+166
+48
+58
+59
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+65
+67
+64
+137
+127
+115
+253
+204
+176
+252
+185
+144
+249
+174
+124
+247
+165
+111
+247
+165
+111
+247
+165
+111
+251
+168
+115
+249
+174
+124
+248
+180
+134
+230
+173
+136
+219
+170
+138
+203
+161
+131
+209
+171
+139
+230
+173
+136
+245
+179
+138
+250
+176
+132
+251
+168
+115
+249
+159
+103
+249
+159
+103
+246
+156
+93
+249
+159
+103
+251
+168
+115
+248
+180
+134
+250
+197
+158
+161
+144
+134
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+227
+126
+50
+173
+106
+60
+51
+62
+63
+187
+166
+150
+255
+215
+190
+255
+215
+190
+234
+204
+183
+207
+178
+158
+209
+171
+139
+209
+171
+139
+230
+173
+136
+248
+180
+134
+249
+174
+124
+247
+165
+111
+249
+152
+92
+247
+143
+74
+248
+138
+64
+247
+130
+53
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+130
+53
+248
+138
+64
+247
+143
+74
+249
+152
+92
+247
+165
+111
+249
+174
+124
+248
+180
+134
+240
+181
+138
+219
+170
+138
+203
+161
+131
+203
+161
+131
+219
+170
+138
+240
+181
+138
+248
+180
+134
+249
+174
+124
+247
+165
+111
+249
+152
+92
+247
+143
+74
+248
+138
+64
+247
+130
+53
+247
+123
+41
+247
+123
+41
+247
+123
+41
+247
+130
+53
+247
+130
+60
+247
+143
+74
+249
+152
+92
+249
+159
+103
+249
+174
+124
+250
+176
+132
+240
+181
+138
+219
+170
+138
+203
+161
+131
+203
+161
+131
+230
+173
+136
+251
+192
+154
+249
+189
+146
+249
+189
+146
+252
+185
+144
+252
+185
+144
+248
+180
+134
+234
+168
+124
+250
+176
+132
+248
+180
+134
+250
+176
+132
+250
+176
+132
+250
+176
+132
+248
+180
+134
+248
+180
+134
+230
+173
+136
+240
+181
+138
+252
+185
+144
+252
+185
+144
+252
+185
+144
+252
+185
+144
+248
+180
+134
+234
+168
+124
+234
+168
+124
+249
+174
+124
+251
+168
+115
+247
+165
+111
+247
+165
+111
+247
+165
+111
+251
+168
+115
+249
+174
+124
+250
+176
+132
+248
+180
+134
+230
+173
+136
+219
+170
+138
+209
+171
+139
+207
+178
+158
+227
+196
+175
+253
+212
+188
+255
+215
+190
+217
+187
+166
+51
+62
+63
+155
+100
+63
+234
+125
+52
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+249
+189
+146
+247
+165
+111
+247
+143
+74
+247
+130
+53
+246
+116
+28
+247
+111
+26
+246
+109
+10
+246
+109
+10
+247
+111
+26
+246
+116
+28
+247
+123
+41
+247
+130
+60
+247
+143
+74
+249
+152
+92
+249
+159
+103
+249
+174
+124
+248
+180
+134
+240
+181
+138
+219
+170
+138
+203
+161
+131
+203
+161
+131
+219
+170
+138
+240
+181
+138
+248
+180
+134
+249
+174
+124
+247
+165
+111
+249
+159
+103
+247
+150
+84
+249
+146
+83
+247
+143
+74
+247
+143
+74
+249
+146
+83
+249
+152
+92
+249
+159
+103
+247
+165
+111
+234
+168
+124
+234
+168
+124
+248
+180
+134
+252
+185
+144
+252
+185
+144
+252
+185
+144
+248
+180
+134
+250
+176
+132
+234
+168
+124
+249
+174
+124
+251
+168
+115
+247
+165
+111
+247
+165
+111
+249
+159
+103
+247
+165
+111
+251
+168
+115
+249
+174
+124
+250
+176
+132
+248
+180
+134
+230
+173
+136
+203
+161
+131
+203
+161
+131
+219
+170
+138
+239
+182
+144
+251
+192
+154
+249
+189
+146
+252
+185
+144
+252
+185
+144
+248
+180
+134
+234
+168
+124
+238
+159
+107
+247
+165
+111
+249
+152
+92
+247
+143
+74
+247
+130
+60
+247
+123
+41
+246
+116
+28
+247
+111
+26
+246
+109
+10
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+111
+26
+246
+116
+28
+247
+130
+53
+247
+143
+74
+247
+165
+111
+252
+185
+144
+154
+133
+118
+24
+22
+23
+108
+87
+46
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+171
+129
+45
+71
+60
+43
+85
+71
+43
+101
+83
+47
+89
+84
+82
+152
+147
+147
+24
+22
+23
+24
+22
+23
+108
+87
+46
+168
+127
+42
+224
+207
+180
+253
+255
+252
+209
+171
+139
+101
+83
+47
+24
+22
+23
+35
+31
+30
+35
+31
+30
+167
+142
+123
+253
+212
+188
+250
+197
+158
+248
+180
+134
+247
+165
+111
+247
+150
+84
+250
+139
+73
+247
+130
+60
+247
+130
+60
+248
+138
+64
+249
+146
+83
+249
+159
+103
+250
+176
+132
+232
+190
+161
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+97
+98
+96
+217
+187
+166
+137
+127
+115
+91
+92
+89
+55
+66
+67
+48
+58
+59
+48
+58
+59
+55
+66
+67
+84
+85
+82
+133
+120
+107
+209
+171
+139
+248
+180
+134
+251
+168
+115
+249
+159
+103
+247
+150
+84
+247
+143
+74
+250
+139
+73
+250
+139
+73
+249
+146
+83
+249
+152
+92
+247
+165
+111
+249
+174
+124
+245
+179
+138
+178
+146
+122
+124
+111
+99
+76
+78
+76
+51
+62
+63
+48
+58
+59
+48
+58
+59
+58
+69
+70
+91
+92
+89
+144
+125
+110
+203
+161
+131
+248
+180
+134
+249
+174
+124
+249
+159
+103
+247
+150
+84
+247
+143
+74
+248
+138
+64
+248
+138
+64
+250
+139
+73
+249
+146
+83
+246
+156
+93
+247
+165
+111
+250
+176
+132
+230
+173
+136
+154
+133
+118
+101
+100
+92
+58
+69
+70
+48
+58
+59
+48
+58
+59
+51
+62
+63
+84
+85
+82
+137
+127
+115
+217
+187
+166
+253
+212
+188
+227
+196
+175
+144
+125
+110
+89
+84
+82
+81
+77
+76
+115
+102
+92
+210
+156
+119
+249
+174
+124
+251
+168
+115
+251
+168
+115
+251
+168
+115
+249
+174
+124
+250
+176
+132
+252
+185
+144
+195
+157
+134
+124
+111
+99
+76
+78
+76
+51
+62
+63
+48
+58
+59
+48
+58
+59
+70
+79
+77
+120
+114
+108
+187
+166
+150
+253
+212
+188
+253
+212
+188
+172
+150
+134
+101
+100
+92
+77
+85
+81
+101
+100
+92
+176
+156
+141
+255
+215
+190
+217
+187
+166
+48
+58
+59
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+63
+69
+60
+137
+127
+115
+253
+212
+188
+250
+197
+158
+252
+185
+144
+248
+180
+134
+248
+180
+134
+252
+185
+144
+239
+182
+144
+167
+142
+123
+109
+106
+99
+70
+79
+77
+48
+58
+59
+48
+58
+59
+48
+58
+59
+58
+69
+70
+91
+92
+89
+150
+125
+114
+219
+170
+138
+248
+180
+134
+249
+174
+124
+249
+174
+124
+249
+174
+124
+250
+176
+132
+249
+189
+146
+253
+204
+176
+161
+144
+134
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+234
+125
+52
+183
+110
+59
+51
+62
+63
+176
+156
+141
+187
+166
+150
+109
+106
+99
+63
+74
+74
+43
+57
+62
+43
+57
+62
+43
+57
+62
+63
+74
+74
+109
+106
+99
+178
+146
+122
+245
+179
+138
+249
+174
+124
+249
+159
+103
+247
+150
+84
+247
+143
+74
+248
+138
+64
+248
+138
+64
+248
+138
+64
+247
+143
+74
+247
+150
+84
+249
+159
+103
+249
+174
+124
+252
+185
+144
+195
+157
+134
+124
+111
+99
+77
+85
+81
+51
+62
+63
+41
+58
+57
+43
+57
+62
+51
+62
+63
+77
+85
+81
+124
+111
+99
+195
+157
+134
+252
+185
+144
+249
+174
+124
+249
+159
+103
+247
+150
+84
+247
+143
+74
+248
+138
+64
+247
+130
+60
+248
+138
+64
+250
+139
+73
+247
+150
+84
+249
+159
+103
+251
+168
+115
+248
+180
+134
+203
+161
+131
+124
+111
+99
+77
+85
+81
+48
+58
+59
+43
+57
+62
+43
+57
+62
+63
+74
+74
+109
+106
+99
+187
+166
+150
+253
+212
+188
+253
+212
+188
+187
+166
+150
+109
+106
+99
+77
+85
+81
+84
+85
+82
+150
+125
+114
+232
+190
+161
+253
+204
+176
+253
+204
+176
+172
+150
+134
+101
+100
+92
+77
+85
+81
+91
+92
+89
+137
+127
+115
+227
+196
+175
+253
+212
+188
+186
+157
+134
+109
+106
+99
+77
+85
+81
+84
+85
+82
+124
+111
+99
+219
+170
+138
+249
+189
+146
+249
+189
+146
+249
+189
+146
+251
+192
+154
+250
+197
+158
+186
+157
+134
+109
+106
+99
+70
+79
+77
+43
+57
+62
+43
+57
+62
+41
+58
+57
+63
+74
+74
+101
+100
+92
+176
+156
+141
+194
+173
+157
+55
+66
+67
+155
+100
+63
+234
+125
+52
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+249
+189
+146
+247
+165
+111
+247
+143
+74
+247
+130
+53
+247
+118
+39
+247
+111
+26
+246
+109
+10
+247
+111
+26
+246
+116
+28
+247
+123
+41
+247
+130
+60
+249
+146
+83
+249
+159
+103
+249
+174
+124
+252
+185
+144
+203
+161
+131
+133
+120
+107
+84
+85
+82
+55
+66
+67
+43
+57
+62
+41
+58
+57
+51
+62
+63
+77
+85
+81
+124
+111
+99
+178
+146
+122
+239
+182
+144
+250
+176
+132
+249
+174
+124
+247
+165
+111
+249
+159
+103
+249
+159
+103
+247
+165
+111
+249
+174
+124
+210
+156
+119
+124
+111
+99
+77
+85
+81
+77
+85
+81
+109
+106
+99
+194
+173
+157
+253
+212
+188
+217
+187
+166
+133
+120
+107
+89
+84
+82
+76
+78
+76
+101
+100
+92
+178
+146
+122
+249
+189
+146
+252
+185
+144
+252
+185
+144
+252
+185
+144
+251
+192
+154
+236
+186
+153
+167
+142
+123
+101
+100
+92
+63
+74
+74
+41
+58
+57
+43
+57
+62
+51
+62
+63
+77
+85
+81
+137
+127
+115
+217
+187
+166
+253
+212
+188
+227
+196
+175
+144
+125
+110
+84
+85
+82
+76
+78
+76
+115
+102
+92
+204
+141
+99
+249
+159
+103
+247
+143
+74
+247
+130
+60
+247
+123
+41
+247
+111
+26
+246
+109
+10
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+123
+41
+248
+138
+64
+249
+152
+92
+249
+174
+124
+250
+197
+158
+82
+69
+65
+47
+40
+38
+152
+119
+47
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+171
+129
+45
+101
+83
+47
+59
+50
+39
+101
+83
+47
+24
+22
+23
+35
+31
+30
+24
+22
+23
+24
+22
+23
+108
+87
+46
+168
+127
+42
+195
+167
+113
+253
+255
+252
+253
+255
+252
+239
+227
+208
+186
+157
+134
+162
+125
+96
+105
+93
+60
+47
+40
+38
+150
+125
+114
+217
+187
+166
+250
+200
+166
+252
+185
+144
+251
+168
+115
+246
+156
+93
+249
+146
+83
+247
+143
+74
+249
+146
+83
+249
+152
+92
+247
+165
+111
+252
+185
+144
+232
+190
+161
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+55
+66
+67
+58
+69
+70
+56
+64
+60
+83
+78
+61
+105
+93
+60
+117
+98
+55
+117
+98
+55
+105
+93
+60
+83
+78
+61
+56
+64
+60
+55
+66
+67
+144
+125
+110
+239
+182
+144
+250
+176
+132
+247
+165
+111
+249
+159
+103
+246
+156
+93
+249
+159
+103
+247
+165
+111
+249
+174
+124
+252
+185
+144
+195
+157
+134
+89
+84
+82
+48
+58
+59
+63
+69
+60
+95
+87
+59
+111
+94
+57
+123
+102
+54
+117
+98
+55
+105
+93
+60
+83
+78
+61
+56
+64
+60
+51
+62
+63
+124
+111
+99
+219
+170
+138
+248
+180
+134
+251
+168
+115
+249
+159
+103
+249
+152
+92
+249
+152
+92
+246
+156
+93
+247
+165
+111
+249
+174
+124
+252
+185
+144
+167
+142
+123
+70
+79
+77
+51
+62
+63
+75
+74
+61
+100
+89
+56
+117
+98
+55
+123
+102
+54
+105
+93
+60
+83
+78
+61
+51
+62
+63
+63
+74
+74
+172
+150
+134
+109
+106
+99
+51
+62
+63
+83
+78
+61
+95
+87
+59
+65
+67
+64
+65
+67
+64
+209
+171
+139
+249
+189
+146
+249
+189
+146
+249
+189
+146
+250
+197
+158
+212
+173
+150
+109
+106
+99
+48
+58
+59
+63
+69
+60
+95
+87
+59
+111
+94
+57
+123
+102
+54
+117
+98
+55
+95
+87
+59
+62
+63
+61
+48
+58
+59
+137
+127
+115
+146
+135
+124
+48
+58
+59
+75
+74
+61
+95
+87
+59
+75
+74
+61
+48
+58
+59
+161
+144
+134
+217
+187
+166
+48
+58
+59
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+63
+69
+60
+137
+127
+115
+255
+215
+190
+251
+209
+178
+250
+200
+166
+250
+200
+166
+250
+200
+166
+172
+150
+134
+77
+85
+81
+48
+58
+59
+69
+69
+61
+95
+87
+59
+111
+94
+57
+123
+102
+54
+117
+98
+55
+100
+89
+56
+75
+74
+61
+56
+64
+60
+55
+66
+67
+133
+120
+107
+236
+186
+153
+251
+192
+154
+249
+189
+146
+251
+192
+154
+250
+200
+166
+253
+212
+188
+161
+144
+134
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+227
+126
+50
+173
+106
+60
+51
+62
+63
+63
+74
+74
+48
+58
+59
+76
+70
+64
+118
+86
+65
+146
+97
+64
+155
+100
+63
+146
+97
+64
+118
+86
+65
+76
+70
+64
+43
+57
+62
+91
+92
+89
+203
+161
+131
+248
+180
+134
+251
+168
+115
+249
+159
+103
+249
+152
+92
+247
+150
+84
+249
+152
+92
+249
+159
+103
+251
+168
+115
+248
+180
+134
+209
+171
+139
+101
+100
+92
+43
+57
+62
+69
+69
+61
+106
+82
+65
+135
+94
+64
+155
+100
+63
+155
+100
+63
+135
+94
+64
+106
+82
+65
+65
+67
+64
+43
+57
+62
+101
+100
+92
+209
+171
+139
+248
+180
+134
+251
+168
+115
+249
+159
+103
+249
+152
+92
+247
+150
+84
+247
+150
+84
+246
+156
+93
+247
+165
+111
+250
+176
+132
+219
+170
+138
+124
+111
+99
+48
+58
+59
+62
+63
+61
+106
+82
+65
+139
+96
+61
+155
+100
+63
+146
+97
+64
+125
+90
+64
+76
+70
+64
+41
+58
+57
+120
+114
+108
+172
+150
+134
+51
+62
+63
+69
+69
+61
+112
+85
+63
+95
+78
+64
+51
+62
+63
+120
+114
+108
+245
+212
+186
+146
+135
+124
+43
+57
+62
+81
+73
+62
+118
+86
+65
+95
+78
+64
+56
+64
+60
+101
+100
+92
+133
+120
+107
+43
+57
+62
+76
+70
+64
+112
+85
+63
+106
+82
+65
+62
+63
+61
+77
+85
+81
+227
+196
+175
+253
+212
+188
+253
+212
+188
+217
+187
+166
+109
+106
+99
+41
+58
+57
+69
+69
+61
+112
+85
+63
+139
+96
+61
+155
+100
+63
+146
+97
+64
+118
+86
+65
+81
+73
+62
+48
+58
+59
+58
+69
+70
+51
+62
+63
+155
+100
+63
+234
+125
+52
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+251
+192
+154
+247
+165
+111
+249
+146
+83
+247
+130
+53
+247
+118
+39
+247
+111
+26
+247
+111
+26
+246
+116
+28
+247
+123
+41
+248
+138
+64
+249
+146
+83
+249
+159
+103
+250
+176
+132
+219
+170
+138
+124
+111
+99
+43
+57
+62
+62
+63
+61
+106
+82
+65
+135
+94
+64
+155
+100
+63
+155
+100
+63
+139
+96
+61
+106
+82
+65
+69
+69
+61
+43
+57
+62
+91
+92
+89
+195
+157
+134
+251
+192
+154
+252
+185
+144
+248
+180
+134
+248
+180
+134
+252
+185
+144
+203
+161
+131
+63
+74
+74
+62
+63
+61
+106
+82
+65
+112
+85
+63
+69
+69
+61
+55
+66
+67
+146
+135
+124
+63
+74
+74
+56
+64
+60
+95
+78
+64
+112
+85
+63
+76
+70
+64
+48
+58
+59
+172
+150
+134
+253
+204
+176
+251
+209
+178
+251
+209
+178
+187
+166
+150
+77
+85
+81
+48
+58
+59
+81
+73
+62
+125
+90
+64
+146
+97
+64
+155
+100
+63
+139
+96
+61
+95
+78
+64
+56
+64
+60
+58
+69
+70
+161
+144
+134
+109
+106
+99
+51
+62
+63
+95
+78
+64
+112
+85
+63
+65
+67
+64
+65
+67
+64
+204
+141
+99
+246
+156
+93
+250
+139
+73
+247
+130
+53
+247
+118
+39
+247
+111
+26
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+246
+116
+28
+247
+130
+53
+247
+143
+74
+249
+159
+103
+252
+185
+144
+209
+171
+139
+24
+22
+23
+85
+71
+43
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+137
+110
+49
+47
+40
+38
+137
+110
+49
+101
+83
+47
+59
+50
+39
+59
+50
+39
+101
+83
+47
+158
+125
+46
+160
+120
+43
+192
+155
+91
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+237
+233
+225
+152
+147
+147
+81
+77
+76
+55
+48
+48
+115
+102
+92
+212
+173
+150
+251
+192
+154
+249
+174
+124
+247
+165
+111
+249
+159
+103
+249
+159
+103
+247
+165
+111
+249
+174
+124
+249
+189
+146
+238
+205
+179
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+43
+57
+62
+95
+87
+59
+145
+114
+49
+168
+127
+42
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+168
+127
+42
+145
+114
+49
+95
+87
+59
+48
+58
+59
+109
+106
+99
+236
+186
+153
+252
+185
+144
+248
+180
+134
+250
+176
+132
+250
+176
+132
+252
+185
+144
+251
+192
+154
+150
+125
+114
+48
+58
+59
+69
+69
+61
+117
+98
+55
+158
+125
+46
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+168
+127
+42
+152
+119
+47
+100
+89
+56
+56
+64
+60
+63
+74
+74
+186
+157
+134
+249
+189
+146
+248
+180
+134
+249
+174
+124
+249
+174
+124
+250
+176
+132
+252
+185
+144
+251
+192
+154
+133
+120
+107
+48
+58
+59
+75
+74
+61
+137
+110
+49
+168
+127
+42
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+145
+114
+49
+75
+74
+61
+43
+57
+62
+51
+62
+63
+123
+102
+54
+171
+129
+45
+171
+129
+45
+145
+114
+49
+56
+64
+60
+133
+120
+107
+253
+212
+188
+251
+209
+178
+253
+212
+188
+194
+173
+157
+63
+74
+74
+56
+64
+60
+111
+94
+57
+158
+125
+46
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+158
+125
+46
+105
+93
+60
+51
+62
+63
+43
+57
+62
+88
+82
+59
+168
+127
+42
+171
+129
+45
+168
+127
+42
+88
+82
+59
+63
+74
+74
+187
+166
+150
+55
+66
+67
+111
+94
+57
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+63
+69
+60
+137
+127
+115
+255
+215
+190
+255
+215
+190
+255
+215
+190
+245
+212
+186
+133
+120
+107
+48
+58
+59
+75
+74
+61
+129
+106
+52
+158
+125
+46
+171
+129
+45
+171
+129
+45
+171
+129
+45
+168
+127
+42
+171
+129
+45
+168
+127
+42
+145
+114
+49
+95
+87
+59
+51
+62
+63
+77
+85
+81
+212
+173
+150
+253
+204
+176
+253
+204
+176
+251
+209
+178
+255
+215
+190
+161
+144
+134
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+227
+126
+50
+183
+110
+59
+41
+58
+57
+69
+69
+61
+155
+100
+63
+214
+121
+50
+234
+126
+45
+234
+126
+45
+234
+126
+45
+234
+126
+45
+234
+126
+45
+224
+123
+55
+155
+100
+63
+69
+69
+61
+51
+62
+63
+178
+146
+122
+249
+189
+146
+250
+176
+132
+251
+168
+115
+251
+168
+115
+249
+174
+124
+250
+176
+132
+249
+189
+146
+167
+142
+123
+55
+66
+67
+65
+67
+64
+146
+97
+64
+212
+120
+56
+234
+126
+45
+234
+125
+52
+234
+126
+45
+234
+125
+52
+234
+126
+45
+234
+125
+52
+209
+117
+53
+146
+97
+64
+65
+67
+64
+55
+66
+67
+178
+146
+122
+249
+189
+146
+250
+176
+132
+251
+168
+115
+247
+165
+111
+251
+168
+115
+249
+174
+124
+252
+185
+144
+203
+161
+131
+63
+74
+74
+56
+64
+60
+125
+90
+64
+209
+117
+53
+234
+126
+45
+234
+126
+45
+234
+125
+52
+234
+126
+45
+234
+126
+45
+214
+121
+50
+146
+97
+64
+56
+64
+60
+41
+58
+57
+81
+73
+62
+209
+117
+53
+234
+126
+45
+234
+126
+45
+125
+90
+64
+51
+62
+63
+176
+156
+141
+55
+66
+67
+106
+82
+65
+225
+124
+48
+234
+126
+45
+234
+126
+45
+146
+97
+64
+41
+58
+57
+43
+57
+62
+125
+90
+64
+214
+121
+50
+234
+126
+45
+234
+126
+45
+183
+110
+59
+56
+64
+60
+137
+127
+115
+255
+215
+190
+194
+173
+157
+63
+74
+74
+62
+63
+61
+146
+97
+64
+214
+121
+50
+234
+125
+52
+234
+126
+45
+234
+125
+52
+234
+125
+52
+234
+126
+45
+225
+124
+48
+173
+106
+60
+81
+73
+62
+35
+56
+60
+155
+100
+63
+234
+125
+52
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+251
+192
+154
+247
+165
+111
+249
+146
+83
+247
+130
+53
+247
+118
+39
+246
+116
+28
+246
+116
+28
+247
+123
+41
+247
+130
+60
+249
+146
+83
+247
+165
+111
+248
+180
+134
+186
+157
+134
+58
+69
+70
+56
+64
+60
+135
+94
+64
+199
+115
+54
+234
+125
+52
+234
+126
+45
+234
+125
+52
+234
+125
+52
+234
+126
+45
+234
+125
+52
+212
+120
+56
+155
+100
+63
+76
+70
+64
+51
+62
+63
+146
+135
+124
+251
+209
+178
+253
+204
+176
+250
+200
+166
+253
+204
+176
+101
+100
+92
+69
+69
+61
+194
+112
+58
+234
+126
+45
+234
+126
+45
+199
+115
+54
+65
+67
+64
+35
+56
+60
+81
+73
+62
+194
+112
+58
+234
+125
+52
+234
+126
+45
+214
+121
+50
+95
+78
+64
+63
+74
+74
+238
+205
+179
+255
+215
+190
+161
+144
+134
+43
+57
+62
+81
+73
+62
+173
+106
+60
+225
+124
+48
+234
+126
+45
+234
+126
+45
+234
+125
+52
+234
+126
+45
+234
+126
+45
+194
+112
+58
+95
+78
+64
+41
+58
+57
+48
+58
+59
+155
+100
+63
+234
+126
+45
+234
+126
+45
+199
+115
+54
+69
+69
+61
+99
+90
+79
+251
+168
+115
+247
+150
+84
+247
+130
+60
+247
+123
+41
+247
+111
+26
+246
+109
+10
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+103
+7
+247
+111
+26
+247
+118
+39
+247
+130
+60
+247
+150
+84
+249
+174
+124
+251
+192
+154
+124
+111
+99
+35
+31
+30
+137
+110
+49
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+47
+40
+38
+108
+87
+46
+175
+132
+40
+161
+127
+40
+168
+127
+42
+171
+129
+45
+158
+125
+46
+152
+119
+47
+203
+161
+131
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+186
+181
+179
+89
+84
+82
+47
+40
+38
+139
+115
+96
+236
+186
+153
+252
+185
+144
+250
+176
+132
+249
+174
+124
+250
+176
+132
+252
+185
+144
+250
+197
+158
+238
+205
+179
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+111
+94
+57
+171
+129
+45
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+171
+129
+45
+111
+94
+57
+48
+58
+59
+109
+106
+99
+253
+204
+176
+250
+200
+166
+250
+200
+166
+250
+200
+166
+253
+204
+176
+137
+127
+115
+43
+57
+62
+88
+82
+59
+158
+125
+46
+171
+129
+45
+161
+127
+40
+158
+125
+46
+158
+125
+46
+168
+127
+42
+161
+127
+40
+158
+125
+46
+158
+125
+46
+168
+127
+42
+171
+129
+45
+145
+114
+49
+69
+69
+61
+51
+62
+63
+187
+166
+150
+250
+200
+166
+250
+197
+158
+251
+192
+154
+250
+197
+158
+253
+204
+176
+133
+120
+107
+48
+58
+59
+95
+87
+59
+168
+127
+42
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+171
+129
+45
+158
+125
+46
+75
+74
+61
+62
+63
+61
+168
+127
+42
+161
+127
+40
+158
+125
+46
+171
+129
+45
+83
+78
+61
+91
+92
+89
+255
+215
+190
+255
+215
+190
+207
+178
+158
+58
+69
+70
+63
+69
+60
+145
+114
+49
+171
+129
+45
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+171
+129
+45
+105
+93
+60
+43
+57
+62
+137
+110
+49
+171
+129
+45
+158
+125
+46
+171
+129
+45
+137
+110
+49
+51
+62
+63
+146
+135
+124
+58
+69
+70
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+152
+119
+47
+65
+67
+64
+137
+127
+115
+255
+215
+190
+255
+215
+190
+245
+212
+186
+120
+114
+108
+48
+58
+59
+100
+89
+56
+168
+127
+42
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+171
+129
+45
+129
+106
+52
+61
+67
+58
+63
+74
+74
+207
+178
+158
+255
+215
+190
+255
+215
+190
+255
+215
+190
+161
+144
+134
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+234
+125
+52
+173
+106
+60
+95
+78
+64
+209
+117
+53
+234
+126
+45
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+126
+45
+209
+117
+53
+89
+75
+66
+51
+62
+63
+187
+166
+150
+250
+197
+158
+251
+192
+154
+249
+189
+146
+251
+192
+154
+250
+200
+166
+161
+144
+134
+41
+58
+57
+95
+78
+64
+199
+115
+54
+234
+126
+45
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+126
+45
+199
+115
+54
+89
+75
+66
+41
+58
+57
+167
+142
+123
+250
+200
+166
+251
+192
+154
+252
+185
+144
+249
+189
+146
+250
+197
+158
+212
+173
+150
+63
+74
+74
+69
+69
+61
+183
+110
+59
+234
+126
+45
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+126
+45
+163
+104
+61
+41
+58
+57
+135
+94
+64
+234
+126
+45
+224
+123
+55
+234
+125
+52
+188
+112
+56
+51
+62
+63
+109
+106
+99
+51
+62
+63
+188
+112
+56
+234
+126
+45
+224
+123
+55
+234
+125
+52
+188
+112
+56
+43
+57
+62
+112
+85
+63
+234
+126
+45
+227
+126
+50
+224
+123
+55
+227
+126
+50
+234
+126
+45
+95
+78
+64
+109
+106
+99
+217
+187
+166
+58
+69
+70
+69
+69
+61
+188
+112
+56
+234
+126
+45
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+125
+52
+214
+121
+50
+95
+78
+64
+146
+97
+64
+234
+125
+52
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+251
+192
+154
+247
+165
+111
+249
+146
+83
+247
+130
+53
+247
+123
+41
+247
+118
+39
+247
+123
+41
+247
+130
+53
+247
+143
+74
+249
+159
+103
+250
+176
+132
+186
+157
+134
+51
+62
+63
+81
+73
+62
+188
+112
+56
+234
+126
+45
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+126
+45
+212
+120
+56
+106
+82
+65
+41
+58
+57
+146
+135
+124
+255
+215
+190
+255
+215
+190
+234
+204
+183
+63
+74
+74
+125
+90
+64
+234
+126
+45
+224
+123
+55
+227
+126
+50
+234
+125
+52
+89
+75
+66
+62
+63
+61
+199
+115
+54
+234
+126
+45
+224
+123
+55
+224
+123
+55
+234
+126
+45
+163
+104
+61
+48
+58
+59
+217
+187
+166
+172
+150
+134
+41
+58
+57
+106
+82
+65
+214
+121
+50
+234
+126
+45
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+225
+124
+48
+81
+73
+62
+69
+69
+61
+227
+126
+50
+227
+126
+50
+224
+123
+55
+238
+123
+45
+125
+90
+64
+55
+66
+67
+250
+176
+132
+246
+156
+93
+250
+139
+73
+247
+123
+41
+247
+111
+26
+246
+109
+10
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+123
+41
+250
+139
+73
+249
+159
+103
+248
+180
+134
+232
+190
+161
+47
+40
+38
+71
+60
+43
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+171
+129
+45
+71
+60
+43
+71
+60
+43
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+160
+120
+43
+170
+137
+67
+237
+233
+225
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+186
+181
+179
+74
+68
+68
+89
+75
+66
+212
+173
+150
+250
+197
+158
+251
+192
+154
+249
+189
+146
+251
+192
+154
+253
+204
+176
+234
+204
+183
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+152
+119
+47
+168
+127
+42
+158
+125
+46
+158
+125
+46
+168
+127
+42
+171
+129
+45
+171
+129
+45
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+171
+129
+45
+111
+94
+57
+48
+58
+59
+161
+144
+134
+255
+215
+190
+255
+215
+190
+255
+215
+190
+172
+150
+134
+48
+58
+59
+95
+87
+59
+168
+127
+42
+168
+127
+42
+158
+125
+46
+161
+127
+40
+171
+129
+45
+158
+125
+46
+152
+119
+47
+152
+119
+47
+168
+127
+42
+168
+127
+42
+158
+125
+46
+158
+125
+46
+168
+127
+42
+152
+119
+47
+69
+69
+61
+58
+69
+70
+217
+187
+166
+255
+215
+190
+255
+215
+190
+255
+215
+190
+172
+150
+134
+43
+57
+62
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+171
+129
+45
+171
+129
+45
+171
+129
+45
+158
+125
+46
+168
+127
+42
+137
+110
+49
+83
+78
+61
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+88
+82
+59
+84
+85
+82
+255
+215
+190
+238
+205
+179
+84
+85
+82
+62
+63
+61
+145
+114
+49
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+171
+129
+45
+171
+129
+45
+171
+129
+45
+168
+127
+42
+161
+127
+40
+158
+125
+46
+88
+82
+59
+152
+119
+47
+161
+127
+40
+158
+125
+46
+168
+127
+42
+145
+114
+49
+51
+62
+63
+137
+127
+115
+58
+69
+70
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+152
+119
+47
+63
+69
+60
+137
+127
+115
+255
+215
+190
+255
+215
+190
+137
+127
+115
+48
+58
+59
+105
+93
+60
+171
+129
+45
+161
+127
+40
+158
+125
+46
+168
+127
+42
+168
+127
+42
+158
+125
+46
+152
+119
+47
+152
+119
+47
+168
+127
+42
+171
+129
+45
+158
+125
+46
+158
+125
+46
+171
+129
+45
+145
+114
+49
+62
+63
+61
+70
+79
+77
+227
+196
+175
+255
+215
+190
+255
+215
+190
+161
+144
+134
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+227
+126
+50
+212
+120
+56
+214
+121
+50
+227
+126
+50
+224
+123
+55
+227
+126
+50
+234
+126
+45
+234
+126
+45
+234
+125
+52
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+209
+117
+53
+76
+70
+64
+70
+79
+77
+234
+204
+183
+253
+212
+188
+251
+209
+178
+253
+212
+188
+187
+166
+150
+43
+57
+62
+95
+78
+64
+225
+124
+48
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+125
+52
+234
+126
+45
+234
+126
+45
+227
+126
+50
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+125
+52
+214
+121
+50
+95
+78
+64
+48
+58
+59
+194
+173
+157
+253
+212
+188
+251
+209
+178
+251
+209
+178
+245
+212
+186
+91
+92
+89
+62
+63
+61
+188
+112
+56
+234
+126
+45
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+125
+52
+234
+125
+52
+234
+126
+45
+227
+126
+50
+224
+123
+55
+234
+126
+45
+125
+90
+64
+146
+97
+64
+234
+125
+52
+224
+123
+55
+227
+126
+50
+194
+112
+58
+56
+64
+60
+97
+98
+96
+56
+64
+60
+188
+112
+56
+227
+126
+50
+224
+123
+55
+224
+123
+55
+212
+120
+56
+183
+110
+59
+214
+121
+50
+227
+126
+50
+224
+123
+55
+227
+126
+50
+227
+126
+50
+234
+126
+45
+95
+78
+64
+84
+85
+82
+91
+92
+89
+62
+63
+61
+188
+112
+56
+234
+126
+45
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+125
+52
+234
+126
+45
+234
+126
+45
+227
+126
+50
+224
+123
+55
+227
+126
+50
+224
+123
+55
+209
+117
+53
+227
+126
+50
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+251
+192
+154
+247
+165
+111
+249
+146
+83
+247
+130
+60
+247
+123
+41
+247
+123
+41
+247
+130
+53
+248
+138
+64
+249
+152
+92
+249
+174
+124
+209
+171
+139
+58
+69
+70
+81
+73
+62
+209
+117
+53
+234
+125
+52
+224
+123
+55
+224
+123
+55
+227
+126
+50
+227
+126
+50
+234
+125
+52
+234
+125
+52
+234
+125
+52
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+227
+126
+50
+112
+85
+63
+41
+58
+57
+172
+150
+134
+255
+215
+190
+227
+196
+175
+63
+74
+74
+135
+94
+64
+234
+125
+52
+224
+123
+55
+224
+123
+55
+224
+123
+55
+194
+112
+58
+199
+115
+54
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+238
+128
+40
+163
+104
+61
+55
+66
+67
+161
+144
+134
+58
+69
+70
+95
+78
+64
+225
+124
+48
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+227
+126
+50
+234
+126
+45
+234
+126
+45
+234
+125
+52
+227
+126
+50
+234
+125
+52
+173
+106
+60
+118
+86
+65
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+125
+52
+146
+97
+64
+51
+62
+63
+252
+185
+144
+249
+159
+103
+247
+143
+74
+247
+130
+53
+246
+116
+28
+246
+109
+10
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+111
+26
+247
+118
+39
+247
+130
+53
+249
+146
+83
+251
+168
+115
+251
+192
+154
+154
+133
+118
+24
+22
+23
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+171
+129
+45
+108
+87
+46
+47
+40
+38
+158
+125
+46
+158
+125
+46
+158
+125
+46
+160
+120
+43
+156
+125
+62
+224
+207
+180
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+152
+147
+147
+35
+31
+30
+55
+48
+48
+154
+133
+118
+217
+187
+166
+253
+204
+176
+253
+204
+176
+253
+212
+188
+234
+204
+183
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+158
+125
+46
+168
+127
+42
+158
+125
+46
+123
+102
+54
+105
+93
+60
+111
+94
+57
+129
+106
+52
+168
+127
+42
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+171
+129
+45
+83
+78
+61
+58
+69
+70
+227
+196
+175
+255
+215
+190
+217
+187
+166
+58
+69
+70
+75
+74
+61
+168
+127
+42
+161
+127
+40
+158
+125
+46
+168
+127
+42
+152
+119
+47
+105
+93
+60
+69
+69
+61
+62
+63
+61
+62
+63
+61
+75
+74
+61
+117
+98
+55
+161
+127
+40
+161
+127
+40
+158
+125
+46
+171
+129
+45
+145
+114
+49
+56
+64
+60
+97
+98
+96
+245
+212
+186
+255
+215
+190
+227
+196
+175
+63
+74
+74
+75
+74
+61
+158
+125
+46
+168
+127
+42
+158
+125
+46
+158
+125
+46
+168
+127
+42
+158
+125
+46
+129
+106
+52
+111
+94
+57
+105
+93
+60
+129
+106
+52
+158
+125
+46
+168
+127
+42
+161
+127
+40
+152
+119
+47
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+84
+85
+82
+255
+215
+190
+161
+144
+134
+48
+58
+59
+123
+102
+54
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+145
+114
+49
+117
+98
+55
+105
+93
+60
+117
+98
+55
+145
+114
+49
+171
+129
+45
+168
+127
+42
+152
+119
+47
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+145
+114
+49
+51
+62
+63
+137
+127
+115
+58
+69
+70
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+63
+69
+60
+137
+127
+115
+255
+215
+190
+194
+173
+157
+48
+58
+59
+88
+82
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+152
+119
+47
+95
+87
+59
+69
+69
+61
+62
+63
+61
+62
+63
+61
+83
+78
+61
+123
+102
+54
+168
+127
+42
+161
+127
+40
+158
+125
+46
+171
+129
+45
+129
+106
+52
+51
+62
+63
+120
+114
+108
+255
+215
+190
+255
+215
+190
+161
+144
+134
+56
+64
+60
+199
+115
+54
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+227
+126
+50
+227
+126
+50
+227
+126
+50
+188
+112
+56
+146
+97
+64
+135
+94
+64
+146
+97
+64
+199
+115
+54
+234
+125
+52
+224
+123
+55
+224
+123
+55
+224
+123
+55
+234
+126
+45
+173
+106
+60
+48
+58
+59
+146
+135
+124
+255
+215
+190
+255
+215
+190
+234
+204
+183
+77
+85
+81
+76
+70
+64
+214
+121
+50
+234
+125
+52
+224
+123
+55
+224
+123
+55
+234
+125
+52
+214
+121
+50
+163
+104
+61
+135
+94
+64
+135
+94
+64
+163
+104
+61
+224
+123
+55
+234
+125
+52
+224
+123
+55
+224
+123
+55
+227
+126
+50
+212
+120
+56
+76
+70
+64
+77
+85
+81
+238
+205
+179
+255
+215
+190
+255
+215
+190
+161
+144
+134
+48
+58
+59
+155
+100
+63
+234
+126
+45
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+125
+52
+199
+115
+54
+155
+100
+63
+135
+94
+64
+146
+97
+64
+188
+112
+56
+227
+126
+50
+227
+126
+50
+214
+121
+50
+209
+117
+53
+227
+126
+50
+224
+123
+55
+227
+126
+50
+194
+112
+58
+56
+64
+60
+101
+100
+92
+56
+64
+60
+188
+112
+56
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+234
+125
+52
+227
+126
+50
+224
+123
+55
+227
+126
+50
+227
+126
+50
+199
+115
+54
+125
+90
+64
+51
+62
+63
+55
+66
+67
+41
+58
+57
+146
+97
+64
+234
+126
+45
+224
+123
+55
+224
+123
+55
+224
+123
+55
+234
+126
+45
+209
+117
+53
+155
+100
+63
+135
+94
+64
+139
+96
+61
+183
+110
+59
+227
+126
+50
+227
+126
+50
+227
+126
+50
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+251
+192
+154
+247
+165
+111
+249
+146
+83
+247
+130
+60
+247
+130
+53
+247
+130
+53
+247
+130
+60
+249
+146
+83
+247
+165
+111
+252
+185
+144
+101
+100
+92
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+227
+126
+50
+173
+106
+60
+135
+94
+64
+135
+94
+64
+163
+104
+61
+214
+121
+50
+234
+125
+52
+224
+123
+55
+224
+123
+55
+227
+126
+50
+224
+123
+55
+81
+73
+62
+58
+69
+70
+227
+196
+175
+234
+204
+183
+63
+74
+74
+135
+94
+64
+234
+126
+45
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+227
+126
+50
+224
+123
+55
+227
+126
+50
+234
+125
+52
+212
+120
+56
+155
+100
+63
+69
+69
+61
+76
+78
+76
+84
+85
+82
+65
+67
+64
+209
+117
+53
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+227
+126
+50
+183
+110
+59
+139
+96
+61
+135
+94
+64
+155
+100
+63
+209
+117
+53
+234
+125
+52
+224
+123
+55
+212
+120
+56
+224
+123
+55
+224
+123
+55
+224
+123
+55
+234
+126
+45
+139
+96
+61
+55
+66
+67
+251
+192
+154
+251
+168
+115
+249
+146
+83
+247
+130
+53
+247
+118
+39
+246
+109
+10
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+123
+41
+248
+138
+64
+249
+152
+92
+250
+176
+132
+232
+190
+161
+65
+58
+56
+59
+50
+39
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+145
+114
+49
+47
+40
+38
+129
+106
+52
+168
+127
+42
+160
+120
+43
+158
+125
+46
+224
+207
+180
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+219
+212
+208
+62
+63
+61
+35
+31
+30
+91
+92
+89
+164
+158
+157
+186
+181
+179
+82
+69
+65
+176
+156
+141
+255
+215
+190
+255
+215
+190
+238
+205
+179
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+129
+106
+52
+65
+67
+64
+48
+58
+59
+55
+66
+67
+55
+66
+67
+48
+58
+59
+83
+78
+61
+145
+114
+49
+168
+127
+42
+158
+125
+46
+158
+125
+46
+168
+127
+42
+137
+110
+49
+51
+62
+63
+146
+135
+124
+255
+215
+190
+120
+114
+108
+56
+64
+60
+145
+114
+49
+171
+129
+45
+158
+125
+46
+168
+127
+42
+152
+119
+47
+69
+69
+61
+43
+57
+62
+109
+106
+99
+146
+135
+124
+137
+127
+115
+91
+92
+89
+43
+57
+62
+88
+82
+59
+158
+125
+46
+161
+127
+40
+158
+125
+46
+171
+129
+45
+117
+98
+55
+48
+58
+59
+172
+150
+134
+255
+215
+190
+146
+135
+124
+51
+62
+63
+137
+110
+49
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+145
+114
+49
+75
+74
+61
+48
+58
+59
+55
+66
+67
+55
+66
+67
+48
+58
+59
+69
+69
+61
+137
+110
+49
+168
+127
+42
+161
+127
+40
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+91
+92
+89
+234
+204
+183
+70
+79
+77
+83
+78
+61
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+111
+94
+57
+56
+64
+60
+43
+57
+62
+58
+69
+70
+48
+58
+59
+56
+64
+60
+100
+89
+56
+158
+125
+46
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+145
+114
+49
+51
+62
+63
+137
+127
+115
+58
+69
+70
+111
+94
+57
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+65
+67
+64
+137
+127
+115
+255
+215
+190
+97
+98
+96
+62
+63
+61
+152
+119
+47
+168
+127
+42
+158
+125
+46
+168
+127
+42
+137
+110
+49
+62
+63
+61
+51
+62
+63
+120
+114
+108
+146
+135
+124
+137
+127
+115
+84
+85
+82
+43
+57
+62
+95
+87
+59
+168
+127
+42
+158
+125
+46
+158
+125
+46
+171
+129
+45
+100
+89
+56
+43
+57
+62
+194
+173
+157
+255
+215
+190
+161
+144
+134
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+224
+123
+55
+118
+86
+65
+51
+62
+63
+43
+57
+62
+58
+69
+70
+41
+58
+57
+56
+64
+60
+146
+97
+64
+234
+126
+45
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+125
+52
+106
+82
+65
+63
+74
+74
+234
+204
+183
+255
+215
+190
+161
+144
+134
+48
+58
+59
+173
+106
+60
+234
+125
+52
+224
+123
+55
+224
+123
+55
+234
+125
+52
+183
+110
+59
+76
+70
+64
+43
+57
+62
+55
+66
+67
+55
+66
+67
+48
+58
+59
+81
+73
+62
+183
+110
+59
+234
+125
+52
+224
+123
+55
+224
+123
+55
+234
+126
+45
+163
+104
+61
+48
+58
+59
+161
+144
+134
+255
+215
+190
+234
+204
+183
+63
+74
+74
+95
+78
+64
+234
+126
+45
+224
+123
+55
+224
+123
+55
+227
+126
+50
+227
+126
+50
+135
+94
+64
+62
+63
+61
+43
+57
+62
+58
+69
+70
+43
+57
+62
+51
+62
+63
+125
+90
+64
+225
+124
+48
+227
+126
+50
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+194
+112
+58
+56
+64
+60
+97
+98
+96
+56
+64
+60
+188
+112
+56
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+234
+125
+52
+227
+126
+50
+173
+106
+60
+95
+78
+64
+56
+64
+60
+51
+62
+63
+120
+114
+108
+70
+79
+77
+89
+75
+66
+225
+124
+48
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+126
+45
+163
+104
+61
+65
+67
+64
+41
+58
+57
+55
+66
+67
+51
+62
+63
+48
+58
+59
+106
+82
+65
+209
+117
+53
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+251
+192
+154
+247
+165
+111
+249
+146
+83
+248
+138
+64
+247
+130
+53
+247
+130
+60
+250
+139
+73
+246
+156
+93
+250
+176
+132
+186
+157
+134
+41
+58
+57
+146
+97
+64
+234
+126
+45
+224
+123
+55
+224
+123
+55
+234
+125
+52
+199
+115
+54
+89
+75
+66
+48
+58
+59
+51
+62
+63
+55
+66
+67
+43
+57
+62
+76
+70
+64
+173
+106
+60
+234
+125
+52
+224
+123
+55
+224
+123
+55
+227
+126
+50
+183
+110
+59
+51
+62
+63
+137
+127
+115
+234
+204
+183
+63
+74
+74
+135
+94
+64
+234
+125
+52
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+126
+45
+199
+115
+54
+125
+90
+64
+69
+69
+61
+41
+58
+57
+97
+98
+96
+146
+135
+124
+51
+62
+63
+146
+97
+64
+234
+126
+45
+224
+123
+55
+224
+123
+55
+227
+126
+50
+214
+121
+50
+106
+82
+65
+48
+58
+59
+51
+62
+63
+55
+66
+67
+41
+58
+57
+65
+67
+64
+163
+104
+61
+234
+126
+45
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+234
+125
+52
+139
+96
+61
+55
+66
+67
+250
+197
+158
+251
+168
+115
+247
+150
+84
+247
+130
+60
+247
+118
+39
+247
+111
+26
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+246
+116
+28
+247
+130
+53
+247
+143
+74
+249
+159
+103
+252
+185
+144
+154
+133
+118
+24
+22
+23
+108
+87
+46
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+171
+129
+45
+71
+60
+43
+85
+71
+43
+171
+129
+45
+160
+120
+43
+216
+194
+154
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+237
+233
+225
+65
+58
+56
+62
+63
+61
+219
+212
+208
+253
+255
+252
+237
+233
+225
+120
+114
+108
+35
+31
+30
+55
+48
+48
+227
+196
+175
+255
+215
+190
+238
+205
+179
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+129
+106
+52
+51
+62
+63
+84
+85
+82
+187
+166
+150
+227
+196
+175
+227
+196
+175
+161
+144
+134
+51
+62
+63
+69
+69
+61
+152
+119
+47
+168
+127
+42
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+91
+92
+89
+217
+187
+166
+55
+66
+67
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+75
+74
+61
+58
+69
+70
+187
+166
+150
+255
+215
+190
+255
+215
+190
+255
+215
+190
+245
+212
+186
+161
+144
+134
+43
+57
+62
+100
+89
+56
+171
+129
+45
+158
+125
+46
+158
+125
+46
+161
+127
+40
+75
+74
+61
+84
+85
+82
+234
+204
+183
+76
+78
+76
+88
+82
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+145
+114
+49
+62
+63
+61
+63
+74
+74
+176
+156
+141
+227
+196
+175
+227
+196
+175
+176
+156
+141
+70
+79
+77
+62
+63
+61
+145
+114
+49
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+97
+98
+96
+172
+150
+134
+48
+58
+59
+129
+106
+52
+168
+127
+42
+158
+125
+46
+158
+125
+46
+171
+129
+45
+105
+93
+60
+43
+57
+62
+120
+114
+108
+207
+178
+158
+227
+196
+175
+217
+187
+166
+120
+114
+108
+41
+58
+57
+95
+87
+59
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+145
+114
+49
+56
+64
+60
+137
+127
+115
+58
+69
+70
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+65
+67
+64
+146
+135
+124
+207
+178
+158
+48
+58
+59
+111
+94
+57
+171
+129
+45
+158
+125
+46
+168
+127
+42
+152
+119
+47
+62
+63
+61
+70
+79
+77
+207
+178
+158
+255
+215
+190
+255
+215
+190
+255
+215
+190
+238
+205
+179
+137
+127
+115
+43
+57
+62
+117
+98
+55
+168
+127
+42
+158
+125
+46
+168
+127
+42
+152
+119
+47
+62
+63
+61
+109
+106
+99
+255
+215
+190
+161
+144
+134
+56
+64
+60
+199
+115
+54
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+227
+126
+50
+106
+82
+65
+41
+58
+57
+137
+127
+115
+217
+187
+166
+227
+196
+175
+207
+178
+158
+109
+106
+99
+41
+58
+57
+146
+97
+64
+234
+125
+52
+224
+123
+55
+224
+123
+55
+234
+125
+52
+173
+106
+60
+48
+58
+59
+176
+156
+141
+245
+212
+186
+70
+79
+77
+95
+78
+64
+234
+125
+52
+224
+123
+55
+224
+123
+55
+234
+125
+52
+188
+112
+56
+56
+64
+60
+70
+79
+77
+176
+156
+141
+227
+196
+175
+227
+196
+175
+176
+156
+141
+63
+74
+74
+62
+63
+61
+194
+112
+58
+227
+126
+50
+224
+123
+55
+227
+126
+50
+227
+126
+50
+95
+78
+64
+77
+85
+81
+245
+212
+186
+172
+150
+134
+48
+58
+59
+173
+106
+60
+234
+126
+45
+224
+123
+55
+224
+123
+55
+234
+125
+52
+135
+94
+64
+35
+56
+60
+120
+114
+108
+207
+178
+158
+227
+196
+175
+217
+187
+166
+133
+120
+107
+35
+56
+60
+118
+86
+65
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+194
+112
+58
+56
+64
+60
+101
+100
+92
+56
+64
+60
+188
+112
+56
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+194
+112
+58
+95
+78
+64
+48
+58
+59
+70
+79
+77
+146
+135
+124
+217
+187
+166
+207
+178
+158
+51
+62
+63
+155
+100
+63
+234
+126
+45
+224
+123
+55
+224
+123
+55
+234
+125
+52
+163
+104
+61
+48
+58
+59
+91
+92
+89
+194
+173
+157
+227
+196
+175
+217
+187
+166
+146
+135
+124
+43
+57
+62
+89
+75
+66
+214
+121
+50
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+251
+192
+154
+247
+165
+111
+247
+150
+84
+248
+138
+64
+247
+130
+60
+248
+138
+64
+249
+146
+83
+247
+165
+111
+239
+182
+144
+91
+92
+89
+76
+70
+64
+224
+123
+55
+227
+126
+50
+224
+123
+55
+227
+126
+50
+209
+117
+53
+76
+70
+64
+55
+66
+67
+172
+150
+134
+227
+196
+175
+227
+196
+175
+187
+166
+150
+77
+85
+81
+51
+62
+63
+173
+106
+60
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+126
+45
+118
+86
+65
+58
+69
+70
+217
+187
+166
+70
+79
+77
+135
+94
+64
+234
+125
+52
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+225
+124
+48
+125
+90
+64
+56
+64
+60
+55
+66
+67
+120
+114
+108
+187
+166
+150
+245
+212
+186
+120
+114
+108
+76
+70
+64
+214
+121
+50
+227
+126
+50
+224
+123
+55
+227
+126
+50
+225
+124
+48
+95
+78
+64
+43
+57
+62
+146
+135
+124
+217
+187
+166
+227
+196
+175
+194
+173
+157
+91
+92
+89
+48
+58
+59
+163
+104
+61
+234
+125
+52
+224
+123
+55
+224
+123
+55
+224
+123
+55
+234
+126
+45
+139
+96
+61
+55
+66
+67
+250
+197
+158
+249
+174
+124
+247
+150
+84
+247
+130
+60
+247
+118
+39
+247
+111
+26
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+111
+26
+247
+118
+39
+247
+130
+53
+249
+146
+83
+251
+168
+115
+239
+182
+144
+65
+58
+56
+59
+50
+39
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+171
+129
+45
+108
+87
+46
+47
+40
+38
+152
+119
+47
+170
+137
+67
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+174
+168
+167
+24
+22
+23
+109
+106
+99
+152
+147
+147
+97
+98
+96
+47
+40
+38
+24
+22
+23
+35
+31
+30
+35
+31
+30
+176
+156
+141
+255
+215
+190
+238
+205
+179
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+69
+69
+61
+76
+78
+76
+227
+196
+175
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+187
+166
+150
+51
+62
+63
+95
+87
+59
+168
+127
+42
+158
+125
+46
+158
+125
+46
+171
+129
+45
+117
+98
+55
+55
+66
+67
+109
+106
+99
+48
+58
+59
+137
+110
+49
+168
+127
+42
+158
+125
+46
+168
+127
+42
+117
+98
+55
+48
+58
+59
+187
+166
+150
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+137
+127
+115
+51
+62
+63
+145
+114
+49
+168
+127
+42
+158
+125
+46
+171
+129
+45
+117
+98
+55
+55
+66
+67
+137
+127
+115
+55
+66
+67
+123
+102
+54
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+55
+66
+67
+207
+178
+158
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+217
+187
+166
+58
+69
+70
+83
+78
+61
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+88
+82
+59
+91
+92
+89
+109
+106
+99
+69
+69
+61
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+145
+114
+49
+51
+62
+63
+120
+114
+108
+245
+212
+186
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+137
+127
+115
+48
+58
+59
+129
+106
+52
+168
+127
+42
+158
+125
+46
+158
+125
+46
+168
+127
+42
+145
+114
+49
+51
+62
+63
+137
+127
+115
+58
+69
+70
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+65
+67
+64
+146
+135
+124
+146
+135
+124
+62
+63
+61
+152
+119
+47
+168
+127
+42
+158
+125
+46
+168
+127
+42
+100
+89
+56
+51
+62
+63
+207
+178
+158
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+109
+106
+99
+63
+69
+60
+158
+125
+46
+158
+125
+46
+158
+125
+46
+171
+129
+45
+100
+89
+56
+51
+62
+63
+227
+196
+175
+172
+150
+134
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+126
+45
+155
+100
+63
+41
+58
+57
+146
+135
+124
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+245
+212
+186
+109
+106
+99
+56
+64
+60
+199
+115
+54
+227
+126
+50
+224
+123
+55
+227
+126
+50
+224
+123
+55
+76
+70
+64
+109
+106
+99
+194
+173
+157
+43
+57
+62
+163
+104
+61
+234
+125
+52
+224
+123
+55
+224
+123
+55
+225
+124
+48
+89
+75
+66
+63
+74
+74
+217
+187
+166
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+217
+187
+166
+58
+69
+70
+95
+78
+64
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+126
+45
+155
+100
+63
+43
+57
+62
+207
+178
+158
+109
+106
+99
+76
+70
+64
+224
+123
+55
+227
+126
+50
+224
+123
+55
+227
+126
+50
+194
+112
+58
+51
+62
+63
+120
+114
+108
+253
+212
+188
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+137
+127
+115
+48
+58
+59
+173
+106
+60
+234
+125
+52
+224
+123
+55
+224
+123
+55
+227
+126
+50
+194
+112
+58
+56
+64
+60
+101
+100
+92
+56
+64
+60
+188
+112
+56
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+188
+112
+56
+62
+63
+61
+58
+69
+70
+161
+144
+134
+234
+204
+183
+255
+215
+190
+255
+215
+190
+137
+127
+115
+62
+63
+61
+209
+117
+53
+227
+126
+50
+224
+123
+55
+227
+126
+50
+212
+120
+56
+69
+69
+61
+77
+85
+81
+234
+204
+183
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+176
+156
+141
+35
+56
+60
+135
+94
+64
+234
+126
+45
+224
+123
+55
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+251
+192
+154
+251
+168
+115
+247
+150
+84
+250
+139
+73
+248
+138
+64
+250
+139
+73
+249
+152
+92
+249
+174
+124
+209
+171
+139
+43
+57
+62
+135
+94
+64
+234
+126
+45
+224
+123
+55
+224
+123
+55
+234
+126
+45
+112
+85
+63
+51
+62
+63
+194
+173
+157
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+227
+196
+175
+70
+79
+77
+76
+70
+64
+214
+121
+50
+227
+126
+50
+224
+123
+55
+227
+126
+50
+183
+110
+59
+48
+58
+59
+146
+135
+124
+77
+85
+81
+135
+94
+64
+234
+125
+52
+224
+123
+55
+224
+123
+55
+227
+126
+50
+214
+121
+50
+95
+78
+64
+35
+56
+60
+120
+114
+108
+217
+187
+166
+255
+215
+190
+255
+215
+190
+227
+196
+175
+58
+69
+70
+125
+90
+64
+234
+125
+52
+224
+123
+55
+224
+123
+55
+234
+125
+52
+139
+96
+61
+41
+58
+57
+172
+150
+134
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+234
+204
+183
+77
+85
+81
+76
+70
+64
+214
+121
+50
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+125
+52
+139
+96
+61
+51
+62
+63
+250
+200
+166
+249
+174
+124
+249
+152
+92
+247
+130
+60
+247
+118
+39
+247
+111
+26
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+111
+26
+247
+123
+41
+248
+138
+64
+249
+152
+92
+249
+174
+124
+178
+146
+122
+24
+22
+23
+101
+83
+47
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+152
+119
+47
+47
+40
+38
+123
+102
+54
+209
+171
+139
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+164
+158
+157
+24
+22
+23
+24
+22
+23
+24
+22
+23
+24
+22
+23
+24
+22
+23
+35
+31
+30
+35
+31
+30
+47
+40
+38
+194
+173
+157
+255
+215
+190
+238
+205
+179
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+129
+106
+52
+48
+58
+59
+176
+156
+141
+255
+215
+190
+255
+215
+190
+253
+212
+188
+255
+215
+190
+255
+215
+190
+255
+215
+190
+120
+114
+108
+56
+64
+60
+152
+119
+47
+161
+127
+40
+158
+125
+46
+168
+127
+42
+137
+110
+49
+51
+62
+63
+48
+58
+59
+75
+74
+61
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+63
+74
+74
+194
+173
+157
+207
+178
+158
+207
+178
+158
+207
+178
+158
+207
+178
+158
+207
+178
+158
+207
+178
+158
+172
+150
+134
+48
+58
+59
+111
+94
+57
+171
+129
+45
+158
+125
+46
+168
+127
+42
+152
+119
+47
+56
+64
+60
+51
+62
+63
+56
+64
+60
+152
+119
+47
+168
+127
+42
+158
+125
+46
+168
+127
+42
+145
+114
+49
+51
+62
+63
+146
+135
+124
+255
+215
+190
+255
+215
+190
+253
+212
+188
+253
+212
+188
+255
+215
+190
+255
+215
+190
+146
+135
+124
+51
+62
+63
+145
+114
+49
+168
+127
+42
+158
+125
+46
+158
+125
+46
+168
+127
+42
+88
+82
+59
+70
+79
+77
+63
+74
+74
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+171
+129
+45
+95
+87
+59
+55
+66
+67
+227
+196
+175
+255
+215
+190
+255
+215
+190
+253
+212
+188
+255
+215
+190
+255
+215
+190
+234
+204
+183
+70
+79
+77
+88
+82
+59
+168
+127
+42
+158
+125
+46
+158
+125
+46
+168
+127
+42
+145
+114
+49
+56
+64
+60
+137
+127
+115
+58
+69
+70
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+63
+69
+60
+137
+127
+115
+97
+98
+96
+83
+78
+61
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+69
+69
+61
+84
+85
+82
+207
+178
+158
+207
+178
+158
+207
+178
+158
+207
+178
+158
+207
+178
+158
+207
+178
+158
+217
+187
+166
+146
+135
+124
+48
+58
+59
+129
+106
+52
+168
+127
+42
+158
+125
+46
+168
+127
+42
+129
+106
+52
+51
+62
+63
+187
+166
+150
+176
+156
+141
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+89
+75
+66
+70
+79
+77
+245
+212
+186
+255
+215
+190
+255
+215
+190
+253
+212
+188
+255
+215
+190
+255
+215
+190
+217
+187
+166
+43
+57
+62
+125
+90
+64
+234
+126
+45
+224
+123
+55
+224
+123
+55
+234
+126
+45
+106
+82
+65
+77
+85
+81
+133
+120
+107
+62
+63
+61
+209
+117
+53
+227
+126
+50
+224
+123
+55
+227
+126
+50
+183
+110
+59
+48
+58
+59
+161
+144
+134
+255
+215
+190
+255
+215
+190
+253
+212
+188
+253
+212
+188
+255
+215
+190
+255
+215
+190
+146
+135
+124
+48
+58
+59
+188
+112
+56
+227
+126
+50
+224
+123
+55
+227
+126
+50
+199
+115
+54
+62
+63
+61
+133
+120
+107
+77
+85
+81
+118
+86
+65
+234
+126
+45
+224
+123
+55
+224
+123
+55
+234
+126
+45
+125
+90
+64
+55
+66
+67
+227
+196
+175
+255
+215
+190
+255
+215
+190
+253
+212
+188
+255
+215
+190
+255
+215
+190
+234
+204
+183
+63
+74
+74
+106
+82
+65
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+194
+112
+58
+56
+64
+60
+97
+98
+96
+56
+64
+60
+188
+112
+56
+227
+126
+50
+224
+123
+55
+227
+126
+50
+224
+123
+55
+89
+75
+66
+63
+74
+74
+217
+187
+166
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+91
+92
+89
+95
+78
+64
+227
+126
+50
+227
+126
+50
+224
+123
+55
+234
+126
+45
+146
+97
+64
+43
+57
+62
+187
+166
+150
+255
+215
+190
+255
+215
+190
+253
+212
+188
+255
+215
+190
+255
+215
+190
+255
+215
+190
+101
+100
+92
+76
+70
+64
+224
+123
+55
+227
+126
+50
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+251
+192
+154
+251
+168
+115
+247
+150
+84
+250
+139
+73
+250
+139
+73
+247
+143
+74
+249
+159
+103
+250
+176
+132
+154
+133
+118
+51
+62
+63
+183
+110
+59
+227
+126
+50
+224
+123
+55
+227
+126
+50
+199
+115
+54
+62
+63
+61
+133
+120
+107
+255
+215
+190
+255
+215
+190
+253
+212
+188
+253
+212
+188
+255
+215
+190
+255
+215
+190
+176
+156
+141
+43
+57
+62
+163
+104
+61
+234
+125
+52
+224
+123
+55
+227
+126
+50
+214
+121
+50
+76
+70
+64
+91
+92
+89
+70
+79
+77
+135
+94
+64
+234
+126
+45
+224
+123
+55
+224
+123
+55
+234
+125
+52
+146
+97
+64
+35
+56
+60
+161
+144
+134
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+194
+173
+157
+48
+58
+59
+163
+104
+61
+234
+126
+45
+224
+123
+55
+227
+126
+50
+214
+121
+50
+76
+70
+64
+97
+98
+96
+255
+215
+190
+255
+215
+190
+255
+215
+190
+253
+212
+188
+255
+215
+190
+255
+215
+190
+187
+166
+150
+43
+57
+62
+163
+104
+61
+234
+125
+52
+224
+123
+55
+224
+123
+55
+234
+125
+52
+139
+96
+61
+55
+66
+67
+250
+200
+166
+249
+174
+124
+249
+152
+92
+247
+130
+60
+247
+118
+39
+247
+111
+26
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+109
+10
+247
+111
+26
+247
+123
+41
+248
+138
+64
+249
+159
+103
+248
+180
+134
+124
+111
+99
+35
+31
+30
+137
+110
+49
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+59
+50
+39
+85
+71
+43
+216
+194
+154
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+207
+202
+200
+47
+40
+38
+24
+22
+23
+35
+31
+30
+35
+31
+30
+35
+31
+30
+35
+31
+30
+24
+22
+23
+65
+58
+56
+238
+205
+179
+255
+215
+190
+238
+205
+179
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+100
+89
+56
+63
+74
+74
+227
+196
+175
+255
+215
+190
+253
+204
+176
+250
+200
+166
+250
+200
+166
+251
+209
+178
+255
+215
+190
+194
+173
+157
+48
+58
+59
+123
+102
+54
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+63
+69
+60
+43
+57
+62
+95
+87
+59
+168
+127
+42
+158
+125
+46
+161
+127
+40
+158
+125
+46
+63
+69
+60
+43
+57
+62
+51
+62
+63
+51
+62
+63
+51
+62
+63
+51
+62
+63
+51
+62
+63
+51
+62
+63
+51
+62
+63
+51
+62
+63
+43
+57
+62
+88
+82
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+75
+74
+61
+43
+57
+62
+75
+74
+61
+158
+125
+46
+158
+125
+46
+158
+125
+46
+171
+129
+45
+117
+98
+55
+51
+62
+63
+217
+187
+166
+255
+215
+190
+253
+204
+176
+250
+200
+166
+250
+200
+166
+253
+204
+176
+255
+215
+190
+217
+187
+166
+48
+58
+59
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+88
+82
+59
+48
+58
+59
+48
+58
+59
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+69
+69
+61
+109
+106
+99
+255
+215
+190
+253
+212
+188
+253
+204
+176
+250
+200
+166
+250
+200
+166
+253
+212
+188
+255
+215
+190
+120
+114
+108
+63
+69
+60
+158
+125
+46
+161
+127
+40
+158
+125
+46
+168
+127
+42
+145
+114
+49
+51
+62
+63
+137
+127
+115
+58
+69
+70
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+63
+69
+60
+120
+114
+108
+70
+79
+77
+105
+93
+60
+171
+129
+45
+158
+125
+46
+168
+127
+42
+152
+119
+47
+56
+64
+60
+51
+62
+63
+51
+62
+63
+51
+62
+63
+51
+62
+63
+51
+62
+63
+51
+62
+63
+51
+62
+63
+51
+62
+63
+51
+62
+63
+43
+57
+62
+111
+94
+57
+171
+129
+45
+158
+125
+46
+161
+127
+40
+152
+119
+47
+62
+63
+61
+146
+135
+124
+172
+150
+134
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+227
+126
+50
+199
+115
+54
+62
+63
+61
+146
+135
+124
+255
+215
+190
+253
+212
+188
+250
+200
+166
+250
+200
+166
+253
+204
+176
+253
+212
+188
+253
+212
+188
+97
+98
+96
+89
+75
+66
+227
+126
+50
+227
+126
+50
+224
+123
+55
+234
+126
+45
+139
+96
+61
+51
+62
+63
+63
+74
+74
+89
+75
+66
+227
+126
+50
+227
+126
+50
+224
+123
+55
+234
+125
+52
+135
+94
+64
+55
+66
+67
+217
+187
+166
+255
+215
+190
+253
+204
+176
+250
+200
+166
+250
+200
+166
+253
+204
+176
+255
+215
+190
+217
+187
+166
+51
+62
+63
+139
+96
+61
+234
+126
+45
+224
+123
+55
+227
+126
+50
+225
+124
+48
+81
+73
+62
+58
+69
+70
+51
+62
+63
+146
+97
+64
+234
+126
+45
+224
+123
+55
+227
+126
+50
+224
+123
+55
+81
+73
+62
+109
+106
+99
+255
+215
+190
+253
+212
+188
+253
+204
+176
+250
+200
+166
+250
+200
+166
+253
+212
+188
+255
+215
+190
+120
+114
+108
+69
+69
+61
+212
+120
+56
+227
+126
+50
+224
+123
+55
+227
+126
+50
+194
+112
+58
+56
+64
+60
+101
+100
+92
+56
+64
+60
+188
+112
+56
+234
+125
+52
+224
+123
+55
+227
+126
+50
+194
+112
+58
+51
+62
+63
+146
+135
+124
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+234
+204
+183
+70
+79
+77
+118
+86
+65
+234
+125
+52
+224
+123
+55
+227
+126
+50
+227
+126
+50
+106
+82
+65
+77
+85
+81
+245
+212
+186
+255
+215
+190
+253
+204
+176
+250
+200
+166
+250
+200
+166
+251
+209
+178
+255
+215
+190
+176
+156
+141
+56
+64
+60
+188
+112
+56
+234
+125
+52
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+251
+192
+154
+251
+168
+115
+249
+152
+92
+247
+143
+74
+247
+143
+74
+247
+150
+84
+249
+159
+103
+248
+180
+134
+120
+114
+108
+69
+69
+61
+212
+120
+56
+227
+126
+50
+224
+123
+55
+234
+125
+52
+155
+100
+63
+43
+57
+62
+194
+173
+157
+255
+215
+190
+253
+204
+176
+250
+200
+166
+250
+200
+166
+253
+204
+176
+255
+215
+190
+234
+204
+183
+63
+74
+74
+112
+85
+63
+234
+125
+52
+227
+126
+50
+224
+123
+55
+234
+125
+52
+106
+82
+65
+58
+69
+70
+55
+66
+67
+135
+94
+64
+234
+125
+52
+224
+123
+55
+227
+126
+50
+227
+126
+50
+95
+78
+64
+77
+85
+81
+245
+212
+186
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+161
+144
+134
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+227
+126
+50
+183
+110
+59
+48
+58
+59
+172
+150
+134
+255
+215
+190
+251
+209
+178
+250
+200
+166
+250
+200
+166
+253
+204
+176
+255
+215
+190
+245
+212
+186
+63
+74
+74
+112
+85
+63
+234
+125
+52
+224
+123
+55
+224
+123
+55
+234
+126
+45
+139
+96
+61
+55
+66
+67
+250
+200
+166
+249
+174
+124
+249
+152
+92
+247
+130
+60
+247
+118
+39
+247
+111
+26
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+123
+41
+250
+139
+73
+249
+159
+103
+252
+185
+144
+82
+69
+65
+47
+40
+38
+158
+125
+46
+161
+127
+40
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+171
+129
+45
+85
+71
+43
+59
+50
+39
+216
+194
+154
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+164
+158
+157
+47
+40
+38
+24
+22
+23
+24
+22
+23
+24
+22
+23
+35
+31
+30
+65
+67
+64
+65
+58
+56
+227
+196
+175
+255
+215
+190
+238
+205
+179
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+88
+82
+59
+84
+85
+82
+255
+215
+190
+251
+209
+178
+250
+197
+158
+251
+192
+154
+251
+192
+154
+250
+200
+166
+253
+212
+188
+227
+196
+175
+58
+69
+70
+105
+93
+60
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+75
+74
+61
+41
+58
+57
+111
+94
+57
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+123
+102
+54
+123
+102
+54
+123
+102
+54
+123
+102
+54
+123
+102
+54
+123
+102
+54
+123
+102
+54
+123
+102
+54
+123
+102
+54
+123
+102
+54
+123
+102
+54
+137
+110
+49
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+41
+58
+57
+83
+78
+61
+168
+127
+42
+158
+125
+46
+158
+125
+46
+171
+129
+45
+95
+87
+59
+70
+79
+77
+245
+212
+186
+253
+212
+188
+250
+200
+166
+251
+192
+154
+251
+192
+154
+250
+200
+166
+253
+212
+188
+238
+205
+179
+70
+79
+77
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+88
+82
+59
+48
+58
+59
+48
+58
+59
+129
+106
+52
+168
+127
+42
+158
+125
+46
+168
+127
+42
+152
+119
+47
+56
+64
+60
+146
+135
+124
+255
+215
+190
+253
+204
+176
+250
+197
+158
+251
+192
+154
+251
+192
+154
+253
+204
+176
+255
+215
+190
+172
+150
+134
+51
+62
+63
+145
+114
+49
+168
+127
+42
+158
+125
+46
+168
+127
+42
+145
+114
+49
+51
+62
+63
+137
+127
+115
+58
+69
+70
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+63
+69
+60
+97
+98
+96
+55
+66
+67
+123
+102
+54
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+123
+102
+54
+123
+102
+54
+123
+102
+54
+123
+102
+54
+123
+102
+54
+123
+102
+54
+123
+102
+54
+123
+102
+54
+123
+102
+54
+123
+102
+54
+117
+98
+55
+145
+114
+49
+161
+127
+40
+158
+125
+46
+158
+125
+46
+158
+125
+46
+69
+69
+61
+137
+127
+115
+172
+150
+134
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+234
+125
+52
+183
+110
+59
+51
+62
+63
+187
+166
+150
+255
+215
+190
+253
+204
+176
+251
+192
+154
+251
+192
+154
+250
+197
+158
+253
+204
+176
+255
+215
+190
+137
+127
+115
+65
+67
+64
+209
+117
+53
+227
+126
+50
+224
+123
+55
+234
+125
+52
+163
+104
+61
+43
+57
+62
+41
+58
+57
+106
+82
+65
+234
+125
+52
+224
+123
+55
+224
+123
+55
+234
+125
+52
+106
+82
+65
+77
+85
+81
+245
+212
+186
+251
+209
+178
+250
+197
+158
+249
+189
+146
+251
+192
+154
+250
+197
+158
+251
+209
+178
+238
+205
+179
+77
+85
+81
+112
+85
+63
+234
+126
+45
+224
+123
+55
+224
+123
+55
+227
+126
+50
+106
+82
+65
+41
+58
+57
+48
+58
+59
+163
+104
+61
+234
+125
+52
+224
+123
+55
+227
+126
+50
+209
+117
+53
+62
+63
+61
+146
+135
+124
+255
+215
+190
+253
+204
+176
+250
+197
+158
+251
+192
+154
+251
+192
+154
+253
+204
+176
+255
+215
+190
+176
+156
+141
+56
+64
+60
+188
+112
+56
+227
+126
+50
+224
+123
+55
+227
+126
+50
+194
+112
+58
+56
+64
+60
+101
+100
+92
+56
+64
+60
+188
+112
+56
+234
+125
+52
+224
+123
+55
+227
+126
+50
+183
+110
+59
+48
+58
+59
+176
+156
+141
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+227
+196
+175
+58
+69
+70
+139
+96
+61
+234
+125
+52
+224
+123
+55
+227
+126
+50
+214
+121
+50
+76
+70
+64
+120
+114
+108
+255
+215
+190
+253
+204
+176
+250
+197
+158
+251
+192
+154
+251
+192
+154
+250
+200
+166
+255
+215
+190
+207
+178
+158
+48
+58
+59
+163
+104
+61
+234
+125
+52
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+251
+192
+154
+249
+174
+124
+246
+156
+93
+247
+150
+84
+249
+146
+83
+249
+152
+92
+251
+168
+115
+249
+189
+146
+97
+98
+96
+89
+75
+66
+225
+124
+48
+227
+126
+50
+224
+123
+55
+234
+126
+45
+125
+90
+64
+58
+69
+70
+227
+196
+175
+253
+212
+188
+250
+200
+166
+251
+192
+154
+249
+189
+146
+250
+197
+158
+251
+209
+178
+255
+215
+190
+97
+98
+96
+89
+75
+66
+227
+126
+50
+227
+126
+50
+224
+123
+55
+234
+126
+45
+125
+90
+64
+43
+57
+62
+43
+57
+62
+135
+94
+64
+234
+125
+52
+224
+123
+55
+227
+126
+50
+227
+126
+50
+89
+75
+66
+101
+100
+92
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+137
+127
+115
+69
+69
+61
+212
+120
+56
+227
+126
+50
+224
+123
+55
+234
+126
+45
+155
+100
+63
+43
+57
+62
+207
+178
+158
+255
+215
+190
+250
+200
+166
+251
+192
+154
+251
+192
+154
+250
+197
+158
+251
+209
+178
+255
+215
+190
+109
+106
+99
+89
+75
+66
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+126
+45
+139
+96
+61
+55
+66
+67
+250
+200
+166
+249
+174
+124
+249
+152
+92
+247
+130
+60
+247
+118
+39
+247
+111
+26
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+123
+41
+247
+143
+74
+249
+159
+103
+252
+185
+144
+55
+48
+48
+59
+50
+39
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+156
+125
+62
+101
+83
+47
+59
+50
+39
+209
+171
+139
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+219
+212
+208
+137
+127
+115
+101
+100
+92
+120
+114
+108
+186
+181
+179
+152
+147
+147
+55
+48
+48
+227
+196
+175
+255
+215
+190
+238
+205
+179
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+97
+98
+96
+255
+215
+190
+253
+204
+176
+251
+192
+154
+249
+189
+146
+249
+189
+146
+250
+197
+158
+251
+209
+178
+234
+204
+183
+70
+79
+77
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+161
+127
+40
+75
+74
+61
+41
+58
+57
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+168
+127
+42
+168
+127
+42
+168
+127
+42
+171
+129
+45
+75
+74
+61
+41
+58
+57
+88
+82
+59
+168
+127
+42
+158
+125
+46
+158
+125
+46
+171
+129
+45
+88
+82
+59
+77
+85
+81
+245
+212
+186
+251
+209
+178
+250
+197
+158
+249
+189
+146
+249
+189
+146
+250
+197
+158
+251
+209
+178
+245
+212
+186
+84
+85
+82
+88
+82
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+88
+82
+59
+43
+57
+62
+48
+58
+59
+129
+106
+52
+168
+127
+42
+158
+125
+46
+168
+127
+42
+145
+114
+49
+56
+64
+60
+161
+144
+134
+255
+215
+190
+250
+200
+166
+251
+192
+154
+249
+189
+146
+251
+192
+154
+250
+200
+166
+255
+215
+190
+187
+166
+150
+51
+62
+63
+137
+110
+49
+168
+127
+42
+158
+125
+46
+168
+127
+42
+145
+114
+49
+51
+62
+63
+137
+127
+115
+58
+69
+70
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+65
+67
+64
+91
+92
+89
+55
+66
+67
+129
+106
+52
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+171
+129
+45
+168
+127
+42
+168
+127
+42
+168
+127
+42
+158
+125
+46
+63
+69
+60
+137
+127
+115
+172
+150
+134
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+227
+126
+50
+173
+106
+60
+48
+58
+59
+187
+166
+150
+255
+215
+190
+250
+200
+166
+251
+192
+154
+249
+189
+146
+251
+192
+154
+250
+200
+166
+255
+215
+190
+161
+144
+134
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+234
+125
+52
+173
+106
+60
+48
+58
+59
+41
+58
+57
+118
+86
+65
+234
+126
+45
+224
+123
+55
+224
+123
+55
+234
+125
+52
+95
+78
+64
+91
+92
+89
+255
+215
+190
+253
+204
+176
+251
+192
+154
+252
+185
+144
+252
+185
+144
+251
+192
+154
+253
+204
+176
+245
+212
+186
+91
+92
+89
+106
+82
+65
+234
+125
+52
+224
+123
+55
+224
+123
+55
+234
+125
+52
+112
+85
+63
+41
+58
+57
+48
+58
+59
+173
+106
+60
+234
+125
+52
+224
+123
+55
+227
+126
+50
+199
+115
+54
+56
+64
+60
+161
+144
+134
+255
+215
+190
+250
+200
+166
+251
+192
+154
+249
+189
+146
+251
+192
+154
+250
+200
+166
+255
+215
+190
+187
+166
+150
+48
+58
+59
+183
+110
+59
+234
+125
+52
+224
+123
+55
+227
+126
+50
+194
+112
+58
+56
+64
+60
+101
+100
+92
+56
+64
+60
+188
+112
+56
+227
+126
+50
+224
+123
+55
+227
+126
+50
+183
+110
+59
+51
+62
+63
+176
+156
+141
+255
+215
+190
+253
+212
+188
+251
+209
+178
+253
+212
+188
+217
+187
+166
+55
+66
+67
+146
+97
+64
+234
+126
+45
+224
+123
+55
+227
+126
+50
+214
+121
+50
+69
+69
+61
+137
+127
+115
+255
+215
+190
+253
+204
+176
+251
+192
+154
+249
+189
+146
+249
+189
+146
+250
+200
+166
+253
+212
+188
+217
+187
+166
+51
+62
+63
+155
+100
+63
+234
+125
+52
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+250
+197
+158
+249
+174
+124
+249
+159
+103
+249
+152
+92
+249
+152
+92
+249
+159
+103
+249
+174
+124
+250
+197
+158
+91
+92
+89
+95
+78
+64
+227
+126
+50
+227
+126
+50
+224
+123
+55
+234
+125
+52
+125
+90
+64
+70
+79
+77
+234
+204
+183
+251
+209
+178
+250
+197
+158
+249
+189
+146
+252
+185
+144
+251
+192
+154
+253
+204
+176
+255
+215
+190
+120
+114
+108
+81
+73
+62
+224
+123
+55
+227
+126
+50
+224
+123
+55
+234
+126
+45
+135
+94
+64
+41
+58
+57
+41
+58
+57
+135
+94
+64
+234
+125
+52
+224
+123
+55
+227
+126
+50
+227
+126
+50
+89
+75
+66
+101
+100
+92
+253
+212
+188
+253
+212
+188
+251
+209
+178
+251
+209
+178
+255
+215
+190
+137
+127
+115
+76
+70
+64
+214
+121
+50
+227
+126
+50
+224
+123
+55
+234
+125
+52
+146
+97
+64
+51
+62
+63
+227
+196
+175
+253
+212
+188
+250
+197
+158
+249
+189
+146
+249
+189
+146
+251
+192
+154
+253
+204
+176
+255
+215
+190
+120
+114
+108
+81
+73
+62
+227
+126
+50
+227
+126
+50
+224
+123
+55
+234
+126
+45
+139
+96
+61
+51
+62
+63
+250
+200
+166
+249
+174
+124
+249
+152
+92
+247
+130
+60
+247
+118
+39
+247
+111
+26
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+123
+41
+250
+139
+73
+249
+159
+103
+252
+185
+144
+55
+48
+48
+59
+50
+39
+161
+127
+40
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+154
+125
+71
+170
+137
+67
+108
+87
+46
+59
+50
+39
+192
+155
+91
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+186
+181
+179
+47
+40
+38
+65
+58
+56
+245
+212
+186
+255
+215
+190
+238
+205
+179
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+88
+82
+59
+84
+85
+82
+253
+212
+188
+251
+209
+178
+250
+197
+158
+251
+192
+154
+251
+192
+154
+250
+200
+166
+253
+212
+188
+234
+204
+183
+63
+74
+74
+100
+89
+56
+171
+129
+45
+158
+125
+46
+158
+125
+46
+161
+127
+40
+75
+74
+61
+41
+58
+57
+111
+94
+57
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+111
+94
+57
+56
+64
+60
+43
+57
+62
+83
+78
+61
+168
+127
+42
+158
+125
+46
+158
+125
+46
+171
+129
+45
+95
+87
+59
+70
+79
+77
+245
+212
+186
+251
+209
+178
+250
+197
+158
+251
+192
+154
+251
+192
+154
+250
+197
+158
+251
+209
+178
+245
+212
+186
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+88
+82
+59
+43
+57
+62
+48
+58
+59
+129
+106
+52
+168
+127
+42
+158
+125
+46
+158
+125
+46
+152
+119
+47
+56
+64
+60
+161
+144
+134
+255
+215
+190
+253
+204
+176
+251
+192
+154
+249
+189
+146
+251
+192
+154
+250
+200
+166
+255
+215
+190
+176
+156
+141
+51
+62
+63
+137
+110
+49
+168
+127
+42
+158
+125
+46
+168
+127
+42
+145
+114
+49
+51
+62
+63
+137
+127
+115
+58
+69
+70
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+63
+69
+60
+91
+92
+89
+55
+66
+67
+123
+102
+54
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+145
+114
+49
+100
+89
+56
+48
+58
+59
+187
+166
+150
+176
+156
+141
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+227
+126
+50
+183
+110
+59
+51
+62
+63
+176
+156
+141
+255
+215
+190
+250
+200
+166
+251
+192
+154
+251
+192
+154
+250
+197
+158
+253
+204
+176
+255
+215
+190
+146
+135
+124
+62
+63
+61
+209
+117
+53
+227
+126
+50
+224
+123
+55
+234
+125
+52
+163
+104
+61
+48
+58
+59
+41
+58
+57
+112
+85
+63
+234
+125
+52
+224
+123
+55
+224
+123
+55
+234
+125
+52
+106
+82
+65
+84
+85
+82
+255
+215
+190
+251
+209
+178
+250
+197
+158
+249
+189
+146
+249
+189
+146
+250
+197
+158
+251
+209
+178
+238
+205
+179
+84
+85
+82
+106
+82
+65
+234
+125
+52
+224
+123
+55
+227
+126
+50
+227
+126
+50
+106
+82
+65
+41
+58
+57
+48
+58
+59
+173
+106
+60
+227
+126
+50
+224
+123
+55
+227
+126
+50
+199
+115
+54
+62
+63
+61
+146
+135
+124
+255
+215
+190
+253
+204
+176
+251
+192
+154
+249
+189
+146
+251
+192
+154
+250
+200
+166
+255
+215
+190
+176
+156
+141
+51
+62
+63
+183
+110
+59
+227
+126
+50
+224
+123
+55
+227
+126
+50
+194
+112
+58
+56
+64
+60
+101
+100
+92
+56
+64
+60
+188
+112
+56
+227
+126
+50
+224
+123
+55
+227
+126
+50
+183
+110
+59
+51
+62
+63
+176
+156
+141
+253
+212
+188
+253
+204
+176
+250
+200
+166
+253
+204
+176
+217
+187
+166
+55
+66
+67
+146
+97
+64
+234
+125
+52
+224
+123
+55
+227
+126
+50
+214
+121
+50
+76
+70
+64
+120
+114
+108
+255
+215
+190
+253
+204
+176
+250
+197
+158
+251
+192
+154
+251
+192
+154
+250
+200
+166
+253
+212
+188
+207
+178
+158
+48
+58
+59
+163
+104
+61
+227
+126
+50
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+250
+200
+166
+248
+180
+134
+251
+168
+115
+247
+165
+111
+247
+165
+111
+251
+168
+115
+248
+180
+134
+250
+200
+166
+91
+92
+89
+89
+75
+66
+225
+124
+48
+227
+126
+50
+224
+123
+55
+234
+126
+45
+125
+90
+64
+63
+74
+74
+227
+196
+175
+251
+209
+178
+250
+197
+158
+249
+189
+146
+249
+189
+146
+250
+197
+158
+253
+204
+176
+255
+215
+190
+109
+106
+99
+89
+75
+66
+225
+124
+48
+227
+126
+50
+224
+123
+55
+234
+125
+52
+125
+90
+64
+43
+57
+62
+41
+58
+57
+135
+94
+64
+234
+126
+45
+224
+123
+55
+227
+126
+50
+227
+126
+50
+89
+75
+66
+101
+100
+92
+253
+212
+188
+253
+204
+176
+250
+200
+166
+250
+200
+166
+251
+209
+178
+137
+127
+115
+76
+70
+64
+214
+121
+50
+227
+126
+50
+224
+123
+55
+234
+125
+52
+155
+100
+63
+43
+57
+62
+217
+187
+166
+253
+212
+188
+250
+200
+166
+251
+192
+154
+249
+189
+146
+250
+197
+158
+253
+204
+176
+255
+215
+190
+120
+114
+108
+81
+73
+62
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+125
+52
+139
+96
+61
+55
+66
+67
+250
+200
+166
+249
+174
+124
+249
+152
+92
+247
+130
+60
+247
+118
+39
+247
+111
+26
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+123
+41
+250
+139
+73
+249
+159
+103
+248
+180
+134
+76
+70
+64
+47
+40
+38
+152
+119
+47
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+156
+125
+62
+154
+125
+71
+170
+137
+67
+101
+83
+47
+59
+50
+39
+170
+137
+67
+255
+238
+227
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+152
+147
+147
+35
+31
+30
+24
+22
+23
+115
+102
+92
+255
+215
+190
+255
+215
+190
+238
+205
+179
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+171
+129
+45
+105
+93
+60
+58
+69
+70
+227
+196
+175
+255
+215
+190
+253
+204
+176
+250
+200
+166
+250
+200
+166
+253
+204
+176
+255
+215
+190
+207
+178
+158
+48
+58
+59
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+69
+69
+61
+43
+57
+62
+100
+89
+56
+171
+129
+45
+158
+125
+46
+161
+127
+40
+158
+125
+46
+75
+74
+61
+48
+58
+59
+56
+64
+60
+56
+64
+60
+56
+64
+60
+56
+64
+60
+56
+64
+60
+56
+64
+60
+56
+64
+60
+56
+64
+60
+56
+64
+60
+56
+64
+60
+56
+64
+60
+56
+64
+60
+56
+64
+60
+48
+58
+59
+101
+100
+92
+91
+92
+89
+75
+74
+61
+168
+127
+42
+158
+125
+46
+158
+125
+46
+171
+129
+45
+111
+94
+57
+55
+66
+67
+227
+196
+175
+255
+215
+190
+253
+204
+176
+250
+200
+166
+250
+200
+166
+253
+204
+176
+255
+215
+190
+227
+196
+175
+51
+62
+63
+105
+93
+60
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+48
+58
+59
+48
+58
+59
+123
+102
+54
+168
+127
+42
+158
+125
+46
+161
+127
+40
+158
+125
+46
+69
+69
+61
+120
+114
+108
+255
+215
+190
+251
+209
+178
+250
+200
+166
+250
+197
+158
+250
+200
+166
+251
+209
+178
+255
+215
+190
+146
+135
+124
+56
+64
+60
+152
+119
+47
+168
+127
+42
+158
+125
+46
+168
+127
+42
+145
+114
+49
+51
+62
+63
+137
+127
+115
+58
+69
+70
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+63
+69
+60
+109
+106
+99
+63
+74
+74
+111
+94
+57
+171
+129
+45
+158
+125
+46
+161
+127
+40
+152
+119
+47
+69
+69
+61
+51
+62
+63
+56
+64
+60
+56
+64
+60
+56
+64
+60
+56
+64
+60
+56
+64
+60
+56
+64
+60
+56
+64
+60
+56
+64
+60
+56
+64
+60
+56
+64
+60
+56
+64
+60
+56
+64
+60
+51
+62
+63
+48
+58
+59
+120
+114
+108
+245
+212
+186
+172
+150
+134
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+227
+126
+50
+209
+117
+53
+62
+63
+61
+137
+127
+115
+255
+215
+190
+251
+209
+178
+250
+200
+166
+250
+200
+166
+250
+200
+166
+253
+212
+188
+255
+215
+190
+109
+106
+99
+81
+73
+62
+224
+123
+55
+227
+126
+50
+224
+123
+55
+234
+125
+52
+155
+100
+63
+48
+58
+59
+43
+57
+62
+95
+78
+64
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+125
+52
+125
+90
+64
+63
+74
+74
+227
+196
+175
+253
+212
+188
+250
+200
+166
+250
+197
+158
+250
+197
+158
+253
+204
+176
+255
+215
+190
+227
+196
+175
+55
+66
+67
+125
+90
+64
+234
+125
+52
+224
+123
+55
+224
+123
+55
+227
+126
+50
+89
+75
+66
+48
+58
+59
+48
+58
+59
+155
+100
+63
+234
+126
+45
+224
+123
+55
+227
+126
+50
+214
+121
+50
+76
+70
+64
+120
+114
+108
+255
+215
+190
+251
+209
+178
+250
+200
+166
+250
+197
+158
+250
+200
+166
+251
+209
+178
+255
+215
+190
+137
+127
+115
+62
+63
+61
+209
+117
+53
+227
+126
+50
+224
+123
+55
+227
+126
+50
+194
+112
+58
+56
+64
+60
+97
+98
+96
+56
+64
+60
+188
+112
+56
+227
+126
+50
+224
+123
+55
+227
+126
+50
+183
+110
+59
+48
+58
+59
+176
+156
+141
+251
+209
+178
+250
+200
+166
+250
+197
+158
+250
+200
+166
+227
+196
+175
+63
+74
+74
+135
+94
+64
+234
+126
+45
+224
+123
+55
+227
+126
+50
+227
+126
+50
+95
+78
+64
+91
+92
+89
+253
+212
+188
+253
+212
+188
+250
+200
+166
+250
+200
+166
+250
+200
+166
+251
+209
+178
+255
+215
+190
+172
+150
+134
+56
+64
+60
+188
+112
+56
+227
+126
+50
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+251
+209
+178
+251
+192
+154
+250
+176
+132
+249
+174
+124
+249
+174
+124
+248
+180
+134
+251
+192
+154
+251
+209
+178
+109
+106
+99
+76
+70
+64
+214
+121
+50
+227
+126
+50
+224
+123
+55
+234
+126
+45
+146
+97
+64
+43
+57
+62
+217
+187
+166
+255
+215
+190
+253
+204
+176
+250
+197
+158
+250
+197
+158
+250
+200
+166
+253
+212
+188
+245
+212
+186
+70
+79
+77
+106
+82
+65
+234
+125
+52
+224
+123
+55
+224
+123
+55
+234
+125
+52
+112
+85
+63
+51
+62
+63
+51
+62
+63
+135
+94
+64
+234
+126
+45
+224
+123
+55
+227
+126
+50
+227
+126
+50
+89
+75
+66
+101
+100
+92
+245
+212
+186
+250
+200
+166
+251
+192
+154
+250
+197
+158
+253
+204
+176
+146
+135
+124
+65
+67
+64
+209
+117
+53
+227
+126
+50
+224
+123
+55
+234
+125
+52
+173
+106
+60
+48
+58
+59
+187
+166
+150
+255
+215
+190
+253
+204
+176
+250
+200
+166
+250
+197
+158
+250
+200
+166
+253
+212
+188
+255
+215
+190
+84
+85
+82
+95
+78
+64
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+125
+52
+139
+96
+61
+55
+66
+67
+250
+200
+166
+249
+174
+124
+249
+152
+92
+247
+130
+60
+247
+118
+39
+247
+111
+26
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+109
+10
+247
+111
+26
+247
+123
+41
+248
+138
+64
+249
+152
+92
+249
+174
+124
+121
+100
+85
+35
+31
+30
+108
+87
+46
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+156
+125
+62
+154
+125
+71
+154
+125
+71
+171
+129
+45
+85
+71
+43
+71
+60
+43
+171
+129
+45
+224
+207
+180
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+237
+233
+225
+174
+168
+167
+81
+77
+76
+24
+22
+23
+35
+31
+30
+35
+31
+30
+187
+166
+150
+255
+215
+190
+255
+215
+190
+234
+204
+183
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+129
+106
+52
+51
+62
+63
+176
+156
+141
+255
+215
+190
+255
+215
+190
+253
+212
+188
+253
+212
+188
+255
+215
+190
+255
+215
+190
+146
+135
+124
+51
+62
+63
+145
+114
+49
+168
+127
+42
+158
+125
+46
+158
+125
+46
+152
+119
+47
+56
+64
+60
+43
+57
+62
+83
+78
+61
+168
+127
+42
+158
+125
+46
+158
+125
+46
+168
+127
+42
+88
+82
+59
+48
+58
+59
+146
+135
+124
+161
+144
+134
+161
+144
+134
+161
+144
+134
+161
+144
+134
+161
+144
+134
+161
+144
+134
+161
+144
+134
+161
+144
+134
+172
+150
+134
+172
+150
+134
+146
+135
+124
+146
+135
+124
+194
+173
+157
+245
+212
+186
+137
+127
+115
+63
+69
+60
+158
+125
+46
+161
+127
+40
+158
+125
+46
+168
+127
+42
+137
+110
+49
+51
+62
+63
+161
+144
+134
+255
+215
+190
+255
+215
+190
+253
+212
+188
+253
+212
+188
+255
+215
+190
+255
+215
+190
+161
+144
+134
+48
+58
+59
+137
+110
+49
+168
+127
+42
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+55
+66
+67
+51
+62
+63
+105
+93
+60
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+88
+82
+59
+70
+79
+77
+245
+212
+186
+255
+215
+190
+253
+212
+188
+251
+209
+178
+253
+212
+188
+255
+215
+190
+255
+215
+190
+91
+92
+89
+75
+74
+61
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+145
+114
+49
+51
+62
+63
+137
+127
+115
+58
+69
+70
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+63
+69
+60
+133
+120
+107
+84
+85
+82
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+75
+74
+61
+55
+66
+67
+161
+144
+134
+161
+144
+134
+161
+144
+134
+161
+144
+134
+161
+144
+134
+161
+144
+134
+161
+144
+134
+161
+144
+134
+161
+144
+134
+172
+150
+134
+172
+150
+134
+137
+127
+115
+146
+135
+124
+207
+178
+158
+245
+212
+186
+255
+215
+190
+161
+144
+134
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+227
+126
+50
+227
+126
+50
+89
+75
+66
+76
+78
+76
+245
+212
+186
+255
+215
+190
+253
+212
+188
+253
+212
+188
+253
+212
+188
+255
+215
+190
+227
+196
+175
+58
+69
+70
+118
+86
+65
+234
+125
+52
+224
+123
+55
+224
+123
+55
+234
+125
+52
+125
+90
+64
+63
+74
+74
+97
+98
+96
+76
+70
+64
+214
+121
+50
+227
+126
+50
+224
+123
+55
+234
+125
+52
+163
+104
+61
+48
+58
+59
+187
+166
+150
+255
+215
+190
+255
+215
+190
+251
+209
+178
+251
+209
+178
+255
+215
+190
+255
+215
+190
+176
+156
+141
+48
+58
+59
+173
+106
+60
+227
+126
+50
+224
+123
+55
+227
+126
+50
+212
+120
+56
+69
+69
+61
+101
+100
+92
+63
+74
+74
+125
+90
+64
+234
+125
+52
+224
+123
+55
+224
+123
+55
+234
+125
+52
+106
+82
+65
+63
+74
+74
+234
+204
+183
+255
+215
+190
+253
+212
+188
+253
+212
+188
+253
+212
+188
+255
+215
+190
+245
+212
+186
+70
+79
+77
+89
+75
+66
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+194
+112
+58
+56
+64
+60
+101
+100
+92
+56
+64
+60
+188
+112
+56
+227
+126
+50
+224
+123
+55
+234
+125
+52
+183
+110
+59
+51
+62
+63
+176
+156
+141
+253
+204
+176
+251
+192
+154
+251
+192
+154
+251
+192
+154
+250
+200
+166
+77
+85
+81
+106
+82
+65
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+126
+45
+135
+94
+64
+51
+62
+63
+217
+187
+166
+255
+215
+190
+255
+215
+190
+253
+212
+188
+253
+212
+188
+255
+215
+190
+255
+215
+190
+109
+106
+99
+76
+70
+64
+224
+123
+55
+227
+126
+50
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+255
+215
+190
+250
+200
+166
+251
+192
+154
+252
+185
+144
+252
+185
+144
+251
+192
+154
+250
+200
+166
+255
+215
+190
+146
+135
+124
+56
+64
+60
+199
+115
+54
+227
+126
+50
+224
+123
+55
+227
+126
+50
+194
+112
+58
+51
+62
+63
+146
+135
+124
+255
+215
+190
+255
+215
+190
+251
+209
+178
+251
+209
+178
+253
+212
+188
+255
+215
+190
+194
+173
+157
+43
+57
+62
+146
+97
+64
+234
+126
+45
+224
+123
+55
+227
+126
+50
+227
+126
+50
+89
+75
+66
+77
+85
+81
+63
+74
+74
+135
+94
+64
+234
+125
+52
+224
+123
+55
+227
+126
+50
+227
+126
+50
+89
+75
+66
+101
+100
+92
+251
+209
+178
+250
+197
+158
+249
+189
+146
+249
+189
+146
+250
+200
+166
+172
+150
+134
+56
+64
+60
+188
+112
+56
+227
+126
+50
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+120
+114
+108
+255
+215
+190
+255
+215
+190
+253
+212
+188
+251
+209
+178
+253
+212
+188
+255
+215
+190
+217
+187
+166
+51
+62
+63
+135
+94
+64
+234
+126
+45
+224
+123
+55
+224
+123
+55
+234
+126
+45
+139
+96
+61
+55
+66
+67
+250
+200
+166
+249
+174
+124
+249
+152
+92
+247
+130
+60
+247
+118
+39
+247
+111
+26
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+111
+26
+247
+118
+39
+247
+130
+60
+247
+150
+84
+251
+168
+115
+187
+140
+108
+24
+22
+23
+59
+50
+39
+168
+127
+42
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+156
+125
+62
+154
+125
+71
+154
+125
+71
+154
+125
+71
+156
+125
+62
+158
+125
+46
+47
+40
+38
+108
+87
+46
+158
+125
+46
+195
+167
+113
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+219
+212
+208
+164
+158
+157
+109
+106
+99
+65
+58
+56
+24
+22
+23
+24
+22
+23
+94
+60
+47
+178
+86
+46
+59
+50
+39
+150
+125
+114
+255
+215
+190
+255
+215
+190
+234
+204
+183
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+69
+69
+61
+84
+85
+82
+234
+204
+183
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+217
+187
+166
+55
+66
+67
+83
+78
+61
+168
+127
+42
+158
+125
+46
+158
+125
+46
+171
+129
+45
+123
+102
+54
+51
+62
+63
+76
+78
+76
+56
+64
+60
+152
+119
+47
+168
+127
+42
+158
+125
+46
+168
+127
+42
+129
+106
+52
+48
+58
+59
+161
+144
+134
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+217
+187
+166
+133
+120
+107
+77
+85
+81
+77
+85
+81
+146
+135
+124
+245
+212
+186
+176
+156
+141
+51
+62
+63
+137
+110
+49
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+75
+74
+61
+63
+74
+74
+227
+196
+175
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+234
+204
+183
+76
+78
+76
+75
+74
+61
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+88
+82
+59
+77
+85
+81
+77
+85
+81
+88
+82
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+129
+106
+52
+48
+58
+59
+146
+135
+124
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+172
+150
+134
+48
+58
+59
+117
+98
+55
+168
+127
+42
+158
+125
+46
+158
+125
+46
+168
+127
+42
+145
+114
+49
+51
+62
+63
+137
+127
+115
+58
+69
+70
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+63
+69
+60
+146
+135
+124
+120
+114
+108
+69
+69
+61
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+111
+94
+57
+51
+62
+63
+176
+156
+141
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+194
+173
+157
+120
+114
+108
+70
+79
+77
+84
+85
+82
+161
+144
+134
+255
+215
+190
+255
+215
+190
+161
+144
+134
+56
+64
+60
+199
+115
+54
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+126
+45
+155
+100
+63
+41
+58
+57
+161
+144
+134
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+137
+127
+115
+48
+58
+59
+183
+110
+59
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+89
+75
+66
+97
+98
+96
+172
+150
+134
+48
+58
+59
+183
+110
+59
+227
+126
+50
+224
+123
+55
+227
+126
+50
+214
+121
+50
+76
+70
+64
+84
+85
+82
+234
+204
+183
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+234
+204
+183
+77
+85
+81
+81
+73
+62
+224
+123
+55
+227
+126
+50
+224
+123
+55
+234
+125
+52
+173
+106
+60
+48
+58
+59
+176
+156
+141
+97
+98
+96
+95
+78
+64
+227
+126
+50
+227
+126
+50
+224
+123
+55
+234
+125
+52
+173
+106
+60
+48
+58
+59
+146
+135
+124
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+161
+144
+134
+41
+58
+57
+155
+100
+63
+234
+126
+45
+224
+123
+55
+224
+123
+55
+227
+126
+50
+194
+112
+58
+56
+64
+60
+101
+100
+92
+56
+64
+60
+188
+112
+56
+227
+126
+50
+224
+123
+55
+227
+126
+50
+183
+110
+59
+51
+62
+63
+176
+156
+141
+250
+200
+166
+249
+189
+146
+252
+185
+144
+249
+189
+146
+250
+200
+166
+120
+114
+108
+69
+69
+61
+214
+121
+50
+227
+126
+50
+224
+123
+55
+227
+126
+50
+199
+115
+54
+62
+63
+61
+101
+100
+92
+245
+212
+186
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+187
+166
+150
+43
+57
+62
+135
+94
+64
+234
+126
+45
+224
+123
+55
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+255
+215
+190
+253
+212
+188
+253
+204
+176
+250
+200
+166
+250
+200
+166
+253
+204
+176
+253
+212
+188
+255
+215
+190
+187
+166
+150
+41
+58
+57
+155
+100
+63
+234
+125
+52
+224
+123
+55
+227
+126
+50
+227
+126
+50
+95
+78
+64
+58
+69
+70
+227
+196
+175
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+245
+212
+186
+91
+92
+89
+62
+63
+61
+209
+117
+53
+227
+126
+50
+224
+123
+55
+227
+126
+50
+199
+115
+54
+62
+63
+61
+133
+120
+107
+77
+85
+81
+135
+94
+64
+234
+126
+45
+224
+123
+55
+227
+126
+50
+227
+126
+50
+89
+75
+66
+101
+100
+92
+253
+204
+176
+251
+192
+154
+252
+185
+144
+252
+185
+144
+251
+192
+154
+212
+173
+150
+48
+58
+59
+155
+100
+63
+234
+126
+45
+224
+123
+55
+224
+123
+55
+234
+125
+52
+118
+86
+65
+51
+62
+63
+207
+178
+158
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+109
+106
+99
+56
+64
+60
+199
+115
+54
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+125
+52
+139
+96
+61
+55
+66
+67
+250
+200
+166
+249
+174
+124
+249
+152
+92
+247
+130
+60
+247
+118
+39
+247
+111
+26
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+247
+111
+26
+246
+116
+28
+247
+130
+53
+247
+143
+74
+249
+159
+103
+248
+180
+134
+89
+75
+66
+24
+22
+23
+85
+71
+43
+171
+129
+45
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+156
+125
+62
+154
+125
+71
+154
+125
+71
+154
+125
+71
+156
+125
+62
+175
+132
+40
+85
+71
+43
+47
+40
+38
+158
+125
+46
+158
+125
+46
+170
+137
+67
+237
+233
+225
+253
+255
+252
+253
+255
+252
+253
+255
+252
+207
+202
+200
+164
+158
+157
+146
+135
+124
+120
+114
+108
+89
+84
+82
+65
+58
+56
+47
+40
+38
+24
+22
+23
+24
+22
+23
+35
+31
+30
+94
+60
+47
+178
+86
+46
+226
+110
+35
+241
+100
+24
+144
+77
+47
+65
+58
+56
+253
+212
+188
+255
+215
+190
+238
+205
+179
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+171
+129
+45
+129
+106
+52
+48
+58
+59
+101
+100
+92
+217
+187
+166
+245
+212
+186
+245
+212
+186
+194
+173
+157
+76
+78
+76
+56
+64
+60
+145
+114
+49
+168
+127
+42
+158
+125
+46
+158
+125
+46
+171
+129
+45
+88
+82
+59
+77
+85
+81
+176
+156
+141
+48
+58
+59
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+95
+87
+59
+41
+58
+57
+137
+127
+115
+227
+196
+175
+255
+215
+190
+255
+215
+190
+255
+215
+190
+245
+212
+186
+207
+178
+158
+120
+114
+108
+48
+58
+59
+62
+63
+61
+100
+89
+56
+95
+87
+59
+51
+62
+63
+120
+114
+108
+227
+196
+175
+55
+66
+67
+100
+89
+56
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+137
+110
+49
+51
+62
+63
+84
+85
+82
+207
+178
+158
+245
+212
+186
+245
+212
+186
+207
+178
+158
+97
+98
+96
+51
+62
+63
+137
+110
+49
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+88
+82
+59
+91
+92
+89
+120
+114
+108
+63
+69
+60
+158
+125
+46
+161
+127
+40
+158
+125
+46
+158
+125
+46
+168
+127
+42
+88
+82
+59
+43
+57
+62
+161
+144
+134
+227
+196
+175
+253
+212
+188
+234
+204
+183
+161
+144
+134
+51
+62
+63
+75
+74
+61
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+145
+114
+49
+51
+62
+63
+137
+127
+115
+58
+69
+70
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+63
+69
+60
+146
+135
+124
+176
+156
+141
+48
+58
+59
+137
+110
+49
+171
+129
+45
+158
+125
+46
+161
+127
+40
+158
+125
+46
+75
+74
+61
+43
+57
+62
+161
+144
+134
+234
+204
+183
+255
+215
+190
+255
+215
+190
+255
+215
+190
+245
+212
+186
+194
+173
+157
+109
+106
+99
+43
+57
+62
+69
+69
+61
+105
+93
+60
+88
+82
+59
+48
+58
+59
+146
+135
+124
+255
+215
+190
+161
+144
+134
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+225
+124
+48
+95
+78
+64
+43
+57
+62
+161
+144
+134
+234
+204
+183
+245
+212
+186
+227
+196
+175
+146
+135
+124
+35
+56
+60
+125
+90
+64
+234
+125
+52
+224
+123
+55
+224
+123
+55
+234
+125
+52
+188
+112
+56
+51
+62
+63
+161
+144
+134
+234
+204
+183
+51
+62
+63
+125
+90
+64
+234
+126
+45
+224
+123
+55
+224
+123
+55
+234
+125
+52
+163
+104
+61
+43
+57
+62
+97
+98
+96
+207
+178
+158
+245
+212
+186
+245
+212
+186
+207
+178
+158
+91
+92
+89
+48
+58
+59
+173
+106
+60
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+126
+45
+118
+86
+65
+55
+66
+67
+234
+204
+183
+146
+135
+124
+56
+64
+60
+194
+112
+58
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+125
+52
+112
+85
+63
+35
+56
+60
+146
+135
+124
+227
+196
+175
+253
+212
+188
+234
+204
+183
+161
+144
+134
+43
+57
+62
+95
+78
+64
+225
+124
+48
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+194
+112
+58
+56
+64
+60
+101
+100
+92
+56
+64
+60
+188
+112
+56
+227
+126
+50
+224
+123
+55
+227
+126
+50
+183
+110
+59
+51
+62
+63
+176
+156
+141
+250
+197
+158
+252
+185
+144
+248
+180
+134
+248
+180
+134
+251
+192
+154
+172
+150
+134
+48
+58
+59
+173
+106
+60
+234
+125
+52
+224
+123
+55
+224
+123
+55
+234
+126
+45
+139
+96
+61
+41
+58
+57
+120
+114
+108
+217
+187
+166
+245
+212
+186
+234
+204
+183
+176
+156
+141
+58
+69
+70
+81
+73
+62
+214
+121
+50
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+255
+215
+190
+255
+215
+190
+217
+187
+166
+133
+120
+107
+84
+85
+82
+91
+92
+89
+146
+135
+124
+234
+204
+183
+238
+205
+179
+63
+74
+74
+95
+78
+64
+234
+126
+45
+224
+123
+55
+224
+123
+55
+227
+126
+50
+194
+112
+58
+56
+64
+60
+84
+85
+82
+194
+173
+157
+245
+212
+186
+245
+212
+186
+217
+187
+166
+109
+106
+99
+41
+58
+57
+146
+97
+64
+234
+126
+45
+224
+123
+55
+224
+123
+55
+234
+126
+45
+146
+97
+64
+51
+62
+63
+187
+166
+150
+76
+78
+76
+135
+94
+64
+234
+126
+45
+224
+123
+55
+227
+126
+50
+227
+126
+50
+89
+75
+66
+97
+98
+96
+250
+200
+166
+249
+189
+146
+248
+180
+134
+248
+180
+134
+252
+185
+144
+232
+190
+161
+70
+79
+77
+112
+85
+63
+234
+126
+45
+224
+123
+55
+224
+123
+55
+227
+126
+50
+199
+115
+54
+65
+67
+64
+70
+79
+77
+187
+166
+150
+238
+205
+179
+245
+212
+186
+217
+187
+166
+133
+120
+107
+35
+56
+60
+135
+94
+64
+234
+126
+45
+224
+123
+55
+224
+123
+55
+224
+123
+55
+234
+126
+45
+139
+96
+61
+55
+66
+67
+250
+200
+166
+249
+174
+124
+249
+152
+92
+247
+130
+60
+247
+118
+39
+247
+111
+26
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+123
+41
+247
+130
+60
+247
+150
+84
+251
+168
+115
+203
+161
+131
+55
+48
+48
+24
+22
+23
+71
+60
+43
+145
+114
+49
+171
+129
+45
+171
+129
+45
+158
+125
+46
+156
+125
+62
+154
+125
+71
+154
+125
+71
+156
+125
+62
+156
+125
+62
+171
+129
+45
+171
+129
+45
+101
+83
+47
+35
+31
+30
+123
+102
+54
+171
+129
+45
+158
+125
+46
+160
+120
+43
+224
+207
+180
+253
+255
+252
+253
+255
+252
+219
+212
+208
+47
+40
+38
+24
+22
+23
+24
+22
+23
+24
+22
+23
+24
+22
+23
+24
+22
+23
+35
+31
+30
+35
+31
+30
+24
+22
+23
+47
+40
+38
+226
+110
+35
+241
+100
+24
+226
+110
+35
+226
+110
+35
+144
+77
+47
+55
+48
+48
+238
+205
+179
+255
+215
+190
+238
+205
+179
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+171
+129
+45
+123
+102
+54
+56
+64
+60
+51
+62
+63
+84
+85
+82
+84
+85
+82
+48
+58
+59
+63
+69
+60
+129
+106
+52
+168
+127
+42
+158
+125
+46
+158
+125
+46
+168
+127
+42
+145
+114
+49
+56
+64
+60
+137
+127
+115
+245
+212
+186
+84
+85
+82
+69
+69
+61
+158
+125
+46
+158
+125
+46
+158
+125
+46
+161
+127
+40
+158
+125
+46
+95
+87
+59
+48
+58
+59
+63
+74
+74
+109
+106
+99
+133
+120
+107
+133
+120
+107
+91
+92
+89
+51
+62
+63
+56
+64
+60
+100
+89
+56
+152
+119
+47
+171
+129
+45
+175
+132
+40
+100
+89
+56
+48
+58
+59
+217
+187
+166
+120
+114
+108
+63
+69
+60
+152
+119
+47
+161
+127
+40
+158
+125
+46
+158
+125
+46
+168
+127
+42
+129
+106
+52
+61
+67
+58
+51
+62
+63
+84
+85
+82
+84
+85
+82
+51
+62
+63
+56
+64
+60
+123
+102
+54
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+97
+98
+96
+187
+166
+150
+48
+58
+59
+123
+102
+54
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+158
+125
+46
+83
+78
+61
+48
+58
+59
+63
+74
+74
+91
+92
+89
+70
+79
+77
+48
+58
+59
+75
+74
+61
+152
+119
+47
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+145
+114
+49
+51
+62
+63
+137
+127
+115
+58
+69
+70
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+63
+69
+60
+146
+135
+124
+234
+204
+183
+63
+74
+74
+83
+78
+61
+168
+127
+42
+158
+125
+46
+158
+125
+46
+168
+127
+42
+152
+119
+47
+83
+78
+61
+48
+58
+59
+70
+79
+77
+109
+106
+99
+133
+120
+107
+120
+114
+108
+84
+85
+82
+48
+58
+59
+61
+67
+58
+111
+94
+57
+158
+125
+46
+171
+129
+45
+171
+129
+45
+88
+82
+59
+58
+69
+70
+238
+205
+179
+172
+150
+134
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+212
+120
+56
+95
+78
+64
+43
+57
+62
+70
+79
+77
+84
+85
+82
+63
+74
+74
+48
+58
+59
+118
+86
+65
+225
+124
+48
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+126
+45
+112
+85
+63
+55
+66
+67
+227
+196
+175
+255
+215
+190
+120
+114
+108
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+155
+100
+63
+62
+63
+61
+51
+62
+63
+77
+85
+81
+77
+85
+81
+51
+62
+63
+62
+63
+61
+155
+100
+63
+234
+125
+52
+224
+123
+55
+224
+123
+55
+234
+125
+52
+199
+115
+54
+56
+64
+60
+120
+114
+108
+255
+215
+190
+217
+187
+166
+43
+57
+62
+125
+90
+64
+234
+126
+45
+224
+123
+55
+224
+123
+55
+227
+126
+50
+224
+123
+55
+106
+82
+65
+48
+58
+59
+63
+74
+74
+84
+85
+82
+70
+79
+77
+43
+57
+62
+95
+78
+64
+212
+120
+56
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+194
+112
+58
+56
+64
+60
+101
+100
+92
+56
+64
+60
+188
+112
+56
+227
+126
+50
+224
+123
+55
+234
+125
+52
+183
+110
+59
+51
+62
+63
+172
+150
+134
+251
+192
+154
+248
+180
+134
+249
+174
+124
+249
+174
+124
+248
+180
+134
+236
+186
+153
+63
+74
+74
+95
+78
+64
+234
+126
+45
+224
+123
+55
+224
+123
+55
+227
+126
+50
+227
+126
+50
+135
+94
+64
+51
+62
+63
+55
+66
+67
+84
+85
+82
+70
+79
+77
+41
+58
+57
+81
+73
+62
+199
+115
+54
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+255
+215
+190
+194
+173
+157
+58
+69
+70
+62
+63
+61
+106
+82
+65
+95
+78
+64
+51
+62
+63
+91
+92
+89
+238
+205
+179
+161
+144
+134
+48
+58
+59
+183
+110
+59
+234
+125
+52
+224
+123
+55
+224
+123
+55
+234
+125
+52
+173
+106
+60
+65
+67
+64
+48
+58
+59
+77
+85
+81
+84
+85
+82
+55
+66
+67
+56
+64
+60
+146
+97
+64
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+209
+117
+53
+69
+69
+61
+101
+100
+92
+227
+196
+175
+63
+74
+74
+135
+94
+64
+234
+125
+52
+224
+123
+55
+227
+126
+50
+227
+126
+50
+89
+75
+66
+101
+100
+92
+250
+197
+158
+252
+185
+144
+249
+174
+124
+249
+174
+124
+250
+176
+132
+251
+192
+154
+120
+114
+108
+62
+63
+61
+209
+117
+53
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+188
+112
+56
+76
+70
+64
+41
+58
+57
+77
+85
+81
+84
+85
+82
+58
+69
+70
+48
+58
+59
+125
+90
+64
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+234
+126
+45
+139
+96
+61
+55
+66
+67
+250
+200
+166
+249
+174
+124
+249
+152
+92
+247
+130
+60
+247
+118
+39
+247
+111
+26
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+243
+101
+2
+247
+103
+7
+247
+103
+7
+247
+111
+26
+247
+118
+39
+247
+130
+53
+250
+139
+73
+246
+156
+93
+249
+174
+124
+203
+161
+131
+55
+48
+48
+24
+22
+23
+35
+31
+30
+85
+71
+43
+137
+110
+49
+152
+119
+47
+168
+127
+42
+171
+129
+45
+171
+129
+45
+168
+127
+42
+152
+119
+47
+117
+98
+55
+59
+50
+39
+35
+31
+30
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+152
+119
+47
+224
+207
+180
+253
+255
+252
+253
+255
+252
+253
+255
+252
+146
+135
+124
+65
+58
+56
+35
+31
+30
+24
+22
+23
+24
+22
+23
+35
+31
+30
+35
+31
+30
+35
+31
+30
+35
+31
+30
+24
+22
+23
+83
+53
+42
+236
+108
+29
+236
+108
+29
+226
+110
+35
+94
+60
+47
+65
+58
+56
+253
+212
+188
+255
+215
+190
+238
+205
+179
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+161
+127
+40
+168
+127
+42
+145
+114
+49
+105
+93
+60
+83
+78
+61
+83
+78
+61
+111
+94
+57
+158
+125
+46
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+171
+129
+45
+88
+82
+59
+51
+62
+63
+217
+187
+166
+255
+215
+190
+176
+156
+141
+43
+57
+62
+105
+93
+60
+171
+129
+45
+158
+125
+46
+158
+125
+46
+161
+127
+40
+168
+127
+42
+137
+110
+49
+88
+82
+59
+69
+69
+61
+62
+63
+61
+63
+69
+60
+75
+74
+61
+105
+93
+60
+152
+119
+47
+171
+129
+45
+168
+127
+42
+158
+125
+46
+171
+129
+45
+129
+106
+52
+48
+58
+59
+194
+173
+157
+207
+178
+158
+43
+57
+62
+100
+89
+56
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+152
+119
+47
+111
+94
+57
+83
+78
+61
+83
+78
+61
+105
+93
+60
+145
+114
+49
+168
+127
+42
+161
+127
+40
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+88
+82
+59
+84
+85
+82
+245
+212
+186
+77
+85
+81
+75
+74
+61
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+168
+127
+42
+129
+106
+52
+95
+87
+59
+81
+73
+62
+95
+87
+59
+123
+102
+54
+168
+127
+42
+168
+127
+42
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+145
+114
+49
+56
+64
+60
+137
+127
+115
+58
+69
+70
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+63
+69
+60
+137
+127
+115
+255
+215
+190
+161
+144
+134
+48
+58
+59
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+168
+127
+42
+129
+106
+52
+88
+82
+59
+69
+69
+61
+62
+63
+61
+63
+69
+60
+75
+74
+61
+117
+98
+55
+152
+119
+47
+171
+129
+45
+161
+127
+40
+158
+125
+46
+171
+129
+45
+111
+94
+57
+48
+58
+59
+227
+196
+175
+176
+156
+141
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+227
+126
+50
+227
+126
+50
+163
+104
+61
+112
+85
+63
+95
+78
+64
+118
+86
+65
+173
+106
+60
+227
+126
+50
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+125
+52
+183
+110
+59
+51
+62
+63
+133
+120
+107
+255
+215
+190
+255
+215
+190
+217
+187
+166
+51
+62
+63
+106
+82
+65
+234
+126
+45
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+126
+45
+199
+115
+54
+135
+94
+64
+95
+78
+64
+95
+78
+64
+135
+94
+64
+199
+115
+54
+234
+125
+52
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+126
+45
+106
+82
+65
+51
+62
+63
+217
+187
+166
+255
+215
+190
+255
+215
+190
+120
+114
+108
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+227
+126
+50
+173
+106
+60
+118
+86
+65
+95
+78
+64
+112
+85
+63
+163
+104
+61
+227
+126
+50
+227
+126
+50
+227
+126
+50
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+194
+112
+58
+56
+64
+60
+101
+100
+92
+56
+64
+60
+188
+112
+56
+227
+126
+50
+224
+123
+55
+227
+126
+50
+183
+110
+59
+51
+62
+63
+172
+150
+134
+252
+185
+144
+249
+174
+124
+247
+165
+111
+247
+165
+111
+249
+174
+124
+252
+185
+144
+154
+133
+118
+48
+58
+59
+163
+104
+61
+234
+126
+45
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+125
+52
+188
+112
+56
+125
+90
+64
+95
+78
+64
+106
+82
+65
+155
+100
+63
+224
+123
+55
+234
+125
+52
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+137
+127
+115
+253
+212
+188
+91
+92
+89
+69
+69
+61
+194
+112
+58
+234
+126
+45
+234
+126
+45
+163
+104
+61
+51
+62
+63
+137
+127
+115
+238
+205
+179
+63
+74
+74
+89
+75
+66
+227
+126
+50
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+209
+117
+53
+146
+97
+64
+106
+82
+65
+95
+78
+64
+125
+90
+64
+194
+112
+58
+234
+126
+45
+227
+126
+50
+224
+123
+55
+227
+126
+50
+234
+126
+45
+125
+90
+64
+41
+58
+57
+194
+173
+157
+238
+205
+179
+63
+74
+74
+135
+94
+64
+234
+125
+52
+224
+123
+55
+227
+126
+50
+227
+126
+50
+89
+75
+66
+101
+100
+92
+251
+192
+154
+250
+176
+132
+251
+168
+115
+247
+165
+111
+249
+174
+124
+245
+179
+138
+195
+157
+134
+41
+58
+57
+135
+94
+64
+234
+126
+45
+224
+123
+55
+224
+123
+55
+224
+123
+55
+234
+125
+52
+214
+121
+50
+146
+97
+64
+106
+82
+65
+95
+78
+64
+125
+90
+64
+183
+110
+59
+227
+126
+50
+227
+126
+50
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+234
+125
+52
+139
+96
+61
+55
+66
+67
+250
+200
+166
+249
+174
+124
+249
+152
+92
+247
+130
+60
+247
+118
+39
+247
+111
+26
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+247
+103
+7
+246
+109
+10
+247
+111
+26
+247
+118
+39
+247
+130
+53
+247
+143
+74
+249
+159
+103
+250
+176
+132
+219
+170
+138
+115
+102
+92
+47
+40
+38
+24
+22
+23
+35
+31
+30
+47
+40
+38
+59
+50
+39
+59
+50
+39
+59
+50
+39
+59
+50
+39
+47
+40
+38
+47
+40
+38
+71
+60
+43
+137
+110
+49
+171
+129
+45
+158
+125
+46
+158
+125
+46
+152
+119
+47
+170
+137
+67
+219
+212
+208
+237
+233
+225
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+219
+212
+208
+152
+147
+147
+109
+106
+99
+65
+67
+64
+35
+31
+30
+35
+31
+30
+35
+31
+30
+35
+31
+30
+24
+22
+23
+94
+60
+47
+178
+86
+46
+109
+63
+45
+35
+31
+30
+124
+111
+99
+251
+209
+178
+251
+209
+178
+234
+204
+183
+76
+78
+76
+95
+87
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+117
+98
+55
+129
+106
+52
+168
+127
+42
+168
+127
+42
+171
+129
+45
+168
+127
+42
+168
+127
+42
+171
+129
+45
+161
+127
+40
+158
+125
+46
+158
+125
+46
+158
+125
+46
+171
+129
+45
+117
+98
+55
+48
+58
+59
+146
+135
+124
+255
+215
+190
+255
+215
+190
+255
+215
+190
+120
+114
+108
+51
+62
+63
+123
+102
+54
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+168
+127
+42
+158
+125
+46
+152
+119
+47
+152
+119
+47
+158
+125
+46
+168
+127
+42
+168
+127
+42
+158
+125
+46
+158
+125
+46
+168
+127
+42
+158
+125
+46
+81
+73
+62
+58
+69
+70
+227
+196
+175
+255
+215
+190
+120
+114
+108
+48
+58
+59
+129
+106
+52
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+161
+127
+40
+168
+127
+42
+168
+127
+42
+168
+127
+42
+171
+129
+45
+168
+127
+42
+168
+127
+42
+152
+119
+47
+117
+98
+55
+168
+127
+42
+158
+125
+46
+158
+125
+46
+168
+127
+42
+88
+82
+59
+84
+85
+82
+255
+215
+190
+176
+156
+141
+48
+58
+59
+111
+94
+57
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+168
+127
+42
+168
+127
+42
+168
+127
+42
+168
+127
+42
+158
+125
+46
+158
+125
+46
+145
+114
+49
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+145
+114
+49
+51
+62
+63
+137
+127
+115
+58
+69
+70
+117
+98
+55
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+63
+69
+60
+137
+127
+115
+255
+215
+190
+238
+205
+179
+91
+92
+89
+56
+64
+60
+137
+110
+49
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+168
+127
+42
+158
+125
+46
+152
+119
+47
+158
+125
+46
+168
+127
+42
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+171
+129
+45
+152
+119
+47
+69
+69
+61
+84
+85
+82
+245
+212
+186
+172
+150
+134
+62
+63
+61
+199
+115
+54
+227
+126
+50
+224
+123
+55
+227
+126
+50
+199
+115
+54
+125
+90
+64
+227
+126
+50
+227
+126
+50
+227
+126
+50
+234
+125
+52
+227
+126
+50
+234
+125
+52
+234
+125
+52
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+214
+121
+50
+81
+73
+62
+63
+74
+74
+227
+196
+175
+255
+215
+190
+253
+212
+188
+255
+215
+190
+146
+135
+124
+48
+58
+59
+146
+97
+64
+234
+126
+45
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+126
+45
+227
+126
+50
+227
+126
+50
+234
+126
+45
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+126
+45
+139
+96
+61
+48
+58
+59
+146
+135
+124
+255
+215
+190
+253
+212
+188
+255
+215
+190
+217
+187
+166
+55
+66
+67
+95
+78
+64
+225
+124
+48
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+125
+52
+227
+126
+50
+227
+126
+50
+227
+126
+50
+224
+123
+55
+234
+126
+45
+163
+104
+61
+183
+110
+59
+227
+126
+50
+224
+123
+55
+227
+126
+50
+194
+112
+58
+56
+64
+60
+97
+98
+96
+56
+64
+60
+188
+112
+56
+227
+126
+50
+224
+123
+55
+227
+126
+50
+183
+110
+59
+51
+62
+63
+167
+142
+123
+248
+180
+134
+247
+165
+111
+249
+159
+103
+246
+156
+93
+249
+159
+103
+249
+174
+124
+239
+182
+144
+77
+85
+81
+65
+67
+64
+199
+115
+54
+234
+125
+52
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+125
+52
+227
+126
+50
+227
+126
+50
+234
+125
+52
+227
+126
+50
+227
+126
+50
+135
+94
+64
+188
+112
+56
+227
+126
+50
+224
+123
+55
+227
+126
+50
+209
+117
+53
+65
+67
+64
+146
+135
+124
+227
+196
+175
+43
+57
+62
+146
+97
+64
+234
+126
+45
+224
+123
+55
+224
+123
+55
+234
+126
+45
+106
+82
+65
+70
+79
+77
+253
+212
+188
+176
+156
+141
+41
+58
+57
+125
+90
+64
+234
+126
+45
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+125
+52
+234
+125
+52
+227
+126
+50
+234
+125
+52
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+126
+45
+155
+100
+63
+48
+58
+59
+120
+114
+108
+253
+212
+188
+234
+204
+183
+63
+74
+74
+135
+94
+64
+234
+126
+45
+224
+123
+55
+227
+126
+50
+227
+126
+50
+89
+75
+66
+101
+100
+92
+252
+185
+144
+245
+169
+119
+249
+159
+103
+249
+159
+103
+247
+165
+111
+249
+174
+124
+251
+192
+154
+109
+106
+99
+62
+63
+61
+188
+112
+56
+234
+125
+52
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+125
+52
+234
+125
+52
+227
+126
+50
+234
+125
+52
+227
+126
+50
+227
+126
+50
+212
+120
+56
+199
+115
+54
+224
+123
+55
+224
+123
+55
+224
+123
+55
+234
+126
+45
+139
+96
+61
+55
+66
+67
+250
+200
+166
+249
+174
+124
+247
+150
+84
+247
+130
+60
+247
+118
+39
+247
+111
+26
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+243
+101
+2
+243
+101
+2
+247
+103
+7
+247
+111
+26
+247
+111
+26
+247
+123
+41
+247
+130
+60
+243
+141
+78
+249
+159
+103
+250
+176
+132
+251
+192
+154
+207
+178
+158
+154
+133
+118
+82
+69
+65
+24
+22
+23
+71
+60
+43
+101
+83
+47
+101
+83
+47
+101
+83
+47
+117
+98
+55
+145
+114
+49
+171
+129
+45
+168
+127
+42
+160
+120
+43
+160
+120
+43
+158
+125
+46
+192
+155
+91
+237
+233
+225
+81
+77
+76
+55
+48
+48
+74
+68
+68
+81
+77
+76
+89
+84
+82
+91
+92
+89
+89
+84
+82
+81
+77
+76
+65
+58
+56
+47
+40
+38
+35
+31
+30
+55
+48
+48
+115
+102
+92
+172
+150
+134
+55
+48
+48
+24
+22
+23
+24
+22
+23
+24
+22
+23
+65
+58
+56
+230
+173
+136
+251
+192
+154
+250
+197
+158
+250
+200
+166
+84
+85
+82
+88
+82
+59
+171
+129
+45
+158
+125
+46
+158
+125
+46
+171
+129
+45
+83
+78
+61
+69
+69
+61
+168
+127
+42
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+171
+129
+45
+117
+98
+55
+48
+58
+59
+101
+100
+92
+238
+205
+179
+253
+204
+176
+250
+200
+166
+253
+204
+176
+238
+205
+179
+91
+92
+89
+51
+62
+63
+117
+98
+55
+171
+129
+45
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+161
+127
+40
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+171
+129
+45
+145
+114
+49
+75
+74
+61
+48
+58
+59
+172
+150
+134
+253
+212
+188
+255
+215
+190
+234
+204
+183
+84
+85
+82
+56
+64
+60
+129
+106
+52
+171
+129
+45
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+168
+127
+42
+81
+73
+62
+63
+69
+60
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+83
+78
+61
+84
+85
+82
+255
+215
+190
+245
+212
+186
+109
+106
+99
+51
+62
+63
+123
+102
+54
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+161
+127
+40
+171
+129
+45
+105
+93
+60
+51
+62
+63
+137
+110
+49
+168
+127
+42
+158
+125
+46
+168
+127
+42
+145
+114
+49
+51
+62
+63
+137
+127
+115
+58
+69
+70
+111
+94
+57
+171
+129
+45
+158
+125
+46
+158
+125
+46
+158
+125
+46
+62
+63
+61
+137
+127
+115
+255
+215
+190
+255
+215
+190
+227
+196
+175
+77
+85
+81
+56
+64
+60
+129
+106
+52
+171
+129
+45
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+161
+127
+40
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+168
+127
+42
+137
+110
+49
+69
+69
+61
+51
+62
+63
+187
+166
+150
+255
+215
+190
+172
+150
+134
+51
+62
+63
+194
+112
+58
+227
+126
+50
+224
+123
+55
+234
+125
+52
+183
+110
+59
+48
+58
+59
+155
+100
+63
+234
+126
+45
+224
+123
+55
+224
+123
+55
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+125
+52
+209
+117
+53
+89
+75
+66
+48
+58
+59
+187
+166
+150
+250
+200
+166
+250
+197
+158
+251
+192
+154
+250
+197
+158
+250
+200
+166
+109
+106
+99
+48
+58
+59
+135
+94
+64
+234
+125
+52
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+227
+126
+50
+135
+94
+64
+43
+57
+62
+120
+114
+108
+250
+200
+166
+250
+197
+158
+251
+192
+154
+250
+197
+158
+250
+200
+166
+172
+150
+134
+41
+58
+57
+106
+82
+65
+214
+121
+50
+234
+125
+52
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+224
+123
+55
+227
+126
+50
+234
+126
+45
+183
+110
+59
+48
+58
+59
+135
+94
+64
+234
+126
+45
+224
+123
+55
+227
+126
+50
+188
+112
+56
+51
+62
+63
+109
+106
+99
+51
+62
+63
+183
+110
+59
+227
+126
+50
+224
+123
+55
+234
+125
+52
+173
+106
+60
+48
+58
+59
+178
+146
+122
+245
+169
+119
+246
+156
+93
+247
+150
+84
+249
+146
+83
+247
+150
+84
+249
+159
+103
+249
+174
+124
+203
+161
+131
+58
+69
+70
+76
+70
+64
+194
+112
+58
+234
+126
+45
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+126
+45
+183
+110
+59
+48
+58
+59
+163
+104
+61
+234
+126
+45
+224
+123
+55
+227
+126
+50
+209
+117
+53
+62
+63
+61
+146
+135
+124
+217
+187
+166
+43
+57
+62
+163
+104
+61
+234
+125
+52
+224
+123
+55
+224
+123
+55
+234
+126
+45
+125
+90
+64
+58
+69
+70
+234
+204
+183
+255
+215
+190
+137
+127
+115
+41
+58
+57
+118
+86
+65
+225
+124
+48
+234
+126
+45
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+126
+45
+146
+97
+64
+51
+62
+63
+97
+98
+96
+238
+205
+179
+255
+215
+190
+234
+204
+183
+63
+74
+74
+118
+86
+65
+234
+126
+45
+224
+123
+55
+227
+126
+50
+227
+126
+50
+81
+73
+62
+101
+100
+92
+250
+176
+132
+247
+165
+111
+246
+156
+93
+249
+152
+92
+249
+159
+103
+251
+168
+115
+252
+185
+144
+217
+187
+166
+58
+69
+70
+69
+69
+61
+199
+115
+54
+234
+126
+45
+227
+126
+50
+224
+123
+55
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+224
+123
+55
+227
+126
+50
+225
+124
+48
+81
+73
+62
+81
+73
+62
+227
+126
+50
+227
+126
+50
+224
+123
+55
+234
+126
+45
+139
+96
+61
+55
+66
+67
+250
+197
+158
+249
+174
+124
+247
+150
+84
+247
+130
+60
+247
+118
+39
+247
+111
+26
+247
+103
+7
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+237
+95
+0
+237
+95
+0
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+237
+95
+0
+243
+101
+2
+247
+103
+7
+236
+102
+14
+247
+111
+26
+246
+116
+28
+247
+123
+41
+247
+130
+60
+243
+141
+78
+249
+159
+103
+249
+174
+124
+249
+189
+146
+253
+204
+176
+124
+111
+99
+35
+31
+30
+145
+114
+49
+175
+132
+40
+171
+129
+45
+168
+127
+42
+192
+155
+91
+216
+194
+154
+224
+207
+180
+224
+207
+180
+216
+194
+154
+216
+194
+154
+239
+227
+208
+253
+255
+252
+253
+255
+252
+186
+181
+179
+146
+135
+124
+120
+114
+108
+109
+106
+99
+95
+78
+64
+71
+60
+43
+85
+71
+43
+101
+83
+47
+108
+87
+46
+35
+31
+30
+150
+125
+114
+227
+196
+175
+255
+215
+190
+253
+212
+188
+212
+173
+150
+121
+100
+85
+95
+78
+64
+129
+102
+78
+234
+168
+124
+250
+176
+132
+250
+176
+132
+248
+180
+134
+249
+189
+146
+124
+111
+99
+62
+63
+61
+152
+119
+47
+171
+129
+45
+171
+129
+45
+145
+114
+49
+56
+64
+60
+43
+57
+62
+83
+78
+61
+152
+119
+47
+171
+129
+45
+171
+129
+45
+168
+127
+42
+168
+127
+42
+171
+129
+45
+171
+129
+45
+152
+119
+47
+95
+87
+59
+48
+58
+59
+101
+100
+92
+236
+186
+153
+251
+192
+154
+252
+185
+144
+248
+180
+134
+245
+179
+138
+249
+189
+146
+236
+186
+153
+101
+100
+92
+48
+58
+59
+88
+82
+59
+137
+110
+49
+168
+127
+42
+171
+129
+45
+168
+127
+42
+168
+127
+42
+168
+127
+42
+168
+127
+42
+171
+129
+45
+171
+129
+45
+168
+127
+42
+145
+114
+49
+100
+89
+56
+56
+64
+60
+58
+69
+70
+172
+150
+134
+250
+200
+166
+251
+192
+154
+250
+197
+158
+250
+200
+166
+217
+187
+166
+84
+85
+82
+51
+62
+63
+105
+93
+60
+158
+125
+46
+171
+129
+45
+171
+129
+45
+168
+127
+42
+168
+127
+42
+168
+127
+42
+171
+129
+45
+152
+119
+47
+83
+78
+61
+43
+57
+62
+48
+58
+59
+129
+106
+52
+175
+132
+40
+171
+129
+45
+158
+125
+46
+63
+69
+60
+120
+114
+108
+255
+215
+190
+255
+215
+190
+227
+196
+175
+84
+85
+82
+51
+62
+63
+105
+93
+60
+158
+125
+46
+171
+129
+45
+171
+129
+45
+168
+127
+42
+168
+127
+42
+168
+127
+42
+171
+129
+45
+158
+125
+46
+105
+93
+60
+48
+58
+59
+48
+58
+59
+129
+106
+52
+168
+127
+42
+158
+125
+46
+168
+127
+42
+145
+114
+49
+51
+62
+63
+172
+150
+134
+91
+92
+89
+75
+74
+61
+168
+127
+42
+171
+129
+45
+175
+132
+40
+117
+98
+55
+48
+58
+59
+176
+156
+141
+253
+204
+176
+253
+204
+176
+253
+204
+176
+217
+187
+166
+84
+85
+82
+48
+58
+59
+95
+87
+59
+145
+114
+49
+168
+127
+42
+171
+129
+45
+168
+127
+42
+168
+127
+42
+168
+127
+42
+168
+127
+42
+171
+129
+45
+171
+129
+45
+158
+125
+46
+137
+110
+49
+95
+87
+59
+51
+62
+63
+70
+79
+77
+187
+166
+150
+251
+209
+178
+251
+209
+178
+207
+178
+158
+43
+57
+62
+135
+94
+64
+238
+123
+45
+234
+126
+45
+234
+126
+45
+118
+86
+65
+35
+56
+60
+56
+64
+60
+155
+100
+63
+234
+125
+52
+234
+126
+45
+234
+125
+52
+227
+126
+50
+227
+126
+50
+234
+126
+45
+227
+126
+50
+163
+104
+61
+76
+70
+64
+51
+62
+63
+167
+142
+123
+251
+192
+154
+248
+180
+134
+249
+174
+124
+249
+174
+124
+250
+176
+132
+245
+179
+138
+236
+186
+153
+109
+106
+99
+41
+58
+57
+95
+78
+64
+183
+110
+59
+234
+125
+52
+234
+126
+45
+234
+125
+52
+227
+126
+50
+227
+126
+50
+234
+125
+52
+234
+126
+45
+227
+126
+50
+183
+110
+59
+95
+78
+64
+43
+57
+62
+124
+111
+99
+236
+186
+153
+252
+185
+144
+250
+176
+132
+249
+174
+124
+249
+174
+124
+248
+180
+134
+251
+192
+154
+154
+133
+118
+43
+57
+62
+81
+73
+62
+173
+106
+60
+227
+126
+50
+234
+126
+45
+227
+126
+50
+227
+126
+50
+227
+126
+50
+234
+126
+45
+234
+125
+52
+155
+100
+63
+56
+64
+60
+35
+56
+60
+89
+75
+66
+227
+126
+50
+234
+126
+45
+238
+128
+40
+146
+97
+64
+43
+57
+62
+176
+156
+141
+58
+69
+70
+118
+86
+65
+234
+126
+45
+234
+126
+45
+234
+126
+45
+112
+85
+63
+43
+57
+62
+210
+156
+119
+245
+162
+103
+247
+150
+84
+247
+143
+74
+248
+138
+64
+241
+138
+68
+249
+146
+83
+249
+159
+103
+250
+176
+132
+195
+157
+134
+58
+69
+70
+65
+67
+64
+155
+100
+63
+227
+126
+50
+234
+126
+45
+227
+126
+50
+227
+126
+50
+234
+125
+52
+234
+126
+45
+234
+126
+45
+173
+106
+60
+65
+67
+64
+35
+56
+60
+106
+82
+65
+234
+126
+45
+234
+126
+45
+238
+128
+40
+146
+97
+64
+43
+57
+62
+187
+166
+150
+234
+204
+183
+55
+66
+67
+106
+82
+65
+234
+126
+45
+234
+125
+52
+234
+125
+52
+224
+123
+55
+81
+73
+62
+91
+92
+89
+245
+212
+186
+253
+212
+188
+253
+212
+188
+137
+127
+115
+41
+58
+57
+89
+75
+66
+173
+106
+60
+227
+126
+50
+234
+126
+45
+227
+126
+50
+227
+126
+50
+227
+126
+50
+234
+125
+52
+234
+126
+45
+234
+125
+52
+194
+112
+58
+106
+82
+65
+43
+57
+62
+101
+100
+92
+227
+196
+175
+251
+209
+178
+251
+209
+178
+253
+212
+188
+97
+98
+96
+69
+69
+61
+209
+117
+53
+234
+126
+45
+238
+128
+40
+173
+106
+60
+51
+62
+63
+139
+115
+96
+251
+168
+115
+246
+156
+93
+247
+150
+84
+249
+146
+83
+249
+152
+92
+247
+165
+111
+248
+180
+134
+250
+200
+166
+187
+166
+150
+55
+66
+67
+69
+69
+61
+163
+104
+61
+234
+125
+52
+234
+126
+45
+234
+125
+52
+227
+126
+50
+227
+126
+50
+234
+126
+45
+234
+126
+45
+199
+115
+54
+95
+78
+64
+35
+56
+60
+81
+73
+62
+227
+126
+50
+227
+126
+50
+224
+123
+55
+234
+126
+45
+139
+96
+61
+51
+62
+63
+250
+197
+158
+245
+169
+119
+247
+150
+84
+247
+130
+60
+247
+118
+39
+235
+107
+16
+243
+101
+2
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+246
+97
+3
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+246
+97
+3
+237
+95
+0
+243
+101
+2
+247
+103
+7
+236
+102
+14
+247
+111
+26
+246
+116
+28
+238
+123
+45
+241
+132
+59
+247
+143
+74
+246
+156
+93
+245
+169
+119
+230
+173
+136
+47
+40
+38
+59
+50
+39
+168
+127
+42
+161
+127
+40
+160
+120
+43
+192
+155
+91
+255
+238
+227
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+253
+255
+252
+239
+227
+208
+170
+137
+67
+171
+129
+45
+171
+129
+45
+171
+129
+45
+59
+50
+39
+154
+133
+118
+250
+200
+166
+250
+197
+158
+249
+189
+146
+248
+180
+134
+249
+174
+124
+247
+165
+111
+247
+165
+111
+245
+162
+103
+249
+159
+103
+245
+162
+103
+247
+165
+111
+249
+174
+124
+203
+161
+131
+55
+66
+67
+69
+69
+61
+111
+94
+57
+105
+93
+60
+69
+69
+61
+63
+74
+74
+137
+127
+115
+51
+62
+63
+62
+63
+61
+95
+87
+59
+129
+106
+52
+137
+110
+49
+137
+110
+49
+123
+102
+54
+95
+87
+59
+62
+63
+61
+51
+62
+63
+133
+120
+107
+239
+182
+144
+248
+180
+134
+245
+169
+119
+247
+165
+111
+249
+159
+103
+245
+162
+103
+251
+168
+115
+250
+176
+132
+239
+182
+144
+154
+133
+118
+63
+74
+74
+51
+62
+63
+75
+74
+61
+105
+93
+60
+123
+102
+54
+137
+110
+49
+137
+110
+49
+137
+110
+49
+123
+102
+54
+100
+89
+56
+75
+74
+61
+56
+64
+60
+55
+66
+67
+124
+111
+99
+219
+170
+138
+252
+185
+144
+250
+176
+132
+249
+174
+124
+249
+174
+124
+250
+176
+132
+252
+185
+144
+236
+186
+153
+124
+111
+99
+48
+58
+59
+63
+69
+60
+95
+87
+59
+123
+102
+54
+137
+110
+49
+137
+110
+49
+129
+106
+52
+95
+87
+59
+62
+63
+61
+55
+66
+67
+146
+135
+124
+77
+85
+81
+61
+67
+58
+105
+93
+60
+111
+94
+57
+75
+74
+61
+48
+58
+59
+194
+173
+157
+255
+215
+190
+255
+215
+190
+255
+215
+190
+234
+204
+183
+120
+114
+108
+43
+57
+62
+69
+69
+61
+100
+89
+56
+129
+106
+52
+137
+110
+49
+137
+110
+49
+129
+106
+52
+105
+93
+60
+69
+69
+61
+48
+58
+59
+77
+85
+81
+51
+62
+63
+137
+110
+49
+168
+127
+42
+158
+125
+46
+168
+127
+42
+137
+110
+49
+51
+62
+63
+187
+166
+150
+187
+166
+150
+48
+58
+59
+75
+74
+61
+111
+94
+57
+95
+87
+59
+56
+64
+60
+99
+90
+79
+239
+182
+144
+252
+185
+144
+245
+179
+138
+252
+185
+144
+249
+189
+146
+236
+186
+153
+137
+127
+115
+55
+66
+67
+56
+64
+60
+83
+78
+61
+111
+94
+57
+129
+106
+52
+137
+110
+49
+137
+110
+49
+129
+106
+52
+117
+98
+55
+95
+87
+59
+69
+69
+61
+51
+62
+63
+63
+74
+74
+133
+120
+107
+236
+186
+153
+250
+197
+158
+251
+192
+154
+251
+192
+154
+250
+197
+158
+124
+111
+99
+51
+62
+63
+112
+85
+63
+146
+97
+64
+106
+82
+65
+48
+58
+59
+120
+114
+108
+101
+100
+92
+48
+58
+59
+95
+78
+64
+146
+97
+64
+183
+110
+59
+188
+112
+56
+173
+106
+60
+139
+96
+61
+89
+75
+66
+48
+58
+59
+77
+85
+81
+186
+157
+134
+245
+179
+138
+245
+169
+119
+245
+162
+103
+246
+156
+93
+246
+156
+93
+246
+156
+93
+247
+165
+111
+249
+174
+124
+249
+189
+146
+154
+133
+118
+58
+69
+70
+51
+62
+63
+95
+78
+64
+139
+96
+61
+173
+106
+60
+183
+110
+59
+183
+110
+59
+173
+106
+60
+139
+96
+61
+95
+78
+64
+51
+62
+63
+63
+74
+74
+167
+142
+123
+249
+189
+146
+249
+174
+124
+247
+165
+111
+246
+156
+93
+246
+156
+93
+246
+156
+93
+245
+162
+103
+245
+169
+119
+245
+179
+138
+178
+146
+122
+70
+79
+77
+48
+58
+59
+89
+75
+66
+139
+96
+61
+173
+106
+60
+188
+112
+56
+183
+110
+59
+155
+100
+63
+95
+78
+64
+48
+58
+59
+101
+100
+92
+146
+135
+124
+48
+58
+59
+95
+78
+64
+146
+97
+64
+125
+90
+64
+62
+63
+61
+101
+100
+92
+245
+212
+186
+137
+127
+115
+48
+58
+59
+106
+82
+65
+146
+97
+64
+106
+82
+65
+48
+58
+59
+124
+111
+99
+247
+165
+111
+247
+150
+84
+241
+138
+68
+241
+132
+59
+247
+130
+53
+247
+130
+53
+242
+133
+67
+241
+145
+79
+245
+162
+103
+250
+176
+132
+203
+161
+131
+91
+92
+89
+43
+57
+62
+81
+73
+62
+135
+94
+64
+173
+106
+60
+188
+112
+56
+183
+110
+59
+155
+100
+63
+106
+82
+65
+51
+62
+63
+91
+92
+89
+133
+120
+107
+48
+58
+59
+95
+78
+64
+146
+97
+64
+118
+86
+65
+56
+64
+60
+101
+100
+92
+245
+212
+186
+253
+212
+188
+146
+135
+124
+48
+58
+59
+118
+86
+65
+183
+110
+59
+173
+106
+60
+95
+78
+64
+43
+57
+62
+186
+157
+134
+250
+197
+158
+251
+192
+154
+250
+197
+158
+250
+200
+166
+172
+150
+134
+70
+79
+77
+48
+58
+59
+89
+75
+66
+135
+94
+64
+163
+104
+61
+183
+110
+59
+183
+110
+59
+173
+106
+60
+146
+97
+64
+95
+78
+64
+56
+64
+60
+55
+66
+67
+150
+125
+114
+236
+186
+153
+251
+192
+154
+249
+189
+146
+249
+189
+146
+251
+192
+154
+195
+157
+134
+51
+62
+63
+76
+70
+64
+139
+96
+61
+125
+90
+64
+65
+67
+64
+76
+78
+76
+234
+168
+124
+249
+159
+103
+247
+150
+84
+243
+141
+78
+247
+143
+74
+247
+150
+84
+249
+159
+103
+250
+176
+132
+250
+197
+158
+255
+215
+190
+207
+178
+158
+84
+85
+82
+48
+58
+59
+89
+75
+66
+146
+97
+64
+173
+106
+60
+183
+110
+59
+183
+110
+59
+163
+104
+61
+118
+86
+65
+62
+63
+61
+58
+69
+70
+63
+74
+74
+81
+73
+62
+227
+126
+50
+227
+126
+50
+224
+123
+55
+234
+126
+45
+135
+94
+64
+58
+69
+70
+251
+192
+154
+245
+169
+119
+249
+146
+83
+247
+130
+53
+238
+116
+34
+235
+107
+16
+243
+101
+2
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+246
+97
+3
+246
+97
+3
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+243
+101
+2
+236
+102
+14
+236
+102
+14
+235
+107
+16
+246
+116
+28
+239
+117
+44
+241
+132
+59
+247
+143
+74
+249
+152
+92
+214
+151
+109
+118
+86
+65
+146
+111
+88
+192
+155
+91
+192
+155
+91
+195
+167
+113
+239
+227
+208
+255
+238
+227
+255
+238
+227
+255
+238
+227
+255
+238
+227
+255
+238
+227
+255
+238
+227
+255
+238
+227
+255
+238
+227
+255
+238
+227
+255
+238
+227
+255
+238
+227
+255
+238
+227
+255
+238
+227
+255
+238
+227
+216
+194
+154
+192
+155
+91
+192
+155
+91
+192
+155
+91
+146
+111
+88
+162
+125
+96
+250
+176
+132
+245
+169
+119
+247
+165
+111
+249
+159
+103
+246
+156
+93
+247
+150
+84
+243
+141
+78
+243
+141
+78
+243
+141
+78
+241
+145
+79
+247
+150
+84
+249
+159
+103
+245
+169
+119
+187
+140
+108
+89
+84
+82
+48
+58
+59
+48
+58
+59
+91
+92
+89
+194
+173
+157
+255
+215
+190
+207
+178
+158
+109
+106
+99
+51
+62
+63
+48
+58
+59
+51
+62
+63
+48
+58
+59
+48
+58
+59
+55
+66
+67
+124
+111
+99
+203
+161
+131
+248
+180
+134
+245
+169
+119
+249
+159
+103
+247
+150
+84
+243
+141
+78
+243
+141
+78
+243
+141
+78
+247
+150
+84
+249
+159
+103
+245
+169
+119
+248
+180
+134
+219
+170
+138
+154
+133
+118
+84
+85
+82
+51
+62
+63
+48
+58
+59
+51
+62
+63
+51
+62
+63
+48
+58
+59
+48
+58
+59
+55
+66
+67
+91
+92
+89
+154
+133
+118
+209
+171
+139
+245
+179
+138
+249
+174
+124
+247
+165
+111
+249
+159
+103
+246
+156
+93
+246
+156
+93
+249
+159
+103
+247
+165
+111
+249
+174
+124
+252
+185
+144
+195
+157
+134
+109
+106
+99
+55
+66
+67
+48
+58
+59
+51
+62
+63
+51
+62
+63
+48
+58
+59
+51
+62
+63
+109
+106
+99
+207
+178
+158
+255
+215
+190
+217
+187
+166
+91
+92
+89
+51
+62
+63
+48
+58
+59
+76
+78
+76
+172
+150
+134
+253
+212
+188
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+255
+215
+190
+194
+173
+157
+101
+100
+92
+51
+62
+63
+48
+58
+59
+48
+58
+59
+51
+62
+63
+48
+58
+59
+48
+58
+59
+97
+98
+96
+194
+173
+157
+146
+135
+124
+56
+64
+60
+145
+114
+49
+168
+127
+42
+158
+125
+46
+168
+127
+42
+129
+106
+52
+48
+58
+59
+194
+173
+157
+255
+215
+190
+176
+156
+141
+76
+78
+76
+48
+58
+59
+55
+66
+67
+115
+102
+92
+234
+168
+124
+245
+169
+119
+247
+165
+111
+247
+165
+111
+247
+165
+111
+245
+169
+119
+249
+174
+124
+245
+179
+138
+209
+171
+139
+144
+125
+110
+76
+78
+76
+48
+58
+59
+48
+58
+59
+51
+62
+63
+51
+62
+63
+48
+58
+59
+48
+58
+59
+58
+69
+70
+101
+100
+92
+154
+133
+118
+219
+170
+138
+252
+185
+144
+248
+180
+134
+249
+174
+124
+245
+169
+119
+249
+174
+124
+250
+176
+132
+230
+173
+136
+124
+111
+99
+55
+66
+67
+43
+57
+62
+58
+69
+70
+137
+127
+115
+245
+212
+186
+245
+212
+186
+161
+144
+134
+70
+79
+77
+43
+57
+62
+51
+62
+63
+51
+62
+63
+48
+58
+59
+43
+57
+62
+84
+85
+82
+154
+133
+118
+240
+181
+138
+249
+174
+124
+247
+165
+111
+249
+152
+92
+243
+141
+78
+241
+138
+68
+242
+133
+67
+241
+138
+68
+241
+145
+79
+246
+156
+93
+247
+165
+111
+250
+176
+132
+219
+170
+138
+144
+125
+110
+77
+85
+81
+43
+57
+62
+48
+58
+59
+48
+58
+59
+51
+62
+63
+48
+58
+59
+43
+57
+62
+77
+85
+81
+150
+125
+114
+219
+170
+138
+250
+176
+132
+247
+165
+111
+246
+156
+93
+241
+145
+79
+241
+138
+68
+241
+138
+68
+241
+138
+68
+243
+141
+78
+249
+152
+92
+247
+165
+111
+250
+176
+132
+230
+173
+136
+154
+133
+118
+77
+85
+81
+43
+57
+62
+48
+58
+59
+51
+62
+63
+48
+58
+59
+43
+57
+62
+70
+79
+77
+161
+144
+134
+245
+212
+186
+255
+215
+190
+161
+144
+134
+63
+74
+74
+43
+57
+62
+51
+62
+63
+109
+106
+99
+217
+187
+166
+251
+209
+178
+238
+205
+179
+137
+127
+115
+58
+69
+70
+43
+57
+62
+58
+69
+70
+139
+115
+96
+238
+159
+107
+249
+152
+92
+241
+138
+68
+247
+130
+53
+238
+123
+45
+239
+117
+44
+247
+118
+39
+238
+123
+45
+241
+132
+59
+241
+145
+79
+249
+159
+103
+249
+174
+124
+240
+181
+138
+167
+142
+123
+91
+92
+89
+43
+57
+62
+48
+58
+59
+51
+62
+63
+48
+58
+59
+43
+57
+62
+63
+74
+74
+137
+127
+115
+234
+204
+183
+255
+215
+190
+146
+135
+124
+63
+74
+74
+43
+57
+62
+51
+62
+63
+115
+102
+92
+236
+186
+153
+251
+192
+154
+251
+192
+154
+236
+186
+153
+133
+120
+107
+43
+57
+62
+48
+58
+59
+48
+58
+59
+55
+66
+67
+158
+130
+108
+248
+180
+134
+250
+176
+132
+249
+174
+124
+249
+174
+124
+250
+176
+132
+252
+185
+144
+239
+182
+144
+154
+133
+118
+84
+85
+82
+43
+57
+62
+48
+58
+59
+48
+58
+59
+51
+62
+63
+48
+58
+59
+43
+57
+62
+70
+79
+77
+133
+120
+107
+219
+170
+138
+245
+179
+138
+250
+176
+132
+245
+169
+119
+247
+165
+111
+247
+165
+111
+245
+169
+119
+249
+174
+124
+187
+140
+108
+81
+77
+76
+43
+57
+62
+43
+57
+62
+99
+90
+79
+214
+151
+109
+249
+159
+103
+247
+150
+84
+247
+143
+74
+241
+138
+68
+241
+138
+68
+249
+146
+83
+249
+159
+103
+250
+176
+132
+250
+197
+158
+255
+215
+190
+255
+215
+190
+245
+212
+186
+161
+144
+134
+77
+85
+81
+43
+57
+62
+48
+58
+59
+51
+62
+63
+48
+58
+59
+41
+58
+57
+55
+66
+67
+120
+114
+108
+217
+187
+166
+97
+98
+96
+95
+78
+64
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+125
+52
+112
+85
+63
+70
+79
+77
+249
+189
+146
+247
+165
+111
+243
+141
+78
+247
+130
+53
+238
+116
+34
+236
+102
+14
+243
+101
+2
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+235
+94
+9
+235
+94
+9
+236
+102
+14
+235
+107
+16
+236
+108
+29
+239
+117
+44
+238
+123
+53
+242
+133
+67
+241
+145
+79
+241
+153
+96
+247
+165
+111
+249
+174
+124
+250
+176
+132
+245
+179
+138
+252
+185
+144
+249
+189
+146
+249
+189
+146
+249
+189
+146
+249
+189
+146
+249
+189
+146
+249
+189
+146
+249
+189
+146
+249
+189
+146
+249
+189
+146
+249
+189
+146
+249
+189
+146
+249
+189
+146
+249
+189
+146
+249
+189
+146
+252
+185
+144
+245
+179
+138
+250
+176
+132
+249
+174
+124
+245
+169
+119
+245
+162
+103
+241
+153
+96
+241
+145
+86
+243
+141
+78
+241
+138
+68
+242
+133
+67
+241
+132
+59
+238
+123
+53
+238
+123
+53
+238
+123
+53
+241
+132
+59
+242
+133
+67
+243
+141
+78
+241
+145
+86
+249
+159
+103
+238
+159
+107
+210
+156
+119
+210
+156
+119
+240
+181
+138
+249
+189
+146
+251
+192
+154
+251
+192
+154
+250
+197
+158
+212
+173
+150
+186
+157
+134
+167
+142
+123
+167
+142
+123
+195
+157
+134
+219
+170
+138
+248
+180
+134
+245
+169
+119
+245
+162
+103
+247
+150
+84
+243
+141
+78
+241
+132
+59
+238
+123
+53
+238
+123
+53
+238
+123
+53
+241
+132
+59
+241
+138
+68
+247
+150
+84
+245
+162
+103
+245
+169
+119
+250
+176
+132
+239
+182
+144
+219
+170
+138
+186
+157
+134
+167
+142
+123
+167
+142
+123
+172
+150
+134
+195
+157
+134
+219
+170
+138
+239
+182
+144
+248
+180
+134
+245
+169
+119
+245
+162
+103
+241
+153
+96
+241
+145
+79
+241
+138
+68
+241
+138
+68
+241
+138
+68
+241
+138
+68
+241
+145
+79
+241
+153
+96
+247
+165
+111
+249
+174
+124
+245
+179
+138
+219
+170
+138
+186
+157
+134
+167
+142
+123
+167
+142
+123
+186
+157
+134
+212
+173
+150
+250
+197
+158
+251
+192
+154
+251
+192
+154
+249
+189
+146
+239
+182
+144
+219
+170
+138
+219
+170
+138
+239
+182
+144
+250
+197
+158
+250
+200
+166
+251
+209
+178
+238
+205
+179
+172
+150
+134
+137
+127
+115
+161
+144
+134
+217
+187
+166
+253
+212
+188
+227
+196
+175
+194
+173
+157
+176
+156
+141
+172
+150
+134
+187
+166
+150
+217
+187
+166
+255
+215
+190
+245
+212
+186
+76
+78
+76
+75
+74
+61
+158
+125
+46
+158
+125
+46
+158
+125
+46
+171
+129
+45
+105
+93
+60
+58
+69
+70
+217
+187
+166
+255
+215
+190
+253
+204
+176
+236
+186
+153
+210
+156
+119
+210
+156
+119
+247
+165
+111
+249
+159
+103
+249
+152
+92
+241
+145
+86
+243
+141
+78
+241
+145
+79
+247
+150
+84
+241
+153
+96
+245
+162
+103
+245
+169
+119
+248
+180
+134
+239
+182
+144
+209
+171
+139
+186
+157
+134
+167
+142
+123
+167
+142
+123
+178
+146
+122
+195
+157
+134
+230
+173
+136
+239
+182
+144
+250
+176
+132
+245
+169
+119
+247
+165
+111
+249
+159
+103
+241
+153
+96
+249
+152
+92
+249
+152
+92
+241
+153
+96
+245
+162
+103
+247
+165
+111
+210
+156
+119
+210
+156
+119
+230
+173
+136
+249
+189
+146
+249
+189
+146
+251
+192
+154
+250
+197
+158
+236
+186
+153
+203
+161
+131
+167
+142
+123
+167
+142
+123
+178
+146
+122
+203
+161
+131
+240
+181
+138
+249
+174
+124
+247
+165
+111
+241
+153
+96
+243
+141
+78
+242
+133
+67
+238
+123
+53
+238
+123
+45
+238
+123
+45
+238
+123
+45
+241
+132
+59
+241
+138
+68
+241
+145
+86
+249
+159
+103
+245
+169
+119
+250
+176
+132
+240
+181
+138
+209
+171
+139
+178
+146
+122
+167
+142
+123
+167
+142
+123
+186
+157
+134
+209
+171
+139
+240
+181
+138
+250
+176
+132
+245
+169
+119
+249
+159
+103
+241
+145
+86
+241
+138
+68
+241
+132
+59
+238
+123
+45
+238
+123
+45
+238
+123
+45
+247
+130
+53
+242
+133
+67
+241
+145
+79
+241
+153
+96
+247
+165
+111
+250
+176
+132
+240
+181
+138
+203
+161
+131
+178
+146
+122
+167
+142
+123
+167
+142
+123
+195
+157
+134
+236
+186
+153
+251
+192
+154
+251
+192
+154
+249
+189
+146
+249
+189
+146
+230
+173
+136
+203
+161
+131
+219
+170
+138
+245
+179
+138
+245
+179
+138
+245
+179
+138
+245
+179
+138
+248
+180
+134
+234
+168
+124
+214
+151
+109
+214
+151
+109
+245
+162
+103
+241
+145
+86
+241
+138
+68
+238
+123
+53
+239
+117
+44
+238
+116
+34
+236
+108
+29
+236
+108
+29
+238
+116
+34
+238
+123
+45
+241
+132
+59
+243
+141
+78
+241
+153
+96
+247
+165
+111
+249
+174
+124
+240
+181
+138
+209
+171
+139
+178
+146
+122
+167
+142
+123
+167
+142
+123
+195
+157
+134
+236
+186
+153
+250
+197
+158
+251
+192
+154
+249
+189
+146
+249
+189
+146
+230
+173
+136
+210
+156
+119
+210
+156
+119
+250
+176
+132
+249
+174
+124
+249
+174
+124
+249
+174
+124
+249
+174
+124
+250
+176
+132
+210
+156
+119
+162
+125
+96
+162
+125
+96
+214
+151
+109
+247
+165
+111
+245
+162
+103
+241
+153
+96
+241
+153
+96
+241
+153
+96
+249
+159
+103
+247
+165
+111
+245
+169
+119
+250
+176
+132
+240
+181
+138
+209
+171
+139
+186
+157
+134
+167
+142
+123
+167
+142
+123
+178
+146
+122
+203
+161
+131
+239
+182
+144
+248
+180
+134
+245
+169
+119
+245
+162
+103
+241
+153
+96
+241
+145
+86
+241
+145
+86
+241
+145
+86
+247
+150
+84
+241
+153
+96
+245
+162
+103
+238
+159
+107
+204
+141
+99
+214
+151
+109
+241
+153
+96
+249
+152
+92
+243
+141
+78
+242
+133
+67
+241
+132
+59
+241
+132
+59
+241
+138
+68
+241
+145
+79
+245
+162
+103
+248
+180
+134
+212
+173
+150
+146
+135
+124
+137
+127
+115
+176
+156
+141
+234
+204
+183
+253
+212
+188
+217
+187
+166
+187
+166
+150
+172
+150
+134
+176
+156
+141
+194
+173
+157
+234
+204
+183
+255
+215
+190
+194
+173
+157
+43
+57
+62
+139
+96
+61
+234
+126
+45
+224
+123
+55
+227
+126
+50
+227
+126
+50
+89
+75
+66
+101
+100
+92
+245
+179
+138
+245
+162
+103
+241
+138
+68
+238
+123
+45
+236
+108
+29
+236
+102
+14
+235
+94
+9
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+235
+94
+9
+235
+94
+9
+236
+102
+14
+235
+107
+16
+236
+108
+29
+238
+116
+34
+238
+123
+45
+241
+132
+59
+241
+138
+68
+241
+145
+79
+249
+152
+92
+241
+153
+96
+245
+162
+103
+245
+162
+103
+247
+165
+111
+247
+165
+111
+247
+165
+111
+247
+165
+111
+247
+165
+111
+247
+165
+111
+247
+165
+111
+247
+165
+111
+247
+165
+111
+247
+165
+111
+247
+165
+111
+247
+165
+111
+247
+165
+111
+247
+165
+111
+245
+162
+103
+245
+162
+103
+241
+153
+96
+241
+153
+96
+241
+145
+86
+243
+141
+78
+241
+138
+68
+241
+132
+59
+238
+123
+53
+238
+123
+45
+239
+117
+44
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+239
+117
+44
+238
+123
+45
+238
+123
+53
+241
+132
+59
+243
+141
+78
+241
+145
+86
+241
+153
+96
+245
+162
+103
+245
+162
+103
+247
+165
+111
+247
+165
+111
+245
+169
+119
+245
+169
+119
+245
+169
+119
+249
+174
+124
+245
+169
+119
+245
+169
+119
+245
+169
+119
+247
+165
+111
+241
+153
+96
+241
+145
+86
+243
+141
+78
+241
+132
+59
+238
+123
+53
+239
+117
+44
+238
+116
+34
+238
+116
+34
+238
+116
+34
+239
+117
+44
+238
+123
+45
+241
+132
+59
+241
+138
+68
+241
+145
+86
+241
+153
+96
+245
+162
+103
+245
+169
+119
+249
+174
+124
+250
+176
+132
+250
+176
+132
+250
+176
+132
+249
+174
+124
+245
+169
+119
+247
+165
+111
+241
+153
+96
+241
+145
+86
+243
+141
+78
+242
+133
+67
+241
+132
+59
+238
+123
+45
+238
+123
+45
+238
+123
+45
+238
+123
+45
+241
+132
+59
+242
+133
+67
+243
+141
+78
+249
+152
+92
+245
+162
+103
+247
+165
+111
+245
+169
+119
+245
+169
+119
+245
+169
+119
+245
+169
+119
+245
+169
+119
+245
+169
+119
+245
+169
+119
+247
+165
+111
+247
+165
+111
+247
+165
+111
+247
+165
+111
+245
+169
+119
+249
+174
+124
+245
+179
+138
+251
+192
+154
+232
+190
+161
+101
+100
+92
+51
+62
+63
+63
+69
+60
+51
+62
+63
+55
+66
+67
+109
+106
+99
+176
+156
+141
+234
+204
+183
+255
+215
+190
+255
+215
+190
+255
+215
+190
+245
+212
+186
+207
+178
+158
+91
+92
+89
+51
+62
+63
+129
+106
+52
+168
+127
+42
+158
+125
+46
+158
+125
+46
+168
+127
+42
+75
+74
+61
+91
+92
+89
+245
+212
+186
+250
+200
+166
+252
+185
+144
+249
+174
+124
+247
+165
+111
+241
+153
+96
+241
+145
+79
+241
+138
+68
+242
+133
+67
+241
+132
+59
+238
+123
+53
+241
+132
+59
+241
+132
+59
+241
+138
+68
+243
+141
+78
+241
+145
+86
+241
+153
+96
+247
+165
+111
+245
+169
+119
+249
+174
+124
+250
+176
+132
+250
+176
+132
+249
+174
+124
+249
+174
+124
+245
+169
+119
+245
+162
+103
+241
+153
+96
+241
+145
+86
+241
+145
+79
+241
+138
+68
+242
+133
+67
+242
+133
+67
+242
+133
+67
+241
+138
+68
+243
+141
+78
+241
+145
+86
+241
+153
+96
+241
+153
+96
+245
+162
+103
+245
+162
+103
+247
+165
+111
+245
+169
+119
+245
+169
+119
+245
+169
+119
+245
+169
+119
+245
+169
+119
+245
+169
+119
+245
+169
+119
+247
+165
+111
+245
+162
+103
+241
+153
+96
+241
+145
+79
+241
+138
+68
+238
+123
+53
+238
+123
+45
+238
+116
+34
+235
+113
+30
+235
+113
+30
+238
+116
+34
+239
+117
+44
+238
+123
+45
+241
+132
+59
+241
+138
+68
+241
+145
+86
+241
+153
+96
+245
+162
+103
+245
+169
+119
+245
+169
+119
+249
+174
+124
+249
+174
+124
+245
+169
+119
+245
+169
+119
+245
+162
+103
+241
+153
+96
+241
+145
+86
+241
+138
+68
+241
+132
+59
+238
+123
+45
+239
+117
+44
+238
+116
+34
+235
+113
+30
+235
+113
+30
+238
+116
+34
+238
+123
+45
+241
+132
+59
+241
+138
+68
+241
+145
+86
+241
+153
+96
+245
+162
+103
+247
+165
+111
+245
+169
+119
+245
+169
+119
+245
+169
+119
+245
+169
+119
+245
+169
+119
+245
+169
+119
+247
+165
+111
+247
+165
+111
+247
+165
+111
+245
+162
+103
+245
+162
+103
+245
+162
+103
+245
+162
+103
+245
+162
+103
+245
+162
+103
+245
+162
+103
+245
+162
+103
+241
+153
+96
+241
+153
+96
+241
+145
+86
+243
+141
+78
+241
+132
+59
+238
+123
+53
+239
+117
+44
+235
+113
+30
+236
+108
+29
+235
+107
+16
+235
+107
+16
+236
+108
+29
+235
+113
+30
+239
+117
+44
+238
+123
+53
+242
+133
+67
+241
+145
+79
+241
+153
+96
+245
+162
+103
+247
+165
+111
+245
+169
+119
+245
+169
+119
+249
+174
+124
+245
+169
+119
+245
+169
+119
+245
+169
+119
+245
+169
+119
+247
+165
+111
+247
+165
+111
+245
+162
+103
+245
+162
+103
+241
+153
+96
+241
+153
+96
+241
+153
+96
+241
+153
+96
+241
+153
+96
+241
+153
+96
+241
+153
+96
+241
+153
+96
+241
+153
+96
+241
+153
+96
+249
+152
+92
+241
+145
+86
+243
+141
+78
+241
+138
+68
+241
+138
+68
+241
+138
+68
+241
+138
+68
+243
+141
+78
+241
+145
+86
+241
+153
+96
+245
+162
+103
+245
+169
+119
+245
+169
+119
+249
+174
+124
+249
+174
+124
+249
+174
+124
+245
+169
+119
+247
+165
+111
+241
+153
+96
+241
+145
+86
+243
+141
+78
+241
+138
+68
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+138
+68
+243
+141
+78
+241
+145
+79
+241
+145
+79
+241
+145
+79
+243
+141
+78
+241
+138
+68
+241
+132
+59
+238
+123
+53
+238
+123
+53
+238
+123
+53
+242
+133
+67
+241
+145
+86
+247
+165
+111
+210
+156
+119
+63
+74
+74
+62
+63
+61
+69
+69
+61
+48
+58
+59
+63
+74
+74
+133
+120
+107
+194
+173
+157
+245
+212
+186
+255
+215
+190
+255
+215
+190
+255
+215
+190
+245
+212
+186
+176
+156
+141
+55
+66
+67
+76
+70
+64
+212
+120
+56
+227
+126
+50
+224
+123
+55
+234
+125
+52
+194
+112
+58
+56
+64
+60
+154
+133
+118
+250
+176
+132
+241
+153
+96
+242
+133
+67
+239
+117
+44
+236
+108
+29
+236
+102
+14
+235
+94
+9
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+235
+94
+9
+235
+94
+9
+236
+102
+14
+236
+102
+14
+236
+108
+29
+235
+113
+30
+239
+117
+44
+238
+123
+45
+238
+123
+53
+241
+132
+59
+241
+138
+68
+241
+138
+68
+243
+141
+78
+243
+141
+78
+241
+145
+79
+241
+145
+79
+241
+145
+79
+241
+145
+79
+241
+145
+79
+241
+145
+79
+241
+145
+79
+241
+145
+79
+241
+145
+79
+241
+145
+79
+241
+145
+79
+243
+141
+78
+243
+141
+78
+243
+141
+78
+241
+138
+68
+241
+138
+68
+241
+132
+59
+241
+132
+59
+238
+123
+53
+238
+123
+45
+238
+116
+34
+238
+116
+34
+236
+108
+29
+236
+108
+29
+235
+107
+16
+235
+107
+16
+235
+107
+16
+236
+108
+29
+236
+108
+29
+235
+113
+30
+238
+116
+34
+238
+123
+45
+238
+123
+53
+241
+132
+59
+242
+133
+67
+241
+138
+68
+243
+141
+78
+243
+141
+78
+241
+145
+79
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+86
+243
+141
+78
+241
+138
+68
+241
+132
+59
+238
+123
+53
+239
+117
+44
+238
+116
+34
+236
+108
+29
+236
+108
+29
+235
+107
+16
+235
+107
+16
+236
+108
+29
+238
+116
+34
+239
+117
+44
+238
+123
+45
+241
+132
+59
+241
+138
+68
+243
+141
+78
+241
+145
+86
+249
+152
+92
+241
+153
+96
+241
+153
+96
+241
+153
+96
+249
+152
+92
+241
+145
+86
+243
+141
+78
+241
+138
+68
+241
+132
+59
+238
+123
+53
+238
+123
+45
+238
+116
+34
+235
+113
+30
+236
+108
+29
+236
+108
+29
+235
+113
+30
+238
+116
+34
+238
+123
+45
+238
+123
+53
+241
+132
+59
+241
+138
+68
+241
+145
+79
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+79
+241
+145
+79
+241
+145
+79
+241
+145
+86
+241
+153
+96
+245
+162
+103
+245
+169
+119
+245
+179
+138
+144
+125
+110
+51
+62
+63
+117
+98
+55
+158
+125
+46
+145
+114
+49
+105
+93
+60
+69
+69
+61
+48
+58
+59
+58
+69
+70
+91
+92
+89
+120
+114
+108
+120
+114
+108
+91
+92
+89
+48
+58
+59
+56
+64
+60
+123
+102
+54
+171
+129
+45
+158
+125
+46
+158
+125
+46
+168
+127
+42
+137
+110
+49
+48
+58
+59
+161
+144
+134
+250
+197
+158
+248
+180
+134
+247
+165
+111
+241
+153
+96
+241
+145
+79
+241
+138
+68
+241
+132
+59
+238
+123
+53
+238
+123
+45
+239
+117
+44
+238
+116
+34
+238
+116
+34
+239
+117
+44
+238
+123
+45
+238
+123
+53
+241
+132
+59
+241
+138
+68
+243
+141
+78
+241
+145
+86
+249
+152
+92
+241
+153
+96
+241
+153
+96
+241
+153
+96
+241
+145
+86
+241
+145
+86
+243
+141
+78
+241
+138
+68
+241
+132
+59
+238
+123
+53
+238
+123
+45
+238
+123
+45
+239
+117
+44
+238
+123
+45
+238
+123
+45
+238
+123
+53
+241
+132
+59
+241
+132
+59
+241
+138
+68
+241
+138
+68
+243
+141
+78
+241
+145
+79
+241
+145
+79
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+79
+243
+141
+78
+242
+133
+67
+241
+132
+59
+238
+123
+45
+238
+116
+34
+235
+113
+30
+236
+108
+29
+235
+107
+16
+235
+107
+16
+235
+107
+16
+236
+108
+29
+235
+113
+30
+239
+117
+44
+238
+123
+45
+241
+132
+59
+241
+138
+68
+243
+141
+78
+241
+145
+86
+241
+145
+86
+241
+153
+96
+241
+153
+96
+241
+145
+86
+241
+145
+86
+243
+141
+78
+241
+138
+68
+241
+132
+59
+238
+123
+45
+239
+117
+44
+235
+113
+30
+236
+108
+29
+235
+107
+16
+235
+107
+16
+235
+107
+16
+236
+108
+29
+235
+113
+30
+239
+117
+44
+238
+123
+45
+241
+132
+59
+242
+133
+67
+243
+141
+78
+241
+145
+79
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+79
+241
+145
+79
+243
+141
+78
+243
+141
+78
+243
+141
+78
+243
+141
+78
+241
+138
+68
+241
+138
+68
+241
+138
+68
+241
+138
+68
+241
+138
+68
+241
+138
+68
+242
+133
+67
+241
+132
+59
+238
+123
+53
+238
+123
+45
+238
+116
+34
+236
+108
+29
+235
+107
+16
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+235
+107
+16
+236
+108
+29
+238
+116
+34
+238
+123
+45
+238
+123
+53
+242
+133
+67
+241
+138
+68
+241
+145
+79
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+86
+241
+145
+79
+243
+141
+78
+243
+141
+78
+241
+138
+68
+241
+138
+68
+241
+138
+68
+242
+133
+67
+242
+133
+67
+242
+133
+67
+241
+138
+68
+241
+138
+68
+241
+138
+68
+241
+138
+68
+242
+133
+67
+241
+132
+59
+241
+132
+59
+238
+123
+53
+238
+123
+45
+238
+123
+45
+238
+123
+45
+238
+123
+45
+238
+123
+53
+241
+132
+59
+241
+138
+68
+243
+141
+78
+241
+145
+86
+241
+145
+86
+241
+153
+96
+241
+153
+96
+241
+145
+86
+241
+145
+86
+243
+141
+78
+241
+138
+68
+241
+132
+59
+238
+123
+53
+238
+123
+45
+239
+117
+44
+239
+117
+44
+239
+117
+44
+239
+117
+44
+238
+123
+45
+238
+123
+53
+238
+123
+53
+241
+132
+59
+241
+132
+59
+238
+123
+53
+238
+123
+45
+239
+117
+44
+239
+117
+44
+239
+117
+44
+238
+123
+53
+242
+133
+67
+241
+145
+86
+238
+159
+107
+84
+85
+82
+69
+69
+61
+188
+112
+56
+214
+121
+50
+173
+106
+60
+112
+85
+63
+62
+63
+61
+41
+58
+57
+63
+74
+74
+97
+98
+96
+120
+114
+108
+109
+106
+99
+77
+85
+81
+41
+58
+57
+81
+73
+62
+194
+112
+58
+234
+125
+52
+224
+123
+55
+224
+123
+55
+234
+126
+45
+125
+90
+64
+51
+62
+63
+209
+171
+139
+245
+169
+119
+241
+145
+86
+241
+132
+59
+238
+116
+34
+235
+107
+16
+236
+102
+14
+235
+94
+9
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+237
+95
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+230
+97
+5
+235
+94
+9
+235
+94
+9
+236
+102
+14
+235
+107
+16
+236
+108
+29
+235
+113
+30
+238
+116
+34
+239
+117
+44
+238
+123
+45
+238
+123
+45
+238
+123
+45
+238
+123
+53
+238
+123
+53
+238
+123
+53
+238
+123
+53
+238
+123
+53
+238
+123
+53
+238
+123
+53
+238
+123
+53
+238
+123
+53
+238
+123
+53
+238
+123
+53
+238
+123
+53
+238
+123
+53
+238
+123
+53
+238
+123
+45
+238
+123
+45
+239
+117
+44
+239
+117
+44
+238
+116
+34
+235
+113
+30
+236
+108
+29
+235
+107
+16
+235
+107
+16
+236
+102
+14
+236
+102
+14
+235
+94
+9
+235
+94
+9
+235
+94
+9
+236
+102
+14
+236
+102
+14
+235
+107
+16
+236
+108
+29
+236
+108
+29
+238
+116
+34
+239
+117
+44
+239
+117
+44
+238
+123
+45
+238
+123
+45
+238
+123
+53
+238
+123
+53
+238
+123
+53
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+238
+123
+53
+238
+123
+53
+238
+123
+45
+239
+117
+44
+238
+116
+34
+236
+108
+29
+235
+107
+16
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+235
+107
+16
+236
+108
+29
+235
+113
+30
+238
+116
+34
+238
+123
+45
+238
+123
+53
+238
+123
+53
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+238
+123
+53
+238
+123
+45
+239
+117
+44
+238
+116
+34
+236
+108
+29
+235
+107
+16
+235
+107
+16
+236
+102
+14
+236
+102
+14
+235
+107
+16
+236
+108
+29
+236
+108
+29
+238
+116
+34
+239
+117
+44
+238
+123
+45
+238
+123
+53
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+238
+123
+53
+238
+123
+53
+238
+123
+53
+238
+123
+53
+241
+132
+59
+241
+138
+68
+241
+145
+86
+238
+159
+107
+234
+168
+124
+84
+85
+82
+83
+78
+61
+171
+129
+45
+158
+125
+46
+168
+127
+42
+168
+127
+42
+158
+125
+46
+129
+106
+52
+100
+89
+56
+83
+78
+61
+75
+74
+61
+69
+69
+61
+83
+78
+61
+105
+93
+60
+152
+119
+47
+168
+127
+42
+158
+125
+46
+158
+125
+46
+161
+127
+40
+168
+127
+42
+75
+74
+61
+63
+74
+74
+236
+186
+153
+245
+179
+138
+238
+159
+107
+241
+145
+86
+241
+138
+68
+241
+132
+59
+238
+123
+45
+238
+116
+34
+235
+113
+30
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+238
+116
+34
+239
+117
+44
+238
+123
+45
+238
+123
+53
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+238
+123
+53
+238
+123
+53
+238
+123
+45
+239
+117
+44
+238
+116
+34
+235
+113
+30
+236
+108
+29
+236
+108
+29
+236
+108
+29
+235
+113
+30
+238
+116
+34
+238
+116
+34
+239
+117
+44
+238
+123
+45
+238
+123
+45
+238
+123
+53
+238
+123
+53
+238
+123
+53
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+238
+123
+53
+238
+123
+45
+239
+117
+44
+238
+116
+34
+235
+113
+30
+236
+108
+29
+236
+102
+14
+236
+102
+14
+236
+102
+14
+235
+94
+9
+236
+102
+14
+236
+102
+14
+235
+107
+16
+236
+108
+29
+235
+113
+30
+238
+116
+34
+238
+123
+45
+238
+123
+53
+238
+123
+53
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+238
+123
+53
+238
+123
+53
+238
+123
+45
+238
+116
+34
+235
+113
+30
+236
+108
+29
+235
+107
+16
+236
+102
+14
+236
+102
+14
+235
+94
+9
+236
+102
+14
+236
+102
+14
+235
+107
+16
+236
+108
+29
+235
+113
+30
+238
+116
+34
+238
+123
+45
+238
+123
+53
+238
+123
+53
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+238
+123
+53
+238
+123
+53
+238
+123
+53
+238
+123
+53
+238
+123
+53
+238
+123
+45
+238
+123
+45
+238
+123
+45
+238
+123
+45
+238
+123
+45
+238
+123
+45
+238
+123
+45
+238
+123
+45
+239
+117
+44
+239
+117
+44
+238
+116
+34
+236
+108
+29
+236
+108
+29
+235
+107
+16
+236
+102
+14
+235
+94
+9
+235
+94
+9
+235
+94
+9
+235
+94
+9
+236
+102
+14
+236
+102
+14
+235
+107
+16
+236
+108
+29
+238
+116
+34
+239
+117
+44
+238
+123
+45
+238
+123
+53
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+238
+123
+53
+238
+123
+53
+238
+123
+53
+238
+123
+45
+238
+123
+45
+238
+123
+45
+238
+123
+45
+239
+117
+44
+239
+117
+44
+239
+117
+44
+238
+123
+45
+238
+123
+45
+238
+123
+45
+238
+123
+45
+238
+123
+45
+239
+117
+44
+239
+117
+44
+238
+116
+34
+235
+113
+30
+236
+108
+29
+236
+108
+29
+235
+113
+30
+238
+116
+34
+239
+117
+44
+238
+123
+45
+238
+123
+53
+238
+123
+53
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+241
+132
+59
+238
+123
+53
+238
+123
+45
+239
+117
+44
+238
+116
+34
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+235
+113
+30
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+235
+113
+30
+236
+108
+29
+235
+113
+30
+238
+116
+34
+238
+123
+45
+241
+132
+59
+241
+145
+86
+204
+141
+99
+41
+58
+57
+155
+100
+63
+234
+126
+45
+227
+126
+50
+227
+126
+50
+234
+125
+52
+209
+117
+53
+155
+100
+63
+118
+86
+65
+89
+75
+66
+81
+73
+62
+81
+73
+62
+106
+82
+65
+155
+100
+63
+214
+121
+50
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+194
+112
+58
+56
+64
+60
+109
+106
+99
+245
+179
+138
+245
+162
+103
+241
+138
+68
+238
+123
+45
+235
+113
+30
+236
+102
+14
+235
+94
+9
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+235
+94
+9
+235
+94
+9
+235
+94
+9
+236
+102
+14
+236
+102
+14
+235
+107
+16
+235
+107
+16
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+235
+113
+30
+235
+113
+30
+235
+113
+30
+235
+113
+30
+235
+113
+30
+235
+113
+30
+235
+113
+30
+235
+113
+30
+235
+113
+30
+235
+113
+30
+235
+113
+30
+235
+113
+30
+235
+113
+30
+235
+113
+30
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+235
+107
+16
+236
+102
+14
+236
+102
+14
+236
+102
+14
+235
+94
+9
+235
+94
+9
+235
+94
+9
+230
+97
+5
+230
+97
+5
+235
+94
+9
+235
+94
+9
+235
+94
+9
+235
+94
+9
+236
+102
+14
+236
+102
+14
+235
+107
+16
+236
+108
+29
+236
+108
+29
+236
+108
+29
+235
+113
+30
+235
+113
+30
+235
+113
+30
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+235
+113
+30
+236
+108
+29
+236
+108
+29
+235
+107
+16
+236
+102
+14
+236
+102
+14
+235
+94
+9
+235
+94
+9
+235
+94
+9
+235
+94
+9
+235
+94
+9
+235
+94
+9
+236
+102
+14
+235
+107
+16
+236
+108
+29
+236
+108
+29
+235
+113
+30
+238
+116
+34
+238
+116
+34
+239
+117
+44
+239
+117
+44
+239
+117
+44
+238
+116
+34
+238
+116
+34
+235
+113
+30
+236
+108
+29
+236
+108
+29
+235
+107
+16
+236
+102
+14
+236
+102
+14
+235
+94
+9
+235
+94
+9
+235
+94
+9
+235
+94
+9
+236
+102
+14
+236
+102
+14
+235
+107
+16
+236
+108
+29
+236
+108
+29
+235
+113
+30
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+235
+113
+30
+235
+113
+30
+238
+116
+34
+238
+123
+45
+238
+123
+53
+241
+138
+68
+241
+145
+86
+238
+159
+107
+89
+84
+82
+75
+74
+61
+168
+127
+42
+168
+127
+42
+158
+125
+46
+158
+125
+46
+161
+127
+40
+168
+127
+42
+171
+129
+45
+168
+127
+42
+158
+125
+46
+158
+125
+46
+168
+127
+42
+171
+129
+45
+168
+127
+42
+158
+125
+46
+158
+125
+46
+168
+127
+42
+171
+129
+45
+95
+87
+59
+48
+58
+59
+167
+142
+123
+245
+179
+138
+238
+159
+107
+241
+145
+86
+242
+133
+67
+238
+123
+45
+238
+116
+34
+236
+108
+29
+236
+108
+29
+235
+107
+16
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+235
+107
+16
+236
+108
+29
+236
+108
+29
+235
+113
+30
+238
+116
+34
+238
+116
+34
+239
+117
+44
+239
+117
+44
+239
+117
+44
+238
+116
+34
+238
+116
+34
+235
+113
+30
+236
+108
+29
+236
+108
+29
+235
+107
+16
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+235
+107
+16
+235
+107
+16
+236
+108
+29
+236
+108
+29
+236
+108
+29
+235
+113
+30
+235
+113
+30
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+235
+113
+30
+236
+108
+29
+235
+107
+16
+236
+102
+14
+236
+102
+14
+235
+94
+9
+235
+94
+9
+235
+94
+9
+235
+94
+9
+235
+94
+9
+235
+94
+9
+235
+94
+9
+236
+102
+14
+235
+107
+16
+236
+108
+29
+236
+108
+29
+235
+113
+30
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+235
+113
+30
+236
+108
+29
+236
+108
+29
+235
+107
+16
+236
+102
+14
+235
+94
+9
+235
+94
+9
+235
+94
+9
+235
+94
+9
+235
+94
+9
+235
+94
+9
+235
+94
+9
+236
+102
+14
+236
+102
+14
+235
+107
+16
+236
+108
+29
+235
+113
+30
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+235
+113
+30
+235
+113
+30
+235
+113
+30
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+235
+107
+16
+235
+107
+16
+236
+102
+14
+236
+102
+14
+235
+94
+9
+235
+94
+9
+235
+94
+9
+230
+97
+5
+235
+94
+9
+235
+94
+9
+235
+94
+9
+236
+102
+14
+236
+102
+14
+235
+107
+16
+236
+108
+29
+235
+113
+30
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+235
+113
+30
+235
+113
+30
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+236
+108
+29
+235
+107
+16
+235
+107
+16
+236
+102
+14
+236
+102
+14
+236
+102
+14
+235
+107
+16
+236
+108
+29
+236
+108
+29
+235
+113
+30
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+238
+116
+34
+235
+113
+30
+236
+108
+29
+236
+108
+29
+235
+107
+16
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+235
+107
+16
+235
+107
+16
+236
+108
+29
+236
+108
+29
+235
+107
+16
+235
+107
+16
+235
+107
+16
+236
+108
+29
+235
+113
+30
+239
+117
+44
+241
+132
+59
+241
+145
+79
+204
+141
+99
+48
+58
+59
+139
+96
+61
+234
+126
+45
+224
+123
+55
+224
+123
+55
+224
+123
+55
+227
+126
+50
+234
+126
+45
+234
+126
+45
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+126
+45
+234
+126
+45
+227
+126
+50
+224
+123
+55
+224
+123
+55
+234
+125
+52
+214
+121
+50
+81
+73
+62
+58
+69
+70
+219
+170
+138
+245
+169
+119
+241
+145
+86
+241
+132
+59
+239
+117
+44
+236
+108
+29
+236
+102
+14
+235
+94
+9
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+230
+97
+5
+230
+97
+5
+235
+94
+9
+230
+97
+5
+229
+102
+7
+229
+102
+7
+236
+102
+14
+236
+102
+14
+224
+98
+18
+224
+98
+18
+224
+98
+18
+236
+102
+14
+224
+98
+18
+236
+102
+14
+236
+102
+14
+224
+98
+18
+224
+98
+18
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+224
+98
+18
+236
+102
+14
+236
+102
+14
+229
+102
+7
+229
+102
+7
+230
+97
+5
+235
+94
+9
+235
+94
+9
+230
+97
+5
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+230
+97
+5
+235
+94
+9
+230
+97
+5
+235
+94
+9
+235
+94
+9
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+236
+102
+14
+224
+98
+18
+236
+102
+14
+235
+94
+9
+235
+94
+9
+235
+94
+9
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+230
+97
+5
+235
+94
+9
+230
+97
+5
+229
+102
+7
+236
+102
+14
+236
+102
+14
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+236
+102
+14
+224
+98
+18
+236
+102
+14
+229
+102
+7
+230
+97
+5
+235
+94
+9
+235
+94
+9
+230
+97
+5
+231
+91
+2
+230
+97
+5
+235
+94
+9
+235
+94
+9
+235
+94
+9
+230
+97
+5
+229
+102
+7
+236
+102
+14
+236
+102
+14
+236
+102
+14
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+236
+102
+14
+224
+98
+18
+236
+102
+14
+235
+107
+16
+236
+108
+29
+239
+117
+44
+234
+125
+52
+231
+136
+72
+241
+153
+96
+162
+125
+96
+48
+58
+59
+95
+87
+59
+158
+125
+46
+171
+129
+45
+168
+127
+42
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+158
+125
+46
+168
+127
+42
+171
+129
+45
+158
+125
+46
+95
+87
+59
+48
+58
+59
+124
+111
+99
+245
+179
+138
+247
+165
+111
+241
+145
+86
+241
+132
+59
+238
+123
+45
+238
+116
+34
+236
+108
+29
+224
+98
+18
+229
+102
+7
+230
+97
+5
+235
+94
+9
+235
+94
+9
+230
+97
+5
+230
+97
+5
+230
+97
+5
+235
+94
+9
+230
+97
+5
+229
+102
+7
+236
+102
+14
+236
+102
+14
+236
+102
+14
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+236
+102
+14
+236
+102
+14
+236
+102
+14
+235
+94
+9
+230
+97
+5
+235
+94
+9
+235
+94
+9
+235
+94
+9
+235
+94
+9
+235
+94
+9
+236
+102
+14
+236
+102
+14
+236
+102
+14
+224
+98
+18
+224
+98
+18
+236
+102
+14
+236
+102
+14
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+224
+98
+18
+236
+102
+14
+229
+102
+7
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+231
+91
+2
+231
+91
+2
+231
+91
+2
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+229
+102
+7
+236
+102
+14
+224
+98
+18
+236
+102
+14
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+236
+102
+14
+224
+98
+18
+236
+102
+14
+229
+102
+7
+230
+97
+5
+235
+94
+9
+230
+97
+5
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+230
+97
+5
+230
+97
+5
+235
+94
+9
+235
+94
+9
+229
+102
+7
+236
+102
+14
+236
+102
+14
+236
+102
+14
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+236
+102
+14
+235
+107
+16
+236
+102
+14
+224
+98
+18
+224
+98
+18
+236
+102
+14
+224
+98
+18
+224
+98
+18
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+229
+102
+7
+236
+102
+14
+235
+94
+9
+230
+97
+5
+235
+94
+9
+235
+94
+9
+230
+97
+5
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+235
+94
+9
+230
+97
+5
+230
+97
+5
+229
+102
+7
+236
+102
+14
+224
+98
+18
+236
+102
+14
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+236
+102
+14
+236
+102
+14
+236
+102
+14
+224
+98
+18
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+236
+102
+14
+224
+98
+18
+236
+102
+14
+236
+102
+14
+236
+102
+14
+235
+94
+9
+235
+94
+9
+235
+94
+9
+235
+94
+9
+235
+94
+9
+236
+102
+14
+236
+102
+14
+224
+98
+18
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+235
+107
+16
+236
+102
+14
+236
+102
+14
+236
+102
+14
+229
+102
+7
+230
+97
+5
+235
+94
+9
+235
+94
+9
+235
+94
+9
+235
+94
+9
+235
+94
+9
+230
+97
+5
+235
+94
+9
+236
+102
+14
+236
+102
+14
+236
+102
+14
+229
+102
+7
+230
+97
+5
+229
+102
+7
+224
+98
+18
+236
+108
+29
+238
+116
+34
+238
+123
+53
+243
+141
+78
+241
+153
+96
+99
+90
+79
+56
+64
+60
+155
+100
+63
+234
+126
+45
+234
+126
+45
+227
+126
+50
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+227
+126
+50
+227
+126
+50
+224
+123
+55
+224
+123
+55
+227
+126
+50
+227
+126
+50
+234
+126
+45
+194
+112
+58
+81
+73
+62
+48
+58
+59
+178
+146
+122
+249
+174
+124
+241
+153
+96
+231
+136
+72
+234
+125
+52
+238
+116
+34
+235
+107
+16
+229
+102
+7
+235
+94
+9
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+229
+102
+7
+236
+102
+14
+235
+113
+30
+239
+117
+44
+230
+128
+60
+236
+147
+85
+238
+159
+107
+139
+115
+96
+48
+58
+59
+69
+69
+61
+111
+94
+57
+145
+114
+49
+158
+125
+46
+168
+127
+42
+171
+129
+45
+168
+127
+42
+168
+127
+42
+168
+127
+42
+168
+127
+42
+171
+129
+45
+168
+127
+42
+152
+119
+47
+117
+98
+55
+69
+69
+61
+48
+58
+59
+144
+125
+110
+240
+181
+138
+247
+165
+111
+236
+147
+85
+242
+133
+67
+238
+123
+45
+235
+113
+30
+235
+107
+16
+236
+102
+14
+230
+97
+5
+230
+97
+5
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+230
+97
+5
+229
+102
+7
+235
+107
+16
+235
+113
+30
+238
+123
+45
+242
+133
+67
+241
+153
+96
+214
+151
+109
+99
+90
+79
+48
+58
+59
+95
+78
+64
+155
+100
+63
+209
+117
+53
+227
+126
+50
+234
+125
+52
+234
+125
+52
+234
+125
+52
+234
+125
+52
+234
+125
+52
+234
+126
+45
+234
+126
+45
+227
+126
+50
+194
+112
+58
+125
+90
+64
+56
+64
+60
+58
+69
+70
+178
+146
+122
+250
+176
+132
+238
+159
+107
+241
+145
+79
+234
+125
+52
+239
+117
+44
+236
+108
+29
+224
+98
+18
+230
+97
+5
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+231
+91
+2
+226
+93
+0
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+231
+91
+2
+226
+93
+0
+226
+93
+0
+226
+93
+0
+231
+91
+2
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+226
+93
+0
+226
+93
+0
+231
+91
+2
+226
+93
+0
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+231
+91
+2
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+231
+91
+2
+230
+97
+5
+229
+102
+7
+223
+103
+18
+226
+110
+35
+234
+125
+52
+231
+136
+72
+241
+153
+96
+245
+169
+119
+178
+146
+122
+101
+100
+92
+48
+58
+59
+56
+64
+60
+69
+69
+61
+95
+87
+59
+111
+94
+57
+123
+102
+54
+129
+106
+52
+129
+106
+52
+123
+102
+54
+105
+93
+60
+88
+82
+59
+62
+63
+61
+48
+58
+59
+91
+92
+89
+186
+157
+134
+245
+179
+138
+238
+159
+107
+236
+147
+85
+230
+128
+60
+234
+125
+52
+226
+110
+35
+223
+103
+18
+224
+98
+18
+230
+97
+5
+226
+93
+0
+226
+93
+0
+231
+91
+2
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+231
+91
+2
+226
+93
+0
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+226
+93
+0
+226
+93
+0
+226
+93
+0
+226
+93
+0
+231
+91
+2
+226
+93
+0
+226
+93
+0
+231
+91
+2
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+226
+93
+0
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+226
+93
+0
+226
+93
+0
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+226
+93
+0
+226
+93
+0
+226
+93
+0
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+230
+97
+5
+224
+98
+18
+236
+108
+29
+239
+117
+44
+230
+123
+57
+243
+141
+78
+238
+159
+107
+234
+168
+124
+158
+130
+108
+76
+78
+76
+41
+58
+57
+62
+63
+61
+95
+78
+64
+125
+90
+64
+146
+97
+64
+163
+104
+61
+173
+106
+60
+163
+104
+61
+155
+100
+63
+125
+90
+64
+95
+78
+64
+56
+64
+60
+43
+57
+62
+124
+111
+99
+209
+171
+139
+234
+168
+124
+238
+159
+107
+241
+145
+79
+230
+128
+60
+239
+117
+44
+236
+108
+29
+236
+102
+14
+229
+102
+7
+230
+97
+5
+226
+93
+0
+226
+93
+0
+226
+93
+0
+226
+93
+0
+226
+93
+0
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+231
+91
+2
+226
+93
+0
+226
+93
+0
+226
+93
+0
+226
+93
+0
+226
+93
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+230
+97
+5
+230
+97
+5
+224
+98
+18
+236
+108
+29
+226
+110
+35
+230
+123
+57
+231
+136
+72
+241
+153
+96
+238
+159
+107
+240
+181
+138
+203
+161
+131
+150
+125
+114
+101
+100
+92
+76
+78
+76
+55
+66
+67
+48
+58
+59
+48
+58
+59
+48
+58
+59
+48
+58
+59
+58
+69
+70
+84
+85
+82
+124
+111
+99
+178
+146
+122
+240
+181
+138
+234
+168
+124
+238
+159
+107
+236
+147
+85
+230
+128
+60
+234
+125
+52
+226
+110
+35
+223
+103
+18
+224
+98
+18
+230
+97
+5
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+230
+97
+5
+224
+98
+18
+223
+103
+18
+226
+110
+35
+225
+124
+48
+230
+128
+60
+236
+147
+85
+241
+153
+96
+234
+168
+124
+230
+173
+136
+186
+157
+134
+133
+120
+107
+91
+92
+89
+63
+74
+74
+51
+62
+63
+48
+58
+59
+48
+58
+59
+48
+58
+59
+51
+62
+63
+63
+74
+74
+91
+92
+89
+144
+125
+110
+203
+161
+131
+240
+181
+138
+245
+169
+119
+241
+153
+96
+241
+145
+79
+230
+128
+60
+225
+124
+48
+226
+110
+35
+223
+103
+18
+224
+98
+18
+230
+97
+5
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+230
+97
+5
+224
+98
+18
+223
+103
+18
+226
+110
+35
+239
+117
+44
+230
+123
+57
+231
+136
+72
+236
+147
+85
+238
+159
+107
+245
+169
+119
+234
+168
+124
+240
+181
+138
+239
+182
+144
+236
+186
+153
+250
+197
+158
+250
+197
+158
+250
+197
+158
+251
+192
+154
+236
+186
+153
+239
+182
+144
+245
+179
+138
+234
+168
+124
+238
+159
+107
+241
+153
+96
+231
+136
+72
+230
+128
+60
+225
+124
+48
+226
+110
+35
+223
+103
+18
+224
+98
+18
+230
+97
+5
+230
+97
+5
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+230
+97
+5
+224
+98
+18
+223
+103
+18
+226
+110
+35
+225
+124
+48
+230
+128
+60
+231
+136
+72
+241
+153
+96
+238
+159
+107
+234
+168
+124
+240
+181
+138
+239
+182
+144
+236
+186
+153
+251
+192
+154
+250
+197
+158
+250
+197
+158
+250
+197
+158
+236
+186
+153
+239
+182
+144
+240
+181
+138
+234
+168
+124
+245
+169
+119
+238
+159
+107
+236
+147
+85
+231
+136
+72
+230
+123
+57
+239
+117
+44
+226
+110
+35
+223
+103
+18
+224
+98
+18
+230
+97
+5
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+225
+92
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+220
+93
+11
+220
+93
+11
+224
+98
+18
+223
+103
+18
+226
+110
+35
+226
+110
+35
+225
+124
+48
+230
+128
+60
+231
+136
+72
+236
+147
+85
+241
+153
+96
+238
+159
+107
+238
+159
+107
+234
+168
+124
+234
+168
+124
+234
+168
+124
+234
+168
+124
+234
+168
+124
+238
+159
+107
+238
+159
+107
+241
+153
+96
+236
+147
+85
+231
+136
+72
+230
+128
+60
+230
+123
+57
+226
+110
+35
+226
+110
+35
+223
+103
+18
+224
+98
+18
+220
+93
+11
+220
+93
+11
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+220
+93
+11
+220
+93
+11
+224
+98
+18
+223
+103
+18
+226
+110
+35
+225
+124
+48
+230
+123
+57
+230
+128
+60
+231
+136
+72
+236
+147
+85
+241
+153
+96
+238
+159
+107
+238
+159
+107
+234
+168
+124
+234
+168
+124
+234
+168
+124
+234
+168
+124
+234
+168
+124
+238
+159
+107
+238
+159
+107
+241
+153
+96
+236
+147
+85
+231
+136
+72
+230
+128
+60
+225
+124
+48
+226
+110
+35
+226
+110
+35
+223
+103
+18
+224
+98
+18
+220
+93
+11
+220
+93
+11
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+220
+93
+11
+220
+93
+11
+220
+93
+11
+224
+98
+18
+223
+103
+18
+226
+110
+35
+226
+110
+35
+225
+124
+48
+230
+128
+60
+230
+128
+60
+231
+136
+72
+231
+136
+72
+236
+147
+85
+236
+147
+85
+236
+147
+85
+236
+147
+85
+236
+147
+85
+231
+136
+72
+231
+136
+72
+231
+136
+72
+230
+128
+60
+227
+126
+50
+225
+124
+48
+226
+110
+35
+223
+103
+18
+223
+103
+18
+224
+98
+18
+220
+93
+11
+220
+93
+11
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+218
+87
+5
+220
+93
+11
+220
+93
+11
+224
+98
+18
+223
+103
+18
+226
+110
+35
+226
+110
+35
+225
+124
+48
+230
+123
+57
+230
+128
+60
+231
+136
+72
+231
+136
+72
+231
+136
+72
+236
+147
+85
+236
+147
+85
+236
+147
+85
+236
+147
+85
+236
+147
+85
+231
+136
+72
+231
+136
+72
+230
+128
+60
+230
+123
+57
+225
+124
+48
+226
+110
+35
+226
+110
+35
+223
+103
+18
+224
+98
+18
+220
+93
+11
+220
+93
+11
+220
+93
+11
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+217
+86
+3
+221
+89
+0
+221
+89
+0
+217
+86
+3
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+217
+86
+3
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+217
+86
+3
+221
+89
+0
+217
+86
+3
+217
+86
+3
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+217
+86
+3
+221
+89
+0
+217
+86
+3
+217
+86
+3
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+217
+86
+3
+221
+89
+0
+217
+86
+3
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+217
+86
+3
+221
+89
+0
+221
+89
+0
+217
+86
+3
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+218
+87
+5
+218
+87
+5
+220
+93
+11
+220
+93
+11
+224
+98
+18
+223
+103
+18
+223
+103
+18
+226
+110
+35
+226
+110
+35
+225
+124
+48
+225
+124
+48
+225
+124
+48
+224
+123
+55
+224
+123
+55
+224
+123
+55
+230
+123
+57
+224
+123
+55
+224
+123
+55
+225
+124
+48
+225
+124
+48
+226
+110
+35
+226
+110
+35
+223
+103
+18
+223
+103
+18
+224
+98
+18
+220
+93
+11
+220
+93
+11
+218
+87
+5
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+217
+86
+3
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+217
+86
+3
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+221
+89
+0
+221
+89
+0
+217
+86
+3
+221
+89
+0
+221
+89
+0
+217
+86
+3
+221
+89
+0
+221
+89
+0
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+217
+86
+3
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+221
+89
+0
+221
+89
+0
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+217
+86
+3
+221
+89
+0
+221
+89
+0
+217
+86
+3
+218
+87
+5
+218
+87
+5
+220
+93
+11
+220
+93
+11
+220
+93
+11
+224
+98
+18
+223
+103
+18
+226
+110
+35
+226
+110
+35
+226
+110
+35
+225
+124
+48
+225
+124
+48
+224
+123
+55
+230
+123
+57
+230
+123
+57
+230
+123
+57
+230
+123
+57
+230
+123
+57
+225
+124
+48
+225
+124
+48
+226
+110
+35
+226
+110
+35
+226
+110
+35
+223
+103
+18
+224
+98
+18
+224
+98
+18
+220
+93
+11
+220
+93
+11
+218
+87
+5
+218
+87
+5
+217
+86
+3
+217
+86
+3
+221
+89
+0
+221
+89
+0
+217
+86
+3
+217
+86
+3
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+221
+89
+0
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+218
+87
+5
+218
+87
+5
+218
+87
+5
+220
+93
+11
+220
+93
+11
+224
+98
+18
+224
+98
+18
+224
+98
+18
+223
+103
+18
+226
+110
+35
+226
+110
+35
+226
+110
+35
+226
+110
+35
+226
+110
+35
+226
+110
+35
+226
+110
+35
+226
+110
+35
+226
+110
+35
+223
+103
+18
+223
+103
+18
+224
+98
+18
+224
+98
+18
+220
+93
+11
+220
+93
+11
+218
+87
+5
+218
+87
+5
+218
+87
+5
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+218
+87
+5
+218
+87
+5
+218
+87
+5
+218
+87
+5
+220
+93
+11
+220
+93
+11
+224
+98
+18
+224
+98
+18
+223
+103
+18
+223
+103
+18
+226
+110
+35
+226
+110
+35
+226
+110
+35
+226
+110
+35
+226
+110
+35
+226
+110
+35
+226
+110
+35
+226
+110
+35
+226
+110
+35
+223
+103
+18
+224
+98
+18
+224
+98
+18
+220
+93
+11
+220
+93
+11
+220
+93
+11
+218
+87
+5
+218
+87
+5
+218
+87
+5
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+218
+87
+5
+218
+87
+5
+218
+87
+5
+218
+87
+5
+218
+87
+5
+220
+93
+11
+220
+93
+11
+220
+93
+11
+220
+93
+11
+224
+98
+18
+224
+98
+18
+224
+98
+18
+224
+98
+18
+224
+98
+18
+224
+98
+18
+220
+93
+11
+224
+98
+18
+220
+93
+11
+220
+93
+11
+220
+93
+11
+218
+87
+5
+218
+87
+5
+218
+87
+5
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+218
+87
+5
+217
+86
+3
+218
+87
+5
+218
+87
+5
+218
+87
+5
+220
+93
+11
+220
+93
+11
+220
+93
+11
+220
+93
+11
+220
+93
+11
+224
+98
+18
+224
+98
+18
+224
+98
+18
+224
+98
+18
+224
+98
+18
+220
+93
+11
+220
+93
+11
+220
+93
+11
+220
+93
+11
+220
+93
+11
+218
+87
+5
+218
+87
+5
+218
+87
+5
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+218
+87
+5
+218
+87
+5
+218
+87
+5
+218
+87
+5
+218
+87
+5
+218
+87
+5
+218
+87
+5
+218
+87
+5
+218
+87
+5
+218
+87
+5
+218
+87
+5
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+218
+87
+5
+218
+87
+5
+218
+87
+5
+218
+87
+5
+218
+87
+5
+218
+87
+5
+218
+87
+5
+218
+87
+5
+218
+87
+5
+218
+87
+5
+218
+87
+5
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+217
+86
+3
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+217
+86
+3
+217
+86
+3
+217
+86
+3
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+217
+86
+3
+217
+86
+3
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+217
+86
+3
+217
+86
+3
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+217
+86
+3
+217
+86
+3
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+217
+86
+3
+217
+86
+3
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+217
+86
+3
+217
+86
+3
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+217
+86
+3
+217
+86
+3
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+217
+86
+3
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+217
+86
+3
+217
+86
+3
+214
+84
+0
+214
+84
+0
+214
+84
+0
+217
+86
+3
+217
+86
+3
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+217
+86
+3
+217
+86
+3
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
+214
+84
+0
diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0001-OMAP3-PM-Adding-T2-enabling-of-smartreflex.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0001-OMAP3-PM-Adding-T2-enabling-of-smartreflex.patch
new file mode 100644
index 00000000..eafc4d30
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0001-OMAP3-PM-Adding-T2-enabling-of-smartreflex.patch
@@ -0,0 +1,60 @@
+From 8548db6d3cf115b29142f803d701122dc4cbb775 Mon Sep 17 00:00:00 2001
+From: Thara Gopinath <thara@ti.com>
+Date: Fri, 31 Dec 2010 13:35:02 +0530
+Subject: [PATCH 01/20] OMAP3: PM: Adding T2 enabling of smartreflex
+
+The smartreflex bit on twl4030 needs to be enabled by default irrespective
+of whether smartreflex module is enabled on the OMAP side or not.
+This is because without this bit enabled the voltage scaling through
+vp forceupdate does not function properly on OMAP3.
+
+Signed-off-by: Thara Gopinath <thara@ti.com>
+---
+ arch/arm/mach-omap2/omap_twl.c | 16 ++++++++++++++++
+ 1 files changed, 16 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c
+index 15f8c6c..a59f36b 100644
+--- a/arch/arm/mach-omap2/omap_twl.c
++++ b/arch/arm/mach-omap2/omap_twl.c
+@@ -58,7 +58,9 @@
+ static bool is_offset_valid;
+ static u8 smps_offset;
+
++#define TWL4030_DCDC_GLOBAL_CFG 0x06
+ #define REG_SMPS_OFFSET 0xE0
++#define SMARTREFLEX_ENABLE BIT(3)
+
+ unsigned long twl4030_vsel_to_uv(const u8 vsel)
+ {
+@@ -256,6 +258,7 @@ int __init omap4_twl_init(void)
+ int __init omap3_twl_init(void)
+ {
+ struct voltagedomain *voltdm;
++ u8 temp;
+
+ if (!cpu_is_omap34xx())
+ return -ENODEV;
+@@ -267,6 +270,19 @@ int __init omap3_twl_init(void)
+ omap3_core_volt_info.vp_vddmax = OMAP3630_VP2_VLIMITTO_VDDMAX;
+ }
+
++ /*
++ * The smartreflex bit on twl4030 needs to be enabled by
++ * default irrespective of whether smartreflex module is
++ * enabled on the OMAP side or not. This is because without
++ * this bit enabled the voltage scaling through
++ * vp forceupdate does not function properly on OMAP3.
++ */
++ twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &temp,
++ TWL4030_DCDC_GLOBAL_CFG);
++ temp |= SMARTREFLEX_ENABLE;
++ twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, temp,
++ TWL4030_DCDC_GLOBAL_CFG);
++
+ voltdm = omap_voltage_domain_lookup("mpu");
+ omap_voltage_register_pmic(voltdm, &omap3_mpu_volt_info);
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0002-OMAP-CPUfreq-ensure-driver-initializes-after-cpufreq.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0002-OMAP-CPUfreq-ensure-driver-initializes-after-cpufreq.patch
new file mode 100644
index 00000000..b6512a5e
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0002-OMAP-CPUfreq-ensure-driver-initializes-after-cpufreq.patch
@@ -0,0 +1,27 @@
+From e446cbf4aa8359d58180a81282df70045b8a41c1 Mon Sep 17 00:00:00 2001
+From: Peter 'p2' De Schrijver <peter.de-schrijver@nokia.com>
+Date: Wed, 11 Aug 2010 17:02:43 -0700
+Subject: [PATCH 02/20] OMAP: CPUfreq: ensure driver initializes after cpufreq framework and governors
+
+Signed-off-by: Peter 'p2' De Schrijver <peter.de-schrijver@nokia.com>
+Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
+---
+ arch/arm/plat-omap/cpu-omap.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
+index 11c54ec..79d2155 100644
+--- a/arch/arm/plat-omap/cpu-omap.c
++++ b/arch/arm/plat-omap/cpu-omap.c
+@@ -160,7 +160,7 @@ static int __init omap_cpufreq_init(void)
+ return cpufreq_register_driver(&omap_driver);
+ }
+
+-arch_initcall(omap_cpufreq_init);
++late_initcall(omap_cpufreq_init);
+
+ /*
+ * if ever we want to remove this, upon cleanup call:
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0003-OMAP-CPUfreq-ensure-policy-is-fully-initialized.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0003-OMAP-CPUfreq-ensure-policy-is-fully-initialized.patch
new file mode 100644
index 00000000..c6826e3c
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0003-OMAP-CPUfreq-ensure-policy-is-fully-initialized.patch
@@ -0,0 +1,31 @@
+From 647691beb64312327646a84dc161faf35935e7f7 Mon Sep 17 00:00:00 2001
+From: Kevin Hilman <khilman@deeprootsystems.com>
+Date: Wed, 11 Aug 2010 17:05:38 -0700
+Subject: [PATCH 03/20] OMAP: CPUfreq: ensure policy is fully initialized
+
+Ensure policy min/max/cur values are initialized when OMAP
+CPUfreq driver starts.
+
+Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
+---
+ arch/arm/plat-omap/cpu-omap.c | 4 ++++
+ 1 files changed, 4 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
+index 79d2155..bfa063b 100644
+--- a/arch/arm/plat-omap/cpu-omap.c
++++ b/arch/arm/plat-omap/cpu-omap.c
+@@ -126,6 +126,10 @@ static int __init omap_cpu_init(struct cpufreq_policy *policy)
+ VERY_HI_RATE) / 1000;
+ }
+
++ policy->min = policy->cpuinfo.min_freq;
++ policy->max = policy->cpuinfo.max_freq;
++ policy->cur = omap_getspeed(0);
++
+ /* FIXME: what's the actual transition time? */
+ policy->cpuinfo.transition_latency = 300 * 1000;
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0004-OMAP3-PM-CPUFreq-driver-for-OMAP3.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0004-OMAP3-PM-CPUFreq-driver-for-OMAP3.patch
new file mode 100644
index 00000000..0371bc3a
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0004-OMAP3-PM-CPUFreq-driver-for-OMAP3.patch
@@ -0,0 +1,269 @@
+From f6b96e3b9e31da193189d92320b3dd9fac7c9ba9 Mon Sep 17 00:00:00 2001
+From: Rajendra Nayak <rnayak@ti.com>
+Date: Mon, 10 Nov 2008 17:00:25 +0530
+Subject: [PATCH 04/20] OMAP3 PM: CPUFreq driver for OMAP3
+
+CPUFreq driver for OMAP3
+
+With additional fixes and cleanups from Tero Kristo:
+- Fix rate calculation bug in omap3_select_table_rate
+- Refreshed DVFS VDD1 control against latest clock fw
+
+Signed-off-by: Tero Kristo <tero.kristo@nokia.com>
+Signed-off-by: Rajendra Nayak <rnayak@ti.com>
+
+OMAP3: PM: CPUFreq: Fix omap_getspeed.
+
+Signed-off-by: Peter 'p2' De Schrijver <peter.de-schrijver@nokia.com>
+
+Make sure omap cpufreq driver initializes after cpufreq framework and governors
+
+Signed-off-by: Peter 'p2' De Schrijver <peter.de-schrijver@nokia.com>
+
+merge: CPUFreq: remove obsolete funcs
+
+OMAP3 clock: Update cpufreq driver
+
+This patch removes all refrences to virtual clock
+nodes in CPUFreq driver.
+
+Signed-off-by: Rajendra Nayak <rnayak@ti.com>
+Signed-off-by: Tero Kristo <tero.kristo@nokia.com>
+Signed-off-by: Jean Pihet <jpihet@mvista.com>
+
+PM: Prevent direct cpufreq scaling during initialization
+
+It is seen that the OMAP specific cpufreq initialization code tries to
+scale the MPU frequency to the highest possible without taking care of
+the voltage level. On power on reset the power IC does not provide the
+necessary voltage for the highest available MPU frequency (that would
+satisfy all Si families). This potentially is an window of opportunity
+for things to go wrong.
+
+Signed-off-by: Romit Dasgupta <romit@ti.com>
+Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
+
+OMAP3: PM: enable 600MHz (overdrive) OPP
+
+Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
+
+omap3: introduce cpufreq
+
+OMAP OPP layer functions now have dependencies of CONFIG_CPU_FREQ only.
+
+With this patch, omap opp layer now has its compilation flags
+bound to CONFIG_CPU_FREQ. Also its code has been removed from pm34xx.c.
+
+A new file has been created to contain cpu freq code related to
+OMAP3: cpufreq34xx.c
+
+OMAP34xx and OMAP36xx family OPPs are made available
+
+Signed-off-by: Eduardo Valentin <eduardo.valentin@nokia.com>
+Signed-off-by: Paul Walmsley <paul@pwsan.com>
+Signed-off-by: Nishanth Menon <nm@ti.com>
+Signed-off-by: Vishwanath BS <vishwanath.bs@ti.com>
+Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
+Signed-off-by: Romit Dasgupta <romit@ti.com>
+Signed-off-by: Rajendra Nayak <rnayak@ti.com>
+
+omap3: cpufreq: allow default opp table init
+
+For board files which choose to override the defaults, the existing
+mechanism will work, for boards that would like to work with defaults,
+allow init_common_hw to call init_opp_table to initialize if not
+already initialized. this will allow all omap boards which have opp
+tables predefined for a silicon to use the same.
+
+Originally reported for overo:
+http://marc.info/?t=127265269400004&r=1&w=2
+
+Signed-off-by: Nishanth Menon <nm@ti.com>
+Reported-by: Peter Tseng <tsenpet09@gmail.com>
+Cc: Cliff Brake <cliff.brake@gmail.com>
+Cc: Kevin Hilman <khilman@deeprootsystems.com>
+
+OMAP2: update OPP data to be device based
+
+Cc: Nishanth Menon <nm@ti.com>
+Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
+
+OMAP3: CPUfreq: update to device-based OPP API
+
+Update usage of OPP API to use new device-based API. This requires
+getting the 'struct device' for the MPU and using that with the OPP
+API.
+
+Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
+
+omap3: opp: make independent of cpufreq
+
+Make opp3xx data which is registered with the opp layer
+dependent purely on CONFIG_PM as opp layer and pm.c users
+are CONFIG_PM dependent not cpufreq dependent.
+so we rename the data definition to opp3xxx_data.c (inline with what
+we have for omap2), also move the build definition to be under
+the existing CONFIG_PM build instead of CPUFREQ.
+
+Cc: Eduardo Valentin <eduardo.valentin@nokia.com>
+Cc: Kevin Hilman <khilman@deeprootsystems.com>
+Cc: Paul Walmsley <paul@pwsan.com>
+Cc: Rajendra Nayak <rnayak@ti.com>
+Cc: Sanjeev Premi <premi@ti.com>
+Cc: Thara Gopinath <thara@ti.com>
+Cc: Tony Lindgren <tony@atomide.com>
+
+Signed-off-by: Nishanth Menon <nm@ti.com>
+---
+ arch/arm/mach-omap2/clock.h | 14 +++++++++++++-
+ arch/arm/mach-omap2/clock34xx.c | 2 ++
+ arch/arm/plat-omap/cpu-omap.c | 35 ++++++++++++++++++++++++++++++++---
+ 3 files changed, 47 insertions(+), 4 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
+index 896584e..29b5cf0 100644
+--- a/arch/arm/mach-omap2/clock.h
++++ b/arch/arm/mach-omap2/clock.h
+@@ -137,7 +137,9 @@ extern const struct clksel_rate gpt_32k_rates[];
+ extern const struct clksel_rate gpt_sys_rates[];
+ extern const struct clksel_rate gfx_l3_rates[];
+
+-#if defined(CONFIG_ARCH_OMAP2) && defined(CONFIG_CPU_FREQ)
++#ifdef CONFIG_CPU_FREQ
++
++#ifdef CONFIG_ARCH_OMAP2
+ extern void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table);
+ extern void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table);
+ #else
+@@ -145,6 +147,16 @@ extern void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table)
+ #define omap2_clk_exit_cpufreq_table 0
+ #endif
+
++#ifdef CONFIG_ARCH_OMAP3
++extern void omap3_clk_init_cpufreq_table(struct cpufreq_frequency_table **table);
++extern void omap3_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table);
++#else
++#define omap3_clk_init_cpufreq_table 0
++#define omap3_clk_exit_cpufreq_table 0
++#endif
++
++#endif /* CONFIG_CPU_FREQ */
++
+ extern const struct clkops clkops_omap3_noncore_dpll_ops;
+
+ #endif
+diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c
+index 287abc4..85d3877 100644
+--- a/arch/arm/mach-omap2/clock34xx.c
++++ b/arch/arm/mach-omap2/clock34xx.c
+@@ -20,6 +20,8 @@
+ #include <linux/kernel.h>
+ #include <linux/clk.h>
+ #include <linux/io.h>
++#include <linux/err.h>
++#include <linux/cpufreq.h>
+
+ #include <plat/clock.h>
+
+diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
+index bfa063b..608216b 100644
+--- a/arch/arm/plat-omap/cpu-omap.c
++++ b/arch/arm/plat-omap/cpu-omap.c
+@@ -8,6 +8,10 @@
+ *
+ * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King
+ *
++ * Copyright (C) 2007-2008 Texas Instruments, Inc.
++ * Updated to support OMAP3
++ * Rajendra Nayak <rnayak@ti.com>
++ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+@@ -21,17 +25,25 @@
+ #include <linux/err.h>
+ #include <linux/clk.h>
+ #include <linux/io.h>
++#include <linux/opp.h>
+
+ #include <mach/hardware.h>
+ #include <plat/clock.h>
++#include <plat/common.h>
+ #include <asm/system.h>
+
++#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE)
++#include <plat/omap-pm.h>
++#endif
++
+ #define VERY_HI_RATE 900000000
+
+ static struct cpufreq_frequency_table *freq_table;
+
+ #ifdef CONFIG_ARCH_OMAP1
+ #define MPU_CLK "mpu"
++#elif CONFIG_ARCH_OMAP3
++#define MPU_CLK "arm_fck"
+ #else
+ #define MPU_CLK "virt_prcm_set"
+ #endif
+@@ -73,7 +85,13 @@ static int omap_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+ {
++#ifdef CONFIG_ARCH_OMAP1
+ struct cpufreq_freqs freqs;
++#endif
++#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE)
++ unsigned long freq;
++ struct device *mpu_dev = omap2_get_mpuss_device();
++#endif
+ int ret = 0;
+
+ /* Ensure desired rate is within allowed range. Some govenors
+@@ -83,13 +101,13 @@ static int omap_target(struct cpufreq_policy *policy,
+ if (target_freq > policy->max)
+ target_freq = policy->max;
+
++#ifdef CONFIG_ARCH_OMAP1
+ freqs.old = omap_getspeed(0);
+ freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000;
+ freqs.cpu = 0;
+
+ if (freqs.old == freqs.new)
+ return ret;
+-
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ #ifdef CONFIG_CPU_FREQ_DEBUG
+ printk(KERN_DEBUG "cpufreq-omap: transition: %u --> %u\n",
+@@ -97,7 +115,11 @@ static int omap_target(struct cpufreq_policy *policy,
+ #endif
+ ret = clk_set_rate(mpu_clk, freqs.new * 1000);
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+-
++#elif defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE)
++ freq = target_freq * 1000;
++ if (opp_find_freq_ceil(mpu_dev, &freq))
++ omap_pm_cpu_set_freq(freq);
++#endif
+ return ret;
+ }
+
+@@ -114,7 +136,14 @@ static int __init omap_cpu_init(struct cpufreq_policy *policy)
+
+ policy->cur = policy->min = policy->max = omap_getspeed(0);
+
+- clk_init_cpufreq_table(&freq_table);
++ if (!cpu_is_omap34xx()) {
++ clk_init_cpufreq_table(&freq_table);
++ } else {
++ struct device *mpu_dev = omap2_get_mpuss_device();
++
++ opp_init_cpufreq_table(mpu_dev, &freq_table);
++ }
++
+ if (freq_table) {
+ result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ if (!result)
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0005-OMAP-PM-CPUFREQ-Fix-conditional-compilation.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0005-OMAP-PM-CPUFREQ-Fix-conditional-compilation.patch
new file mode 100644
index 00000000..b843704e
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0005-OMAP-PM-CPUFREQ-Fix-conditional-compilation.patch
@@ -0,0 +1,32 @@
+From 25ea605d0aaf1d60030b4df122a3384c7878d86e Mon Sep 17 00:00:00 2001
+From: Silesh C V <silesh@ti.com>
+Date: Wed, 29 Sep 2010 14:52:54 +0530
+Subject: [PATCH 05/20] OMAP: PM: CPUFREQ: Fix conditional compilation
+
+Fix conditional compilation. A conditional expresiion
+should follow "#elif", in this case #elif clause should
+check whether CONFIG_ARCH_OMAP3 is defined or not
+(ie. defined(CONFIG_ARCH_OMAP3)) rather than checking for
+the value of the macro.
+
+Signed-off-by: Silesh C V <silesh@ti.com>
+---
+ arch/arm/plat-omap/cpu-omap.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
+index 608216b..671e4b9 100644
+--- a/arch/arm/plat-omap/cpu-omap.c
++++ b/arch/arm/plat-omap/cpu-omap.c
+@@ -42,7 +42,7 @@ static struct cpufreq_frequency_table *freq_table;
+
+ #ifdef CONFIG_ARCH_OMAP1
+ #define MPU_CLK "mpu"
+-#elif CONFIG_ARCH_OMAP3
++#elif defined(CONFIG_ARCH_OMAP3)
+ #define MPU_CLK "arm_fck"
+ #else
+ #define MPU_CLK "virt_prcm_set"
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0006-OMAP-Introduce-a-user-list-for-each-voltage-domain-i.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0006-OMAP-Introduce-a-user-list-for-each-voltage-domain-i.patch
new file mode 100644
index 00000000..516c7cb0
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0006-OMAP-Introduce-a-user-list-for-each-voltage-domain-i.patch
@@ -0,0 +1,199 @@
+From a4107498616e8dafa2a0155a6d45a990766b161b Mon Sep 17 00:00:00 2001
+From: Thara Gopinath <thara@ti.com>
+Date: Fri, 29 Oct 2010 20:43:07 +0530
+Subject: [PATCH 06/20] OMAP: Introduce a user list for each voltage domain instance in the voltage driver.
+
+This patch introduces a user list of devices associated with each
+voltage domain instance. The user list is implemented using plist
+structure with priority node populated with the voltage values.
+This patch also adds an API which will take in a device and
+requested voltage as parameters, adds the info to the user list
+and returns back the maximum voltage requested by all the user
+devices. This can be used anytime to get the voltage that the
+voltage domain instance can be transitioned into.
+
+Signed-off-by: Thara Gopinath <thara@ti.com>
+---
+ arch/arm/mach-omap2/voltage.c | 97 +++++++++++++++++++++++++++++
+ arch/arm/plat-omap/include/plat/voltage.h | 8 +++
+ 2 files changed, 105 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
+index ed6079c..76c98c6 100644
+--- a/arch/arm/mach-omap2/voltage.c
++++ b/arch/arm/mach-omap2/voltage.c
+@@ -24,6 +24,9 @@
+ #include <linux/err.h>
+ #include <linux/debugfs.h>
+ #include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/plist.h>
++#include <linux/slab.h>
+
+ #include <plat/common.h>
+ #include <plat/voltage.h>
+@@ -118,6 +121,20 @@ struct vc_reg_info {
+ };
+
+ /**
++ * struct omap_vdd_user_list - The per vdd user list
++ *
++ * @dev: The device asking for the vdd to be set at a particular
++ * voltage
++ * @node: The list head entry
++ * @volt: The voltage requested by the device <dev>
++ */
++struct omap_vdd_user_list {
++ struct device *dev;
++ struct plist_node node;
++ u32 volt;
++};
++
++/**
+ * omap_vdd_info - Per Voltage Domain info
+ *
+ * @volt_data : voltage table having the distinct voltages supported
+@@ -132,6 +149,10 @@ struct vc_reg_info {
+ * shifts, masks etc.
+ * @voltdm : pointer to the voltage domain structure
+ * @debug_dir : debug directory for this voltage domain.
++ * @user_lock : the lock to be used by the plist user_list
++ * @user_list : the list head maintaining the various users.
++ * @scaling_mutex : the dvfs muutex.
++ * of this vdd with the voltage requested by each user.
+ * @curr_volt : current voltage for this vdd.
+ * @ocp_mod : The prm module for accessing the prm irqstatus reg.
+ * @prm_irqst_reg : prm irqstatus register.
+@@ -146,6 +167,9 @@ struct omap_vdd_info {
+ struct vc_reg_info vc_reg;
+ struct voltagedomain voltdm;
+ struct dentry *debug_dir;
++ spinlock_t user_lock;
++ struct plist_head user_list;
++ struct mutex scaling_mutex;
+ u32 curr_volt;
+ u16 ocp_mod;
+ u8 prm_irqst_reg;
+@@ -869,6 +893,11 @@ static int __init omap3_vdd_data_configure(struct omap_vdd_info *vdd)
+ vdd->write_reg = omap3_voltage_write_reg;
+ vdd->volt_scale = vp_forceupdate_scale_voltage;
+ vdd->vp_enabled = false;
++ /* Init the plist */
++ spin_lock_init(&vdd->user_lock);
++ plist_head_init(&vdd->user_list, &vdd->user_lock);
++ /* Init the DVFS mutex */
++ mutex_init(&vdd->scaling_mutex);
+
+ /* VC parameters */
+ vdd->vc_reg.prm_mod = OMAP3430_GR_MOD;
+@@ -1059,6 +1088,11 @@ static int __init omap4_vdd_data_configure(struct omap_vdd_info *vdd)
+ vdd->write_reg = omap4_voltage_write_reg;
+ vdd->volt_scale = vp_forceupdate_scale_voltage;
+ vdd->vp_enabled = false;
++ /* Init the plist */
++ spin_lock_init(&vdd->user_lock);
++ plist_head_init(&vdd->user_list, &vdd->user_lock);
++ /* Init the DVFS mutex */
++ mutex_init(&vdd->scaling_mutex);
+
+ /* VC parameters */
+ vdd->vc_reg.prm_mod = OMAP4430_PRM_DEVICE_INST;
+@@ -1171,6 +1205,69 @@ unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm)
+
+ return vdd->pmic_info->vsel_to_uv(curr_vsel);
+ }
++/**
++ * omap_voltage_add_request() - API to keep track of various requests to
++ * scale the VDD and returns the best possible
++ * voltage the VDD can be put to.
++ * @volt_domain: pointer to the voltage domain.
++ * @dev: the device pointer.
++ * @volt: the voltage which is requested by the device.
++ *
++ * This API is to be called before the actual voltage scaling is
++ * done to determine what is the best possible voltage the VDD can
++ * be put to. This API adds the device <dev> in the user list of the
++ * vdd <volt_domain> with <volt> as the requested voltage. The user list
++ * is a plist with the priority element absolute voltage values.
++ * The API then finds the maximum of all the requested voltages for
++ * the VDD and returns it back through <volt> pointer itself.
++ * Returns error value in case of any errors.
++ */
++int omap_voltage_add_request(struct voltagedomain *voltdm, struct device *dev,
++ unsigned long *volt)
++{
++ struct omap_vdd_info *vdd;
++ struct omap_vdd_user_list *user;
++ struct plist_node *node;
++ int found = 0;
++
++ if (!voltdm || IS_ERR(voltdm)) {
++ pr_warning("%s: VDD specified does not exist!\n", __func__);
++ return -EINVAL;
++ }
++
++ vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
++
++ mutex_lock(&vdd->scaling_mutex);
++
++ plist_for_each_entry(user, &vdd->user_list, node) {
++ if (user->dev == dev) {
++ found = 1;
++ break;
++ }
++ }
++
++ if (!found) {
++ user = kzalloc(sizeof(struct omap_vdd_user_list), GFP_KERNEL);
++ if (!user) {
++ pr_err("%s: Unable to creat a new user for vdd_%s\n",
++ __func__, voltdm->name);
++ mutex_unlock(&vdd->scaling_mutex);
++ return -ENOMEM;
++ }
++ user->dev = dev;
++ } else {
++ plist_del(&user->node, &vdd->user_list);
++ }
++
++ plist_node_init(&user->node, *volt);
++ plist_add(&user->node, &vdd->user_list);
++ node = plist_last(&vdd->user_list);
++ *volt = user->volt = node->prio;
++
++ mutex_unlock(&vdd->scaling_mutex);
++
++ return 0;
++}
+
+ /**
+ * omap_vp_enable() - API to enable a particular VP
+diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
+index 0ff1233..bd07eca 100644
+--- a/arch/arm/plat-omap/include/plat/voltage.h
++++ b/arch/arm/plat-omap/include/plat/voltage.h
+@@ -132,6 +132,9 @@ int omap_voltage_register_pmic(struct voltagedomain *voltdm,
+ void omap_change_voltscale_method(struct voltagedomain *voltdm,
+ int voltscale_method);
+ int omap_voltage_late_init(void);
++int omap_voltage_add_request(struct voltagedomain *voltdm, struct device *dev,
++ unsigned long *volt);
++
+ #else
+ static inline int omap_voltage_register_pmic(struct voltagedomain *voltdm,
+ struct omap_volt_pmic_info *pmic_info) {}
+@@ -141,6 +144,11 @@ static inline int omap_voltage_late_init(void)
+ {
+ return -EINVAL;
+ }
++static inline int omap_voltage_add_request(struct voltagedomain *voltdm,
++ struct device *dev, unsigned long *volt)
++{
++ return -EINVAL;
++}
+ #endif
+
+ #endif
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0007-OMAP-Introduce-API-in-the-OPP-layer-to-find-the-opp-.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0007-OMAP-Introduce-API-in-the-OPP-layer-to-find-the-opp-.patch
new file mode 100644
index 00000000..58842f25
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0007-OMAP-Introduce-API-in-the-OPP-layer-to-find-the-opp-.patch
@@ -0,0 +1,82 @@
+From dac6c4c03140835b758e32c72eb004d379c35fec Mon Sep 17 00:00:00 2001
+From: Thara Gopinath <thara@ti.com>
+Date: Fri, 29 Oct 2010 20:43:10 +0530
+Subject: [PATCH 07/20] OMAP: Introduce API in the OPP layer to find the opp entry corresponding to a voltage.
+
+This patch adds an API in the opp layer to get the opp table entry
+corresponding to the voltage passed as the parameter.
+
+Signed-off-by: Thara Gopinath <thara@ti.com>
+---
+ drivers/base/power/opp.c | 28 ++++++++++++++++++++++++++++
+ include/linux/opp.h | 8 ++++++++
+ 2 files changed, 36 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
+index 2bb9b4c..60b4478 100644
+--- a/drivers/base/power/opp.c
++++ b/drivers/base/power/opp.c
+@@ -354,6 +354,34 @@ struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq)
+ }
+
+ /**
++ * opp_find_voltage() - search for an exact voltage
++ * @dev: device pointer associated with the opp type
++ * @volt: voltage to search for
++ *
++ * Searches for exact match in the opp list and returns handle to the matching
++ * opp if found, else returns ERR_PTR in case of error and should be handled
++ * using IS_ERR.
++ */
++struct opp *opp_find_voltage(struct device *dev, unsigned long volt)
++{
++ struct device_opp *dev_opp;
++ struct opp *temp_opp, *opp = ERR_PTR(-ENODEV);
++
++ dev_opp = find_device_opp(dev);
++ if (IS_ERR(dev_opp))
++ return opp;
++
++ list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
++ if (temp_opp->available && temp_opp->u_volt == volt) {
++ opp = temp_opp;
++ break;
++ }
++ }
++
++ return opp;
++}
++
++/**
+ * opp_add() - Add an OPP table from a table definitions
+ * @dev: device for which we do this operation
+ * @freq: Frequency in Hz for this OPP
+diff --git a/include/linux/opp.h b/include/linux/opp.h
+index 5449945..4977d5c 100644
+--- a/include/linux/opp.h
++++ b/include/linux/opp.h
+@@ -34,6 +34,8 @@ struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq);
+
+ struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq);
+
++struct opp *opp_find_voltage(struct device *dev, unsigned long volt);
++
+ int opp_add(struct device *dev, unsigned long freq, unsigned long u_volt);
+
+ int opp_enable(struct device *dev, unsigned long freq);
+@@ -74,6 +76,12 @@ static inline struct opp *opp_find_freq_ceil(struct device *dev,
+ return ERR_PTR(-EINVAL);
+ }
+
++static inline struct opp *opp_find_voltage(struct device *dev,
++ unsigned long volt)
++{
++ return ERR_PTR(-EINVAL);
++}
++
+ static inline int opp_add(struct device *dev, unsigned long freq,
+ unsigned long u_volt)
+ {
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0008-OMAP-Introduce-API-to-register-a-device-with-a-volta.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0008-OMAP-Introduce-API-to-register-a-device-with-a-volta.patch
new file mode 100644
index 00000000..d00751d4
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0008-OMAP-Introduce-API-to-register-a-device-with-a-volta.patch
@@ -0,0 +1,182 @@
+From 3fcad983e7df504ecb1d0db79e3fe2e3abc44850 Mon Sep 17 00:00:00 2001
+From: Thara Gopinath <thara@ti.com>
+Date: Fri, 29 Oct 2010 20:43:24 +0530
+Subject: [PATCH 08/20] OMAP: Introduce API to register a device with a voltagedomain
+
+This patch adds an API in the voltage layer that
+can be used during omap_device_build to register the built
+device with the voltage domain. This API is to be typically called
+only once per device during the device registeration. This approach
+makes it easy during dvfs to scale all the devices associated with
+a voltage domain and then scale the voltage domain.
+
+Signed-off-by: Thara Gopinath <thara@ti.com>
+---
+ arch/arm/mach-omap2/voltage.c | 50 +++++++++++++++++++++++++++++
+ arch/arm/plat-omap/include/plat/voltage.h | 7 +++-
+ arch/arm/plat-omap/omap_device.c | 12 +++++++
+ 3 files changed, 68 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
+index 76c98c6..7381fa6 100644
+--- a/arch/arm/mach-omap2/voltage.c
++++ b/arch/arm/mach-omap2/voltage.c
+@@ -134,6 +134,11 @@ struct omap_vdd_user_list {
+ u32 volt;
+ };
+
++struct omap_vdd_dev_list {
++ struct device *dev;
++ struct list_head node;
++};
++
+ /**
+ * omap_vdd_info - Per Voltage Domain info
+ *
+@@ -153,6 +158,7 @@ struct omap_vdd_user_list {
+ * @user_list : the list head maintaining the various users.
+ * @scaling_mutex : the dvfs muutex.
+ * of this vdd with the voltage requested by each user.
++ * @dev_list : list of devices bwlonging to this voltage domain.
+ * @curr_volt : current voltage for this vdd.
+ * @ocp_mod : The prm module for accessing the prm irqstatus reg.
+ * @prm_irqst_reg : prm irqstatus register.
+@@ -170,6 +176,7 @@ struct omap_vdd_info {
+ spinlock_t user_lock;
+ struct plist_head user_list;
+ struct mutex scaling_mutex;
++ struct list_head dev_list;
+ u32 curr_volt;
+ u16 ocp_mod;
+ u8 prm_irqst_reg;
+@@ -1093,6 +1100,8 @@ static int __init omap4_vdd_data_configure(struct omap_vdd_info *vdd)
+ plist_head_init(&vdd->user_list, &vdd->user_lock);
+ /* Init the DVFS mutex */
+ mutex_init(&vdd->scaling_mutex);
++ /* Init the device list */
++ INIT_LIST_HEAD(&vdd->dev_list);
+
+ /* VC parameters */
+ vdd->vc_reg.prm_mod = OMAP4430_PRM_DEVICE_INST;
+@@ -1269,6 +1278,40 @@ int omap_voltage_add_request(struct voltagedomain *voltdm, struct device *dev,
+ return 0;
+ }
+
++int omap_voltage_add_dev(struct voltagedomain *voltdm, struct device *dev)
++{
++ struct omap_vdd_info *vdd;
++ struct omap_vdd_dev_list *temp_dev;
++
++ if (!voltdm || IS_ERR(voltdm)) {
++ pr_warning("%s: VDD specified does not exist!\n", __func__);
++ return -EINVAL;
++ }
++
++ vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
++
++ list_for_each_entry(temp_dev, &vdd->dev_list, node) {
++ if (temp_dev->dev == dev) {
++ dev_warn(dev, "%s: Device already added to vdee_%s\n",
++ __func__, voltdm->name);
++ return -EINVAL;
++ }
++ }
++
++ temp_dev = kzalloc(sizeof(struct omap_vdd_dev_list), GFP_KERNEL);
++ if (!temp_dev) {
++ dev_err(dev, "%s: Unable to creat a new device for vdd_%s\n",
++ __func__, voltdm->name);
++ return -ENOMEM;
++ }
++
++ temp_dev->dev = dev;
++
++ list_add(&temp_dev->node, &vdd->dev_list);
++
++ return 0;
++}
++
+ /**
+ * omap_vp_enable() - API to enable a particular VP
+ * @voltdm: pointer to the VDD whose VP is to be enabled.
+@@ -1649,6 +1692,8 @@ int __init omap_voltage_late_init(void)
+ */
+ static int __init omap_voltage_early_init(void)
+ {
++ int i;
++
+ if (cpu_is_omap34xx()) {
+ vdd_info = omap3_vdd_info;
+ nr_scalable_vdd = OMAP3_NR_SCALABLE_VDD;
+@@ -1661,8 +1706,13 @@ static int __init omap_voltage_early_init(void)
+ vdd_data_configure = omap4_vdd_data_configure;
+ } else {
+ pr_warning("%s: voltage driver support not added\n", __func__);
++ return -EINVAL;
+ }
+
++ /* Init the device list */
++ for (i = 0; i < nr_scalable_vdd; i++)
++ INIT_LIST_HEAD(&(vdd_info[i].dev_list));
++
+ return 0;
+ }
+ core_initcall(omap_voltage_early_init);
+diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
+index bd07eca..adbc6af 100644
+--- a/arch/arm/plat-omap/include/plat/voltage.h
++++ b/arch/arm/plat-omap/include/plat/voltage.h
+@@ -134,7 +134,7 @@ void omap_change_voltscale_method(struct voltagedomain *voltdm,
+ int omap_voltage_late_init(void);
+ int omap_voltage_add_request(struct voltagedomain *voltdm, struct device *dev,
+ unsigned long *volt);
+-
++int omap_voltage_add_dev(struct voltagedomain *voltdm, struct device *dev);
+ #else
+ static inline int omap_voltage_register_pmic(struct voltagedomain *voltdm,
+ struct omap_volt_pmic_info *pmic_info) {}
+@@ -149,6 +149,11 @@ static inline int omap_voltage_add_request(struct voltagedomain *voltdm,
+ {
+ return -EINVAL;
+ }
++static inline int omap_voltage_add_dev(struct voltagedomain *voltdm,
++ struct device *dev)
++{
++ return -EINVAL;
++}
+ #endif
+
+ #endif
+diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
+index 57adb27..2c95e61 100644
+--- a/arch/arm/plat-omap/omap_device.c
++++ b/arch/arm/plat-omap/omap_device.c
+@@ -86,6 +86,7 @@
+
+ #include <plat/omap_device.h>
+ #include <plat/omap_hwmod.h>
++#include <plat/voltage.h>
+
+ /* These parameters are passed to _omap_device_{de,}activate() */
+ #define USE_WAKEUP_LAT 0
+@@ -481,6 +482,17 @@ struct omap_device *omap_device_build_ss(const char *pdev_name, int pdev_id,
+ for (i = 0; i < oh_cnt; i++) {
+ hwmods[i]->od = od;
+ _add_optional_clock_alias(od, hwmods[i]);
++ if (hwmods[i]->vdd_name) {
++ struct omap_hwmod *oh = hwmods[i];
++ struct voltagedomain *voltdm;
++
++ if (is_early_device)
++ continue;
++
++ voltdm = omap_voltage_domain_lookup(oh->vdd_name);
++ if (!omap_voltage_add_dev(voltdm, &od->pdev.dev))
++ oh->voltdm = voltdm;
++ }
+ }
+
+ if (ret)
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0009-OMAP-Introduce-device-specific-set-rate-and-get-rate.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0009-OMAP-Introduce-device-specific-set-rate-and-get-rate.patch
new file mode 100644
index 00000000..f5914aa3
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0009-OMAP-Introduce-device-specific-set-rate-and-get-rate.patch
@@ -0,0 +1,120 @@
+From 6ec7cf889c9a8ddf97fbbcbda4888b0f17930e04 Mon Sep 17 00:00:00 2001
+From: Thara Gopinath <thara@ti.com>
+Date: Fri, 29 Oct 2010 20:43:29 +0530
+Subject: [PATCH 09/20] OMAP: Introduce device specific set rate and get rate in omap_device structure
+
+This patch extends the omap_device structure to contain
+pointers to scale the operating rate of the
+device and to retrieve the operating rate of the device.
+This patch also adds the three new APIs in the omap device layer
+namely omap_device_set_rate that can be called to set a new operating
+rate for a device, omap_device_get_rate that can be called to retrieve
+the operating frequency for a device and omap_device_populate_rate_fns
+to populte the device specific set_rate and get_rate API's.
+The omap_device_set_rate and omap_device_get_rate does some routine error
+checks and finally calls into the device specific set_rate
+and get_rate APIs populated through omap_device_populate_rate_fns.
+
+Signed-off-by: Thara Gopinath <thara@ti.com>
+---
+ arch/arm/plat-omap/include/plat/omap_device.h | 9 +++++
+ arch/arm/plat-omap/omap_device.c | 49 +++++++++++++++++++++++++
+ 2 files changed, 58 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/plat-omap/include/plat/omap_device.h b/arch/arm/plat-omap/include/plat/omap_device.h
+index e4c349f..1178b86 100644
+--- a/arch/arm/plat-omap/include/plat/omap_device.h
++++ b/arch/arm/plat-omap/include/plat/omap_device.h
+@@ -50,6 +50,8 @@ extern struct device omap_device_parent;
+ * @hwmods: (one .. many per omap_device)
+ * @hwmods_cnt: ARRAY_SIZE() of @hwmods
+ * @pm_lats: ptr to an omap_device_pm_latency table
++ * @set_rate: fn ptr to change the operating rate.
++ * @get_rate: fn ptr to retrieve the current operating rate.
+ * @pm_lats_cnt: ARRAY_SIZE() of what is passed to @pm_lats
+ * @pm_lat_level: array index of the last odpl entry executed - -1 if never
+ * @dev_wakeup_lat: dev wakeup latency in nanoseconds
+@@ -67,6 +69,8 @@ struct omap_device {
+ struct platform_device pdev;
+ struct omap_hwmod **hwmods;
+ struct omap_device_pm_latency *pm_lats;
++ int (*set_rate)(struct device *dev, unsigned long rate);
++ unsigned long (*get_rate) (struct device *dev);
+ u32 dev_wakeup_lat;
+ u32 _dev_wakeup_lat_limit;
+ u8 pm_lats_cnt;
+@@ -108,6 +112,11 @@ int omap_device_align_pm_lat(struct platform_device *pdev,
+ u32 new_wakeup_lat_limit);
+ struct powerdomain *omap_device_get_pwrdm(struct omap_device *od);
+ u32 omap_device_get_context_loss_count(struct platform_device *pdev);
++int omap_device_set_rate(struct device *dev, unsigned long freq);
++unsigned long omap_device_get_rate(struct device *dev);
++void omap_device_populate_rate_fns(struct device *dev,
++ int (*set_rate)(struct device *dev, unsigned long rate),
++ unsigned long (*get_rate) (struct device *dev));
+
+ /* Other */
+
+diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
+index 2c95e61..0d67af6 100644
+--- a/arch/arm/plat-omap/omap_device.c
++++ b/arch/arm/plat-omap/omap_device.c
+@@ -813,6 +813,55 @@ int omap_device_enable_clocks(struct omap_device *od)
+ return 0;
+ }
+
++int omap_device_set_rate(struct device *dev, unsigned long freq)
++{
++ struct platform_device *pdev;
++ struct omap_device *od;
++
++ pdev = container_of(dev, struct platform_device, dev);
++ od = _find_by_pdev(pdev);
++
++ if (!od->set_rate) {
++ dev_err(dev, "%s: No set_rate API for scaling device\n",
++ __func__);
++ return -ENODATA;
++ }
++
++ return od->set_rate(dev, freq);
++}
++
++unsigned long omap_device_get_rate(struct device *dev)
++{
++ struct platform_device *pdev;
++ struct omap_device *od;
++
++ pdev = container_of(dev, struct platform_device, dev);
++ od = _find_by_pdev(pdev);
++
++
++ if (!od->get_rate) {
++ dev_err(dev, "%s: No get rate API for the device\n",
++ __func__);
++ return 0;
++ }
++
++ return od->get_rate(dev);
++}
++
++void omap_device_populate_rate_fns(struct device *dev,
++ int (*set_rate)(struct device *dev, unsigned long rate),
++ unsigned long (*get_rate) (struct device *dev))
++{
++ struct platform_device *pdev;
++ struct omap_device *od;
++
++ pdev = container_of(dev, struct platform_device, dev);
++ od = _find_by_pdev(pdev);
++
++ od->set_rate = set_rate;
++ od->get_rate = get_rate;
++}
++
+ struct device omap_device_parent = {
+ .init_name = "omap",
+ .parent = &platform_bus,
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0010-OMAP-Voltage-layer-changes-to-support-DVFS.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0010-OMAP-Voltage-layer-changes-to-support-DVFS.patch
new file mode 100644
index 00000000..ead9cbba
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0010-OMAP-Voltage-layer-changes-to-support-DVFS.patch
@@ -0,0 +1,134 @@
+From 96ee5b07e3162056169689b363f4c0edae7d7303 Mon Sep 17 00:00:00 2001
+From: Thara Gopinath <thara@ti.com>
+Date: Fri, 29 Oct 2010 20:43:34 +0530
+Subject: [PATCH 10/20] OMAP: Voltage layer changes to support DVFS.
+
+This patch introduces an API to take in the voltage domain and the
+new voltage as parameter and to scale all the scalable devices
+associated with the the voltage domain to the rate corresponding to the
+new voltage and scale the voltage domain to the new voltage.
+
+Signed-off-by: Thara Gopinath <thara@ti.com>
+---
+ arch/arm/mach-omap2/voltage.c | 69 +++++++++++++++++++++++++++++
+ arch/arm/plat-omap/include/plat/voltage.h | 7 +++
+ 2 files changed, 76 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
+index 7381fa6..9adf9d1 100644
+--- a/arch/arm/mach-omap2/voltage.c
++++ b/arch/arm/mach-omap2/voltage.c
+@@ -27,9 +27,11 @@
+ #include <linux/spinlock.h>
+ #include <linux/plist.h>
+ #include <linux/slab.h>
++#include <linux/opp.h>
+
+ #include <plat/common.h>
+ #include <plat/voltage.h>
++#include <plat/omap_device.h>
+
+ #include "prm-regbits-34xx.h"
+ #include "prm-regbits-44xx.h"
+@@ -1656,6 +1658,73 @@ struct voltagedomain *omap_voltage_domain_lookup(char *name)
+ }
+
+ /**
++ * omap_voltage_scale : API to scale the devices associated with a
++ * voltage domain vdd voltage.
++ * @volt_domain : the voltage domain to be scaled
++ * @volt : the new voltage for the voltage domain
++ *
++ * This API runs through the list of devices associated with the
++ * voltage domain and scales the device rates to those corresponding
++ * to the new voltage of the voltage domain. This API also scales
++ * the voltage domain voltage to the new value. Returns 0 on success
++ * else the error value.
++ */
++int omap_voltage_scale(struct voltagedomain *voltdm, unsigned long volt)
++{
++ unsigned long curr_volt;
++ int is_volt_scaled = 0;
++ struct omap_vdd_info *vdd;
++ struct omap_vdd_dev_list *temp_dev;
++
++ if (!voltdm || IS_ERR(voltdm)) {
++ pr_warning("%s: VDD specified does not exist!\n", __func__);
++ return -EINVAL;
++ }
++
++ vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
++
++ mutex_lock(&vdd->scaling_mutex);
++
++ curr_volt = omap_voltage_get_nom_volt(voltdm);
++
++ if (curr_volt == volt) {
++ is_volt_scaled = 1;
++ } else if (curr_volt < volt) {
++ omap_voltage_scale_vdd(voltdm, volt);
++ is_volt_scaled = 1;
++ }
++
++ list_for_each_entry(temp_dev, &vdd->dev_list, node) {
++ struct device *dev;
++ struct opp *opp;
++ unsigned long freq;
++
++ dev = temp_dev->dev;
++
++ opp = opp_find_voltage(dev, volt);
++ if (IS_ERR(opp))
++ continue;
++
++ freq = opp_get_freq(opp);
++
++ if (freq == omap_device_get_rate(dev)) {
++ dev_warn(dev, "%s: Already at the requested"
++ "rate %ld\n", __func__, freq);
++ continue;
++ }
++
++ omap_device_set_rate(dev, freq);
++ }
++
++ if (!is_volt_scaled)
++ omap_voltage_scale_vdd(voltdm, volt);
++
++ mutex_unlock(&vdd->scaling_mutex);
++
++ return 0;
++}
++
++/**
+ * omap_voltage_late_init() - Init the various voltage parameters
+ *
+ * This API is to be called in the later stages of the
+diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
+index adbc6af..6782c5e 100644
+--- a/arch/arm/plat-omap/include/plat/voltage.h
++++ b/arch/arm/plat-omap/include/plat/voltage.h
+@@ -135,6 +135,7 @@ int omap_voltage_late_init(void);
+ int omap_voltage_add_request(struct voltagedomain *voltdm, struct device *dev,
+ unsigned long *volt);
+ int omap_voltage_add_dev(struct voltagedomain *voltdm, struct device *dev);
++int omap_voltage_scale(struct voltagedomain *voltdm, unsigned long volt);
+ #else
+ static inline int omap_voltage_register_pmic(struct voltagedomain *voltdm,
+ struct omap_volt_pmic_info *pmic_info) {}
+@@ -154,6 +155,12 @@ static inline int omap_voltage_add_dev(struct voltagedomain *voltdm,
+ {
+ return -EINVAL;
+ }
++
++static inline int omap_voltage_scale(struct voltagedomain *voltdm,
++ unsigned long volt)
++{
++ return -EINVAL;
++}
+ #endif
+
+ #endif
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0011-OMAP-Introduce-dependent-voltage-domain-support.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0011-OMAP-Introduce-dependent-voltage-domain-support.patch
new file mode 100644
index 00000000..6c4ca2ab
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0011-OMAP-Introduce-dependent-voltage-domain-support.patch
@@ -0,0 +1,195 @@
+From b1b41c78d5a19260605fcb259a51ca7cd71c097a Mon Sep 17 00:00:00 2001
+From: Thara Gopinath <thara@ti.com>
+Date: Fri, 2 Jul 2010 13:06:57 +0530
+Subject: [PATCH 11/20] OMAP: Introduce dependent voltage domain support.
+
+There could be dependencies between various voltage domains for
+maintaining system performance or hardware limitation reasons
+like VDD<X> should be at voltage v1 when VDD<Y> is at voltage v2.
+This patch introduce dependent vdd information structures in the
+voltage layer which can be used to populate these dependencies
+for a voltage domain. This patch also adds support to scale
+the dependent vdd and the scalable devices belonging to it
+during the scaling of a main vdd through omap_voltage_scale.
+
+Signed-off-by: Thara Gopinath <thara@ti.com>
+---
+ arch/arm/mach-omap2/voltage.c | 122 +++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 122 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
+index 9adf9d1..c83d968 100644
+--- a/arch/arm/mach-omap2/voltage.c
++++ b/arch/arm/mach-omap2/voltage.c
+@@ -123,6 +123,36 @@ struct vc_reg_info {
+ };
+
+ /**
++ * omap_vdd_dep_volt - Table containing the parent vdd voltage and the
++ * dependent vdd voltage corresponding to it.
++ *
++ * @main_vdd_volt : The main vdd voltage
++ * @dep_vdd_volt : The voltage at which the dependent vdd should be
++ * when the main vdd is at <main_vdd_volt> voltage
++ */
++struct omap_vdd_dep_volt {
++ u32 main_vdd_volt;
++ u32 dep_vdd_volt;
++};
++
++/**
++ * omap_vdd_dep_info - Dependent vdd info
++ *
++ * @name : Dependent vdd name
++ * @voltdm : Dependent vdd pointer
++ * @dep_table : Table containing the dependent vdd voltage
++ * corresponding to every main vdd voltage.
++ * @cur_dep_volt : The voltage to which dependent vdd should be put
++ * to for the current main vdd voltage.
++ */
++struct omap_vdd_dep_info {
++ char *name;
++ struct voltagedomain *voltdm;
++ struct omap_vdd_dep_volt *dep_table;
++ unsigned long cur_dep_volt;
++};
++
++/**
+ * struct omap_vdd_user_list - The per vdd user list
+ *
+ * @dev: The device asking for the vdd to be set at a particular
+@@ -174,11 +204,13 @@ struct omap_vdd_info {
+ struct vp_reg_val vp_reg;
+ struct vc_reg_info vc_reg;
+ struct voltagedomain voltdm;
++ struct omap_vdd_dep_info *dep_vdd_info;
+ struct dentry *debug_dir;
+ spinlock_t user_lock;
+ struct plist_head user_list;
+ struct mutex scaling_mutex;
+ struct list_head dev_list;
++ int nr_dep_vdd;
+ u32 curr_volt;
+ u16 ocp_mod;
+ u8 prm_irqst_reg;
+@@ -1160,6 +1192,80 @@ static int __init omap4_vdd_data_configure(struct omap_vdd_info *vdd)
+ return 0;
+ }
+
++static int calc_dep_vdd_volt(struct device *dev,
++ struct omap_vdd_info *main_vdd, unsigned long main_volt)
++{
++ struct omap_vdd_dep_info *dep_vdds;
++ int i, ret = 0;
++
++ if (!main_vdd->dep_vdd_info) {
++ pr_debug("%s: No dependent VDD's for vdd_%s\n",
++ __func__, main_vdd->voltdm.name);
++ return 0;
++ }
++
++ dep_vdds = main_vdd->dep_vdd_info;
++
++ for (i = 0; i < main_vdd->nr_dep_vdd; i++) {
++ struct omap_vdd_dep_volt *volt_table = dep_vdds[i].dep_table;
++ int nr_volt = 0;
++ unsigned long dep_volt = 0, act_volt = 0;
++
++ while (volt_table[nr_volt].main_vdd_volt != 0) {
++ if (volt_table[nr_volt].main_vdd_volt == main_volt) {
++ dep_volt = volt_table[nr_volt].dep_vdd_volt;
++ break;
++ }
++ nr_volt++;
++ }
++ if (!dep_volt) {
++ pr_warning("%s: Not able to find a matching volt for"
++ "vdd_%s corresponding to vdd_%s %ld volt\n",
++ __func__, dep_vdds[i].name,
++ main_vdd->voltdm.name, main_volt);
++ ret = -EINVAL;
++ continue;
++ }
++
++ if (!dep_vdds[i].voltdm)
++ dep_vdds[i].voltdm =
++ omap_voltage_domain_lookup(dep_vdds[i].name);
++
++ act_volt = dep_volt;
++
++ /* See if dep_volt is possible for the vdd*/
++ ret = omap_voltage_add_request(dep_vdds[i].voltdm, dev,
++ &act_volt);
++
++ /*
++ * Currently we do not bother if the dep volt and act volt are
++ * different. We could add a check if needed.
++ */
++ dep_vdds[i].cur_dep_volt = act_volt;
++ }
++
++ return ret;
++}
++
++static int scale_dep_vdd(struct omap_vdd_info *main_vdd)
++{
++ struct omap_vdd_dep_info *dep_vdds;
++ int i;
++
++ if (!main_vdd->dep_vdd_info) {
++ pr_debug("%s: No dependent VDD's for vdd_%s\n",
++ __func__, main_vdd->voltdm.name);
++ return 0;
++ }
++
++ dep_vdds = main_vdd->dep_vdd_info;
++
++ for (i = 0; i < main_vdd->nr_dep_vdd; i++)
++ omap_voltage_scale(dep_vdds[i].voltdm,
++ dep_vdds[i].cur_dep_volt);
++ return 0;
++}
++
+ /* Public functions */
+ /**
+ * omap_voltage_get_nom_volt() - Gets the current non-auto-compensated voltage
+@@ -1675,6 +1781,8 @@ int omap_voltage_scale(struct voltagedomain *voltdm, unsigned long volt)
+ int is_volt_scaled = 0;
+ struct omap_vdd_info *vdd;
+ struct omap_vdd_dev_list *temp_dev;
++ struct plist_node *node;
++ struct omap_vdd_user_list *user;
+
+ if (!voltdm || IS_ERR(voltdm)) {
+ pr_warning("%s: VDD specified does not exist!\n", __func__);
+@@ -1687,6 +1795,17 @@ int omap_voltage_scale(struct voltagedomain *voltdm, unsigned long volt)
+
+ curr_volt = omap_voltage_get_nom_volt(voltdm);
+
++ /* Find the device requesting the voltage scaling */
++ node = plist_first(&vdd->user_list);
++ user = container_of(node, struct omap_vdd_user_list, node);
++
++ /* calculate the voltages for dependent vdd's */
++ if (calc_dep_vdd_volt(user->dev, vdd, volt)) {
++ pr_warning("%s: Error in calculating dependent vdd voltages"
++ "for vdd_%s\n", __func__, voltdm->name);
++ return -EINVAL;
++ }
++
+ if (curr_volt == volt) {
+ is_volt_scaled = 1;
+ } else if (curr_volt < volt) {
+@@ -1721,6 +1840,9 @@ int omap_voltage_scale(struct voltagedomain *voltdm, unsigned long volt)
+
+ mutex_unlock(&vdd->scaling_mutex);
+
++ /* Scale dependent vdds */
++ scale_dep_vdd(vdd);
++
+ return 0;
+ }
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0012-OMAP-Introduce-device-scale.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0012-OMAP-Introduce-device-scale.patch
new file mode 100644
index 00000000..a6d35bd6
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0012-OMAP-Introduce-device-scale.patch
@@ -0,0 +1,134 @@
+From b461bd17384c73bbb243c54bf1d6466c94e594c3 Mon Sep 17 00:00:00 2001
+From: Thara Gopinath <thara@ti.com>
+Date: Fri, 2 Jul 2010 13:07:35 +0530
+Subject: [PATCH 12/20] OMAP: Introduce device scale
+
+This patch adds omap_device_scale API which can be used to generic
+device rate scaling.
+
+Signed-off-by: Thara Gopinath <thara@ti.com>
+---
+ arch/arm/plat-omap/include/plat/omap_device.h | 3 +-
+ arch/arm/plat-omap/omap_device.c | 78 +++++++++++++++++++++++++
+ 2 files changed, 80 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/plat-omap/include/plat/omap_device.h b/arch/arm/plat-omap/include/plat/omap_device.h
+index 1178b86..e44a0f7 100644
+--- a/arch/arm/plat-omap/include/plat/omap_device.h
++++ b/arch/arm/plat-omap/include/plat/omap_device.h
+@@ -117,6 +117,8 @@ unsigned long omap_device_get_rate(struct device *dev);
+ void omap_device_populate_rate_fns(struct device *dev,
+ int (*set_rate)(struct device *dev, unsigned long rate),
+ unsigned long (*get_rate) (struct device *dev));
++int omap_device_scale(struct device *req_dev, struct device *dev,
++ unsigned long rate);
+
+ /* Other */
+
+@@ -126,7 +128,6 @@ int omap_device_enable_hwmods(struct omap_device *od);
+ int omap_device_disable_clocks(struct omap_device *od);
+ int omap_device_enable_clocks(struct omap_device *od);
+
+-
+ /*
+ * Entries should be kept in latency order ascending
+ *
+diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
+index 0d67af6..458d648 100644
+--- a/arch/arm/plat-omap/omap_device.c
++++ b/arch/arm/plat-omap/omap_device.c
+@@ -83,6 +83,7 @@
+ #include <linux/err.h>
+ #include <linux/io.h>
+ #include <linux/clk.h>
++#include <linux/opp.h>
+
+ #include <plat/omap_device.h>
+ #include <plat/omap_hwmod.h>
+@@ -862,6 +863,83 @@ void omap_device_populate_rate_fns(struct device *dev,
+ od->get_rate = get_rate;
+ }
+
++/**
++ * omap_device_scale() - Set a new rate at which the device is to operate
++ * @req_dev: pointer to the device requesting the scaling.
++ * @dev: pointer to the device that is to be scaled
++ * @rate: the rnew rate for the device.
++ *
++ * This API gets the device opp table associated with this device and
++ * tries putting the device to the requested rate and the voltage domain
++ * associated with the device to the voltage corresponding to the
++ * requested rate. Since multiple devices can be assocciated with a
++ * voltage domain this API finds out the possible voltage the
++ * voltage domain can enter and then decides on the final device
++ * rate. Return 0 on success else the error value
++ */
++int omap_device_scale(struct device *req_dev, struct device *dev,
++ unsigned long rate)
++{
++ struct opp *opp;
++ unsigned long volt, freq, min_freq, max_freq;
++ struct voltagedomain *voltdm;
++ struct platform_device *pdev;
++ struct omap_device *od;
++ int ret;
++
++ pdev = container_of(dev, struct platform_device, dev);
++ od = _find_by_pdev(pdev);
++
++ /*
++ * Figure out if the desired frquency lies between the
++ * maximum and minimum possible for the particular device
++ */
++ min_freq = 0;
++ if (IS_ERR(opp_find_freq_ceil(dev, &min_freq))) {
++ dev_err(dev, "%s: Unable to find lowest opp\n", __func__);
++ return -ENODEV;
++ }
++
++ max_freq = ULONG_MAX;
++ if (IS_ERR(opp_find_freq_floor(dev, &max_freq))) {
++ dev_err(dev, "%s: Unable to find highest opp\n", __func__);
++ return -ENODEV;
++ }
++
++ if (rate < min_freq)
++ freq = min_freq;
++ else if (rate > max_freq)
++ freq = max_freq;
++ else
++ freq = rate;
++
++ opp = opp_find_freq_ceil(dev, &freq);
++ if (IS_ERR(opp)) {
++ dev_err(dev, "%s: Unable to find OPP for freq%ld\n",
++ __func__, rate);
++ return -ENODEV;
++ }
++
++ /* Get the voltage corresponding to the requested frequency */
++ volt = opp_get_voltage(opp);
++
++ /*
++ * Call into the voltage layer to get the final voltage possible
++ * for the voltage domain associated with the device.
++ */
++ voltdm = od->hwmods[0]->voltdm;
++ ret = omap_voltage_add_request(voltdm, req_dev, &volt);
++ if (ret) {
++ dev_err(dev, "%s: Unable to get the final volt for scaling\n",
++ __func__);
++ return ret;
++ }
++
++ /* Do the actual scaling */
++ return omap_voltage_scale(voltdm, volt);
++}
++EXPORT_SYMBOL(omap_device_scale);
++
+ struct device omap_device_parent = {
+ .init_name = "omap",
+ .parent = &platform_bus,
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0013-OMAP-Disable-smartreflex-across-DVFS.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0013-OMAP-Disable-smartreflex-across-DVFS.patch
new file mode 100644
index 00000000..89384a8e
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0013-OMAP-Disable-smartreflex-across-DVFS.patch
@@ -0,0 +1,50 @@
+From 4c68660aa69a5eaeaff7fda7e2297e2d31de0333 Mon Sep 17 00:00:00 2001
+From: Thara Gopinath <thara@ti.com>
+Date: Fri, 2 Jul 2010 13:06:57 +0530
+Subject: [PATCH 13/20] OMAP: Disable smartreflex across DVFS
+
+This patch disables smartreflex for a particular voltage
+domain when the the voltage domain and the devices belonging
+to it is being scaled and re-enables it back once the scaling
+is done.
+
+Signed-off-by: Thara Gopinath <thara@ti.com>
+---
+ arch/arm/mach-omap2/voltage.c | 7 +++++++
+ 1 files changed, 7 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
+index c83d968..2f331de 100644
+--- a/arch/arm/mach-omap2/voltage.c
++++ b/arch/arm/mach-omap2/voltage.c
+@@ -32,6 +32,7 @@
+ #include <plat/common.h>
+ #include <plat/voltage.h>
+ #include <plat/omap_device.h>
++#include <plat/smartreflex.h>
+
+ #include "prm-regbits-34xx.h"
+ #include "prm-regbits-44xx.h"
+@@ -1806,6 +1807,9 @@ int omap_voltage_scale(struct voltagedomain *voltdm, unsigned long volt)
+ return -EINVAL;
+ }
+
++ /* Disable smartreflex module across voltage and frequency scaling */
++ omap_sr_disable(voltdm);
++
+ if (curr_volt == volt) {
+ is_volt_scaled = 1;
+ } else if (curr_volt < volt) {
+@@ -1840,6 +1844,9 @@ int omap_voltage_scale(struct voltagedomain *voltdm, unsigned long volt)
+
+ mutex_unlock(&vdd->scaling_mutex);
+
++ /* Enable Smartreflex module */
++ omap_sr_enable(voltdm);
++
+ /* Scale dependent vdds */
+ scale_dep_vdd(vdd);
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0014-OMAP3-Introduce-custom-set-rate-and-get-rate-APIs-fo.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0014-OMAP3-Introduce-custom-set-rate-and-get-rate-APIs-fo.patch
new file mode 100644
index 00000000..16335ccb
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0014-OMAP3-Introduce-custom-set-rate-and-get-rate-APIs-fo.patch
@@ -0,0 +1,176 @@
+From 6fb7bd2b3da02e6e799d3c7661a1acb6572f9add Mon Sep 17 00:00:00 2001
+From: Thara Gopinath <thara@ti.com>
+Date: Wed, 18 Aug 2010 16:22:32 +0530
+Subject: [PATCH 14/20] OMAP3: Introduce custom set rate and get rate APIs for scalable devices
+
+This patch also introduces omap3_mpu_set_rate, omap3_iva_set_rate,
+omap3_l3_set_rate, omap3_mpu_get_rate, omap3_iva_get_rate,
+omap3_l3_get_rate as device specific set rate and get rate
+APIs for OMAP3 mpu, iva and l3_main devices. This patch also
+calls into omap_device_populate_rate_fns during system init to register
+various set_rate and get_rate APIs with the omap device layer
+
+Signed-off-by: Thara Gopinath <thara@ti.com>
+---
+ arch/arm/mach-omap2/pm.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 110 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
+index d5a102c..94ab0dd 100644
+--- a/arch/arm/mach-omap2/pm.c
++++ b/arch/arm/mach-omap2/pm.c
+@@ -14,6 +14,7 @@
+ #include <linux/io.h>
+ #include <linux/err.h>
+ #include <linux/opp.h>
++#include <linux/delay.h>
+
+ #include <plat/omap-pm.h>
+ #include <plat/omap_device.h>
+@@ -22,6 +23,8 @@
+
+ #include "powerdomain.h"
+ #include "clockdomain.h"
++#include "cm-regbits-34xx.h"
++#include "cm2xxx_3xxx.h"
+ #include "pm.h"
+
+ static struct omap_device_pm_latency *pm_lats;
+@@ -31,6 +34,8 @@ static struct device *iva_dev;
+ static struct device *l3_dev;
+ static struct device *dsp_dev;
+
++static struct clk *dpll1_clk, *dpll2_clk, *dpll3_clk;
++
+ struct device *omap2_get_mpuss_device(void)
+ {
+ WARN_ON_ONCE(!mpu_dev);
+@@ -56,6 +61,26 @@ struct device *omap4_get_dsp_device(void)
+ }
+ EXPORT_SYMBOL(omap4_get_dsp_device);
+
++static unsigned long compute_lpj(unsigned long ref, u_int div, u_int mult)
++{
++ unsigned long new_jiffy_l, new_jiffy_h;
++
++ /*
++ * Recalculate loops_per_jiffy. We do it this way to
++ * avoid math overflow on 32-bit machines. Maybe we
++ * should make this architecture dependent? If you have
++ * a better way of doing this, please replace!
++ *
++ * new = old * mult / div
++ */
++ new_jiffy_h = ref / div;
++ new_jiffy_l = (ref % div) / 100;
++ new_jiffy_h *= mult;
++ new_jiffy_l = new_jiffy_l * mult / div;
++
++ return new_jiffy_h + new_jiffy_l * 100;
++}
++
+ /* static int _init_omap_device(struct omap_hwmod *oh, void *user) */
+ static int _init_omap_device(char *name, struct device **new_dev)
+ {
+@@ -77,6 +102,74 @@ static int _init_omap_device(char *name, struct device **new_dev)
+ return 0;
+ }
+
++static unsigned long omap3_mpu_get_rate(struct device *dev)
++{
++ return dpll1_clk->rate;
++}
++
++static int omap3_mpu_set_rate(struct device *dev, unsigned long rate)
++{
++ unsigned long cur_rate = omap3_mpu_get_rate(dev);
++ int ret;
++
++#ifdef CONFIG_CPU_FREQ
++ struct cpufreq_freqs freqs_notify;
++
++ freqs_notify.old = cur_rate / 1000;
++ freqs_notify.new = rate / 1000;
++ freqs_notify.cpu = 0;
++ /* Send pre notification to CPUFreq */
++ cpufreq_notify_transition(&freqs_notify, CPUFREQ_PRECHANGE);
++#endif
++ ret = clk_set_rate(dpll1_clk, rate);
++ if (ret) {
++ dev_warn(dev, "%s: Unable to set rate to %ld\n",
++ __func__, rate);
++ return ret;
++ }
++
++#ifdef CONFIG_CPU_FREQ
++ /* Send a post notification to CPUFreq */
++ cpufreq_notify_transition(&freqs_notify, CPUFREQ_POSTCHANGE);
++#endif
++
++#ifndef CONFIG_CPU_FREQ
++ /*Update loops_per_jiffy if processor speed is being changed*/
++ loops_per_jiffy = compute_lpj(loops_per_jiffy,
++ cur_rate / 1000, rate / 1000);
++#endif
++ return 0;
++}
++
++static int omap3_iva_set_rate(struct device *dev, unsigned long rate)
++{
++ return clk_set_rate(dpll2_clk, rate);
++}
++
++static unsigned long omap3_iva_get_rate(struct device *dev)
++{
++ return dpll2_clk->rate;
++}
++
++static int omap3_l3_set_rate(struct device *dev, unsigned long rate)
++{
++ int l3_div;
++
++ l3_div = omap2_cm_read_mod_reg(CORE_MOD, CM_CLKSEL) &
++ OMAP3430_CLKSEL_L3_MASK;
++
++ return clk_set_rate(dpll3_clk, rate * l3_div);
++}
++
++static unsigned long omap3_l3_get_rate(struct device *dev)
++{
++ int l3_div;
++
++ l3_div = omap2_cm_read_mod_reg(CORE_MOD, CM_CLKSEL) &
++ OMAP3430_CLKSEL_L3_MASK;
++ return dpll3_clk->rate / l3_div;
++}
++
+ /*
+ * Build omap_devices for processors and bus.
+ */
+@@ -90,6 +183,23 @@ static void omap2_init_processor_devices(void)
+ } else {
+ _init_omap_device("l3_main", &l3_dev);
+ }
++
++ if (cpu_is_omap34xx()) {
++ dpll1_clk = clk_get(NULL, "dpll1_ck");
++ dpll2_clk = clk_get(NULL, "dpll2_ck");
++ dpll3_clk = clk_get(NULL, "dpll3_m2_ck");
++
++ if (mpu_dev)
++ omap_device_populate_rate_fns(mpu_dev,
++ omap3_mpu_set_rate, omap3_mpu_get_rate);
++ if (iva_dev)
++ omap_device_populate_rate_fns(iva_dev,
++ omap3_iva_set_rate, omap3_iva_get_rate);
++ if (l3_dev)
++ omap_device_populate_rate_fns(l3_dev,
++ omap3_l3_set_rate, omap3_l3_get_rate);
++
++ }
+ }
+
+ /* Types of sleep_switch used in omap_set_pwrdm_state */
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0015-OMAP3-Update-cpufreq-driver-to-use-the-new-set_rate-.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0015-OMAP3-Update-cpufreq-driver-to-use-the-new-set_rate-.patch
new file mode 100644
index 00000000..4b9ff5d8
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0015-OMAP3-Update-cpufreq-driver-to-use-the-new-set_rate-.patch
@@ -0,0 +1,54 @@
+From d8fae1dcedb636a37096ee92e6b81b112d5f32a5 Mon Sep 17 00:00:00 2001
+From: Thara Gopinath <thara@ti.com>
+Date: Fri, 2 Jul 2010 13:07:49 +0530
+Subject: [PATCH 15/20] OMAP3: Update cpufreq driver to use the new set_rate API
+
+This patch updates the cpufreq driver to use the device
+set rate API to scale the mpu frequency for OMAP3.
+
+Signed-off-by: Thara Gopinath <thara@ti.com>
+---
+ arch/arm/plat-omap/cpu-omap.c | 11 ++++-------
+ 1 files changed, 4 insertions(+), 7 deletions(-)
+
+diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
+index 671e4b9..71777db 100644
+--- a/arch/arm/plat-omap/cpu-omap.c
++++ b/arch/arm/plat-omap/cpu-omap.c
+@@ -31,10 +31,7 @@
+ #include <plat/clock.h>
+ #include <plat/common.h>
+ #include <asm/system.h>
+-
+-#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE)
+-#include <plat/omap-pm.h>
+-#endif
++#include <plat/omap_device.h>
+
+ #define VERY_HI_RATE 900000000
+
+@@ -88,7 +85,7 @@ static int omap_target(struct cpufreq_policy *policy,
+ #ifdef CONFIG_ARCH_OMAP1
+ struct cpufreq_freqs freqs;
+ #endif
+-#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE)
++#if defined(CONFIG_ARCH_OMAP3)
+ unsigned long freq;
+ struct device *mpu_dev = omap2_get_mpuss_device();
+ #endif
+@@ -115,10 +112,10 @@ static int omap_target(struct cpufreq_policy *policy,
+ #endif
+ ret = clk_set_rate(mpu_clk, freqs.new * 1000);
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+-#elif defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE)
++#elif defined(CONFIG_ARCH_OMAP3)
+ freq = target_freq * 1000;
+ if (opp_find_freq_ceil(mpu_dev, &freq))
+- omap_pm_cpu_set_freq(freq);
++ omap_device_scale(mpu_dev, mpu_dev, freq);
+ #endif
+ return ret;
+ }
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0016-OMAP3-Introduce-voltage-domain-info-in-the-hwmod-str.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0016-OMAP3-Introduce-voltage-domain-info-in-the-hwmod-str.patch
new file mode 100644
index 00000000..fe856527
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0016-OMAP3-Introduce-voltage-domain-info-in-the-hwmod-str.patch
@@ -0,0 +1,45 @@
+From b54b316174e1d59a820e68c45c4abfc1336d8e09 Mon Sep 17 00:00:00 2001
+From: Thara Gopinath <thara@ti.com>
+Date: Wed, 18 Aug 2010 16:22:43 +0530
+Subject: [PATCH 16/20] OMAP3: Introduce voltage domain info in the hwmod structures.
+
+This patch adds voltage domain info in the relevant
+device hwmod structures so as to enable OMAP3 DVFS
+support.
+
+Signed-off-by: Thara Gopinath <thara@ti.com>
+---
+ arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+index 8d81813..c57f34d 100644
+--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
++++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+@@ -94,6 +94,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_l3_main_masters[] = {
+ static struct omap_hwmod omap3xxx_l3_main_hwmod = {
+ .name = "l3_main",
+ .class = &l3_hwmod_class,
++ .vdd_name = "core",
+ .masters = omap3xxx_l3_main_masters,
+ .masters_cnt = ARRAY_SIZE(omap3xxx_l3_main_masters),
+ .slaves = omap3xxx_l3_main_slaves,
+@@ -384,6 +385,7 @@ static struct omap_hwmod omap3xxx_mpu_hwmod = {
+ .name = "mpu",
+ .class = &mpu_hwmod_class,
+ .main_clk = "arm_fck",
++ .vdd_name = "mpu",
+ .masters = omap3xxx_mpu_masters,
+ .masters_cnt = ARRAY_SIZE(omap3xxx_mpu_masters),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+@@ -412,6 +414,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_iva_masters[] = {
+ static struct omap_hwmod omap3xxx_iva_hwmod = {
+ .name = "iva",
+ .class = &iva_hwmod_class,
++ .vdd_name = "mpu",
+ .masters = omap3xxx_iva_masters,
+ .masters_cnt = ARRAY_SIZE(omap3xxx_iva_masters),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0017-OMAP3-Add-voltage-dependency-table-for-VDD1.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0017-OMAP3-Add-voltage-dependency-table-for-VDD1.patch
new file mode 100644
index 00000000..68999391
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0017-OMAP3-Add-voltage-dependency-table-for-VDD1.patch
@@ -0,0 +1,61 @@
+From c196a4ac3941fb9af4654d5d028ad21f4b91d721 Mon Sep 17 00:00:00 2001
+From: Thara Gopinath <thara@ti.com>
+Date: Wed, 18 Aug 2010 16:22:49 +0530
+Subject: [PATCH 17/20] OMAP3: Add voltage dependency table for VDD1.
+
+In OMAP3, for perfomrance reasons when VDD1 is at voltage above
+1.075V, VDD2 should be at 1.15V for perfomrance reasons. This
+patch introduce this cross VDD dependency for OMAP3 VDD1.
+
+Signed-off-by: Thara Gopinath <thara@ti.com>
+---
+ arch/arm/mach-omap2/voltage.c | 24 ++++++++++++++++++++++--
+ 1 files changed, 22 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
+index 2f331de..d10cb1b 100644
+--- a/arch/arm/mach-omap2/voltage.c
++++ b/arch/arm/mach-omap2/voltage.c
+@@ -374,6 +374,23 @@ static struct omap_volt_data omap44xx_vdd_core_volt_data[] = {
+ VOLT_DATA_DEFINE(0, 0, 0, 0),
+ };
+
++/* OMAP 3430 MPU Core VDD dependency table */
++static struct omap_vdd_dep_volt omap34xx_vdd1_vdd2_data[] = {
++ {.main_vdd_volt = 975000, .dep_vdd_volt = 1050000},
++ {.main_vdd_volt = 1075000, .dep_vdd_volt = 1050000},
++ {.main_vdd_volt = 1200000, .dep_vdd_volt = 1150000},
++ {.main_vdd_volt = 1270000, .dep_vdd_volt = 1150000},
++ {.main_vdd_volt = 1350000, .dep_vdd_volt = 1150000},
++ {.main_vdd_volt = 0, .dep_vdd_volt = 0},
++};
++
++static struct omap_vdd_dep_info omap34xx_vdd1_dep_info[] = {
++ {
++ .name = "core",
++ .dep_table = omap34xx_vdd1_vdd2_data,
++ },
++};
++
+ static struct dentry *voltage_dir;
+
+ /* Init function pointers */
+@@ -879,10 +896,13 @@ static int __init omap3_vdd_data_configure(struct omap_vdd_info *vdd)
+ }
+
+ if (!strcmp(vdd->voltdm.name, "mpu")) {
+- if (cpu_is_omap3630())
++ if (cpu_is_omap3630()) {
+ vdd->volt_data = omap36xx_vddmpu_volt_data;
+- else
++ } else {
+ vdd->volt_data = omap34xx_vddmpu_volt_data;
++ vdd->dep_vdd_info = omap34xx_vdd1_dep_info;
++ vdd->nr_dep_vdd = ARRAY_SIZE(omap34xx_vdd1_dep_info);
++ }
+
+ vdd->vp_reg.tranxdone_status = OMAP3430_VP1_TRANXDONE_ST_MASK;
+ vdd->vc_reg.cmdval_reg = OMAP3_PRM_VC_CMD_VAL_0_OFFSET;
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0018-omap3-4-opp-make-omapx_opp_init-non-static.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0018-omap3-4-opp-make-omapx_opp_init-non-static.patch
new file mode 100644
index 00000000..e21fe964
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0018-omap3-4-opp-make-omapx_opp_init-non-static.patch
@@ -0,0 +1,62 @@
+From 16c7667d2908631149ef38b7b6dd7b08d6d5502e Mon Sep 17 00:00:00 2001
+From: Nishanth Menon <nm@ti.com>
+Date: Wed, 5 Jan 2011 14:14:55 -0600
+Subject: [PATCH 18/20] omap3|4: opp: make omapx_opp_init non-static
+
+omap3 and omap4 opp_init should be made non-static to allow
+for platform specific opp table tweaking. making these static
+conflicts with the definition in pm.h(global) as well.
+we include pm.h as well to ensure that there are no such prototype
+conflicts with actual implementation in the future.
+
+Signed-off-by: Nishanth Menon <nm@ti.com>
+---
+ arch/arm/mach-omap2/opp3xxx_data.c | 3 ++-
+ arch/arm/mach-omap2/opp4xxx_data.c | 3 ++-
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/opp3xxx_data.c b/arch/arm/mach-omap2/opp3xxx_data.c
+index 0486fce..fd3a1af 100644
+--- a/arch/arm/mach-omap2/opp3xxx_data.c
++++ b/arch/arm/mach-omap2/opp3xxx_data.c
+@@ -21,6 +21,7 @@
+ #include <plat/cpu.h>
+
+ #include "omap_opp_data.h"
++#include "pm.h"
+
+ static struct omap_opp_def __initdata omap34xx_opp_def_list[] = {
+ /* MPU OPP1 */
+@@ -88,7 +89,7 @@ static struct omap_opp_def __initdata omap36xx_opp_def_list[] = {
+ /**
+ * omap3_opp_init() - initialize omap3 opp table
+ */
+-static int __init omap3_opp_init(void)
++int __init omap3_opp_init(void)
+ {
+ int r = -ENODEV;
+
+diff --git a/arch/arm/mach-omap2/opp4xxx_data.c b/arch/arm/mach-omap2/opp4xxx_data.c
+index a11fa56..f0e9939 100644
+--- a/arch/arm/mach-omap2/opp4xxx_data.c
++++ b/arch/arm/mach-omap2/opp4xxx_data.c
+@@ -22,6 +22,7 @@
+ #include <plat/cpu.h>
+
+ #include "omap_opp_data.h"
++#include "pm.h"
+
+ static struct omap_opp_def __initdata omap44xx_opp_def_list[] = {
+ /* MPU OPP1 - OPP50 */
+@@ -42,7 +43,7 @@ static struct omap_opp_def __initdata omap44xx_opp_def_list[] = {
+ /**
+ * omap4_opp_init() - initialize omap4 opp table
+ */
+-static int __init omap4_opp_init(void)
++int __init omap4_opp_init(void)
+ {
+ int r = -ENODEV;
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0019-OMAP3-beagle-xm-enable-upto-1GHz-OPP.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0019-OMAP3-beagle-xm-enable-upto-1GHz-OPP.patch
new file mode 100644
index 00000000..9d1fa917
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0019-OMAP3-beagle-xm-enable-upto-1GHz-OPP.patch
@@ -0,0 +1,107 @@
+From 897e90138695dccac0dca1601542fd5f4c85b657 Mon Sep 17 00:00:00 2001
+From: Nishanth Menon <nm@ti.com>
+Date: Wed, 5 Jan 2011 14:16:59 -0600
+Subject: [PATCH 19/20] OMAP3: beagle xm: enable upto 1GHz OPP
+
+Beagle XM uses 3730 and the board design allows enabling 800MHz and 1GHz
+OPPs. tweak the default table to allow for higher OPP tables
+
+Reported-by: Koen Kooi <koen@beagleboard.org>
+Signed-off-by: Nishanth Menon <nm@ti.com>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c | 54 +++++++++++++++++++++++++++++++
+ 1 files changed, 54 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index ad0c1d8..1e0870e 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -24,6 +24,7 @@
+ #include <linux/irq.h>
+ #include <linux/input.h>
+ #include <linux/gpio_keys.h>
++#include <linux/opp.h>
+
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+@@ -45,10 +46,12 @@
+ #include <plat/gpmc.h>
+ #include <plat/nand.h>
+ #include <plat/usb.h>
++#include <plat/omap_device.h>
+
+ #include "mux.h"
+ #include "hsmmc.h"
+ #include "timer-gp.h"
++#include "pm.h"
+
+ #define NAND_BLOCK_SIZE SZ_128K
+
+@@ -804,6 +807,56 @@ static int __init expansionboard_setup(char *str)
+ return 0;
+ }
+
++static void __init beagle_opp_init(void)
++{
++ int r = 0;
++
++ /* Initialize the omap3 opp table */
++ if (omap3_opp_init()) {
++ pr_err("%s: opp default init failed\n", __func__);
++ return;
++ }
++
++ /* Custom OPP enabled for XM */
++ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
++ struct omap_hwmod *mh = omap_hwmod_lookup("mpu");
++ struct omap_hwmod *dh = omap_hwmod_lookup("iva");
++ struct device *dev;
++
++ if (!mh || !dh) {
++ pr_err("%s: Aiee.. no mpu/dsp devices? %p %p\n",
++ __func__, mh, dh);
++ r = -EINVAL;
++ } else {
++ /* Enable MPU 1GHz and lower opps */
++ dev = &mh->od->pdev.dev;
++ r = opp_enable(dev, 800000000);
++ r |= opp_enable(dev, 1000000000);
++
++ /* Enable IVA 800MHz and lower opps */
++ dev = &dh->od->pdev.dev;
++ r |= opp_enable(dev, 660000000);
++ r |= opp_enable(dev, 800000000);
++ }
++ if (r) {
++ pr_err("%s: failed to enable higher opp %d\n",
++ __func__, r);
++ /*
++ * Cleanup - disable the higher freqs - we dont care
++ * about the results
++ */
++ dev = &mh->od->pdev.dev;
++ opp_disable(dev, 800000000);
++ opp_disable(dev, 1000000000);
++ dev = &dh->od->pdev.dev;
++ opp_disable(dev, 660000000);
++ opp_disable(dev, 800000000);
++ } else {
++ pr_err("%s: turbo OPPs enabled!\n", __func__);
++ }
++ }
++}
++
+ static void __init omap3_beagle_init(void)
+ {
+ omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+@@ -876,6 +929,7 @@ static void __init omap3_beagle_init(void)
+ omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
+
+ beagle_display_init();
++ beagle_opp_init();
+ }
+
+ early_param("buddy", expansionboard_setup);
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/dvfs/0020-omap3-Add-basic-support-for-720MHz-part.patch b/extras/recipes-kernel/linux/linux-omap/dvfs/0020-omap3-Add-basic-support-for-720MHz-part.patch
new file mode 100644
index 00000000..107e1162
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/dvfs/0020-omap3-Add-basic-support-for-720MHz-part.patch
@@ -0,0 +1,202 @@
+From bb655c594a2f77b17d0747116795f46e00d5ffcb Mon Sep 17 00:00:00 2001
+From: Sanjeev Premi <premi@ti.com>
+Date: Tue, 18 Jan 2011 13:19:55 +0530
+Subject: [PATCH 20/20] omap3: Add basic support for 720MHz part
+
+This patch adds support for new speed enhanced parts with ARM
+and IVA running at 720MHz and 520MHz respectively. These parts
+can be probed at run-time by reading PRODID.SKUID[3:0] at
+0x4830A20C [1].
+
+This patch specifically does following:
+ * Detect devices capable of 720MHz.
+ * Add new OPP
+ * Ensure that OPP is conditionally enabled.
+ * Check for presence of IVA before attempting to enable
+ the corresponding OPP.
+
+ [1] http://focus.ti.com/lit/ug/spruff1d/spruff1d.pdf
+
+Signed-off-by: Sanjeev Premi <premi@ti.com>
+---
+ arch/arm/mach-omap2/control.h | 7 ++++
+ arch/arm/mach-omap2/id.c | 10 +++++
+ arch/arm/mach-omap2/opp3xxx_data.c | 63 ++++++++++++++++++++++++++++++++-
+ arch/arm/plat-omap/include/plat/cpu.h | 2 +
+ 4 files changed, 81 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
+index f0629ae..eebc045 100644
+--- a/arch/arm/mach-omap2/control.h
++++ b/arch/arm/mach-omap2/control.h
+@@ -365,6 +365,13 @@
+ #define FEAT_NEON 0
+ #define FEAT_NEON_NONE 1
+
++/*
++ * Product ID register
++ */
++#define OMAP3_PRODID 0x020C
++
++#define OMAP3_SKUID_MASK 0x0f
++#define OMAP3_SKUID_720MHZ 0x08
+
+ #ifndef __ASSEMBLY__
+ #ifdef CONFIG_ARCH_OMAP2PLUS
+diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
+index 5f9086c..53fbe01 100644
+--- a/arch/arm/mach-omap2/id.c
++++ b/arch/arm/mach-omap2/id.c
+@@ -195,6 +195,15 @@ static void __init omap3_check_features(void)
+ * TODO: Get additional info (where applicable)
+ * e.g. Size of L2 cache.
+ */
++
++ /*
++ * Does it support 720MHz?
++ */
++ status = (OMAP3_SKUID_MASK & read_tap_reg(OMAP3_PRODID));
++
++ if (status & OMAP3_SKUID_720MHZ) {
++ omap3_features |= OMAP3_HAS_720MHZ;
++ }
+ }
+
+ static void __init omap3_check_revision(void)
+@@ -445,6 +454,7 @@ static void __init omap3_cpuinfo(void)
+ OMAP3_SHOW_FEATURE(neon);
+ OMAP3_SHOW_FEATURE(isp);
+ OMAP3_SHOW_FEATURE(192mhz_clk);
++ OMAP3_SHOW_FEATURE(720mhz);
+
+ printk(")\n");
+ }
+diff --git a/arch/arm/mach-omap2/opp3xxx_data.c b/arch/arm/mach-omap2/opp3xxx_data.c
+index fd3a1af..76d26c7 100644
+--- a/arch/arm/mach-omap2/opp3xxx_data.c
++++ b/arch/arm/mach-omap2/opp3xxx_data.c
+@@ -17,8 +17,10 @@
+ * GNU General Public License for more details.
+ */
+ #include <linux/module.h>
++#include <linux/opp.h>
+
+ #include <plat/cpu.h>
++#include <plat/omap_device.h>
+
+ #include "omap_opp_data.h"
+ #include "pm.h"
+@@ -34,6 +36,8 @@ static struct omap_opp_def __initdata omap34xx_opp_def_list[] = {
+ OPP_INITIALIZER("mpu", true, 550000000, 1270000),
+ /* MPU OPP5 */
+ OPP_INITIALIZER("mpu", true, 600000000, 1350000),
++ /* MPU OPP6 */
++ OPP_INITIALIZER("mpu", false, 720000000, 1350000),
+
+ /*
+ * L3 OPP1 - 41.5 MHz is disabled because: The voltage for that OPP is
+@@ -59,6 +63,8 @@ static struct omap_opp_def __initdata omap34xx_opp_def_list[] = {
+ OPP_INITIALIZER("iva", true, 400000000, 1270000),
+ /* DSP OPP5 */
+ OPP_INITIALIZER("iva", true, 430000000, 1350000),
++ /* DSP OPP6 */
++ OPP_INITIALIZER("iva", false, 520000000, 1350000),
+ };
+
+ static struct omap_opp_def __initdata omap36xx_opp_def_list[] = {
+@@ -86,6 +92,57 @@ static struct omap_opp_def __initdata omap36xx_opp_def_list[] = {
+ OPP_INITIALIZER("iva", false, 800000000, 1375000),
+ };
+
++
++/**
++ * omap3_opp_enable_720Mhz() - Enable the OPP corresponding to 720MHz
++ *
++ * This function would be executed only if the silicon is capable of
++ * running at the 720MHz.
++ */
++static int __init omap3_opp_enable_720Mhz(void)
++{
++ int r = -ENODEV;
++ struct omap_hwmod *oh_mpu = omap_hwmod_lookup("mpu");
++ struct omap_hwmod *oh_iva;
++ struct platform_device *pdev;
++
++ if (!oh_mpu || !oh_mpu->od) {
++ goto err;
++ } else {
++ pdev = &oh_mpu->od->pdev;
++
++ r = opp_enable(&pdev->dev, 720000000);
++ if (r < 0) {
++ dev_err(&pdev->dev,
++ "opp_enable() failed for mpu@720MHz");
++ goto err;
++ }
++ }
++
++ if (omap3_has_iva()) {
++ oh_iva = omap_hwmod_lookup("iva");
++
++ if (!oh_iva || !oh_iva->od) {
++ r = -ENODEV;
++ goto err;
++ } else {
++ pdev = &oh_iva->od->pdev;
++
++ r = opp_enable(&pdev->dev, 520000000);
++ if (r < 0) {
++ dev_err(&pdev->dev,
++ "opp_enable() failed for iva@520MHz");
++ goto err;
++ }
++ }
++ }
++
++ dev_info(&pdev->dev, "Enabled OPP corresponding to 720MHz\n");
++
++err:
++ return r;
++}
++
+ /**
+ * omap3_opp_init() - initialize omap3 opp table
+ */
+@@ -99,10 +156,14 @@ int __init omap3_opp_init(void)
+ if (cpu_is_omap3630())
+ r = omap_init_opp_table(omap36xx_opp_def_list,
+ ARRAY_SIZE(omap36xx_opp_def_list));
+- else
++ else {
+ r = omap_init_opp_table(omap34xx_opp_def_list,
+ ARRAY_SIZE(omap34xx_opp_def_list));
+
++ if (omap3_has_720mhz())
++ r = omap3_opp_enable_720Mhz();
++ }
++
+ return r;
+ }
+ device_initcall(omap3_opp_init);
+diff --git a/arch/arm/plat-omap/include/plat/cpu.h b/arch/arm/plat-omap/include/plat/cpu.h
+index 1a8c347..7d24faa 100644
+--- a/arch/arm/plat-omap/include/plat/cpu.h
++++ b/arch/arm/plat-omap/include/plat/cpu.h
+@@ -510,6 +510,7 @@ extern u32 omap3_features;
+ #define OMAP3_HAS_ISP BIT(4)
+ #define OMAP3_HAS_192MHZ_CLK BIT(5)
+ #define OMAP3_HAS_IO_WAKEUP BIT(6)
++#define OMAP3_HAS_720MHZ BIT(7)
+
+ #define OMAP3_HAS_FEATURE(feat,flag) \
+ static inline unsigned int omap3_has_ ##feat(void) \
+@@ -524,5 +525,6 @@ OMAP3_HAS_FEATURE(neon, NEON)
+ OMAP3_HAS_FEATURE(isp, ISP)
+ OMAP3_HAS_FEATURE(192mhz_clk, 192MHZ_CLK)
+ OMAP3_HAS_FEATURE(io_wakeup, IO_WAKEUP)
++OMAP3_HAS_FEATURE(720mhz, 720MHZ)
+
+ #endif
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0001-ARM-pxa-PXA_ESERIES-depends-on-FB_W100.patch b/extras/recipes-kernel/linux/linux-omap/linus/0001-ARM-pxa-PXA_ESERIES-depends-on-FB_W100.patch
new file mode 100644
index 00000000..845a4f9c
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0001-ARM-pxa-PXA_ESERIES-depends-on-FB_W100.patch
@@ -0,0 +1,29 @@
+From 679fd7bc2af7980a4b9360ff42f515c3cc4e3674 Mon Sep 17 00:00:00 2001
+From: Lennert Buytenhek <buytenh@wantstofly.org>
+Date: Wed, 15 Dec 2010 07:20:16 +0800
+Subject: [PATCH 01/65] ARM: pxa: PXA_ESERIES depends on FB_W100.
+
+As arch/arm/mach-pxa/eseries.c references w100fb_gpio_{read,write}()
+directly.
+
+Signed-off-by: Lennert Buytenhek <buytenh@secretlab.ca>
+Signed-off-by: Eric Miao <eric.y.miao@gmail.com>
+---
+ arch/arm/mach-pxa/Kconfig | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
+index dd235ec..c93e73d 100644
+--- a/arch/arm/mach-pxa/Kconfig
++++ b/arch/arm/mach-pxa/Kconfig
+@@ -540,6 +540,7 @@ config MACH_ICONTROL
+ config ARCH_PXA_ESERIES
+ bool "PXA based Toshiba e-series PDAs"
+ select PXA25x
++ select FB_W100
+
+ config MACH_E330
+ bool "Toshiba e330"
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0002-ARM-smp-avoid-incrementing-mm_users-on-CPU-startup.patch b/extras/recipes-kernel/linux/linux-omap/linus/0002-ARM-smp-avoid-incrementing-mm_users-on-CPU-startup.patch
new file mode 100644
index 00000000..19b1a6c6
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0002-ARM-smp-avoid-incrementing-mm_users-on-CPU-startup.patch
@@ -0,0 +1,32 @@
+From d7bbfe094baebc1515d3919a1e886fcfa655ff5a Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Sat, 18 Dec 2010 13:57:00 +0000
+Subject: [PATCH 02/65] ARM: smp: avoid incrementing mm_users on CPU startup
+
+We should not be incrementing mm_users when we startup a secondary
+CPU - doing so results in mm_users incrementing by one each time we
+hotplug a CPU, which will eventually wrap, and will cause problems.
+
+Other architectures such as x86 do not increment mm_users, but only
+mm_count, so we follow that pattern.
+
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ arch/arm/kernel/smp.c | 1 -
+ 1 files changed, 0 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
+index 8c19595..9066473 100644
+--- a/arch/arm/kernel/smp.c
++++ b/arch/arm/kernel/smp.c
+@@ -310,7 +310,6 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
+ * All kernel threads share the same mm context; grab a
+ * reference and switch to it.
+ */
+- atomic_inc(&mm->mm_users);
+ atomic_inc(&mm->mm_count);
+ current->active_mm = mm;
+ cpumask_set_cpu(cpu, mm_cpumask(mm));
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0003-ARM-get-rid-of-kmap_high_l1_vipt.patch b/extras/recipes-kernel/linux/linux-omap/linus/0003-ARM-get-rid-of-kmap_high_l1_vipt.patch
new file mode 100644
index 00000000..d31b0e69
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0003-ARM-get-rid-of-kmap_high_l1_vipt.patch
@@ -0,0 +1,186 @@
+From b4edc88b911049a85162600f579d0364ee311d4e Mon Sep 17 00:00:00 2001
+From: Nicolas Pitre <nicolas.pitre@linaro.org>
+Date: Wed, 15 Dec 2010 15:14:45 -0500
+Subject: [PATCH 03/65] ARM: get rid of kmap_high_l1_vipt()
+
+Since commit 3e4d3af501 "mm: stack based kmap_atomic()", it is no longer
+necessary to carry an ad hoc version of kmap_atomic() added in commit
+7e5a69e83b "ARM: 6007/1: fix highmem with VIPT cache and DMA" to cope
+with reentrancy.
+
+In fact, it is now actively wrong to rely on fixed kmap type indices
+(namely KM_L1_CACHE) as kmap_atomic() totally ignores them now and a
+concurrent instance of it may reuse any slot for any purpose.
+
+Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>
+---
+ arch/arm/include/asm/highmem.h | 3 -
+ arch/arm/mm/dma-mapping.c | 7 ++-
+ arch/arm/mm/flush.c | 7 ++-
+ arch/arm/mm/highmem.c | 87 ----------------------------------------
+ 4 files changed, 8 insertions(+), 96 deletions(-)
+
+diff --git a/arch/arm/include/asm/highmem.h b/arch/arm/include/asm/highmem.h
+index 1fc684e..7080e2c 100644
+--- a/arch/arm/include/asm/highmem.h
++++ b/arch/arm/include/asm/highmem.h
+@@ -25,9 +25,6 @@ extern void *kmap_high(struct page *page);
+ extern void *kmap_high_get(struct page *page);
+ extern void kunmap_high(struct page *page);
+
+-extern void *kmap_high_l1_vipt(struct page *page, pte_t *saved_pte);
+-extern void kunmap_high_l1_vipt(struct page *page, pte_t saved_pte);
+-
+ /*
+ * The following functions are already defined by <linux/highmem.h>
+ * when CONFIG_HIGHMEM is not set.
+diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
+index ac6a361..809f1bf 100644
+--- a/arch/arm/mm/dma-mapping.c
++++ b/arch/arm/mm/dma-mapping.c
+@@ -17,6 +17,7 @@
+ #include <linux/init.h>
+ #include <linux/device.h>
+ #include <linux/dma-mapping.h>
++#include <linux/highmem.h>
+
+ #include <asm/memory.h>
+ #include <asm/highmem.h>
+@@ -480,10 +481,10 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset,
+ op(vaddr, len, dir);
+ kunmap_high(page);
+ } else if (cache_is_vipt()) {
+- pte_t saved_pte;
+- vaddr = kmap_high_l1_vipt(page, &saved_pte);
++ /* unmapped pages might still be cached */
++ vaddr = kmap_atomic(page);
+ op(vaddr + offset, len, dir);
+- kunmap_high_l1_vipt(page, saved_pte);
++ kunmap_atomic(vaddr);
+ }
+ } else {
+ vaddr = page_address(page) + offset;
+diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
+index 391ffae..c29f283 100644
+--- a/arch/arm/mm/flush.c
++++ b/arch/arm/mm/flush.c
+@@ -10,6 +10,7 @@
+ #include <linux/module.h>
+ #include <linux/mm.h>
+ #include <linux/pagemap.h>
++#include <linux/highmem.h>
+
+ #include <asm/cacheflush.h>
+ #include <asm/cachetype.h>
+@@ -180,10 +181,10 @@ void __flush_dcache_page(struct address_space *mapping, struct page *page)
+ __cpuc_flush_dcache_area(addr, PAGE_SIZE);
+ kunmap_high(page);
+ } else if (cache_is_vipt()) {
+- pte_t saved_pte;
+- addr = kmap_high_l1_vipt(page, &saved_pte);
++ /* unmapped pages might still be cached */
++ addr = kmap_atomic(page);
+ __cpuc_flush_dcache_area(addr, PAGE_SIZE);
+- kunmap_high_l1_vipt(page, saved_pte);
++ kunmap_atomic(addr);
+ }
+ }
+
+diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c
+index c435fd9..807c057 100644
+--- a/arch/arm/mm/highmem.c
++++ b/arch/arm/mm/highmem.c
+@@ -140,90 +140,3 @@ struct page *kmap_atomic_to_page(const void *ptr)
+ pte = TOP_PTE(vaddr);
+ return pte_page(*pte);
+ }
+-
+-#ifdef CONFIG_CPU_CACHE_VIPT
+-
+-#include <linux/percpu.h>
+-
+-/*
+- * The VIVT cache of a highmem page is always flushed before the page
+- * is unmapped. Hence unmapped highmem pages need no cache maintenance
+- * in that case.
+- *
+- * However unmapped pages may still be cached with a VIPT cache, and
+- * it is not possible to perform cache maintenance on them using physical
+- * addresses unfortunately. So we have no choice but to set up a temporary
+- * virtual mapping for that purpose.
+- *
+- * Yet this VIPT cache maintenance may be triggered from DMA support
+- * functions which are possibly called from interrupt context. As we don't
+- * want to keep interrupt disabled all the time when such maintenance is
+- * taking place, we therefore allow for some reentrancy by preserving and
+- * restoring the previous fixmap entry before the interrupted context is
+- * resumed. If the reentrancy depth is 0 then there is no need to restore
+- * the previous fixmap, and leaving the current one in place allow it to
+- * be reused the next time without a TLB flush (common with DMA).
+- */
+-
+-static DEFINE_PER_CPU(int, kmap_high_l1_vipt_depth);
+-
+-void *kmap_high_l1_vipt(struct page *page, pte_t *saved_pte)
+-{
+- unsigned int idx, cpu;
+- int *depth;
+- unsigned long vaddr, flags;
+- pte_t pte, *ptep;
+-
+- if (!in_interrupt())
+- preempt_disable();
+-
+- cpu = smp_processor_id();
+- depth = &per_cpu(kmap_high_l1_vipt_depth, cpu);
+-
+- idx = KM_L1_CACHE + KM_TYPE_NR * cpu;
+- vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+- ptep = TOP_PTE(vaddr);
+- pte = mk_pte(page, kmap_prot);
+-
+- raw_local_irq_save(flags);
+- (*depth)++;
+- if (pte_val(*ptep) == pte_val(pte)) {
+- *saved_pte = pte;
+- } else {
+- *saved_pte = *ptep;
+- set_pte_ext(ptep, pte, 0);
+- local_flush_tlb_kernel_page(vaddr);
+- }
+- raw_local_irq_restore(flags);
+-
+- return (void *)vaddr;
+-}
+-
+-void kunmap_high_l1_vipt(struct page *page, pte_t saved_pte)
+-{
+- unsigned int idx, cpu = smp_processor_id();
+- int *depth = &per_cpu(kmap_high_l1_vipt_depth, cpu);
+- unsigned long vaddr, flags;
+- pte_t pte, *ptep;
+-
+- idx = KM_L1_CACHE + KM_TYPE_NR * cpu;
+- vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+- ptep = TOP_PTE(vaddr);
+- pte = mk_pte(page, kmap_prot);
+-
+- BUG_ON(pte_val(*ptep) != pte_val(pte));
+- BUG_ON(*depth <= 0);
+-
+- raw_local_irq_save(flags);
+- (*depth)--;
+- if (*depth != 0 && pte_val(pte) != pte_val(saved_pte)) {
+- set_pte_ext(ptep, saved_pte, 0);
+- local_flush_tlb_kernel_page(vaddr);
+- }
+- raw_local_irq_restore(flags);
+-
+- if (!in_interrupt())
+- preempt_enable();
+-}
+-
+-#endif /* CONFIG_CPU_CACHE_VIPT */
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0004-ARM-fix-cache-xsc3l2-after-stack-based-kmap_atomic.patch b/extras/recipes-kernel/linux/linux-omap/linus/0004-ARM-fix-cache-xsc3l2-after-stack-based-kmap_atomic.patch
new file mode 100644
index 00000000..32643f67
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0004-ARM-fix-cache-xsc3l2-after-stack-based-kmap_atomic.patch
@@ -0,0 +1,189 @@
+From fc077c0fbb09ca255691d05789076d121ae11789 Mon Sep 17 00:00:00 2001
+From: Nicolas Pitre <nicolas.pitre@linaro.org>
+Date: Wed, 15 Dec 2010 23:29:04 -0500
+Subject: [PATCH 04/65] ARM: fix cache-xsc3l2 after stack based kmap_atomic()
+
+Since commit 3e4d3af501 "mm: stack based kmap_atomic()", it is actively
+wrong to rely on fixed kmap type indices (namely KM_L2_CACHE) as
+kmap_atomic() totally ignores them and a concurrent instance of it may
+happily reuse any slot for any purpose. Because kmap_atomic() is now
+able to deal with reentrancy, we can get rid of the ad hoc mapping here,
+and we even don't have to disable IRQs anymore (highmem case).
+
+While the code is made much simpler, there is a needless cache flush
+introduced by the usage of __kunmap_atomic(). It is not clear if the
+performance difference to remove that is worth the cost in code
+maintenance (I don't think there are that many highmem users on that
+platform if at all anyway).
+
+Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>
+---
+ arch/arm/mm/cache-xsc3l2.c | 57 ++++++++++++++++---------------------------
+ 1 files changed, 21 insertions(+), 36 deletions(-)
+
+diff --git a/arch/arm/mm/cache-xsc3l2.c b/arch/arm/mm/cache-xsc3l2.c
+index c315492..5a32020 100644
+--- a/arch/arm/mm/cache-xsc3l2.c
++++ b/arch/arm/mm/cache-xsc3l2.c
+@@ -17,14 +17,10 @@
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+ #include <linux/init.h>
++#include <linux/highmem.h>
+ #include <asm/system.h>
+ #include <asm/cputype.h>
+ #include <asm/cacheflush.h>
+-#include <asm/kmap_types.h>
+-#include <asm/fixmap.h>
+-#include <asm/pgtable.h>
+-#include <asm/tlbflush.h>
+-#include "mm.h"
+
+ #define CR_L2 (1 << 26)
+
+@@ -71,16 +67,15 @@ static inline void xsc3_l2_inv_all(void)
+ dsb();
+ }
+
++static inline void l2_unmap_va(unsigned long va)
++{
+ #ifdef CONFIG_HIGHMEM
+-#define l2_map_save_flags(x) raw_local_save_flags(x)
+-#define l2_map_restore_flags(x) raw_local_irq_restore(x)
+-#else
+-#define l2_map_save_flags(x) ((x) = 0)
+-#define l2_map_restore_flags(x) ((void)(x))
++ if (va != -1)
++ kunmap_atomic((void *)va);
+ #endif
++}
+
+-static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va,
+- unsigned long flags)
++static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va)
+ {
+ #ifdef CONFIG_HIGHMEM
+ unsigned long va = prev_va & PAGE_MASK;
+@@ -89,17 +84,10 @@ static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va,
+ /*
+ * Switching to a new page. Because cache ops are
+ * using virtual addresses only, we must put a mapping
+- * in place for it. We also enable interrupts for a
+- * short while and disable them again to protect this
+- * mapping.
++ * in place for it.
+ */
+- unsigned long idx;
+- raw_local_irq_restore(flags);
+- idx = KM_L2_CACHE + KM_TYPE_NR * smp_processor_id();
+- va = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+- raw_local_irq_restore(flags | PSR_I_BIT);
+- set_pte_ext(TOP_PTE(va), pfn_pte(pa >> PAGE_SHIFT, PAGE_KERNEL), 0);
+- local_flush_tlb_kernel_page(va);
++ l2_unmap_va(prev_va);
++ va = (unsigned long)kmap_atomic_pfn(pa >> PAGE_SHIFT);
+ }
+ return va + (pa_offset >> (32 - PAGE_SHIFT));
+ #else
+@@ -109,7 +97,7 @@ static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va,
+
+ static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
+ {
+- unsigned long vaddr, flags;
++ unsigned long vaddr;
+
+ if (start == 0 && end == -1ul) {
+ xsc3_l2_inv_all();
+@@ -117,13 +105,12 @@ static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
+ }
+
+ vaddr = -1; /* to force the first mapping */
+- l2_map_save_flags(flags);
+
+ /*
+ * Clean and invalidate partial first cache line.
+ */
+ if (start & (CACHE_LINE_SIZE - 1)) {
+- vaddr = l2_map_va(start & ~(CACHE_LINE_SIZE - 1), vaddr, flags);
++ vaddr = l2_map_va(start & ~(CACHE_LINE_SIZE - 1), vaddr);
+ xsc3_l2_clean_mva(vaddr);
+ xsc3_l2_inv_mva(vaddr);
+ start = (start | (CACHE_LINE_SIZE - 1)) + 1;
+@@ -133,7 +120,7 @@ static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
+ * Invalidate all full cache lines between 'start' and 'end'.
+ */
+ while (start < (end & ~(CACHE_LINE_SIZE - 1))) {
+- vaddr = l2_map_va(start, vaddr, flags);
++ vaddr = l2_map_va(start, vaddr);
+ xsc3_l2_inv_mva(vaddr);
+ start += CACHE_LINE_SIZE;
+ }
+@@ -142,31 +129,30 @@ static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
+ * Clean and invalidate partial last cache line.
+ */
+ if (start < end) {
+- vaddr = l2_map_va(start, vaddr, flags);
++ vaddr = l2_map_va(start, vaddr);
+ xsc3_l2_clean_mva(vaddr);
+ xsc3_l2_inv_mva(vaddr);
+ }
+
+- l2_map_restore_flags(flags);
++ l2_unmap_va(vaddr);
+
+ dsb();
+ }
+
+ static void xsc3_l2_clean_range(unsigned long start, unsigned long end)
+ {
+- unsigned long vaddr, flags;
++ unsigned long vaddr;
+
+ vaddr = -1; /* to force the first mapping */
+- l2_map_save_flags(flags);
+
+ start &= ~(CACHE_LINE_SIZE - 1);
+ while (start < end) {
+- vaddr = l2_map_va(start, vaddr, flags);
++ vaddr = l2_map_va(start, vaddr);
+ xsc3_l2_clean_mva(vaddr);
+ start += CACHE_LINE_SIZE;
+ }
+
+- l2_map_restore_flags(flags);
++ l2_unmap_va(vaddr);
+
+ dsb();
+ }
+@@ -193,7 +179,7 @@ static inline void xsc3_l2_flush_all(void)
+
+ static void xsc3_l2_flush_range(unsigned long start, unsigned long end)
+ {
+- unsigned long vaddr, flags;
++ unsigned long vaddr;
+
+ if (start == 0 && end == -1ul) {
+ xsc3_l2_flush_all();
+@@ -201,17 +187,16 @@ static void xsc3_l2_flush_range(unsigned long start, unsigned long end)
+ }
+
+ vaddr = -1; /* to force the first mapping */
+- l2_map_save_flags(flags);
+
+ start &= ~(CACHE_LINE_SIZE - 1);
+ while (start < end) {
+- vaddr = l2_map_va(start, vaddr, flags);
++ vaddr = l2_map_va(start, vaddr);
+ xsc3_l2_clean_mva(vaddr);
+ xsc3_l2_inv_mva(vaddr);
+ start += CACHE_LINE_SIZE;
+ }
+
+- l2_map_restore_flags(flags);
++ l2_unmap_va(vaddr);
+
+ dsb();
+ }
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0005-ARM-fix-cache-feroceon-l2-after-stack-based-kmap_ato.patch b/extras/recipes-kernel/linux/linux-omap/linus/0005-ARM-fix-cache-feroceon-l2-after-stack-based-kmap_ato.patch
new file mode 100644
index 00000000..a9fd1f02
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0005-ARM-fix-cache-feroceon-l2-after-stack-based-kmap_ato.patch
@@ -0,0 +1,119 @@
+From ccb2858c9bd5fff216feab665db14ca32be8d6fe Mon Sep 17 00:00:00 2001
+From: Nicolas Pitre <nicolas.pitre@linaro.org>
+Date: Thu, 16 Dec 2010 14:56:34 -0500
+Subject: [PATCH 05/65] ARM: fix cache-feroceon-l2 after stack based kmap_atomic()
+
+Since commit 3e4d3af501 "mm: stack based kmap_atomic()", it is actively
+wrong to rely on fixed kmap type indices (namely KM_L2_CACHE) as
+kmap_atomic() totally ignores them and a concurrent instance of it may
+happily reuse any slot for any purpose. Because kmap_atomic() is now
+able to deal with reentrancy, we can get rid of the ad hoc mapping here.
+
+While the code is made much simpler, there is a needless cache flush
+introduced by the usage of __kunmap_atomic(). It is not clear if the
+performance difference to remove that is worth the cost in code
+maintenance (I don't think there are that many highmem users on that
+platform anyway) but that should be reconsidered when/if someone cares
+enough to do some measurements.
+
+Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>
+---
+ arch/arm/mm/cache-feroceon-l2.c | 37 +++++++++++++++++++------------------
+ 1 files changed, 19 insertions(+), 18 deletions(-)
+
+diff --git a/arch/arm/mm/cache-feroceon-l2.c b/arch/arm/mm/cache-feroceon-l2.c
+index 6e77c04..e0b0e7a 100644
+--- a/arch/arm/mm/cache-feroceon-l2.c
++++ b/arch/arm/mm/cache-feroceon-l2.c
+@@ -13,13 +13,9 @@
+ */
+
+ #include <linux/init.h>
++#include <linux/highmem.h>
+ #include <asm/cacheflush.h>
+-#include <asm/kmap_types.h>
+-#include <asm/fixmap.h>
+-#include <asm/pgtable.h>
+-#include <asm/tlbflush.h>
+ #include <plat/cache-feroceon-l2.h>
+-#include "mm.h"
+
+ /*
+ * Low-level cache maintenance operations.
+@@ -39,27 +35,30 @@
+ * between which we don't want to be preempted.
+ */
+
+-static inline unsigned long l2_start_va(unsigned long paddr)
++static inline unsigned long l2_get_va(unsigned long paddr)
+ {
+ #ifdef CONFIG_HIGHMEM
+ /*
+- * Let's do our own fixmap stuff in a minimal way here.
+ * Because range ops can't be done on physical addresses,
+ * we simply install a virtual mapping for it only for the
+ * TLB lookup to occur, hence no need to flush the untouched
+- * memory mapping. This is protected with the disabling of
+- * interrupts by the caller.
++ * memory mapping afterwards (note: a cache flush may happen
++ * in some circumstances depending on the path taken in kunmap_atomic).
+ */
+- unsigned long idx = KM_L2_CACHE + KM_TYPE_NR * smp_processor_id();
+- unsigned long vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+- set_pte_ext(TOP_PTE(vaddr), pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL), 0);
+- local_flush_tlb_kernel_page(vaddr);
+- return vaddr + (paddr & ~PAGE_MASK);
++ void *vaddr = kmap_atomic_pfn(paddr >> PAGE_SHIFT);
++ return (unsigned long)vaddr + (paddr & ~PAGE_MASK);
+ #else
+ return __phys_to_virt(paddr);
+ #endif
+ }
+
++static inline void l2_put_va(unsigned long vaddr)
++{
++#ifdef CONFIG_HIGHMEM
++ kunmap_atomic((void *)vaddr);
++#endif
++}
++
+ static inline void l2_clean_pa(unsigned long addr)
+ {
+ __asm__("mcr p15, 1, %0, c15, c9, 3" : : "r" (addr));
+@@ -76,13 +75,14 @@ static inline void l2_clean_pa_range(unsigned long start, unsigned long end)
+ */
+ BUG_ON((start ^ end) >> PAGE_SHIFT);
+
+- raw_local_irq_save(flags);
+- va_start = l2_start_va(start);
++ va_start = l2_get_va(start);
+ va_end = va_start + (end - start);
++ raw_local_irq_save(flags);
+ __asm__("mcr p15, 1, %0, c15, c9, 4\n\t"
+ "mcr p15, 1, %1, c15, c9, 5"
+ : : "r" (va_start), "r" (va_end));
+ raw_local_irq_restore(flags);
++ l2_put_va(va_start);
+ }
+
+ static inline void l2_clean_inv_pa(unsigned long addr)
+@@ -106,13 +106,14 @@ static inline void l2_inv_pa_range(unsigned long start, unsigned long end)
+ */
+ BUG_ON((start ^ end) >> PAGE_SHIFT);
+
+- raw_local_irq_save(flags);
+- va_start = l2_start_va(start);
++ va_start = l2_get_va(start);
+ va_end = va_start + (end - start);
++ raw_local_irq_save(flags);
+ __asm__("mcr p15, 1, %0, c15, c11, 4\n\t"
+ "mcr p15, 1, %1, c15, c11, 5"
+ : : "r" (va_start), "r" (va_end));
+ raw_local_irq_restore(flags);
++ l2_put_va(va_start);
+ }
+
+ static inline void l2_inv_all(void)
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0006-drm-i915-Set-the-required-VFMUNIT-clock-gating-disab.patch b/extras/recipes-kernel/linux/linux-omap/linus/0006-drm-i915-Set-the-required-VFMUNIT-clock-gating-disab.patch
new file mode 100644
index 00000000..8302e6c0
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0006-drm-i915-Set-the-required-VFMUNIT-clock-gating-disab.patch
@@ -0,0 +1,45 @@
+From b4defd15cd77597734bab7089fa721fde6e3cfd5 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Tue, 14 Dec 2010 10:06:46 -0800
+Subject: [PATCH 06/65] drm/i915: Set the required VFMUNIT clock gating disable on Ironlake.
+
+It's required by the specs, but we don't know why. Let's not find out
+why.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+---
+ drivers/gpu/drm/i915/i915_reg.h | 3 +++
+ drivers/gpu/drm/i915/intel_display.c | 2 ++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
+index 878fc76..8470a97 100644
+--- a/drivers/gpu/drm/i915/i915_reg.h
++++ b/drivers/gpu/drm/i915/i915_reg.h
+@@ -2471,6 +2471,9 @@
+ # define MARIUNIT_CLOCK_GATE_DISABLE (1 << 18)
+ # define SVSMUNIT_CLOCK_GATE_DISABLE (1 << 1)
+
++#define PCH_3DCGDIS1 0x46024
++# define VFMUNIT_CLOCK_GATE_DISABLE (1 << 11)
++
+ #define FDI_PLL_FREQ_CTL 0x46030
+ #define FDI_PLL_FREQ_CHANGE_REQUEST (1<<24)
+ #define FDI_PLL_FREQ_LOCK_LIMIT_MASK 0xfff00
+diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
+index d9b7092..97e374e 100644
+--- a/drivers/gpu/drm/i915/intel_display.c
++++ b/drivers/gpu/drm/i915/intel_display.c
+@@ -5825,6 +5825,8 @@ void intel_init_clock_gating(struct drm_device *dev)
+ I915_WRITE(PCH_3DCGDIS0,
+ MARIUNIT_CLOCK_GATE_DISABLE |
+ SVSMUNIT_CLOCK_GATE_DISABLE);
++ I915_WRITE(PCH_3DCGDIS1,
++ VFMUNIT_CLOCK_GATE_DISABLE);
+ }
+
+ I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0007-drm-i915-sdvo-Add-hdmi-connector-properties-after-in.patch b/extras/recipes-kernel/linux/linux-omap/linus/0007-drm-i915-sdvo-Add-hdmi-connector-properties-after-in.patch
new file mode 100644
index 00000000..4e5120a1
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0007-drm-i915-sdvo-Add-hdmi-connector-properties-after-in.patch
@@ -0,0 +1,38 @@
+From 184e12ee6bca758bee292970ed045d7a0405168c Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Thu, 23 Dec 2010 09:43:48 +0000
+Subject: [PATCH 07/65] drm/i915/sdvo: Add hdmi connector properties after initing the connector
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=25012
+Reported-by: Tõnu Raitviir <jussuf@linux.ee>
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+---
+ drivers/gpu/drm/i915/intel_sdvo.c | 3 ++-
+ 1 files changed, 2 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
+index 27e63ab..6bc42fa 100644
+--- a/drivers/gpu/drm/i915/intel_sdvo.c
++++ b/drivers/gpu/drm/i915/intel_sdvo.c
+@@ -2040,13 +2040,14 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
+ SDVO_COLORIMETRY_RGB256);
+ connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
+
+- intel_sdvo_add_hdmi_properties(intel_sdvo_connector);
+ intel_sdvo->is_hdmi = true;
+ }
+ intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
+ (1 << INTEL_ANALOG_CLONE_BIT));
+
+ intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
++ if (intel_sdvo->is_hdmi)
++ intel_sdvo_add_hdmi_properties(intel_sdvo_connector);
+
+ return true;
+ }
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0008-drm-i915-intel_ips-When-i915-loads-after-IPS-make-IP.patch b/extras/recipes-kernel/linux/linux-omap/linus/0008-drm-i915-intel_ips-When-i915-loads-after-IPS-make-IP.patch
new file mode 100644
index 00000000..9fecb7b8
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0008-drm-i915-intel_ips-When-i915-loads-after-IPS-make-IP.patch
@@ -0,0 +1,190 @@
+From 38684934e58030113d3e89a3f60472e22e2e1ea6 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 20 Dec 2010 18:40:06 -0800
+Subject: [PATCH 08/65] drm/i915, intel_ips: When i915 loads after IPS, make IPS relink to i915.
+
+The IPS driver is designed to be able to run detached from i915 and
+just not enable GPU turbo in that case, in order to avoid module
+dependencies between the two drivers. This means that we don't know
+what the load order between the two is going to be, and we had
+previously only supported IPS after (optionally) i915, but not i915
+after IPS. If the wrong order was chosen, you'd get no GPU turbo, and
+something like half the possible graphics performance.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Cc: stable@kernel.org
+---
+ drivers/gpu/drm/i915/i915_dma.c | 23 +++++++++++++++++++++++
+ drivers/platform/x86/intel_ips.c | 36 +++++++++++++++++++++++++++++++++---
+ drivers/platform/x86/intel_ips.h | 21 +++++++++++++++++++++
+ 3 files changed, 77 insertions(+), 3 deletions(-)
+ create mode 100644 drivers/platform/x86/intel_ips.h
+
+diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
+index e680081..cb900dc 100644
+--- a/drivers/gpu/drm/i915/i915_dma.c
++++ b/drivers/gpu/drm/i915/i915_dma.c
+@@ -34,6 +34,7 @@
+ #include "i915_drm.h"
+ #include "i915_drv.h"
+ #include "i915_trace.h"
++#include "../../../platform/x86/intel_ips.h"
+ #include <linux/pci.h>
+ #include <linux/vgaarb.h>
+ #include <linux/acpi.h>
+@@ -1871,6 +1872,26 @@ out_unlock:
+ EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable);
+
+ /**
++ * Tells the intel_ips driver that the i915 driver is now loaded, if
++ * IPS got loaded first.
++ *
++ * This awkward dance is so that neither module has to depend on the
++ * other in order for IPS to do the appropriate communication of
++ * GPU turbo limits to i915.
++ */
++static void
++ips_ping_for_i915_load(void)
++{
++ void (*link)(void);
++
++ link = symbol_get(ips_link_to_i915_driver);
++ if (link) {
++ link();
++ symbol_put(ips_link_to_i915_driver);
++ }
++}
++
++/**
+ * i915_driver_load - setup chip and create an initial config
+ * @dev: DRM device
+ * @flags: startup flags
+@@ -2075,6 +2096,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
+ dev_priv->mchdev_lock = &mchdev_lock;
+ spin_unlock(&mchdev_lock);
+
++ ips_ping_for_i915_load();
++
+ return 0;
+
+ out_workqueue_free:
+diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c
+index c44a5e8..f0b3ad1 100644
+--- a/drivers/platform/x86/intel_ips.c
++++ b/drivers/platform/x86/intel_ips.c
+@@ -75,6 +75,7 @@
+ #include <drm/i915_drm.h>
+ #include <asm/msr.h>
+ #include <asm/processor.h>
++#include "intel_ips.h"
+
+ #define PCI_DEVICE_ID_INTEL_THERMAL_SENSOR 0x3b32
+
+@@ -245,6 +246,7 @@
+ #define thm_writel(off, val) writel((val), ips->regmap + (off))
+
+ static const int IPS_ADJUST_PERIOD = 5000; /* ms */
++static bool late_i915_load = false;
+
+ /* For initial average collection */
+ static const int IPS_SAMPLE_PERIOD = 200; /* ms */
+@@ -339,6 +341,9 @@ struct ips_driver {
+ u64 orig_turbo_ratios;
+ };
+
++static bool
++ips_gpu_turbo_enabled(struct ips_driver *ips);
++
+ /**
+ * ips_cpu_busy - is CPU busy?
+ * @ips: IPS driver struct
+@@ -517,7 +522,7 @@ static void ips_disable_cpu_turbo(struct ips_driver *ips)
+ */
+ static bool ips_gpu_busy(struct ips_driver *ips)
+ {
+- if (!ips->gpu_turbo_enabled)
++ if (!ips_gpu_turbo_enabled(ips))
+ return false;
+
+ return ips->gpu_busy();
+@@ -532,7 +537,7 @@ static bool ips_gpu_busy(struct ips_driver *ips)
+ */
+ static void ips_gpu_raise(struct ips_driver *ips)
+ {
+- if (!ips->gpu_turbo_enabled)
++ if (!ips_gpu_turbo_enabled(ips))
+ return;
+
+ if (!ips->gpu_raise())
+@@ -549,7 +554,7 @@ static void ips_gpu_raise(struct ips_driver *ips)
+ */
+ static void ips_gpu_lower(struct ips_driver *ips)
+ {
+- if (!ips->gpu_turbo_enabled)
++ if (!ips_gpu_turbo_enabled(ips))
+ return;
+
+ if (!ips->gpu_lower())
+@@ -1454,6 +1459,31 @@ out_err:
+ return false;
+ }
+
++static bool
++ips_gpu_turbo_enabled(struct ips_driver *ips)
++{
++ if (!ips->gpu_busy && late_i915_load) {
++ if (ips_get_i915_syms(ips)) {
++ dev_info(&ips->dev->dev,
++ "i915 driver attached, reenabling gpu turbo\n");
++ ips->gpu_turbo_enabled = !(thm_readl(THM_HTS) & HTS_GTD_DIS);
++ }
++ }
++
++ return ips->gpu_turbo_enabled;
++}
++
++void
++ips_link_to_i915_driver()
++{
++ /* We can't cleanly get at the various ips_driver structs from
++ * this caller (the i915 driver), so just set a flag saying
++ * that it's time to try getting the symbols again.
++ */
++ late_i915_load = true;
++}
++EXPORT_SYMBOL_GPL(ips_link_to_i915_driver);
++
+ static DEFINE_PCI_DEVICE_TABLE(ips_id_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_THERMAL_SENSOR), },
+diff --git a/drivers/platform/x86/intel_ips.h b/drivers/platform/x86/intel_ips.h
+new file mode 100644
+index 0000000..73299be
+--- /dev/null
++++ b/drivers/platform/x86/intel_ips.h
+@@ -0,0 +1,21 @@
++/*
++ * Copyright (c) 2010 Intel Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * The full GNU General Public License is included in this distribution in
++ * the file called "COPYING".
++ */
++
++void ips_link_to_i915_driver(void);
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0009-drm-i915-Verify-Ironlake-eDP-presence-on-DP_A-using-.patch b/extras/recipes-kernel/linux/linux-omap/linus/0009-drm-i915-Verify-Ironlake-eDP-presence-on-DP_A-using-.patch
new file mode 100644
index 00000000..e0f4515e
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0009-drm-i915-Verify-Ironlake-eDP-presence-on-DP_A-using-.patch
@@ -0,0 +1,69 @@
+From b3ae260de2254a0aed982b5964396a9914859c0e Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Tue, 14 Dec 2010 19:21:29 +0000
+Subject: [PATCH 09/65] drm/i915: Verify Ironlake eDP presence on DP_A using the capability fuse
+
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+---
+ drivers/gpu/drm/i915/i915_reg.h | 7 +++++++
+ drivers/gpu/drm/i915/intel_display.c | 19 ++++++++++++++++++-
+ 2 files changed, 25 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
+index 8470a97..cb8f434 100644
+--- a/drivers/gpu/drm/i915/i915_reg.h
++++ b/drivers/gpu/drm/i915/i915_reg.h
+@@ -2591,6 +2591,13 @@
+ #define ILK_DISPLAY_CHICKEN2 0x42004
+ #define ILK_DPARB_GATE (1<<22)
+ #define ILK_VSDPFD_FULL (1<<21)
++#define ILK_DISPLAY_CHICKEN_FUSES 0x42014
++#define ILK_INTERNAL_GRAPHICS_DISABLE (1<<31)
++#define ILK_INTERNAL_DISPLAY_DISABLE (1<<30)
++#define ILK_DISPLAY_DEBUG_DISABLE (1<<29)
++#define ILK_HDCP_DISABLE (1<<25)
++#define ILK_eDP_A_DISABLE (1<<24)
++#define ILK_DESKTOP (1<<23)
+ #define ILK_DSPCLK_GATE 0x42020
+ #define ILK_DPARB_CLK_GATE (1<<5)
+ /* According to spec this bit 7/8/9 of 0x42020 should be set to enable FBC */
+diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
+index 97e374e..fca5232 100644
+--- a/drivers/gpu/drm/i915/intel_display.c
++++ b/drivers/gpu/drm/i915/intel_display.c
+@@ -5379,6 +5379,23 @@ static int intel_encoder_clones(struct drm_device *dev, int type_mask)
+ return index_mask;
+ }
+
++static bool has_edp_a(struct drm_device *dev)
++{
++ struct drm_i915_private *dev_priv = dev->dev_private;
++
++ if (!IS_MOBILE(dev))
++ return false;
++
++ if ((I915_READ(DP_A) & DP_DETECTED) == 0)
++ return false;
++
++ if (IS_GEN5(dev) &&
++ (I915_READ(ILK_DISPLAY_CHICKEN_FUSES) & ILK_eDP_A_DISABLE))
++ return false;
++
++ return true;
++}
++
+ static void intel_setup_outputs(struct drm_device *dev)
+ {
+ struct drm_i915_private *dev_priv = dev->dev_private;
+@@ -5396,7 +5413,7 @@ static void intel_setup_outputs(struct drm_device *dev)
+ if (HAS_PCH_SPLIT(dev)) {
+ dpd_is_edp = intel_dpd_is_edp(dev);
+
+- if (IS_MOBILE(dev) && (I915_READ(DP_A) & DP_DETECTED))
++ if (has_edp_a(dev))
+ intel_dp_init(dev, DP_A);
+
+ if (dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED))
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0010-ARM-6536-1-Add-missing-SZ_-32-64-128.patch b/extras/recipes-kernel/linux/linux-omap/linus/0010-ARM-6536-1-Add-missing-SZ_-32-64-128.patch
new file mode 100644
index 00000000..1eeffc28
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0010-ARM-6536-1-Add-missing-SZ_-32-64-128.patch
@@ -0,0 +1,42 @@
+From 233828cbb5d2331e47cba932130428ea5f915f91 Mon Sep 17 00:00:00 2001
+From: Stephen Warren <swarren@nvidia.com>
+Date: Wed, 22 Dec 2010 04:52:05 +0100
+Subject: [PATCH 10/65] ARM: 6536/1: Add missing SZ_{32,64,128}
+
+... and also remove misleading comment stating that this header is
+auto-generated.
+
+Signed-off-by: Stephen Warren <swarren@nvidia.com>
+Acked-by: Uwe Kleine-Knig <u.kleine-koenig@pengutronix.de>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ arch/arm/include/asm/sizes.h | 6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/include/asm/sizes.h b/arch/arm/include/asm/sizes.h
+index 4fc1565..316bb2b 100644
+--- a/arch/arm/include/asm/sizes.h
++++ b/arch/arm/include/asm/sizes.h
+@@ -13,9 +13,6 @@
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+-/* DO NOT EDIT!! - this file automatically generated
+- * from .s file by awk -f s2h.awk
+- */
+ /* Size definitions
+ * Copyright (C) ARM Limited 1998. All rights reserved.
+ */
+@@ -25,6 +22,9 @@
+
+ /* handy sizes */
+ #define SZ_16 0x00000010
++#define SZ_32 0x00000020
++#define SZ_64 0x00000040
++#define SZ_128 0x00000080
+ #define SZ_256 0x00000100
+ #define SZ_512 0x00000200
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0011-ARM-6537-1-update-Nomadik-U300-and-Ux500-maintainers.patch b/extras/recipes-kernel/linux/linux-omap/linus/0011-ARM-6537-1-update-Nomadik-U300-and-Ux500-maintainers.patch
new file mode 100644
index 00000000..99a9ce2a
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0011-ARM-6537-1-update-Nomadik-U300-and-Ux500-maintainers.patch
@@ -0,0 +1,65 @@
+From 1efad2ad25ed60a4d90a87f7e77babb808b3052f Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@stericsson.com>
+Date: Wed, 22 Dec 2010 09:18:29 +0100
+Subject: [PATCH 11/65] ARM: 6537/1: update Nomadik, U300 and Ux500 maintainers
+
+Adding in self as maintainer for Nomadik and Ux500, I'm running
+an active -next tree for that stuff now. Extend file matchers to
+cover a few more relevant drivers and add git references.
+
+Cc: Alessandro Rubini <rubini@unipv.it>
+Acked-by: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
+Signed-off-by: Linus Walleij <linus.walleij@stericsson.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ MAINTAINERS | 17 ++++++++++++++++-
+ 1 files changed, 16 insertions(+), 1 deletions(-)
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 4607f18..1c15602 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -792,11 +792,14 @@ S: Maintained
+
+ ARM/NOMADIK ARCHITECTURE
+ M: Alessandro Rubini <rubini@unipv.it>
++M: Linus Walleij <linus.walleij@stericsson.com>
+ M: STEricsson <STEricsson_nomadik_linux@list.st.com>
+ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+ S: Maintained
+ F: arch/arm/mach-nomadik/
+ F: arch/arm/plat-nomadik/
++F: drivers/i2c/busses/i2c-nomadik.c
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git
+
+ ARM/OPENMOKO NEO FREERUNNER (GTA02) MACHINE SUPPORT
+ M: Nelson Castillo <arhuaco@freaks-unidos.net>
+@@ -998,12 +1001,24 @@ F: drivers/i2c/busses/i2c-stu300.c
+ F: drivers/rtc/rtc-coh901331.c
+ F: drivers/watchdog/coh901327_wdt.c
+ F: drivers/dma/coh901318*
++F: drivers/mfd/ab3100*
++F: drivers/rtc/rtc-ab3100.c
++F: drivers/rtc/rtc-coh901331.c
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git
+
+-ARM/U8500 ARM ARCHITECTURE
++ARM/Ux500 ARM ARCHITECTURE
+ M: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
++M: Linus Walleij <linus.walleij@stericsson.com>
+ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+ S: Maintained
+ F: arch/arm/mach-ux500/
++F: drivers/dma/ste_dma40*
++F: drivers/mfd/ab3550*
++F: drivers/mfd/abx500*
++F: drivers/mfd/ab8500*
++F: drivers/mfd/stmpe*
++F: drivers/rtc/rtc-ab8500.c
++T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git
+
+ ARM/VFP SUPPORT
+ M: Russell King <linux@arm.linux.org.uk>
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0012-ARM-6540-1-Stop-irqsoff-trace-on-return-to-user.patch b/extras/recipes-kernel/linux/linux-omap/linus/0012-ARM-6540-1-Stop-irqsoff-trace-on-return-to-user.patch
new file mode 100644
index 00000000..0e55c525
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0012-ARM-6540-1-Stop-irqsoff-trace-on-return-to-user.patch
@@ -0,0 +1,44 @@
+From d0427fe2982e2f4f644b936fe39636916b69fee1 Mon Sep 17 00:00:00 2001
+From: Todd Android Poynor <toddpoynor@google.com>
+Date: Thu, 23 Dec 2010 01:52:44 +0100
+Subject: [PATCH 12/65] ARM: 6540/1: Stop irqsoff trace on return to user
+
+If the irqsoff tracer is in use, stop tracing the interrupt disable
+interval when returning to userspace. Tracing userspace execution time
+as interrupts disabled time is not helpful for kernel performance
+analysis purposes. Only do so if the irqsoff tracer is enabled, to
+avoid overhead for lockdep, which doesn't care.
+
+Signed-off-by: Todd Poynor <toddpoynor@google.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ arch/arm/kernel/entry-common.S | 6 ++++++
+ 1 files changed, 6 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
+index 8bfa987..80bf8cd 100644
+--- a/arch/arm/kernel/entry-common.S
++++ b/arch/arm/kernel/entry-common.S
+@@ -29,6 +29,9 @@ ret_fast_syscall:
+ ldr r1, [tsk, #TI_FLAGS]
+ tst r1, #_TIF_WORK_MASK
+ bne fast_work_pending
++#if defined(CONFIG_IRQSOFF_TRACER)
++ asm_trace_hardirqs_on
++#endif
+
+ /* perform architecture specific actions before user return */
+ arch_ret_to_user r1, lr
+@@ -65,6 +68,9 @@ ret_slow_syscall:
+ tst r1, #_TIF_WORK_MASK
+ bne work_pending
+ no_work_pending:
++#if defined(CONFIG_IRQSOFF_TRACER)
++ asm_trace_hardirqs_on
++#endif
+ /* perform architecture specific actions before user return */
+ arch_ret_to_user r1, lr
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0013-ueagle-atm-fix-PHY-signal-initialization-race.patch b/extras/recipes-kernel/linux/linux-omap/linus/0013-ueagle-atm-fix-PHY-signal-initialization-race.patch
new file mode 100644
index 00000000..e62a9d8c
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0013-ueagle-atm-fix-PHY-signal-initialization-race.patch
@@ -0,0 +1,100 @@
+From c23a13703fb00384d49a00875fc12a5e00f1946a Mon Sep 17 00:00:00 2001
+From: Dan Williams <dcbw@redhat.com>
+Date: Sun, 19 Dec 2010 08:17:50 +0000
+Subject: [PATCH 13/65] ueagle-atm: fix PHY signal initialization race
+
+A race exists when initializing ueagle-atm devices where the generic atm
+device may not yet be created before the driver attempts to initialize
+it's PHY signal state, which checks whether the atm device has been
+created or not. This often causes the sysfs 'carrier' attribute to be
+'1' even though no signal has actually been found.
+
+uea_probe
+ usbatm_usb_probe
+ driver->bind (uea_bind)
+ uea_boot
+ kthread_run(uea_kthread) uea_kthread
+ usbatm_atm_init uea_start_reset
+ atm_dev_register UPDATE_ATM_SIGNAL
+
+UPDATE_ATM_SIGNAL checks whether the ATM device has been created and if
+not, will not update the PHY signal state. Because of the race that
+does not always happen in time, and the PHY signal state remains
+ATM_PHY_SIG_FOUND even though no signal exists.
+
+To fix the race, just create the kthread during initialization, and only
+after initialization is complete, start the thread that reboots the
+device and initializes PHY state.
+
+[ 3030.490931] uea_probe: calling usbatm_usb_probe
+[ 3030.490946] ueagle-atm 8-2:1.0: usbatm_usb_probe: trying driver ueagle-atm with vendor=1110, product=9031, ifnum 0
+[ 3030.493691] uea_bind: setting usbatm
+[ 3030.496932] usb 8-2: [ueagle-atm] using iso mode
+[ 3030.497283] ueagle-atm 8-2:1.0: usbatm_usb_probe: using 3021 byte buffer for rx channel 0xffff880125953508
+ <kthread already started before usbatm_usb_probe() has returned>
+[ 3030.497292] usb 8-2: [ueagle-atm] (re)booting started
+ <UPDATE_ATM_SIGNAL checks whether ATM device has been created yet before setting PHY state>
+[ 3030.497298] uea_start_reset: atm dev (null)
+ <and since it hasn't been created yet PHY state is not set>
+[ 3030.497306] ueagle-atm 8-2:1.0: usbatm_usb_probe: using 3392 byte buffer for tx channel 0xffff8801259535b8
+[ 3030.497374] usbatm_usb_probe: about to init
+[ 3030.497379] usbatm_usb_probe: calling usbatm_atm_init
+ <atm device finally gets created>
+[ 3030.497384] usbatm_atm_init: creating atm device!
+
+Signed-off-by: Dan Williams <dcbw@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/usb/atm/ueagle-atm.c | 22 +++++++++++++++++++---
+ 1 files changed, 19 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
+index 44447f5..99ac70e 100644
+--- a/drivers/usb/atm/ueagle-atm.c
++++ b/drivers/usb/atm/ueagle-atm.c
+@@ -2206,8 +2206,11 @@ static int uea_boot(struct uea_softc *sc)
+ goto err1;
+ }
+
+- sc->kthread = kthread_run(uea_kthread, sc, "ueagle-atm");
+- if (sc->kthread == ERR_PTR(-ENOMEM)) {
++ /* Create worker thread, but don't start it here. Start it after
++ * all usbatm generic initialization is done.
++ */
++ sc->kthread = kthread_create(uea_kthread, sc, "ueagle-atm");
++ if (IS_ERR(sc->kthread)) {
+ uea_err(INS_TO_USBDEV(sc), "failed to create thread\n");
+ goto err2;
+ }
+@@ -2624,6 +2627,7 @@ static struct usbatm_driver uea_usbatm_driver = {
+ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
+ {
+ struct usb_device *usb = interface_to_usbdev(intf);
++ int ret;
+
+ uea_enters(usb);
+ uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) Rev (%#X): %s\n",
+@@ -2637,7 +2641,19 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
+ if (UEA_IS_PREFIRM(id))
+ return uea_load_firmware(usb, UEA_CHIP_VERSION(id));
+
+- return usbatm_usb_probe(intf, id, &uea_usbatm_driver);
++ ret = usbatm_usb_probe(intf, id, &uea_usbatm_driver);
++ if (ret == 0) {
++ struct usbatm_data *usbatm = usb_get_intfdata(intf);
++ struct uea_softc *sc = usbatm->driver_data;
++
++ /* Ensure carrier is initialized to off as early as possible */
++ UPDATE_ATM_SIGNAL(ATM_PHY_SIG_LOST);
++
++ /* Only start the worker thread when all init is done */
++ wake_up_process(sc->kthread);
++ }
++
++ return ret;
+ }
+
+ static void uea_disconnect(struct usb_interface *intf)
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0014-ehea-Avoid-changing-vlan-flags.patch b/extras/recipes-kernel/linux/linux-omap/linus/0014-ehea-Avoid-changing-vlan-flags.patch
new file mode 100644
index 00000000..24557a3e
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0014-ehea-Avoid-changing-vlan-flags.patch
@@ -0,0 +1,34 @@
+From a6b08e88ed5a716b2f27989c949cdfa0704c1dfd Mon Sep 17 00:00:00 2001
+From: Breno Leitao <leitao@linux.vnet.ibm.com>
+Date: Mon, 20 Dec 2010 09:02:37 +0000
+Subject: [PATCH 14/65] ehea: Avoid changing vlan flags
+
+This patch avoids disabling the vlan flags using ethtool.
+
+Signed-off-by: Breno Leitao <leitao@linux.vnet.ibm.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ehea/ehea_ethtool.c | 7 +++++++
+ 1 files changed, 7 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c
+index 1f37ee6..d6cf502 100644
+--- a/drivers/net/ehea/ehea_ethtool.c
++++ b/drivers/net/ehea/ehea_ethtool.c
+@@ -263,6 +263,13 @@ static void ehea_get_ethtool_stats(struct net_device *dev,
+
+ static int ehea_set_flags(struct net_device *dev, u32 data)
+ {
++ /* Avoid changing the VLAN flags */
++ if ((data & (ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN)) !=
++ (ethtool_op_get_flags(dev) & (ETH_FLAG_RXVLAN |
++ ETH_FLAG_TXVLAN))){
++ return -EINVAL;
++ }
++
+ return ethtool_op_set_flags(dev, data, ETH_FLAG_LRO
+ | ETH_FLAG_TXVLAN
+ | ETH_FLAG_RXVLAN);
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0015-ppp-allow-disabling-multilink-protocol-ID-compressio.patch b/extras/recipes-kernel/linux/linux-omap/linus/0015-ppp-allow-disabling-multilink-protocol-ID-compressio.patch
new file mode 100644
index 00000000..b06d2c56
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0015-ppp-allow-disabling-multilink-protocol-ID-compressio.patch
@@ -0,0 +1,64 @@
+From 3b4878d988f13c50a8a6d68e9359eb28cc432a4f Mon Sep 17 00:00:00 2001
+From: stephen hemminger <shemminger@vyatta.com>
+Date: Mon, 20 Dec 2010 17:58:33 +0000
+Subject: [PATCH 15/65] ppp: allow disabling multilink protocol ID compression
+
+Linux would not connect to other router running old version Cisco IOS (12.0).
+This is most likely a bug in that version of IOS, since it is fixed
+in later versions. As a workaround this patch allows a module parameter
+to be set to disable compressing the protocol ID.
+
+See: https://bugzilla.vyatta.com/show_bug.cgi?id=3979
+
+RFC 1990 allows an implementation to formulate MP fragments as if protocol
+compression had been negotiated. This allows us to always send compressed
+protocol IDs. But some implementations don't accept MP fragments with
+compressed protocol IDs. This parameter allows us to interoperate with
+them. The default value of the configurable parameter is the same as the
+current behavior: protocol compression is enabled. If protocol compression
+is disabled we will not send compressed protocol IDs.
+
+This is based on an earlier patch by Bob Gilligan (using a sysctl).
+Module parameter is writable to allow for enabling even if ppp
+is already loaded for other uses.
+
+Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
+Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
+Acked-by: Paul Mackerras <paulus@samba.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ppp_generic.c | 9 +++++++--
+ 1 files changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
+index 3965997..89294b4 100644
+--- a/drivers/net/ppp_generic.c
++++ b/drivers/net/ppp_generic.c
+@@ -1285,6 +1285,11 @@ ppp_push(struct ppp *ppp)
+ }
+
+ #ifdef CONFIG_PPP_MULTILINK
++static bool mp_protocol_compress __read_mostly = true;
++module_param(mp_protocol_compress, bool, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(mp_protocol_compress,
++ "compress protocol id in multilink fragments");
++
+ /*
+ * Divide a packet to be transmitted into fragments and
+ * send them out the individual links.
+@@ -1347,10 +1352,10 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
+ if (nfree == 0 || nfree < navail / 2)
+ return 0; /* can't take now, leave it in xmit_pending */
+
+- /* Do protocol field compression (XXX this should be optional) */
++ /* Do protocol field compression */
+ p = skb->data;
+ len = skb->len;
+- if (*p == 0) {
++ if (*p == 0 && mp_protocol_compress) {
+ ++p;
+ --len;
+ }
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0016-skfp-testing-the-wrong-variable-in-skfp_driver_init.patch b/extras/recipes-kernel/linux/linux-omap/linus/0016-skfp-testing-the-wrong-variable-in-skfp_driver_init.patch
new file mode 100644
index 00000000..951a2813
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0016-skfp-testing-the-wrong-variable-in-skfp_driver_init.patch
@@ -0,0 +1,31 @@
+From 276d3ef4021021959540cdb7a5041c477432d29e Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <error27@gmail.com>
+Date: Thu, 23 Dec 2010 19:17:34 +0000
+Subject: [PATCH 16/65] skfp: testing the wrong variable in skfp_driver_init()
+
+The intent here was to test if the allocation failed but we tested
+"SharedMemSize" instead of "SharedMemAddr" by mistake.
+
+Signed-off-by: Dan Carpenter <error27@gmail.com>
+Reviewed-by: Jiri Pirko <jpirko@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/skfp/skfddi.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
+index 0a66fed..16c6265 100644
+--- a/drivers/net/skfp/skfddi.c
++++ b/drivers/net/skfp/skfddi.c
+@@ -412,7 +412,7 @@ static int skfp_driver_init(struct net_device *dev)
+ bp->SharedMemAddr = pci_alloc_consistent(&bp->pdev,
+ bp->SharedMemSize,
+ &bp->SharedMemDMA);
+- if (!bp->SharedMemSize) {
++ if (!bp->SharedMemAddr) {
+ printk("could not allocate mem for ");
+ printk("hardware module: %ld byte\n",
+ bp->SharedMemSize);
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0017-ASoC-codecs-Add-missing-control_type-initialization.patch b/extras/recipes-kernel/linux/linux-omap/linus/0017-ASoC-codecs-Add-missing-control_type-initialization.patch
new file mode 100644
index 00000000..bb5a944f
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0017-ASoC-codecs-Add-missing-control_type-initialization.patch
@@ -0,0 +1,84 @@
+From d03eac98a7ae4af982f3c19161f850effbfd0f57 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 28 Dec 2010 21:08:57 +0100
+Subject: [PATCH 17/65] ASoC: codecs: Add missing control_type initialization
+
+Some codec drivers do not initialize the control_type field in their private
+device struct, but still use it when calling snd_soc_codec_set_cache_io.
+This patch fixes the issue by properly initializing it in the drivers probe
+functions.
+
+Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Cc: stable@kernel.org (for 2.6.37 only)
+---
+ sound/soc/codecs/wm8940.c | 1 +
+ sound/soc/codecs/wm8955.c | 1 +
+ sound/soc/codecs/wm8960.c | 1 +
+ sound/soc/codecs/wm8971.c | 1 +
+ sound/soc/codecs/wm9081.c | 1 +
+ 5 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
+index 2cb16f8..23086e2 100644
+--- a/sound/soc/codecs/wm8940.c
++++ b/sound/soc/codecs/wm8940.c
+@@ -768,6 +768,7 @@ static __devinit int wm8940_i2c_probe(struct i2c_client *i2c,
+
+ i2c_set_clientdata(i2c, wm8940);
+ wm8940->control_data = i2c;
++ wm8940->control_type = SND_SOC_I2C;
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8940, &wm8940_dai, 1);
+diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
+index 9cbab8e..a2ad91d 100644
+--- a/sound/soc/codecs/wm8955.c
++++ b/sound/soc/codecs/wm8955.c
+@@ -1003,6 +1003,7 @@ static __devinit int wm8955_i2c_probe(struct i2c_client *i2c,
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, wm8955);
++ wm8955->control_type = SND_SOC_I2C;
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8955, &wm8955_dai, 1);
+diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
+index 21986c4..ff6ff2f 100644
+--- a/sound/soc/codecs/wm8960.c
++++ b/sound/soc/codecs/wm8960.c
+@@ -1013,6 +1013,7 @@ static __devinit int wm8960_i2c_probe(struct i2c_client *i2c,
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, wm8960);
++ wm8960->control_type = SND_SOC_I2C;
+ wm8960->control_data = i2c;
+
+ ret = snd_soc_register_codec(&i2c->dev,
+diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
+index 63f6dbf..9f18db6 100644
+--- a/sound/soc/codecs/wm8971.c
++++ b/sound/soc/codecs/wm8971.c
+@@ -718,6 +718,7 @@ static __devinit int wm8971_i2c_probe(struct i2c_client *i2c,
+ if (wm8971 == NULL)
+ return -ENOMEM;
+
++ wm8971->control_type = SND_SOC_I2C;
+ i2c_set_clientdata(i2c, wm8971);
+
+ ret = snd_soc_register_codec(&i2c->dev,
+diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
+index ecc7c37..a486670 100644
+--- a/sound/soc/codecs/wm9081.c
++++ b/sound/soc/codecs/wm9081.c
+@@ -1335,6 +1335,7 @@ static __devinit int wm9081_i2c_probe(struct i2c_client *i2c,
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, wm9081);
++ wm9081->control_type = SND_SOC_I2C;
+ wm9081->control_data = i2c;
+
+ ret = snd_soc_register_codec(&i2c->dev,
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0018-ASoC-codecs-max98088-Fix-register-cache-incoherency.patch b/extras/recipes-kernel/linux/linux-omap/linus/0018-ASoC-codecs-max98088-Fix-register-cache-incoherency.patch
new file mode 100644
index 00000000..5c139ab5
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0018-ASoC-codecs-max98088-Fix-register-cache-incoherency.patch
@@ -0,0 +1,72 @@
+From 0ff8217bd7272d8aef1e58250d84cf5680b16b2d Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 28 Dec 2010 21:37:56 +0100
+Subject: [PATCH 18/65] ASoC: codecs: max98088: Fix register cache incoherency
+
+The multi-component patch(commit f0fba2ad1) moved the allocation of the
+register cache from the driver to the ASoC core. Most drivers where adjusted to
+this, but the max98088 driver still uses its own register cache for its
+private functions, while functions from the ASoC core use the generic cache.
+Thus we end up with two from each other incoherent caches, which can lead to
+undefined behaviour.
+This patch fixes the issue by changing the max98088 driver to use the
+generic register cache in its private functions.
+
+Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
+Cc: Peter Hsiang <Peter.Hsiang@maxim-ic.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Cc: stable@kernel.org (for 2.6.37 only)
+---
+ sound/soc/codecs/max98088.c | 10 ++++------
+ 1 files changed, 4 insertions(+), 6 deletions(-)
+
+diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
+index d63e287..6447dbb 100644
+--- a/sound/soc/codecs/max98088.c
++++ b/sound/soc/codecs/max98088.c
+@@ -40,7 +40,6 @@ struct max98088_cdata {
+ };
+
+ struct max98088_priv {
+- u8 reg_cache[M98088_REG_CNT];
+ enum max98088_type devtype;
+ void *control_data;
+ struct max98088_pdata *pdata;
+@@ -1588,7 +1587,7 @@ static int max98088_dai2_set_fmt(struct snd_soc_dai *codec_dai,
+
+ static void max98088_sync_cache(struct snd_soc_codec *codec)
+ {
+- struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
++ u16 *reg_cache = codec->reg_cache;
+ int i;
+
+ if (!codec->cache_sync)
+@@ -1599,14 +1598,14 @@ static void max98088_sync_cache(struct snd_soc_codec *codec)
+ /* write back cached values if they're writeable and
+ * different from the hardware default.
+ */
+- for (i = 1; i < ARRAY_SIZE(max98088->reg_cache); i++) {
++ for (i = 1; i < codec->driver->reg_cache_size; i++) {
+ if (!max98088_access[i].writable)
+ continue;
+
+- if (max98088->reg_cache[i] == max98088_reg[i])
++ if (reg_cache[i] == max98088_reg[i])
+ continue;
+
+- snd_soc_write(codec, i, max98088->reg_cache[i]);
++ snd_soc_write(codec, i, reg_cache[i]);
+ }
+
+ codec->cache_sync = 0;
+@@ -1951,7 +1950,6 @@ static int max98088_probe(struct snd_soc_codec *codec)
+ int ret = 0;
+
+ codec->cache_sync = 1;
+- memcpy(codec->reg_cache, max98088_reg, sizeof(max98088_reg));
+
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+ if (ret != 0) {
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0019-ASoC-codecs-wm8523-Fix-register-cache-incoherency.patch b/extras/recipes-kernel/linux/linux-omap/linus/0019-ASoC-codecs-wm8523-Fix-register-cache-incoherency.patch
new file mode 100644
index 00000000..6ef2360a
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0019-ASoC-codecs-wm8523-Fix-register-cache-incoherency.patch
@@ -0,0 +1,74 @@
+From 50e75c326e4d3278b73385a3baf78fc4660d3610 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 28 Dec 2010 21:37:57 +0100
+Subject: [PATCH 19/65] ASoC: codecs: wm8523: Fix register cache incoherency
+
+The multi-component patch(commit f0fba2ad1) moved the allocation of the
+register cache from the driver to the ASoC core. Most drivers where adjusted to
+this, but the wm8523 driver still uses its own register cache for its
+private functions, while functions from the ASoC core use the generic cache.
+Thus we end up with two from each other incoherent caches, which can lead to
+undefined behaviour.
+This patch fixes the issue by changing the wm8523 driver to use the
+generic register cache in its private functions.
+
+Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
+Cc: Ian Lartey <ian@opensource.wolfsonmicro.com>
+Cc: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Cc: stable@kernel.org (for 2.6.37 only)
+---
+ sound/soc/codecs/wm8523.c | 9 +++++----
+ 1 files changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
+index 9a433a5..deca79e 100644
+--- a/sound/soc/codecs/wm8523.c
++++ b/sound/soc/codecs/wm8523.c
+@@ -41,7 +41,6 @@ static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = {
+ /* codec private data */
+ struct wm8523_priv {
+ enum snd_soc_control_type control_type;
+- u16 reg_cache[WM8523_REGISTER_COUNT];
+ struct regulator_bulk_data supplies[WM8523_NUM_SUPPLIES];
+ unsigned int sysclk;
+ unsigned int rate_constraint_list[WM8523_NUM_RATES];
+@@ -314,6 +313,7 @@ static int wm8523_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+ {
+ struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
++ u16 *reg_cache = codec->reg_cache;
+ int ret, i;
+
+ switch (level) {
+@@ -344,7 +344,7 @@ static int wm8523_set_bias_level(struct snd_soc_codec *codec,
+ /* Sync back default/cached values */
+ for (i = WM8523_AIF_CTRL1;
+ i < WM8523_MAX_REGISTER; i++)
+- snd_soc_write(codec, i, wm8523->reg_cache[i]);
++ snd_soc_write(codec, i, reg_cache[i]);
+
+
+ msleep(100);
+@@ -414,6 +414,7 @@ static int wm8523_resume(struct snd_soc_codec *codec)
+ static int wm8523_probe(struct snd_soc_codec *codec)
+ {
+ struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
++ u16 *reg_cache = codec->reg_cache;
+ int ret, i;
+
+ codec->hw_write = (hw_write_t)i2c_master_send;
+@@ -470,8 +471,8 @@ static int wm8523_probe(struct snd_soc_codec *codec)
+ }
+
+ /* Change some default settings - latch VU and enable ZC */
+- wm8523->reg_cache[WM8523_DAC_GAINR] |= WM8523_DACR_VU;
+- wm8523->reg_cache[WM8523_DAC_CTRL3] |= WM8523_ZC;
++ reg_cache[WM8523_DAC_GAINR] |= WM8523_DACR_VU;
++ reg_cache[WM8523_DAC_CTRL3] |= WM8523_ZC;
+
+ wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0020-ASoC-codecs-wm8741-Fix-register-cache-incoherency.patch b/extras/recipes-kernel/linux/linux-omap/linus/0020-ASoC-codecs-wm8741-Fix-register-cache-incoherency.patch
new file mode 100644
index 00000000..f4ee49eb
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0020-ASoC-codecs-wm8741-Fix-register-cache-incoherency.patch
@@ -0,0 +1,61 @@
+From ed4250725ac617b420d25e2b4ca0958818a7cde9 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 28 Dec 2010 21:37:58 +0100
+Subject: [PATCH 20/65] ASoC: codecs: wm8741: Fix register cache incoherency
+
+The multi-component patch(commit f0fba2ad1) moved the allocation of the
+register cache from the driver to the ASoC core. Most drivers where adjusted to
+this, but the wm8741 driver still uses its own register cache for its
+private functions, while functions from the ASoC core use the generic cache.
+Thus we end up with two from each other incoherent caches, which can lead to
+undefined behaviour.
+This patch fixes the issue by changing the wm8741 driver to use the
+generic register cache in its private functions.
+
+Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
+Cc: Ian Lartey <ian@opensource.wolfsonmicro.com>
+Cc: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Cc: stable@kernel.org (for 2.6.37 only)
+---
+ sound/soc/codecs/wm8741.c | 10 +++++-----
+ 1 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
+index 90e31e9..aea60ef 100644
+--- a/sound/soc/codecs/wm8741.c
++++ b/sound/soc/codecs/wm8741.c
+@@ -41,7 +41,6 @@ static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = {
+ /* codec private data */
+ struct wm8741_priv {
+ enum snd_soc_control_type control_type;
+- u16 reg_cache[WM8741_REGISTER_COUNT];
+ struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];
+ unsigned int sysclk;
+ struct snd_pcm_hw_constraint_list *sysclk_constraints;
+@@ -422,6 +421,7 @@ static int wm8741_resume(struct snd_soc_codec *codec)
+ static int wm8741_probe(struct snd_soc_codec *codec)
+ {
+ struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
++ u16 *reg_cache = codec->reg_cache;
+ int ret = 0;
+
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8741->control_type);
+@@ -437,10 +437,10 @@ static int wm8741_probe(struct snd_soc_codec *codec)
+ }
+
+ /* Change some default settings - latch VU */
+- wm8741->reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL;
+- wm8741->reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM;
+- wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL;
+- wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM;
++ reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL;
++ reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM;
++ reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL;
++ reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM;
+
+ snd_soc_add_controls(codec, wm8741_snd_controls,
+ ARRAY_SIZE(wm8741_snd_controls));
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0021-ASoC-codecs-wm8904-Fix-register-cache-incoherency.patch b/extras/recipes-kernel/linux/linux-omap/linus/0021-ASoC-codecs-wm8904-Fix-register-cache-incoherency.patch
new file mode 100644
index 00000000..51363a40
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0021-ASoC-codecs-wm8904-Fix-register-cache-incoherency.patch
@@ -0,0 +1,131 @@
+From 2f369c65cdd41f8eda535cd4065edd63346a016b Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 28 Dec 2010 21:37:59 +0100
+Subject: [PATCH 21/65] ASoC: codecs: wm8904: Fix register cache incoherency
+
+The multi-component patch(commit f0fba2ad1) moved the allocation of the
+register cache from the driver to the ASoC core. Most drivers where adjusted to
+this, but the wm8904 driver still uses its own register cache for its
+private functions, while functions from the ASoC core use the generic cache.
+Thus we end up with two from each other incoherent caches, which can lead to
+undefined behaviour.
+This patch fixes the issue by changing the wm8904 driver to use the
+generic register cache in its private functions.
+
+Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
+Cc: Ian Lartey <ian@opensource.wolfsonmicro.com>
+Cc: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Cc: stable@kernel.org (for 2.6.37 only)
+---
+ sound/soc/codecs/wm8904.c | 37 ++++++++++++++++++-------------------
+ 1 files changed, 18 insertions(+), 19 deletions(-)
+
+diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
+index 9001cc4..1ec12ef 100644
+--- a/sound/soc/codecs/wm8904.c
++++ b/sound/soc/codecs/wm8904.c
+@@ -50,8 +50,6 @@ static const char *wm8904_supply_names[WM8904_NUM_SUPPLIES] = {
+ /* codec private data */
+ struct wm8904_priv {
+
+- u16 reg_cache[WM8904_MAX_REGISTER + 1];
+-
+ enum wm8904_type devtype;
+ void *control_data;
+
+@@ -2094,7 +2092,7 @@ static int wm8904_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+
+ static void wm8904_sync_cache(struct snd_soc_codec *codec)
+ {
+- struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
++ u16 *reg_cache = codec->reg_cache;
+ int i;
+
+ if (!codec->cache_sync)
+@@ -2105,14 +2103,14 @@ static void wm8904_sync_cache(struct snd_soc_codec *codec)
+ /* Sync back cached values if they're different from the
+ * hardware default.
+ */
+- for (i = 1; i < ARRAY_SIZE(wm8904->reg_cache); i++) {
++ for (i = 1; i < codec->driver->reg_cache_size; i++) {
+ if (!wm8904_access[i].writable)
+ continue;
+
+- if (wm8904->reg_cache[i] == wm8904_reg[i])
++ if (reg_cache[i] == wm8904_reg[i])
+ continue;
+
+- snd_soc_write(codec, i, wm8904->reg_cache[i]);
++ snd_soc_write(codec, i, reg_cache[i]);
+ }
+
+ codec->cache_sync = 0;
+@@ -2371,6 +2369,7 @@ static int wm8904_probe(struct snd_soc_codec *codec)
+ {
+ struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+ struct wm8904_pdata *pdata = wm8904->pdata;
++ u16 *reg_cache = codec->reg_cache;
+ int ret, i;
+
+ codec->cache_sync = 1;
+@@ -2437,19 +2436,19 @@ static int wm8904_probe(struct snd_soc_codec *codec)
+ }
+
+ /* Change some default settings - latch VU and enable ZC */
+- wm8904->reg_cache[WM8904_ADC_DIGITAL_VOLUME_LEFT] |= WM8904_ADC_VU;
+- wm8904->reg_cache[WM8904_ADC_DIGITAL_VOLUME_RIGHT] |= WM8904_ADC_VU;
+- wm8904->reg_cache[WM8904_DAC_DIGITAL_VOLUME_LEFT] |= WM8904_DAC_VU;
+- wm8904->reg_cache[WM8904_DAC_DIGITAL_VOLUME_RIGHT] |= WM8904_DAC_VU;
+- wm8904->reg_cache[WM8904_ANALOGUE_OUT1_LEFT] |= WM8904_HPOUT_VU |
++ reg_cache[WM8904_ADC_DIGITAL_VOLUME_LEFT] |= WM8904_ADC_VU;
++ reg_cache[WM8904_ADC_DIGITAL_VOLUME_RIGHT] |= WM8904_ADC_VU;
++ reg_cache[WM8904_DAC_DIGITAL_VOLUME_LEFT] |= WM8904_DAC_VU;
++ reg_cache[WM8904_DAC_DIGITAL_VOLUME_RIGHT] |= WM8904_DAC_VU;
++ reg_cache[WM8904_ANALOGUE_OUT1_LEFT] |= WM8904_HPOUT_VU |
+ WM8904_HPOUTLZC;
+- wm8904->reg_cache[WM8904_ANALOGUE_OUT1_RIGHT] |= WM8904_HPOUT_VU |
++ reg_cache[WM8904_ANALOGUE_OUT1_RIGHT] |= WM8904_HPOUT_VU |
+ WM8904_HPOUTRZC;
+- wm8904->reg_cache[WM8904_ANALOGUE_OUT2_LEFT] |= WM8904_LINEOUT_VU |
++ reg_cache[WM8904_ANALOGUE_OUT2_LEFT] |= WM8904_LINEOUT_VU |
+ WM8904_LINEOUTLZC;
+- wm8904->reg_cache[WM8904_ANALOGUE_OUT2_RIGHT] |= WM8904_LINEOUT_VU |
++ reg_cache[WM8904_ANALOGUE_OUT2_RIGHT] |= WM8904_LINEOUT_VU |
+ WM8904_LINEOUTRZC;
+- wm8904->reg_cache[WM8904_CLOCK_RATES_0] &= ~WM8904_SR_MODE;
++ reg_cache[WM8904_CLOCK_RATES_0] &= ~WM8904_SR_MODE;
+
+ /* Apply configuration from the platform data. */
+ if (wm8904->pdata) {
+@@ -2457,23 +2456,23 @@ static int wm8904_probe(struct snd_soc_codec *codec)
+ if (!pdata->gpio_cfg[i])
+ continue;
+
+- wm8904->reg_cache[WM8904_GPIO_CONTROL_1 + i]
++ reg_cache[WM8904_GPIO_CONTROL_1 + i]
+ = pdata->gpio_cfg[i] & 0xffff;
+ }
+
+ /* Zero is the default value for these anyway */
+ for (i = 0; i < WM8904_MIC_REGS; i++)
+- wm8904->reg_cache[WM8904_MIC_BIAS_CONTROL_0 + i]
++ reg_cache[WM8904_MIC_BIAS_CONTROL_0 + i]
+ = pdata->mic_cfg[i];
+ }
+
+ /* Set Class W by default - this will be managed by the Class
+ * G widget at runtime where bypass paths are available.
+ */
+- wm8904->reg_cache[WM8904_CLASS_W_0] |= WM8904_CP_DYN_PWR;
++ reg_cache[WM8904_CLASS_W_0] |= WM8904_CP_DYN_PWR;
+
+ /* Use normal bias source */
+- wm8904->reg_cache[WM8904_BIAS_CONTROL_0] &= ~WM8904_POBCTRL;
++ reg_cache[WM8904_BIAS_CONTROL_0] &= ~WM8904_POBCTRL;
+
+ wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0022-ASoC-codecs-wm8955-Fix-register-cache-incoherency.patch b/extras/recipes-kernel/linux/linux-omap/linus/0022-ASoC-codecs-wm8955-Fix-register-cache-incoherency.patch
new file mode 100644
index 00000000..420b4cc2
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0022-ASoC-codecs-wm8955-Fix-register-cache-incoherency.patch
@@ -0,0 +1,107 @@
+From 8febc5cbe3b8d4a4a056df364e4a82958a6eb1df Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 28 Dec 2010 21:38:00 +0100
+Subject: [PATCH 22/65] ASoC: codecs: wm8955: Fix register cache incoherency
+
+The multi-component patch(commit f0fba2ad1) moved the allocation of the
+register cache from the driver to the ASoC core. Most drivers where adjusted to
+this, but the wm8955 driver still uses its own register cache for its
+private functions, while functions from the ASoC core use the generic cache.
+Thus we end up with two from each other incoherent caches, which can lead to
+undefined behaviour.
+This patch fixes the issue by changing the wm8955 driver to use the
+generic register cache in its private functions.
+
+Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Cc: stable@kernel.org (for 2.6.37 only)
+---
+ sound/soc/codecs/wm8955.c | 30 +++++++++++++++---------------
+ 1 files changed, 15 insertions(+), 15 deletions(-)
+
+diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
+index a2ad91d..2ac35b0 100644
+--- a/sound/soc/codecs/wm8955.c
++++ b/sound/soc/codecs/wm8955.c
+@@ -42,8 +42,6 @@ static const char *wm8955_supply_names[WM8955_NUM_SUPPLIES] = {
+ struct wm8955_priv {
+ enum snd_soc_control_type control_type;
+
+- u16 reg_cache[WM8955_MAX_REGISTER + 1];
+-
+ unsigned int mclk_rate;
+
+ int deemph;
+@@ -768,6 +766,7 @@ static int wm8955_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+ {
+ struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
++ u16 *reg_cache = codec->reg_cache;
+ int ret, i;
+
+ switch (level) {
+@@ -800,14 +799,14 @@ static int wm8955_set_bias_level(struct snd_soc_codec *codec,
+ /* Sync back cached values if they're
+ * different from the hardware default.
+ */
+- for (i = 0; i < ARRAY_SIZE(wm8955->reg_cache); i++) {
++ for (i = 0; i < codec->driver->reg_cache_size; i++) {
+ if (i == WM8955_RESET)
+ continue;
+
+- if (wm8955->reg_cache[i] == wm8955_reg[i])
++ if (reg_cache[i] == wm8955_reg[i])
+ continue;
+
+- snd_soc_write(codec, i, wm8955->reg_cache[i]);
++ snd_soc_write(codec, i, reg_cache[i]);
+ }
+
+ /* Enable VREF and VMID */
+@@ -902,6 +901,7 @@ static int wm8955_probe(struct snd_soc_codec *codec)
+ {
+ struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
+ struct wm8955_pdata *pdata = dev_get_platdata(codec->dev);
++ u16 *reg_cache = codec->reg_cache;
+ int ret, i;
+
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8955->control_type);
+@@ -934,25 +934,25 @@ static int wm8955_probe(struct snd_soc_codec *codec)
+ }
+
+ /* Change some default settings - latch VU and enable ZC */
+- wm8955->reg_cache[WM8955_LEFT_DAC_VOLUME] |= WM8955_LDVU;
+- wm8955->reg_cache[WM8955_RIGHT_DAC_VOLUME] |= WM8955_RDVU;
+- wm8955->reg_cache[WM8955_LOUT1_VOLUME] |= WM8955_LO1VU | WM8955_LO1ZC;
+- wm8955->reg_cache[WM8955_ROUT1_VOLUME] |= WM8955_RO1VU | WM8955_RO1ZC;
+- wm8955->reg_cache[WM8955_LOUT2_VOLUME] |= WM8955_LO2VU | WM8955_LO2ZC;
+- wm8955->reg_cache[WM8955_ROUT2_VOLUME] |= WM8955_RO2VU | WM8955_RO2ZC;
+- wm8955->reg_cache[WM8955_MONOOUT_VOLUME] |= WM8955_MOZC;
++ reg_cache[WM8955_LEFT_DAC_VOLUME] |= WM8955_LDVU;
++ reg_cache[WM8955_RIGHT_DAC_VOLUME] |= WM8955_RDVU;
++ reg_cache[WM8955_LOUT1_VOLUME] |= WM8955_LO1VU | WM8955_LO1ZC;
++ reg_cache[WM8955_ROUT1_VOLUME] |= WM8955_RO1VU | WM8955_RO1ZC;
++ reg_cache[WM8955_LOUT2_VOLUME] |= WM8955_LO2VU | WM8955_LO2ZC;
++ reg_cache[WM8955_ROUT2_VOLUME] |= WM8955_RO2VU | WM8955_RO2ZC;
++ reg_cache[WM8955_MONOOUT_VOLUME] |= WM8955_MOZC;
+
+ /* Also enable adaptive bass boost by default */
+- wm8955->reg_cache[WM8955_BASS_CONTROL] |= WM8955_BB;
++ reg_cache[WM8955_BASS_CONTROL] |= WM8955_BB;
+
+ /* Set platform data values */
+ if (pdata) {
+ if (pdata->out2_speaker)
+- wm8955->reg_cache[WM8955_ADDITIONAL_CONTROL_2]
++ reg_cache[WM8955_ADDITIONAL_CONTROL_2]
+ |= WM8955_ROUT2INV;
+
+ if (pdata->monoin_diff)
+- wm8955->reg_cache[WM8955_MONO_OUT_MIX_1]
++ reg_cache[WM8955_MONO_OUT_MIX_1]
+ |= WM8955_DMEN;
+ }
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0023-ASoC-codecs-wm8962-Fix-register-cache-incoherency.patch b/extras/recipes-kernel/linux/linux-omap/linus/0023-ASoC-codecs-wm8962-Fix-register-cache-incoherency.patch
new file mode 100644
index 00000000..3e7aa10c
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0023-ASoC-codecs-wm8962-Fix-register-cache-incoherency.patch
@@ -0,0 +1,151 @@
+From 9760063610bb4890c0f88c1dd839ec1531706f33 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 28 Dec 2010 21:38:01 +0100
+Subject: [PATCH 23/65] ASoC: codecs: wm8962: Fix register cache incoherency
+
+The multi-component patch(commit f0fba2ad1) moved the allocation of the
+register cache from the driver to the ASoC core. Most drivers where adjusted to
+this, but the wm8962 driver still uses its own register cache for its
+private functions, while functions from the ASoC core use the generic cache.
+Thus we end up with two from each other incoherent caches, which can lead to
+undefined behaviour.
+This patch fixes the issue by changing the wm8962 driver to use the
+generic register cache in its private functions.
+
+Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Cc: stable@kernel.org (for 2.6.37 only)
+---
+ sound/soc/codecs/wm8962.c | 45 ++++++++++++++++++++-------------------------
+ 1 files changed, 20 insertions(+), 25 deletions(-)
+
+diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
+index 1304ca9..7c421cc 100644
+--- a/sound/soc/codecs/wm8962.c
++++ b/sound/soc/codecs/wm8962.c
+@@ -52,8 +52,6 @@ static const char *wm8962_supply_names[WM8962_NUM_SUPPLIES] = {
+ struct wm8962_priv {
+ struct snd_soc_codec *codec;
+
+- u16 reg_cache[WM8962_MAX_REGISTER + 1];
+-
+ int sysclk;
+ int sysclk_rate;
+
+@@ -1991,8 +1989,7 @@ static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+- u16 *reg_cache = wm8962->reg_cache;
++ u16 *reg_cache = codec->reg_cache;
+ int ret;
+
+ /* Apply the update (if any) */
+@@ -2020,8 +2017,7 @@ static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+- u16 *reg_cache = wm8962->reg_cache;
++ u16 *reg_cache = codec->reg_cache;
+ int ret;
+
+ /* Apply the update (if any) */
+@@ -2329,8 +2325,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+ {
+ struct snd_soc_codec *codec = w->codec;
+- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+- u16 *reg_cache = wm8962->reg_cache;
++ u16 *reg_cache = codec->reg_cache;
+ int reg;
+
+ switch (w->shift) {
+@@ -2719,7 +2714,7 @@ static int wm8962_add_widgets(struct snd_soc_codec *codec)
+
+ static void wm8962_sync_cache(struct snd_soc_codec *codec)
+ {
+- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
++ u16 *reg_cache = codec->reg_cache;
+ int i;
+
+ if (!codec->cache_sync)
+@@ -2732,13 +2727,13 @@ static void wm8962_sync_cache(struct snd_soc_codec *codec)
+ /* Sync back cached values if they're different from the
+ * hardware default.
+ */
+- for (i = 1; i < ARRAY_SIZE(wm8962->reg_cache); i++) {
++ for (i = 1; i < codec->driver->reg_cache_size; i++) {
+ if (i == WM8962_SOFTWARE_RESET)
+ continue;
+- if (wm8962->reg_cache[i] == wm8962_reg[i])
++ if (reg_cache[i] == wm8962_reg[i])
+ continue;
+
+- snd_soc_write(codec, i, wm8962->reg_cache[i]);
++ snd_soc_write(codec, i, reg_cache[i]);
+ }
+
+ codec->cache_sync = 0;
+@@ -3406,12 +3401,11 @@ EXPORT_SYMBOL_GPL(wm8962_mic_detect);
+ #ifdef CONFIG_PM
+ static int wm8962_resume(struct snd_soc_codec *codec)
+ {
+- struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+ u16 *reg_cache = codec->reg_cache;
+ int i;
+
+ /* Restore the registers */
+- for (i = 1; i < ARRAY_SIZE(wm8962->reg_cache); i++) {
++ for (i = 1; i < codec->driver->reg_cache_size; i++) {
+ switch (i) {
+ case WM8962_SOFTWARE_RESET:
+ continue;
+@@ -3705,6 +3699,7 @@ static int wm8962_probe(struct snd_soc_codec *codec)
+ struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+ struct i2c_client *i2c = container_of(codec->dev, struct i2c_client,
+ dev);
++ u16 *reg_cache = codec->reg_cache;
+ int i, trigger, irq_pol;
+
+ wm8962->codec = codec;
+@@ -3804,7 +3799,7 @@ static int wm8962_probe(struct snd_soc_codec *codec)
+
+ /* Put the speakers into mono mode? */
+ if (pdata->spk_mono)
+- wm8962->reg_cache[WM8962_CLASS_D_CONTROL_2]
++ reg_cache[WM8962_CLASS_D_CONTROL_2]
+ |= WM8962_SPK_MONO;
+
+ /* Micbias setup, detection enable and detection
+@@ -3819,16 +3814,16 @@ static int wm8962_probe(struct snd_soc_codec *codec)
+ }
+
+ /* Latch volume update bits */
+- wm8962->reg_cache[WM8962_LEFT_INPUT_VOLUME] |= WM8962_IN_VU;
+- wm8962->reg_cache[WM8962_RIGHT_INPUT_VOLUME] |= WM8962_IN_VU;
+- wm8962->reg_cache[WM8962_LEFT_ADC_VOLUME] |= WM8962_ADC_VU;
+- wm8962->reg_cache[WM8962_RIGHT_ADC_VOLUME] |= WM8962_ADC_VU;
+- wm8962->reg_cache[WM8962_LEFT_DAC_VOLUME] |= WM8962_DAC_VU;
+- wm8962->reg_cache[WM8962_RIGHT_DAC_VOLUME] |= WM8962_DAC_VU;
+- wm8962->reg_cache[WM8962_SPKOUTL_VOLUME] |= WM8962_SPKOUT_VU;
+- wm8962->reg_cache[WM8962_SPKOUTR_VOLUME] |= WM8962_SPKOUT_VU;
+- wm8962->reg_cache[WM8962_HPOUTL_VOLUME] |= WM8962_HPOUT_VU;
+- wm8962->reg_cache[WM8962_HPOUTR_VOLUME] |= WM8962_HPOUT_VU;
++ reg_cache[WM8962_LEFT_INPUT_VOLUME] |= WM8962_IN_VU;
++ reg_cache[WM8962_RIGHT_INPUT_VOLUME] |= WM8962_IN_VU;
++ reg_cache[WM8962_LEFT_ADC_VOLUME] |= WM8962_ADC_VU;
++ reg_cache[WM8962_RIGHT_ADC_VOLUME] |= WM8962_ADC_VU;
++ reg_cache[WM8962_LEFT_DAC_VOLUME] |= WM8962_DAC_VU;
++ reg_cache[WM8962_RIGHT_DAC_VOLUME] |= WM8962_DAC_VU;
++ reg_cache[WM8962_SPKOUTL_VOLUME] |= WM8962_SPKOUT_VU;
++ reg_cache[WM8962_SPKOUTR_VOLUME] |= WM8962_SPKOUT_VU;
++ reg_cache[WM8962_HPOUTL_VOLUME] |= WM8962_HPOUT_VU;
++ reg_cache[WM8962_HPOUTR_VOLUME] |= WM8962_HPOUT_VU;
+
+ wm8962_add_widgets(codec);
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0024-ASoC-codecs-wm9090-Fix-register-cache-incoherency.patch b/extras/recipes-kernel/linux/linux-omap/linus/0024-ASoC-codecs-wm9090-Fix-register-cache-incoherency.patch
new file mode 100644
index 00000000..ad5aedd1
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0024-ASoC-codecs-wm9090-Fix-register-cache-incoherency.patch
@@ -0,0 +1,75 @@
+From 2f2f23c75c1c055ca6274b04bd2dc71d0a6e8c62 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 28 Dec 2010 21:38:02 +0100
+Subject: [PATCH 24/65] ASoC: codecs: wm9090: Fix register cache incoherency
+
+The multi-component patch(commit f0fba2ad1) moved the allocation of the
+register cache from the driver to the ASoC core. Most drivers where adjusted to
+this, but the wm9090 driver still uses its own register cache for its
+private functions, while functions from the ASoC core use the generic cache.
+Thus we end up with two from each other incoherent caches, which can lead to
+undefined behaviour.
+This patch fixes the issue by changing the wm9090 driver to use the
+generic register cache in its private functions.
+
+Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Cc: stable@kernel.org (for 2.6.37 only)
+---
+ sound/soc/codecs/wm9090.c | 18 +++++++++---------
+ 1 files changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c
+index 99c046b..6e5f64f 100644
+--- a/sound/soc/codecs/wm9090.c
++++ b/sound/soc/codecs/wm9090.c
+@@ -141,7 +141,6 @@ static const u16 wm9090_reg_defaults[] = {
+ /* This struct is used to save the context */
+ struct wm9090_priv {
+ struct mutex mutex;
+- u16 reg_cache[WM9090_MAX_REGISTER + 1];
+ struct wm9090_platform_data pdata;
+ void *control_data;
+ };
+@@ -552,6 +551,7 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,
+ static int wm9090_probe(struct snd_soc_codec *codec)
+ {
+ struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec);
++ u16 *reg_cache = codec->reg_cache;
+ int ret;
+
+ codec->control_data = wm9090->control_data;
+@@ -576,22 +576,22 @@ static int wm9090_probe(struct snd_soc_codec *codec)
+ /* Configure some defaults; they will be written out when we
+ * bring the bias up.
+ */
+- wm9090->reg_cache[WM9090_IN1_LINE_INPUT_A_VOLUME] |= WM9090_IN1_VU
++ reg_cache[WM9090_IN1_LINE_INPUT_A_VOLUME] |= WM9090_IN1_VU
+ | WM9090_IN1A_ZC;
+- wm9090->reg_cache[WM9090_IN1_LINE_INPUT_B_VOLUME] |= WM9090_IN1_VU
++ reg_cache[WM9090_IN1_LINE_INPUT_B_VOLUME] |= WM9090_IN1_VU
+ | WM9090_IN1B_ZC;
+- wm9090->reg_cache[WM9090_IN2_LINE_INPUT_A_VOLUME] |= WM9090_IN2_VU
++ reg_cache[WM9090_IN2_LINE_INPUT_A_VOLUME] |= WM9090_IN2_VU
+ | WM9090_IN2A_ZC;
+- wm9090->reg_cache[WM9090_IN2_LINE_INPUT_B_VOLUME] |= WM9090_IN2_VU
++ reg_cache[WM9090_IN2_LINE_INPUT_B_VOLUME] |= WM9090_IN2_VU
+ | WM9090_IN2B_ZC;
+- wm9090->reg_cache[WM9090_SPEAKER_VOLUME_LEFT] |=
++ reg_cache[WM9090_SPEAKER_VOLUME_LEFT] |=
+ WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC;
+- wm9090->reg_cache[WM9090_LEFT_OUTPUT_VOLUME] |=
++ reg_cache[WM9090_LEFT_OUTPUT_VOLUME] |=
+ WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC;
+- wm9090->reg_cache[WM9090_RIGHT_OUTPUT_VOLUME] |=
++ reg_cache[WM9090_RIGHT_OUTPUT_VOLUME] |=
+ WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC;
+
+- wm9090->reg_cache[WM9090_CLOCKING_1] |= WM9090_TOCLK_ENA;
++ reg_cache[WM9090_CLOCKING_1] |= WM9090_TOCLK_ENA;
+
+ wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0025-ASoC-codecs-wm8753-Fix-register-cache-incoherency.patch b/extras/recipes-kernel/linux/linux-omap/linus/0025-ASoC-codecs-wm8753-Fix-register-cache-incoherency.patch
new file mode 100644
index 00000000..574c76ea
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0025-ASoC-codecs-wm8753-Fix-register-cache-incoherency.patch
@@ -0,0 +1,514 @@
+From 0e07d2db08fa60b3e1bbc9837775feaf1cb8a381 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 28 Dec 2010 21:38:03 +0100
+Subject: [PATCH 25/65] ASoC: codecs: wm8753: Fix register cache incoherency
+
+The multi-component patch(commit f0fba2ad1) moved the allocation of the
+register cache from the driver to the ASoC core. Most drivers where adjusted to
+this, but the wm8753 driver still uses its own register cache for its
+private functions, while functions from the ASoC core use the generic cache.
+Furthermore the generic cache uses zero-based numbering while the wm8753 cache
+uses one-based numbering.
+Thus we end up with two from each other incoherent caches, which leads to undefined
+behaviour and crashes.
+This patch fixes the issue by changing the wm8753 driver to use the generic
+register cache in its private functions.
+
+Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+---
+ sound/soc/codecs/wm8753.c | 226 +++++++++++++++++----------------------------
+ 1 files changed, 83 insertions(+), 143 deletions(-)
+
+diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
+index 8f679a1..87caae5 100644
+--- a/sound/soc/codecs/wm8753.c
++++ b/sound/soc/codecs/wm8753.c
+@@ -65,22 +65,22 @@ static void wm8753_set_dai_mode(struct snd_soc_codec *codec,
+ * are using 2 wire for device control, so we cache them instead.
+ */
+ static const u16 wm8753_reg[] = {
+- 0x0008, 0x0000, 0x000a, 0x000a,
+- 0x0033, 0x0000, 0x0007, 0x00ff,
+- 0x00ff, 0x000f, 0x000f, 0x007b,
+- 0x0000, 0x0032, 0x0000, 0x00c3,
+- 0x00c3, 0x00c0, 0x0000, 0x0000,
++ 0x0000, 0x0008, 0x0000, 0x000a,
++ 0x000a, 0x0033, 0x0000, 0x0007,
++ 0x00ff, 0x00ff, 0x000f, 0x000f,
++ 0x007b, 0x0000, 0x0032, 0x0000,
++ 0x00c3, 0x00c3, 0x00c0, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+- 0x0000, 0x0000, 0x0000, 0x0055,
+- 0x0005, 0x0050, 0x0055, 0x0050,
+- 0x0055, 0x0050, 0x0055, 0x0079,
+- 0x0079, 0x0079, 0x0079, 0x0079,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+- 0x0097, 0x0097, 0x0000, 0x0004,
+- 0x0000, 0x0083, 0x0024, 0x01ba,
+- 0x0000, 0x0083, 0x0024, 0x01ba,
+- 0x0000, 0x0000, 0x0000
++ 0x0055, 0x0005, 0x0050, 0x0055,
++ 0x0050, 0x0055, 0x0050, 0x0055,
++ 0x0079, 0x0079, 0x0079, 0x0079,
++ 0x0079, 0x0000, 0x0000, 0x0000,
++ 0x0000, 0x0097, 0x0097, 0x0000,
++ 0x0004, 0x0000, 0x0083, 0x0024,
++ 0x01ba, 0x0000, 0x0083, 0x0024,
++ 0x01ba, 0x0000, 0x0000, 0x0000
+ };
+
+ /* codec private data */
+@@ -88,57 +88,10 @@ struct wm8753_priv {
+ enum snd_soc_control_type control_type;
+ unsigned int sysclk;
+ unsigned int pcmclk;
+- u16 reg_cache[ARRAY_SIZE(wm8753_reg)];
+ int dai_func;
+ };
+
+-/*
+- * read wm8753 register cache
+- */
+-static inline unsigned int wm8753_read_reg_cache(struct snd_soc_codec *codec,
+- unsigned int reg)
+-{
+- u16 *cache = codec->reg_cache;
+- if (reg < 1 || reg >= (ARRAY_SIZE(wm8753_reg) + 1))
+- return -1;
+- return cache[reg - 1];
+-}
+-
+-/*
+- * write wm8753 register cache
+- */
+-static inline void wm8753_write_reg_cache(struct snd_soc_codec *codec,
+- unsigned int reg, unsigned int value)
+-{
+- u16 *cache = codec->reg_cache;
+- if (reg < 1 || reg >= (ARRAY_SIZE(wm8753_reg) + 1))
+- return;
+- cache[reg - 1] = value;
+-}
+-
+-/*
+- * write to the WM8753 register space
+- */
+-static int wm8753_write(struct snd_soc_codec *codec, unsigned int reg,
+- unsigned int value)
+-{
+- u8 data[2];
+-
+- /* data is
+- * D15..D9 WM8753 register offset
+- * D8...D0 register data
+- */
+- data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+- data[1] = value & 0x00ff;
+-
+- wm8753_write_reg_cache(codec, reg, value);
+- if (codec->hw_write(codec->control_data, data, 2) == 2)
+- return 0;
+- else
+- return -EIO;
+-}
+-
+-#define wm8753_reset(c) wm8753_write(c, WM8753_RESET, 0)
++#define wm8753_reset(c) snd_soc_write(c, WM8753_RESET, 0)
+
+ /*
+ * WM8753 Controls
+@@ -218,7 +171,7 @@ static int wm8753_get_dai(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+- int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL);
++ int mode = snd_soc_read(codec, WM8753_IOCTL);
+
+ ucontrol->value.integer.value[0] = (mode & 0xc) >> 2;
+ return 0;
+@@ -228,7 +181,7 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+- int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL);
++ int mode = snd_soc_read(codec, WM8753_IOCTL);
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+
+ if (((mode & 0xc) >> 2) == ucontrol->value.integer.value[0])
+@@ -738,17 +691,17 @@ static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+ if (pll_id == WM8753_PLL1) {
+ offset = 0;
+ enable = 0x10;
+- reg = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xffef;
++ reg = snd_soc_read(codec, WM8753_CLOCK) & 0xffef;
+ } else {
+ offset = 4;
+ enable = 0x8;
+- reg = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfff7;
++ reg = snd_soc_read(codec, WM8753_CLOCK) & 0xfff7;
+ }
+
+ if (!freq_in || !freq_out) {
+ /* disable PLL */
+- wm8753_write(codec, WM8753_PLL1CTL1 + offset, 0x0026);
+- wm8753_write(codec, WM8753_CLOCK, reg);
++ snd_soc_write(codec, WM8753_PLL1CTL1 + offset, 0x0026);
++ snd_soc_write(codec, WM8753_CLOCK, reg);
+ return 0;
+ } else {
+ u16 value = 0;
+@@ -759,20 +712,20 @@ static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+ /* set up N and K PLL divisor ratios */
+ /* bits 8:5 = PLL_N, bits 3:0 = PLL_K[21:18] */
+ value = (pll_div.n << 5) + ((pll_div.k & 0x3c0000) >> 18);
+- wm8753_write(codec, WM8753_PLL1CTL2 + offset, value);
++ snd_soc_write(codec, WM8753_PLL1CTL2 + offset, value);
+
+ /* bits 8:0 = PLL_K[17:9] */
+ value = (pll_div.k & 0x03fe00) >> 9;
+- wm8753_write(codec, WM8753_PLL1CTL3 + offset, value);
++ snd_soc_write(codec, WM8753_PLL1CTL3 + offset, value);
+
+ /* bits 8:0 = PLL_K[8:0] */
+ value = pll_div.k & 0x0001ff;
+- wm8753_write(codec, WM8753_PLL1CTL4 + offset, value);
++ snd_soc_write(codec, WM8753_PLL1CTL4 + offset, value);
+
+ /* set PLL as input and enable */
+- wm8753_write(codec, WM8753_PLL1CTL1 + offset, 0x0027 |
++ snd_soc_write(codec, WM8753_PLL1CTL1 + offset, 0x0027 |
+ (pll_div.div2 << 3));
+- wm8753_write(codec, WM8753_CLOCK, reg | enable);
++ snd_soc_write(codec, WM8753_CLOCK, reg | enable);
+ }
+ return 0;
+ }
+@@ -879,7 +832,7 @@ static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+ {
+ struct snd_soc_codec *codec = codec_dai->codec;
+- u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01ec;
++ u16 voice = snd_soc_read(codec, WM8753_PCM) & 0x01ec;
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+@@ -901,7 +854,7 @@ static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ return -EINVAL;
+ }
+
+- wm8753_write(codec, WM8753_PCM, voice);
++ snd_soc_write(codec, WM8753_PCM, voice);
+ return 0;
+ }
+
+@@ -922,8 +875,8 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+- u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3;
+- u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f;
++ u16 voice = snd_soc_read(codec, WM8753_PCM) & 0x01f3;
++ u16 srate = snd_soc_read(codec, WM8753_SRATE1) & 0x017f;
+
+ /* bit size */
+ switch (params_format(params)) {
+@@ -943,9 +896,9 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream,
+ /* sample rate */
+ if (params_rate(params) * 384 == wm8753->pcmclk)
+ srate |= 0x80;
+- wm8753_write(codec, WM8753_SRATE1, srate);
++ snd_soc_write(codec, WM8753_SRATE1, srate);
+
+- wm8753_write(codec, WM8753_PCM, voice);
++ snd_soc_write(codec, WM8753_PCM, voice);
+ return 0;
+ }
+
+@@ -958,8 +911,8 @@ static int wm8753_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ struct snd_soc_codec *codec = codec_dai->codec;
+ u16 voice, ioctl;
+
+- voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x011f;
+- ioctl = wm8753_read_reg_cache(codec, WM8753_IOCTL) & 0x015d;
++ voice = snd_soc_read(codec, WM8753_PCM) & 0x011f;
++ ioctl = snd_soc_read(codec, WM8753_IOCTL) & 0x015d;
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+@@ -1013,8 +966,8 @@ static int wm8753_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ return -EINVAL;
+ }
+
+- wm8753_write(codec, WM8753_PCM, voice);
+- wm8753_write(codec, WM8753_IOCTL, ioctl);
++ snd_soc_write(codec, WM8753_PCM, voice);
++ snd_soc_write(codec, WM8753_IOCTL, ioctl);
+ return 0;
+ }
+
+@@ -1026,16 +979,16 @@ static int wm8753_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+
+ switch (div_id) {
+ case WM8753_PCMDIV:
+- reg = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0x003f;
+- wm8753_write(codec, WM8753_CLOCK, reg | div);
++ reg = snd_soc_read(codec, WM8753_CLOCK) & 0x003f;
++ snd_soc_write(codec, WM8753_CLOCK, reg | div);
+ break;
+ case WM8753_BCLKDIV:
+- reg = wm8753_read_reg_cache(codec, WM8753_SRATE2) & 0x01c7;
+- wm8753_write(codec, WM8753_SRATE2, reg | div);
++ reg = snd_soc_read(codec, WM8753_SRATE2) & 0x01c7;
++ snd_soc_write(codec, WM8753_SRATE2, reg | div);
+ break;
+ case WM8753_VXCLKDIV:
+- reg = wm8753_read_reg_cache(codec, WM8753_SRATE2) & 0x003f;
+- wm8753_write(codec, WM8753_SRATE2, reg | div);
++ reg = snd_soc_read(codec, WM8753_SRATE2) & 0x003f;
++ snd_soc_write(codec, WM8753_SRATE2, reg | div);
+ break;
+ default:
+ return -EINVAL;
+@@ -1050,7 +1003,7 @@ static int wm8753_hdac_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+ {
+ struct snd_soc_codec *codec = codec_dai->codec;
+- u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01e0;
++ u16 hifi = snd_soc_read(codec, WM8753_HIFI) & 0x01e0;
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+@@ -1072,7 +1025,7 @@ static int wm8753_hdac_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ return -EINVAL;
+ }
+
+- wm8753_write(codec, WM8753_HIFI, hifi);
++ snd_soc_write(codec, WM8753_HIFI, hifi);
+ return 0;
+ }
+
+@@ -1085,8 +1038,8 @@ static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ struct snd_soc_codec *codec = codec_dai->codec;
+ u16 ioctl, hifi;
+
+- hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x011f;
+- ioctl = wm8753_read_reg_cache(codec, WM8753_IOCTL) & 0x00ae;
++ hifi = snd_soc_read(codec, WM8753_HIFI) & 0x011f;
++ ioctl = snd_soc_read(codec, WM8753_IOCTL) & 0x00ae;
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+@@ -1140,8 +1093,8 @@ static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ return -EINVAL;
+ }
+
+- wm8753_write(codec, WM8753_HIFI, hifi);
+- wm8753_write(codec, WM8753_IOCTL, ioctl);
++ snd_soc_write(codec, WM8753_HIFI, hifi);
++ snd_soc_write(codec, WM8753_IOCTL, ioctl);
+ return 0;
+ }
+
+@@ -1162,8 +1115,8 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+- u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0;
+- u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3;
++ u16 srate = snd_soc_read(codec, WM8753_SRATE1) & 0x01c0;
++ u16 hifi = snd_soc_read(codec, WM8753_HIFI) & 0x01f3;
+ int coeff;
+
+ /* is digital filter coefficient valid ? */
+@@ -1172,7 +1125,7 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream,
+ printk(KERN_ERR "wm8753 invalid MCLK or rate\n");
+ return coeff;
+ }
+- wm8753_write(codec, WM8753_SRATE1, srate | (coeff_div[coeff].sr << 1) |
++ snd_soc_write(codec, WM8753_SRATE1, srate | (coeff_div[coeff].sr << 1) |
+ coeff_div[coeff].usb);
+
+ /* bit size */
+@@ -1190,7 +1143,7 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream,
+ break;
+ }
+
+- wm8753_write(codec, WM8753_HIFI, hifi);
++ snd_soc_write(codec, WM8753_HIFI, hifi);
+ return 0;
+ }
+
+@@ -1201,8 +1154,8 @@ static int wm8753_mode1v_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ u16 clock;
+
+ /* set clk source as pcmclk */
+- clock = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfffb;
+- wm8753_write(codec, WM8753_CLOCK, clock);
++ clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb;
++ snd_soc_write(codec, WM8753_CLOCK, clock);
+
+ if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0)
+ return -EINVAL;
+@@ -1224,8 +1177,8 @@ static int wm8753_mode2_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ u16 clock;
+
+ /* set clk source as pcmclk */
+- clock = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfffb;
+- wm8753_write(codec, WM8753_CLOCK, clock);
++ clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb;
++ snd_soc_write(codec, WM8753_CLOCK, clock);
+
+ if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0)
+ return -EINVAL;
+@@ -1239,8 +1192,8 @@ static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ u16 clock;
+
+ /* set clk source as mclk */
+- clock = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfffb;
+- wm8753_write(codec, WM8753_CLOCK, clock | 0x4);
++ clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb;
++ snd_soc_write(codec, WM8753_CLOCK, clock | 0x4);
+
+ if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0)
+ return -EINVAL;
+@@ -1252,19 +1205,19 @@ static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ static int wm8753_mute(struct snd_soc_dai *dai, int mute)
+ {
+ struct snd_soc_codec *codec = dai->codec;
+- u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7;
++ u16 mute_reg = snd_soc_read(codec, WM8753_DAC) & 0xfff7;
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+
+ /* the digital mute covers the HiFi and Voice DAC's on the WM8753.
+ * make sure we check if they are not both active when we mute */
+ if (mute && wm8753->dai_func == 1) {
+ if (!codec->active)
+- wm8753_write(codec, WM8753_DAC, mute_reg | 0x8);
++ snd_soc_write(codec, WM8753_DAC, mute_reg | 0x8);
+ } else {
+ if (mute)
+- wm8753_write(codec, WM8753_DAC, mute_reg | 0x8);
++ snd_soc_write(codec, WM8753_DAC, mute_reg | 0x8);
+ else
+- wm8753_write(codec, WM8753_DAC, mute_reg);
++ snd_soc_write(codec, WM8753_DAC, mute_reg);
+ }
+
+ return 0;
+@@ -1273,23 +1226,23 @@ static int wm8753_mute(struct snd_soc_dai *dai, int mute)
+ static int wm8753_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+ {
+- u16 pwr_reg = wm8753_read_reg_cache(codec, WM8753_PWR1) & 0xfe3e;
++ u16 pwr_reg = snd_soc_read(codec, WM8753_PWR1) & 0xfe3e;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ /* set vmid to 50k and unmute dac */
+- wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0);
++ snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x00c0);
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ /* set vmid to 5k for quick power up */
+- wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x01c1);
++ snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x01c1);
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ /* mute dac and set vmid to 500k, enable VREF */
+- wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x0141);
++ snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x0141);
+ break;
+ case SND_SOC_BIAS_OFF:
+- wm8753_write(codec, WM8753_PWR1, 0x0001);
++ snd_soc_write(codec, WM8753_PWR1, 0x0001);
+ break;
+ }
+ codec->bias_level = level;
+@@ -1477,7 +1430,7 @@ static void wm8753_set_dai_mode(struct snd_soc_codec *codec,
+ else
+ dai->driver = &wm8753_all_dai[(wm8753->dai_func << 1) + 1];
+ }
+- wm8753_write(codec, WM8753_IOCTL, wm8753->dai_func);
++ snd_soc_write(codec, WM8753_IOCTL, wm8753->dai_func);
+ }
+
+ static void wm8753_work(struct work_struct *work)
+@@ -1495,22 +1448,19 @@ static int wm8753_suspend(struct snd_soc_codec *codec, pm_message_t state)
+
+ static int wm8753_resume(struct snd_soc_codec *codec)
+ {
++ u16 *reg_cache = codec->reg_cache;
+ int i;
+- u8 data[2];
+- u16 *cache = codec->reg_cache;
+
+ /* Sync reg_cache with the hardware */
+- for (i = 0; i < ARRAY_SIZE(wm8753_reg); i++) {
+- if (i + 1 == WM8753_RESET)
++ for (i = 1; i < ARRAY_SIZE(wm8753_reg); i++) {
++ if (i == WM8753_RESET)
+ continue;
+
+ /* No point in writing hardware default values back */
+- if (cache[i] == wm8753_reg[i])
++ if (reg_cache[i] == wm8753_reg[i])
+ continue;
+
+- data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001);
+- data[1] = cache[i] & 0x00ff;
+- codec->hw_write(codec->control_data, data, 2);
++ snd_soc_write(codec, i, reg_cache[i]);
+ }
+
+ wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+@@ -1548,7 +1498,7 @@ static int run_delayed_work(struct delayed_work *dwork)
+ static int wm8753_probe(struct snd_soc_codec *codec)
+ {
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+- int ret = 0, reg;
++ int ret;
+
+ INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
+
+@@ -1573,26 +1523,16 @@ static int wm8753_probe(struct snd_soc_codec *codec)
+ msecs_to_jiffies(caps_charge));
+
+ /* set the update bits */
+- reg = wm8753_read_reg_cache(codec, WM8753_LDAC);
+- wm8753_write(codec, WM8753_LDAC, reg | 0x0100);
+- reg = wm8753_read_reg_cache(codec, WM8753_RDAC);
+- wm8753_write(codec, WM8753_RDAC, reg | 0x0100);
+- reg = wm8753_read_reg_cache(codec, WM8753_LADC);
+- wm8753_write(codec, WM8753_LADC, reg | 0x0100);
+- reg = wm8753_read_reg_cache(codec, WM8753_RADC);
+- wm8753_write(codec, WM8753_RADC, reg | 0x0100);
+- reg = wm8753_read_reg_cache(codec, WM8753_LOUT1V);
+- wm8753_write(codec, WM8753_LOUT1V, reg | 0x0100);
+- reg = wm8753_read_reg_cache(codec, WM8753_ROUT1V);
+- wm8753_write(codec, WM8753_ROUT1V, reg | 0x0100);
+- reg = wm8753_read_reg_cache(codec, WM8753_LOUT2V);
+- wm8753_write(codec, WM8753_LOUT2V, reg | 0x0100);
+- reg = wm8753_read_reg_cache(codec, WM8753_ROUT2V);
+- wm8753_write(codec, WM8753_ROUT2V, reg | 0x0100);
+- reg = wm8753_read_reg_cache(codec, WM8753_LINVOL);
+- wm8753_write(codec, WM8753_LINVOL, reg | 0x0100);
+- reg = wm8753_read_reg_cache(codec, WM8753_RINVOL);
+- wm8753_write(codec, WM8753_RINVOL, reg | 0x0100);
++ snd_soc_update_bits(codec, WM8753_LDAC, 0x0100, 0x0100);
++ snd_soc_update_bits(codec, WM8753_RDAC, 0x0100, 0x0100);
++ snd_soc_update_bits(codec, WM8753_LDAC, 0x0100, 0x0100);
++ snd_soc_update_bits(codec, WM8753_RDAC, 0x0100, 0x0100);
++ snd_soc_update_bits(codec, WM8753_LOUT1V, 0x0100, 0x0100);
++ snd_soc_update_bits(codec, WM8753_ROUT1V, 0x0100, 0x0100);
++ snd_soc_update_bits(codec, WM8753_LOUT2V, 0x0100, 0x0100);
++ snd_soc_update_bits(codec, WM8753_ROUT2V, 0x0100, 0x0100);
++ snd_soc_update_bits(codec, WM8753_LINVOL, 0x0100, 0x0100);
++ snd_soc_update_bits(codec, WM8753_RINVOL, 0x0100, 0x0100);
+
+ snd_soc_add_controls(codec, wm8753_snd_controls,
+ ARRAY_SIZE(wm8753_snd_controls));
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0026-KVM-MMU-Fix-incorrect-direct-gfn-for-unpaged-mode-sh.patch b/extras/recipes-kernel/linux/linux-omap/linus/0026-KVM-MMU-Fix-incorrect-direct-gfn-for-unpaged-mode-sh.patch
new file mode 100644
index 00000000..9372cf05
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0026-KVM-MMU-Fix-incorrect-direct-gfn-for-unpaged-mode-sh.patch
@@ -0,0 +1,35 @@
+From 22c5ed7018eb4157e317c8513fe2ced2c8ec5e0c Mon Sep 17 00:00:00 2001
+From: Avi Kivity <avi@redhat.com>
+Date: Tue, 28 Dec 2010 12:09:07 +0200
+Subject: [PATCH 26/65] KVM: MMU: Fix incorrect direct gfn for unpaged mode shadow
+
+We use the physical address instead of the base gfn for the four
+PAE page directories we use in unpaged mode. When the guest accesses
+an address above 1GB that is backed by a large host page, a BUG_ON()
+in kvm_mmu_set_gfn() triggers.
+
+Resolves: https://bugzilla.kernel.org/show_bug.cgi?id=21962
+Reported-and-tested-by: Nicolas Prochazka <prochazka.nicolas@gmail.com>
+KVM-Stable-Tag.
+Signed-off-by: Avi Kivity <avi@redhat.com>
+---
+ arch/x86/kvm/mmu.c | 3 ++-
+ 1 files changed, 2 insertions(+), 1 deletions(-)
+
+diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
+index fb8b376..fbb04ae 100644
+--- a/arch/x86/kvm/mmu.c
++++ b/arch/x86/kvm/mmu.c
+@@ -2394,7 +2394,8 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu)
+ ASSERT(!VALID_PAGE(root));
+ spin_lock(&vcpu->kvm->mmu_lock);
+ kvm_mmu_free_some_pages(vcpu);
+- sp = kvm_mmu_get_page(vcpu, i << 30, i << 30,
++ sp = kvm_mmu_get_page(vcpu, i << (30 - PAGE_SHIFT),
++ i << 30,
+ PT32_ROOT_LEVEL, 1, ACC_ALL,
+ NULL);
+ root = __pa(sp->spt);
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0027-fix-freeing-user_struct-in-user-cache.patch b/extras/recipes-kernel/linux/linux-omap/linus/0027-fix-freeing-user_struct-in-user-cache.patch
new file mode 100644
index 00000000..8ddca9c1
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0027-fix-freeing-user_struct-in-user-cache.patch
@@ -0,0 +1,34 @@
+From 2bffbb04acdf2e58726ba8192d468f2bda528fdf Mon Sep 17 00:00:00 2001
+From: Hillf Danton <dhillf@gmail.com>
+Date: Wed, 29 Dec 2010 21:55:28 +0800
+Subject: [PATCH 27/65] fix freeing user_struct in user cache
+
+When racing on adding into user cache, the new allocated from mm slab
+is freed without putting user namespace.
+
+Since the user namespace is already operated by getting, putting has
+to be issued.
+
+Signed-off-by: Hillf Danton <dhillf@gmail.com>
+Acked-by: Serge Hallyn <serge@hallyn.com>
+Cc: stable@kernel.org
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+---
+ kernel/user.c | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/kernel/user.c b/kernel/user.c
+index 2c7d8d5..5c598ca 100644
+--- a/kernel/user.c
++++ b/kernel/user.c
+@@ -158,6 +158,7 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid)
+ spin_lock_irq(&uidhash_lock);
+ up = uid_hash_find(uid, hashent);
+ if (up) {
++ put_user_ns(ns);
+ key_put(new->uid_keyring);
+ key_put(new->session_keyring);
+ kmem_cache_free(uid_cachep, new);
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0028-spi-omap2_mcspi.c-Force-CS-to-be-in-inactive-state-a.patch b/extras/recipes-kernel/linux/linux-omap/linus/0028-spi-omap2_mcspi.c-Force-CS-to-be-in-inactive-state-a.patch
new file mode 100644
index 00000000..4c3acd7c
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0028-spi-omap2_mcspi.c-Force-CS-to-be-in-inactive-state-a.patch
@@ -0,0 +1,111 @@
+From 72ce69f5fe32170f9662b5c87b0226d6ba19462f Mon Sep 17 00:00:00 2001
+From: Gregory CLEMENT <gregory.clement@free-electrons.com>
+Date: Wed, 29 Dec 2010 11:52:53 +0100
+Subject: [PATCH 28/65] spi/omap2_mcspi.c: Force CS to be in inactive state after off-mode transition
+
+When SPI wake up from OFF mode, CS is in the wrong state: force it to the
+inactive state.
+
+During the system life, I monitored the CS behavior using a oscilloscope.
+I also activated debug in omap2_mcspi, so I saw when driver disable the clocks
+and restore context when device is not used.Each time the CS was in the correct
+state. It was only when system was put suspend to ram with off-mode activated
+that on resume the CS was in wrong state( ie activated).
+
+Changelog:
+* Change from v1 to v2:
+ - Rebase on linus/master (after 2.6.37-rc1)
+ - Do some clean-up and fix indentation on both patches
+ - Add more explanations for patch 2
+
+* Change from v2 to v3:
+ - Use directly resume function of spi_master instead of using function
+ - from spi_device as Grant Likely pointed it out.
+ - Force this transition explicitly for each CS used by a device.
+
+* Change from v3 to v4:
+ - Patch clean-up according to Kevin Hilman and checkpatch.
+ - Now force CS to be in inactive state only if it was inactive when it was
+ suspended.
+
+* Change from v4 to v5:
+ - Rebase on linus/master (after 2.6.37-rc3)
+ - Collapse some lines as pointed by Grant Likely
+ - Fix a spelling
+
+* Change from v5 to v6:
+ - Rebase on linus/master (after 2.6.37-rc7)
+ - Use CONFIG_SUSPEND instead of CONFIG_PM
+ - Didn't use legacy PM methods anymore. Instead, add a struct dev_pm_ops and
+ add the resume method there.
+ - Fix multi-line comment style
+
+* Change from v6 to v7:
+ - Rebase on linus/master (after 2.6.37-rc8)
+ - Drop an extra line
+
+Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
+Acked-by: David Brownell <dbrownell@users.sourceforge.net>
+Reviewed-by: Kevin Hilman <khilman@deeprootsystems.com>
+Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
+---
+ drivers/spi/omap2_mcspi.c | 39 +++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 39 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
+index 2a651e6..951a160 100644
+--- a/drivers/spi/omap2_mcspi.c
++++ b/drivers/spi/omap2_mcspi.c
+@@ -1305,10 +1305,49 @@ static int __exit omap2_mcspi_remove(struct platform_device *pdev)
+ /* work with hotplug and coldplug */
+ MODULE_ALIAS("platform:omap2_mcspi");
+
++#ifdef CONFIG_SUSPEND
++/*
++ * When SPI wake up from off-mode, CS is in activate state. If it was in
++ * unactive state when driver was suspend, then force it to unactive state at
++ * wake up.
++ */
++static int omap2_mcspi_resume(struct device *dev)
++{
++ struct spi_master *master = dev_get_drvdata(dev);
++ struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
++ struct omap2_mcspi_cs *cs;
++
++ omap2_mcspi_enable_clocks(mcspi);
++ list_for_each_entry(cs, &omap2_mcspi_ctx[master->bus_num - 1].cs,
++ node) {
++ if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) {
++
++ /*
++ * We need to toggle CS state for OMAP take this
++ * change in account.
++ */
++ MOD_REG_BIT(cs->chconf0, OMAP2_MCSPI_CHCONF_FORCE, 1);
++ __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
++ MOD_REG_BIT(cs->chconf0, OMAP2_MCSPI_CHCONF_FORCE, 0);
++ __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
++ }
++ }
++ omap2_mcspi_disable_clocks(mcspi);
++ return 0;
++}
++#else
++#define omap2_mcspi_resume NULL
++#endif
++
++static const struct dev_pm_ops omap2_mcspi_pm_ops = {
++ .resume = omap2_mcspi_resume,
++};
++
+ static struct platform_driver omap2_mcspi_driver = {
+ .driver = {
+ .name = "omap2_mcspi",
+ .owner = THIS_MODULE,
++ .pm = &omap2_mcspi_pm_ops
+ },
+ .remove = __exit_p(omap2_mcspi_remove),
+ };
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0029-kconfig-fix-undesirable-side-effect-of-adding-visibl.patch b/extras/recipes-kernel/linux/linux-omap/linus/0029-kconfig-fix-undesirable-side-effect-of-adding-visibl.patch
new file mode 100644
index 00000000..c1af0112
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0029-kconfig-fix-undesirable-side-effect-of-adding-visibl.patch
@@ -0,0 +1,49 @@
+From 38f5b0c391281eded0e6e5b2bc75a28ae72d0abe Mon Sep 17 00:00:00 2001
+From: Jan Beulich <JBeulich@novell.com>
+Date: Thu, 9 Dec 2010 08:11:38 +0000
+Subject: [PATCH 29/65] kconfig: fix undesirable side effect of adding "visible" menu attribute
+
+This lead to non-selected, non-user-selectable options to be written
+out to .config. This is not only pointless, but also preventing the
+user to be prompted should any of those options eventually become
+visible (e.g. by de-selecting the *_AUTO options the "visible"
+attribute was added for.
+
+Furthermore it is quite logical for the "visible" attribute of a menu
+to control the visibility of all contained prompts, which is what the
+patch does.
+
+Signed-off-by: Jan Beulich <jbeulich@novell.com>
+Signed-off-by: Michal Marek <mmarek@suse.cz>
+---
+ scripts/kconfig/menu.c | 14 ++++++++++++++
+ 1 files changed, 14 insertions(+), 0 deletions(-)
+
+diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
+index b9d9aa1..5f77dcb 100644
+--- a/scripts/kconfig/menu.c
++++ b/scripts/kconfig/menu.c
+@@ -140,6 +140,20 @@ struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *e
+ }
+ if (current_entry->prompt && current_entry != &rootmenu)
+ prop_warn(prop, "prompt redefined");
++
++ /* Apply all upper menus' visibilities to actual prompts. */
++ if(type == P_PROMPT) {
++ struct menu *menu = current_entry;
++
++ while ((menu = menu->parent) != NULL) {
++ if (!menu->visibility)
++ continue;
++ prop->visible.expr
++ = expr_alloc_and(prop->visible.expr,
++ menu->visibility);
++ }
++ }
++
+ current_entry->prompt = prop;
+ }
+ prop->text = prompt;
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0030-spi-m68knommu-Coldfire-QSPI-platform-support.patch b/extras/recipes-kernel/linux/linux-omap/linus/0030-spi-m68knommu-Coldfire-QSPI-platform-support.patch
new file mode 100644
index 00000000..c6dcff2c
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0030-spi-m68knommu-Coldfire-QSPI-platform-support.patch
@@ -0,0 +1,33 @@
+From 806e90c4e5253095f9576113edc6fc78b2d5fec1 Mon Sep 17 00:00:00 2001
+From: Jate Sujjavanich <jsujjavanich@syntech-fuelmaster.com>
+Date: Wed, 29 Sep 2010 09:44:32 -0400
+Subject: [PATCH 30/65] spi/m68knommu: Coldfire QSPI platform support
+
+After grabbing a msg from the msgq, the mcfqspi_work function calls
+list_del_init on the mcfqspi->msgq which unintentionally deletes the rest
+of the list before it can be processed. If qspi call was made using
+spi_sync, this can result in a process hang.
+
+Signed-off-by: Jate Sujjavanich <jsujjavanich@syntech-fuelmaster.com>
+Acked-by: Steven King <sfking@fdwdc.com>
+Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
+---
+ drivers/spi/coldfire_qspi.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/spi/coldfire_qspi.c b/drivers/spi/coldfire_qspi.c
+index 052b3c7..8856bcc 100644
+--- a/drivers/spi/coldfire_qspi.c
++++ b/drivers/spi/coldfire_qspi.c
+@@ -317,7 +317,7 @@ static void mcfqspi_work(struct work_struct *work)
+ msg = container_of(mcfqspi->msgq.next, struct spi_message,
+ queue);
+
+- list_del_init(&mcfqspi->msgq);
++ list_del_init(&msg->queue);
+ spin_unlock_irqrestore(&mcfqspi->lock, flags);
+
+ spi = msg->spi;
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0031-sound-Prevent-buffer-overflow-in-OSS-load_mixer_volu.patch b/extras/recipes-kernel/linux/linux-omap/linus/0031-sound-Prevent-buffer-overflow-in-OSS-load_mixer_volu.patch
new file mode 100644
index 00000000..473a408d
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0031-sound-Prevent-buffer-overflow-in-OSS-load_mixer_volu.patch
@@ -0,0 +1,47 @@
+From 6540a62434750fe29b877293e54dbf05c0fb54c4 Mon Sep 17 00:00:00 2001
+From: Dan Rosenberg <drosenberg@vsecurity.com>
+Date: Sat, 25 Dec 2010 16:23:40 -0500
+Subject: [PATCH 31/65] sound: Prevent buffer overflow in OSS load_mixer_volumes
+
+The load_mixer_volumes() function, which can be triggered by
+unprivileged users via the SOUND_MIXER_SETLEVELS ioctl, is vulnerable to
+a buffer overflow. Because the provided "name" argument isn't
+guaranteed to be NULL terminated at the expected 32 bytes, it's possible
+to overflow past the end of the last element in the mixer_vols array.
+Further exploitation can result in an arbitrary kernel write (via
+subsequent calls to load_mixer_volumes()) leading to privilege
+escalation, or arbitrary kernel reads via get_mixer_levels(). In
+addition, the strcmp() may leak bytes beyond the mixer_vols array.
+
+Signed-off-by: Dan Rosenberg <drosenberg@vsecurity.com>
+Cc: stable <stable@kernel.org>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+---
+ sound/oss/soundcard.c | 4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c
+index 46c0d03..fcb14a0 100644
+--- a/sound/oss/soundcard.c
++++ b/sound/oss/soundcard.c
+@@ -87,7 +87,7 @@ int *load_mixer_volumes(char *name, int *levels, int present)
+ int i, n;
+
+ for (i = 0; i < num_mixer_volumes; i++) {
+- if (strcmp(name, mixer_vols[i].name) == 0) {
++ if (strncmp(name, mixer_vols[i].name, 32) == 0) {
+ if (present)
+ mixer_vols[i].num = i;
+ return mixer_vols[i].levels;
+@@ -99,7 +99,7 @@ int *load_mixer_volumes(char *name, int *levels, int present)
+ }
+ n = num_mixer_volumes++;
+
+- strcpy(mixer_vols[n].name, name);
++ strncpy(mixer_vols[n].name, name, 32);
+
+ if (present)
+ mixer_vols[n].num = n;
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0032-ALSA-hda-Use-LPIB-quirk-for-Dell-Inspiron-m101z-1120.patch b/extras/recipes-kernel/linux/linux-omap/linus/0032-ALSA-hda-Use-LPIB-quirk-for-Dell-Inspiron-m101z-1120.patch
new file mode 100644
index 00000000..048a3db1
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0032-ALSA-hda-Use-LPIB-quirk-for-Dell-Inspiron-m101z-1120.patch
@@ -0,0 +1,32 @@
+From 927b580b918babc2ecc22a1ae1b6deef428d933f Mon Sep 17 00:00:00 2001
+From: Daniel T Chen <crimsun@ubuntu.com>
+Date: Tue, 28 Dec 2010 17:20:02 -0500
+Subject: [PATCH 32/65] ALSA: hda: Use LPIB quirk for Dell Inspiron m101z/1120
+
+Sjoerd Simons reports that, without using position_fix=1, recording
+experiences overruns. Work around that by applying the LPIB quirk
+for his hardware.
+
+Reported-and-tested-by: Sjoerd Simons <sjoerd@debian.org>
+Cc: <stable@kernel.org>
+Signed-off-by: Daniel T Chen <crimsun@ubuntu.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+---
+ sound/pci/hda/hda_intel.c | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
+index b030c8e..a1c4008 100644
+--- a/sound/pci/hda/hda_intel.c
++++ b/sound/pci/hda/hda_intel.c
+@@ -2300,6 +2300,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = {
+ SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
+ SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
+ SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB),
++ SND_PCI_QUIRK(0x1028, 0x0470, "Dell Inspiron 1120", POS_FIX_LPIB),
+ SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
+ SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
+ SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB),
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0033-Revert-drm-i915-bios-Reverse-order-of-100-120-Mhz-SS.patch b/extras/recipes-kernel/linux/linux-omap/linus/0033-Revert-drm-i915-bios-Reverse-order-of-100-120-Mhz-SS.patch
new file mode 100644
index 00000000..ffffd87e
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0033-Revert-drm-i915-bios-Reverse-order-of-100-120-Mhz-SS.patch
@@ -0,0 +1,33 @@
+From 5cd3371a75c27fe5b105037b1a9a53b661a3624e Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Thu, 30 Dec 2010 09:07:15 +0000
+Subject: [PATCH 33/65] Revert "drm/i915/bios: Reverse order of 100/120 Mhz SSC clocks"
+
+As I feared, whilst this fixed the clocks for the Lenovo U160, it broke
+many other machines. So lets reverts commit 448f53a1ede54eb854d036abf
+and search for the real bug.
+
+Reported-and-tested-by: Travis Hume <travis@computoring.org> [et al]
+Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=25842
+Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=32698
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+---
+ drivers/gpu/drm/i915/intel_bios.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
+index 2b20786..b0b1200 100644
+--- a/drivers/gpu/drm/i915/intel_bios.c
++++ b/drivers/gpu/drm/i915/intel_bios.c
+@@ -270,7 +270,7 @@ parse_general_features(struct drm_i915_private *dev_priv,
+ general->ssc_freq ? 66 : 48;
+ else if (IS_GEN5(dev) || IS_GEN6(dev))
+ dev_priv->lvds_ssc_freq =
+- general->ssc_freq ? 120 : 100;
++ general->ssc_freq ? 100 : 120;
+ else
+ dev_priv->lvds_ssc_freq =
+ general->ssc_freq ? 100 : 96;
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0034-drm-i915-dvo-Report-LVDS-attached-to-ch701x-as-conne.patch b/extras/recipes-kernel/linux/linux-omap/linus/0034-drm-i915-dvo-Report-LVDS-attached-to-ch701x-as-conne.patch
new file mode 100644
index 00000000..8747c9f2
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0034-drm-i915-dvo-Report-LVDS-attached-to-ch701x-as-conne.patch
@@ -0,0 +1,30 @@
+From a5cbe1d2c6eede52b1773eefcff8e3c1c171b99b Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Thu, 30 Dec 2010 12:54:00 +0000
+Subject: [PATCH 34/65] drm/i915/dvo: Report LVDS attached to ch701x as connected
+
+As we have already detected something attached to the chip during
+initialisation, always report the LVDS connector status as connected
+during probing.
+
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+---
+ drivers/gpu/drm/i915/dvo_ch7017.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/gpu/drm/i915/dvo_ch7017.c b/drivers/gpu/drm/i915/dvo_ch7017.c
+index af70337..d3e8c54 100644
+--- a/drivers/gpu/drm/i915/dvo_ch7017.c
++++ b/drivers/gpu/drm/i915/dvo_ch7017.c
+@@ -242,7 +242,7 @@ fail:
+
+ static enum drm_connector_status ch7017_detect(struct intel_dvo_device *dvo)
+ {
+- return connector_status_unknown;
++ return connector_status_connected;
+ }
+
+ static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo,
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0035-update-Documentation-filesystems-Locking.patch b/extras/recipes-kernel/linux/linux-omap/linus/0035-update-Documentation-filesystems-Locking.patch
new file mode 100644
index 00000000..5a5610b5
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0035-update-Documentation-filesystems-Locking.patch
@@ -0,0 +1,402 @@
+From 84a03bcb1f1fb5b6a9f6f508fa0a1fae41a5827a Mon Sep 17 00:00:00 2001
+From: Christoph Hellwig <hch>
+Date: Thu, 16 Dec 2010 12:04:54 +0100
+Subject: [PATCH 35/65] update Documentation/filesystems/Locking
+
+Mostly inspired by all the recent BKL removal changes, but a lot of older
+updates also weren't properly recorded.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+---
+ Documentation/filesystems/Locking | 214 ++++++++++++++++++-------------------
+ 1 files changed, 102 insertions(+), 112 deletions(-)
+
+diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
+index b6426f1..7686e76 100644
+--- a/Documentation/filesystems/Locking
++++ b/Documentation/filesystems/Locking
+@@ -18,7 +18,6 @@ prototypes:
+ char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
+
+ locking rules:
+- none have BKL
+ dcache_lock rename_lock ->d_lock may block
+ d_revalidate: no no no yes
+ d_hash no no no yes
+@@ -42,18 +41,23 @@ ata *);
+ int (*rename) (struct inode *, struct dentry *,
+ struct inode *, struct dentry *);
+ int (*readlink) (struct dentry *, char __user *,int);
+- int (*follow_link) (struct dentry *, struct nameidata *);
++ void * (*follow_link) (struct dentry *, struct nameidata *);
++ void (*put_link) (struct dentry *, struct nameidata *, void *);
+ void (*truncate) (struct inode *);
+ int (*permission) (struct inode *, int, struct nameidata *);
++ int (*check_acl)(struct inode *, int);
+ int (*setattr) (struct dentry *, struct iattr *);
+ int (*getattr) (struct vfsmount *, struct dentry *, struct kstat *);
+ int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
+ ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
+ ssize_t (*listxattr) (struct dentry *, char *, size_t);
+ int (*removexattr) (struct dentry *, const char *);
++ void (*truncate_range)(struct inode *, loff_t, loff_t);
++ long (*fallocate)(struct inode *inode, int mode, loff_t offset, loff_t len);
++ int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len);
+
+ locking rules:
+- all may block, none have BKL
++ all may block
+ i_mutex(inode)
+ lookup: yes
+ create: yes
+@@ -66,19 +70,24 @@ rmdir: yes (both) (see below)
+ rename: yes (all) (see below)
+ readlink: no
+ follow_link: no
++put_link: no
+ truncate: yes (see below)
+ setattr: yes
+ permission: no
++check_acl: no
+ getattr: no
+ setxattr: yes
+ getxattr: no
+ listxattr: no
+ removexattr: yes
++truncate_range: yes
++fallocate: no
++fiemap: no
+ Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
+ victim.
+ cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem.
+ ->truncate() is never called directly - it's a callback, not a
+-method. It's called by vmtruncate() - library function normally used by
++method. It's called by vmtruncate() - deprecated library function used by
+ ->setattr(). Locking information above applies to that call (i.e. is
+ inherited from ->setattr() - vmtruncate() is used when ATTR_SIZE had been
+ passed).
+@@ -91,7 +100,7 @@ prototypes:
+ struct inode *(*alloc_inode)(struct super_block *sb);
+ void (*destroy_inode)(struct inode *);
+ void (*dirty_inode) (struct inode *);
+- int (*write_inode) (struct inode *, int);
++ int (*write_inode) (struct inode *, struct writeback_control *wbc);
+ int (*drop_inode) (struct inode *);
+ void (*evict_inode) (struct inode *);
+ void (*put_super) (struct super_block *);
+@@ -105,10 +114,11 @@ prototypes:
+ int (*show_options)(struct seq_file *, struct vfsmount *);
+ ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
+ ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
++ int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t);
++ int (*trim_fs) (struct super_block *, struct fstrim_range *);
+
+ locking rules:
+ All may block [not true, see below]
+- None have BKL
+ s_umount
+ alloc_inode:
+ destroy_inode:
+@@ -127,6 +137,8 @@ umount_begin: no
+ show_options: no (namespace_sem)
+ quota_read: no (see below)
+ quota_write: no (see below)
++bdev_try_to_free_page: no (see below)
++trim_fs: no
+
+ ->statfs() has s_umount (shared) when called by ustat(2) (native or
+ compat), but that's an accident of bad API; s_umount is used to pin
+@@ -139,19 +151,25 @@ be the only ones operating on the quota file by the quota code (via
+ dqio_sem) (unless an admin really wants to screw up something and
+ writes to quota files with quotas on). For other details about locking
+ see also dquot_operations section.
++->bdev_try_to_free_page is called from the ->releasepage handler of
++the block device inode. See there for more details.
+
+ --------------------------- file_system_type ---------------------------
+ prototypes:
+ int (*get_sb) (struct file_system_type *, int,
+ const char *, void *, struct vfsmount *);
++ struct dentry *(*mount) (struct file_system_type *, int,
++ const char *, void *);
+ void (*kill_sb) (struct super_block *);
+ locking rules:
+- may block BKL
+-get_sb yes no
+-kill_sb yes no
++ may block
++get_sb yes
++mount yes
++kill_sb yes
+
+ ->get_sb() returns error or 0 with locked superblock attached to the vfsmount
+ (exclusive on ->s_umount).
++->mount() returns ERR_PTR or the root dentry.
+ ->kill_sb() takes a write-locked superblock, does all shutdown work on it,
+ unlocks and drops the reference.
+
+@@ -176,27 +194,35 @@ prototypes:
+ void (*freepage)(struct page *);
+ int (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
+ loff_t offset, unsigned long nr_segs);
+- int (*launder_page) (struct page *);
++ int (*get_xip_mem)(struct address_space *, pgoff_t, int, void **,
++ unsigned long *);
++ int (*migratepage)(struct address_space *, struct page *, struct page *);
++ int (*launder_page)(struct page *);
++ int (*is_partially_uptodate)(struct page *, read_descriptor_t *, unsigned long);
++ int (*error_remove_page)(struct address_space *, struct page *);
+
+ locking rules:
+ All except set_page_dirty and freepage may block
+
+- BKL PageLocked(page) i_mutex
+-writepage: no yes, unlocks (see below)
+-readpage: no yes, unlocks
+-sync_page: no maybe
+-writepages: no
+-set_page_dirty no no
+-readpages: no
+-write_begin: no locks the page yes
+-write_end: no yes, unlocks yes
+-perform_write: no n/a yes
+-bmap: no
+-invalidatepage: no yes
+-releasepage: no yes
+-freepage: no yes
+-direct_IO: no
+-launder_page: no yes
++ PageLocked(page) i_mutex
++writepage: yes, unlocks (see below)
++readpage: yes, unlocks
++sync_page: maybe
++writepages:
++set_page_dirty no
++readpages:
++write_begin: locks the page yes
++write_end: yes, unlocks yes
++bmap:
++invalidatepage: yes
++releasepage: yes
++freepage: yes
++direct_IO:
++get_xip_mem: maybe
++migratepage: yes (both)
++launder_page: yes
++is_partially_uptodate: yes
++error_remove_page: yes
+
+ ->write_begin(), ->write_end(), ->sync_page() and ->readpage()
+ may be called from the request handler (/dev/loop).
+@@ -276,9 +302,8 @@ under spinlock (it cannot block) and is sometimes called with the page
+ not locked.
+
+ ->bmap() is currently used by legacy ioctl() (FIBMAP) provided by some
+-filesystems and by the swapper. The latter will eventually go away. All
+-instances do not actually need the BKL. Please, keep it that way and don't
+-breed new callers.
++filesystems and by the swapper. The latter will eventually go away. Please,
++keep it that way and don't breed new callers.
+
+ ->invalidatepage() is called when the filesystem must attempt to drop
+ some or all of the buffers from the page when it is being truncated. It
+@@ -299,47 +324,37 @@ cleaned, or an error value if not. Note that in order to prevent the page
+ getting mapped back in and redirtied, it needs to be kept locked
+ across the entire operation.
+
+- Note: currently almost all instances of address_space methods are
+-using BKL for internal serialization and that's one of the worst sources
+-of contention. Normally they are calling library functions (in fs/buffer.c)
+-and pass foo_get_block() as a callback (on local block-based filesystems,
+-indeed). BKL is not needed for library stuff and is usually taken by
+-foo_get_block(). It's an overkill, since block bitmaps can be protected by
+-internal fs locking and real critical areas are much smaller than the areas
+-filesystems protect now.
+-
+ ----------------------- file_lock_operations ------------------------------
+ prototypes:
+- void (*fl_insert)(struct file_lock *); /* lock insertion callback */
+- void (*fl_remove)(struct file_lock *); /* lock removal callback */
+ void (*fl_copy_lock)(struct file_lock *, struct file_lock *);
+ void (*fl_release_private)(struct file_lock *);
+
+
+ locking rules:
+- BKL may block
+-fl_insert: yes no
+-fl_remove: yes no
+-fl_copy_lock: yes no
+-fl_release_private: yes yes
++ file_lock_lock may block
++fl_copy_lock: yes no
++fl_release_private: maybe no
+
+ ----------------------- lock_manager_operations ---------------------------
+ prototypes:
+ int (*fl_compare_owner)(struct file_lock *, struct file_lock *);
+ void (*fl_notify)(struct file_lock *); /* unblock callback */
++ int (*fl_grant)(struct file_lock *, struct file_lock *, int);
+ void (*fl_release_private)(struct file_lock *);
+ void (*fl_break)(struct file_lock *); /* break_lease callback */
++ int (*fl_mylease)(struct file_lock *, struct file_lock *);
++ int (*fl_change)(struct file_lock **, int);
+
+ locking rules:
+- BKL may block
+-fl_compare_owner: yes no
+-fl_notify: yes no
+-fl_release_private: yes yes
+-fl_break: yes no
+-
+- Currently only NFSD and NLM provide instances of this class. None of the
+-them block. If you have out-of-tree instances - please, show up. Locking
+-in that area will change.
++ file_lock_lock may block
++fl_compare_owner: yes no
++fl_notify: yes no
++fl_grant: no no
++fl_release_private: maybe no
++fl_break: yes no
++fl_mylease: yes no
++fl_change yes no
++
+ --------------------------- buffer_head -----------------------------------
+ prototypes:
+ void (*b_end_io)(struct buffer_head *bh, int uptodate);
+@@ -364,17 +379,17 @@ prototypes:
+ void (*swap_slot_free_notify) (struct block_device *, unsigned long);
+
+ locking rules:
+- BKL bd_mutex
+-open: no yes
+-release: no yes
+-ioctl: no no
+-compat_ioctl: no no
+-direct_access: no no
+-media_changed: no no
+-unlock_native_capacity: no no
+-revalidate_disk: no no
+-getgeo: no no
+-swap_slot_free_notify: no no (see below)
++ bd_mutex
++open: yes
++release: yes
++ioctl: no
++compat_ioctl: no
++direct_access: no
++media_changed: no
++unlock_native_capacity: no
++revalidate_disk: no
++getgeo: no
++swap_slot_free_notify: no (see below)
+
+ media_changed, unlock_native_capacity and revalidate_disk are called only from
+ check_disk_change().
+@@ -413,34 +428,21 @@ prototypes:
+ unsigned long (*get_unmapped_area)(struct file *, unsigned long,
+ unsigned long, unsigned long, unsigned long);
+ int (*check_flags)(int);
++ int (*flock) (struct file *, int, struct file_lock *);
++ ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *,
++ size_t, unsigned int);
++ ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *,
++ size_t, unsigned int);
++ int (*setlease)(struct file *, long, struct file_lock **);
+ };
+
+ locking rules:
+- All may block.
+- BKL
+-llseek: no (see below)
+-read: no
+-aio_read: no
+-write: no
+-aio_write: no
+-readdir: no
+-poll: no
+-unlocked_ioctl: no
+-compat_ioctl: no
+-mmap: no
+-open: no
+-flush: no
+-release: no
+-fsync: no (see below)
+-aio_fsync: no
+-fasync: no
+-lock: yes
+-readv: no
+-writev: no
+-sendfile: no
+-sendpage: no
+-get_unmapped_area: no
+-check_flags: no
++ All may block except for ->setlease.
++ No VFS locks held on entry except for ->fsync and ->setlease.
++
++->fsync() has i_mutex on inode.
++
++->setlease has the file_list_lock held and must not sleep.
+
+ ->llseek() locking has moved from llseek to the individual llseek
+ implementations. If your fs is not using generic_file_llseek, you
+@@ -450,17 +452,10 @@ mutex or just to use i_size_read() instead.
+ Note: this does not protect the file->f_pos against concurrent modifications
+ since this is something the userspace has to take care about.
+
+-Note: ext2_release() was *the* source of contention on fs-intensive
+-loads and dropping BKL on ->release() helps to get rid of that (we still
+-grab BKL for cases when we close a file that had been opened r/w, but that
+-can and should be done using the internal locking with smaller critical areas).
+-Current worst offender is ext2_get_block()...
+-
+-->fasync() is called without BKL protection, and is responsible for
+-maintaining the FASYNC bit in filp->f_flags. Most instances call
+-fasync_helper(), which does that maintenance, so it's not normally
+-something one needs to worry about. Return values > 0 will be mapped to
+-zero in the VFS layer.
++->fasync() is responsible for maintaining the FASYNC bit in filp->f_flags.
++Most instances call fasync_helper(), which does that maintenance, so it's
++not normally something one needs to worry about. Return values > 0 will be
++mapped to zero in the VFS layer.
+
+ ->readdir() and ->ioctl() on directories must be changed. Ideally we would
+ move ->readdir() to inode_operations and use a separate method for directory
+@@ -471,8 +466,6 @@ components. And there are other reasons why the current interface is a mess...
+ ->read on directories probably must go away - we should just enforce -EISDIR
+ in sys_read() and friends.
+
+-->fsync() has i_mutex on inode.
+-
+ --------------------------- dquot_operations -------------------------------
+ prototypes:
+ int (*write_dquot) (struct dquot *);
+@@ -507,12 +500,12 @@ prototypes:
+ int (*access)(struct vm_area_struct *, unsigned long, void*, int, int);
+
+ locking rules:
+- BKL mmap_sem PageLocked(page)
+-open: no yes
+-close: no yes
+-fault: no yes can return with page locked
+-page_mkwrite: no yes can return with page locked
+-access: no yes
++ mmap_sem PageLocked(page)
++open: yes
++close: yes
++fault: yes can return with page locked
++page_mkwrite: yes can return with page locked
++access: yes
+
+ ->fault() is called when a previously not present pte is about
+ to be faulted in. The filesystem must find and return the page associated
+@@ -539,6 +532,3 @@ VM_IO | VM_PFNMAP VMAs.
+
+ (if you break something or notice that it is broken and do not fix it yourself
+ - at least put it here)
+-
+-ipc/shm.c::shm_delete() - may need BKL.
+-->read() and ->write() in many drivers are (probably) missing BKL.
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0036-memcg-fix-wrong-VM_BUG_ON-in-try_charge-s-mm-owner-c.patch b/extras/recipes-kernel/linux/linux-omap/linus/0036-memcg-fix-wrong-VM_BUG_ON-in-try_charge-s-mm-owner-c.patch
new file mode 100644
index 00000000..cbdc9bea
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0036-memcg-fix-wrong-VM_BUG_ON-in-try_charge-s-mm-owner-c.patch
@@ -0,0 +1,63 @@
+From 06410121f430702f9f482331a1f6d9ba3ebe5911 Mon Sep 17 00:00:00 2001
+From: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
+Date: Wed, 29 Dec 2010 14:07:11 -0800
+Subject: [PATCH 36/65] memcg: fix wrong VM_BUG_ON() in try_charge()'s mm->owner check
+
+At __mem_cgroup_try_charge(), VM_BUG_ON(!mm->owner) is checked.
+But as commented in mem_cgroup_from_task(), mm->owner can be NULL
+in some racy case. This check of VM_BUG_ON() is bad.
+
+A possible story to hit this is at swapoff()->try_to_unuse(). It passes
+mm_struct to mem_cgroup_try_charge_swapin() while mm->owner is NULL. If we
+can't get proper mem_cgroup from swap_cgroup information, mm->owner is used
+as charge target and we see NULL.
+
+Cc: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
+Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
+Reported-by: Hugh Dickins <hughd@google.com>
+Reported-by: Thomas Meyer <thomas@m3y3r.de>
+Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
+Reviewed-by: Balbir Singh <balbir@linux.vnet.ibm.com>
+Signed-off-by: Hugh Dickins <hughd@google.com>
+Cc: stable@kernel.org
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+---
+ mm/memcontrol.c | 19 +++++++++----------
+ 1 files changed, 9 insertions(+), 10 deletions(-)
+
+diff --git a/mm/memcontrol.c b/mm/memcontrol.c
+index 7a22b41..00bb8a6 100644
+--- a/mm/memcontrol.c
++++ b/mm/memcontrol.c
+@@ -1925,19 +1925,18 @@ again:
+
+ rcu_read_lock();
+ p = rcu_dereference(mm->owner);
+- VM_BUG_ON(!p);
+ /*
+- * because we don't have task_lock(), "p" can exit while
+- * we're here. In that case, "mem" can point to root
+- * cgroup but never be NULL. (and task_struct itself is freed
+- * by RCU, cgroup itself is RCU safe.) Then, we have small
+- * risk here to get wrong cgroup. But such kind of mis-account
+- * by race always happens because we don't have cgroup_mutex().
+- * It's overkill and we allow that small race, here.
++ * Because we don't have task_lock(), "p" can exit.
++ * In that case, "mem" can point to root or p can be NULL with
++ * race with swapoff. Then, we have small risk of mis-accouning.
++ * But such kind of mis-account by race always happens because
++ * we don't have cgroup_mutex(). It's overkill and we allo that
++ * small race, here.
++ * (*) swapoff at el will charge against mm-struct not against
++ * task-struct. So, mm->owner can be NULL.
+ */
+ mem = mem_cgroup_from_task(p);
+- VM_BUG_ON(!mem);
+- if (mem_cgroup_is_root(mem)) {
++ if (!mem || mem_cgroup_is_root(mem)) {
+ rcu_read_unlock();
+ goto done;
+ }
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0037-Revert-Staging-zram-work-around-oops-due-to-startup-.patch b/extras/recipes-kernel/linux/linux-omap/linus/0037-Revert-Staging-zram-work-around-oops-due-to-startup-.patch
new file mode 100644
index 00000000..03e390eb
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0037-Revert-Staging-zram-work-around-oops-due-to-startup-.patch
@@ -0,0 +1,54 @@
+From 9214e9d423fea726c5497ae5be07d3069246e6bd Mon Sep 17 00:00:00 2001
+From: Nitin Gupta <ngupta@vflare.org>
+Date: Thu, 30 Dec 2010 04:07:58 -0500
+Subject: [PATCH 37/65] Revert "Staging: zram: work around oops due to startup ordering snafu"
+
+This reverts commit 7e24cce38a99f373450db67bf576fe73e8168d66 because it
+was never appropriate for mainline.
+
+Do not check for init flag before starting I/O - zram module is unusable
+without this fix.
+
+The oops mentioned in the reverted commit message was actually a problem
+only with the zram version as present in project's own repository where
+we allocate struct zram_stats_cpu upon device initialization. OTOH, In
+mainline/staging version of zram, we allocate struct stats upfront, so
+this oops cannot happen in mainline version.
+
+Checking for init_done flag in zram_make_request() results in a *no-op*
+for any I/O operation since we simply always return success. This flag
+is actually set when the first write occurs on a zram disk which
+triggers its initialization.
+
+Bug report: https://bugzilla.kernel.org/show_bug.cgi?id=25722
+
+Reported-by: Dennis Jansen <dennis.jansen@web.de>
+Signed-off-by: Nitin Gupta <ngupta@vflare.org>
+Cc: Anton Blanchard <anton@samba.org>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Cc: Greg Kroah-Hartman <gregkh@suse.de>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+---
+ drivers/staging/zram/zram_drv.c | 6 ------
+ 1 files changed, 0 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
+index 8c3c057..d0e9e02 100644
+--- a/drivers/staging/zram/zram_drv.c
++++ b/drivers/staging/zram/zram_drv.c
+@@ -435,12 +435,6 @@ static int zram_make_request(struct request_queue *queue, struct bio *bio)
+ int ret = 0;
+ struct zram *zram = queue->queuedata;
+
+- if (unlikely(!zram->init_done)) {
+- set_bit(BIO_UPTODATE, &bio->bi_flags);
+- bio_endio(bio, 0);
+- return 0;
+- }
+-
+ if (!valid_io_request(zram, bio)) {
+ zram_stat64_inc(zram, &zram->stats.invalid_io);
+ bio_io_error(bio);
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0038-CAN-Use-inode-instead-of-kernel-address-for-proc-fil.patch b/extras/recipes-kernel/linux/linux-omap/linus/0038-CAN-Use-inode-instead-of-kernel-address-for-proc-fil.patch
new file mode 100644
index 00000000..130a6407
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0038-CAN-Use-inode-instead-of-kernel-address-for-proc-fil.patch
@@ -0,0 +1,43 @@
+From 177f55e48f91842a6e33e896d64ebb9a44db298b Mon Sep 17 00:00:00 2001
+From: Dan Rosenberg <drosenberg@vsecurity.com>
+Date: Sun, 26 Dec 2010 06:54:53 +0000
+Subject: [PATCH 38/65] CAN: Use inode instead of kernel address for /proc file
+
+Since the socket address is just being used as a unique identifier, its
+inode number is an alternative that does not leak potentially sensitive
+information.
+
+CC-ing stable because MITRE has assigned CVE-2010-4565 to the issue.
+
+Signed-off-by: Dan Rosenberg <drosenberg@vsecurity.com>
+Acked-by: Oliver Hartkopp <socketcan@hartkopp.net>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ net/can/bcm.c | 4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/can/bcm.c b/net/can/bcm.c
+index 6faa825..9d5e8ac 100644
+--- a/net/can/bcm.c
++++ b/net/can/bcm.c
+@@ -125,7 +125,7 @@ struct bcm_sock {
+ struct list_head tx_ops;
+ unsigned long dropped_usr_msgs;
+ struct proc_dir_entry *bcm_proc_read;
+- char procname [20]; /* pointer printed in ASCII with \0 */
++ char procname [32]; /* inode number in decimal with \0 */
+ };
+
+ static inline struct bcm_sock *bcm_sk(const struct sock *sk)
+@@ -1521,7 +1521,7 @@ static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len,
+
+ if (proc_dir) {
+ /* unique socket address as filename */
+- sprintf(bo->procname, "%p", sock);
++ sprintf(bo->procname, "%lu", sock_i_ino(sk));
+ bo->bcm_proc_read = proc_create_data(bo->procname, 0644,
+ proc_dir,
+ &bcm_proc_fops, sk);
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0039-ISDN-Gigaset-Fix-memory-leak-in-do_disconnect_req.patch b/extras/recipes-kernel/linux/linux-omap/linus/0039-ISDN-Gigaset-Fix-memory-leak-in-do_disconnect_req.patch
new file mode 100644
index 00000000..24fdff6c
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0039-ISDN-Gigaset-Fix-memory-leak-in-do_disconnect_req.patch
@@ -0,0 +1,56 @@
+From 7b63a1b5eed2e8f4c90cef7ba893dd95ab1d71ae Mon Sep 17 00:00:00 2001
+From: Jesper Juhl <jj@chaosbits.net>
+Date: Sun, 26 Dec 2010 09:59:58 +0000
+Subject: [PATCH 39/65] ISDN, Gigaset: Fix memory leak in do_disconnect_req()
+
+Hi,
+
+In drivers/isdn/gigaset/capi.c::do_disconnect_req() we will leak the
+memory allocated (with kmalloc) to 'b3cmsg' if the call to alloc_skb()
+fails.
+
+...
+ b3cmsg = kmalloc(sizeof(*b3cmsg), GFP_KERNEL);
+ allocation here ------^
+ if (!b3cmsg) {
+ dev_err(cs->dev, "%s: out of memory\n", __func__);
+ send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR);
+ return;
+ }
+ capi_cmsg_header(b3cmsg, ap->id, CAPI_DISCONNECT_B3, CAPI_IND,
+ ap->nextMessageNumber++,
+ cmsg->adr.adrPLCI | (1 << 16));
+ b3cmsg->Reason_B3 = CapiProtocolErrorLayer1;
+ b3skb = alloc_skb(CAPI_DISCONNECT_B3_IND_BASELEN, GFP_KERNEL);
+ if (b3skb == NULL) {
+ dev_err(cs->dev, "%s: out of memory\n", __func__);
+ send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR);
+ return;
+ leak here ------^
+...
+
+This leak is easily fixed by just kfree()'ing the memory allocated to
+'b3cmsg' right before we return. The following patch does that.
+
+Signed-off-by: Jesper Juhl <jj@chaosbits.net>
+Acked-by: Tilman Schmidt <tilman@imap.cc>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/isdn/gigaset/capi.c | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c
+index bcc174e..658e75f 100644
+--- a/drivers/isdn/gigaset/capi.c
++++ b/drivers/isdn/gigaset/capi.c
+@@ -1900,6 +1900,7 @@ static void do_disconnect_req(struct gigaset_capi_ctr *iif,
+ if (b3skb == NULL) {
+ dev_err(cs->dev, "%s: out of memory\n", __func__);
+ send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR);
++ kfree(b3cmsg);
+ return;
+ }
+ capi_cmsg2message(b3cmsg,
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0040-Broadcom-CNIC-core-network-driver-fix-mem-leak-on-al.patch b/extras/recipes-kernel/linux/linux-omap/linus/0040-Broadcom-CNIC-core-network-driver-fix-mem-leak-on-al.patch
new file mode 100644
index 00000000..b9be4132
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0040-Broadcom-CNIC-core-network-driver-fix-mem-leak-on-al.patch
@@ -0,0 +1,58 @@
+From dcb64d3c0d57e8bc674ec4ca6bf7f4812f49f7b2 Mon Sep 17 00:00:00 2001
+From: Jesper Juhl <jj@chaosbits.net>
+Date: Fri, 31 Dec 2010 11:18:48 -0800
+Subject: [PATCH 40/65] Broadcom CNIC core network driver: fix mem leak on allocation failures in cnic_alloc_uio_rings()
+
+We are leaking memory in drivers/net/cnic.c::cnic_alloc_uio_rings() if
+either of the calls to dma_alloc_coherent() fail. This patch fixes it by
+freeing both the memory allocated with kzalloc() and memory allocated with
+previous calls to dma_alloc_coherent() when there's a failure.
+
+Thanks to Joe Perches <joe@perches.com> for suggesting a better
+implementation than my initial version.
+
+Signed-off-by: Jesper Juhl <jj@chaosbits.net>
+Acked-by: Michael Chan <mchan@broadcom.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/cnic.c | 10 ++++++++--
+ 1 files changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
+index 92bac19..6dff321 100644
+--- a/drivers/net/cnic.c
++++ b/drivers/net/cnic.c
+@@ -940,7 +940,7 @@ static int cnic_alloc_uio_rings(struct cnic_dev *dev, int pages)
+ &udev->l2_ring_map,
+ GFP_KERNEL | __GFP_COMP);
+ if (!udev->l2_ring)
+- return -ENOMEM;
++ goto err_udev;
+
+ udev->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size;
+ udev->l2_buf_size = PAGE_ALIGN(udev->l2_buf_size);
+@@ -948,7 +948,7 @@ static int cnic_alloc_uio_rings(struct cnic_dev *dev, int pages)
+ &udev->l2_buf_map,
+ GFP_KERNEL | __GFP_COMP);
+ if (!udev->l2_buf)
+- return -ENOMEM;
++ goto err_dma;
+
+ write_lock(&cnic_dev_lock);
+ list_add(&udev->list, &cnic_udev_list);
+@@ -959,6 +959,12 @@ static int cnic_alloc_uio_rings(struct cnic_dev *dev, int pages)
+ cp->udev = udev;
+
+ return 0;
++ err_dma:
++ dma_free_coherent(&udev->pdev->dev, udev->l2_ring_size,
++ udev->l2_ring, udev->l2_ring_map);
++ err_udev:
++ kfree(udev);
++ return -ENOMEM;
+ }
+
+ static int cnic_init_uio(struct cnic_dev *dev)
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0041-tg3-fix-return-value-check-in-tg3_read_vpd.patch b/extras/recipes-kernel/linux/linux-omap/linus/0041-tg3-fix-return-value-check-in-tg3_read_vpd.patch
new file mode 100644
index 00000000..c77fb857
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0041-tg3-fix-return-value-check-in-tg3_read_vpd.patch
@@ -0,0 +1,35 @@
+From 8742365f4de2afdd0168366b49a3118e67354a21 Mon Sep 17 00:00:00 2001
+From: David Sterba <dsterba@suse.cz>
+Date: Wed, 29 Dec 2010 03:40:31 +0000
+Subject: [PATCH 41/65] tg3: fix return value check in tg3_read_vpd()
+
+Besides -ETIMEDOUT and -EINTR, pci_read_vpd may return other error
+values like -ENODEV or -EINVAL which are ignored due to the buggy
+check, but the data are not read from VPD anyway and this is checked
+subsequently with at most 3 needless loop iterations. This does not
+show up as a runtime bug.
+
+CC: Matt Carlson <mcarlson@broadcom.com>
+CC: Michael Chan <mchan@broadcom.com>
+Signed-off-by: David Sterba <dsterba@suse.cz>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/tg3.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
+index 30ccbb6..6f97b7b 100644
+--- a/drivers/net/tg3.c
++++ b/drivers/net/tg3.c
+@@ -12658,7 +12658,7 @@ static void __devinit tg3_read_vpd(struct tg3 *tp)
+ cnt = pci_read_vpd(tp->pdev, pos,
+ TG3_NVM_VPD_LEN - pos,
+ &vpd_data[pos]);
+- if (cnt == -ETIMEDOUT || -EINTR)
++ if (cnt == -ETIMEDOUT || cnt == -EINTR)
+ cnt = 0;
+ else if (cnt < 0)
+ goto out_not_found;
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0042-starfire-Fix-dma_addr_t-size-test-for-MIPS.patch b/extras/recipes-kernel/linux/linux-omap/linus/0042-starfire-Fix-dma_addr_t-size-test-for-MIPS.patch
new file mode 100644
index 00000000..c2ed56ea
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0042-starfire-Fix-dma_addr_t-size-test-for-MIPS.patch
@@ -0,0 +1,37 @@
+From f6a826af05cb9de0de0218f3cd05af203170fd12 Mon Sep 17 00:00:00 2001
+From: Ben Hutchings <ben@decadent.org.uk>
+Date: Wed, 29 Dec 2010 04:26:17 +0000
+Subject: [PATCH 42/65] starfire: Fix dma_addr_t size test for MIPS
+
+Commit 56543af "starfire: use BUILD_BUG_ON for netdrv_addr_t" revealed
+that the preprocessor condition used to find the size of dma_addr_t
+yielded the wrong result for some architectures and configurations.
+This was kluged for 64-bit PowerPC in commit 3e502e6 by adding yet
+another case to the condition. However, 64-bit MIPS configurations
+are not detected reliably either.
+
+This should be fixed by using CONFIG_ARCH_DMA_ADDR_T_64BIT, but that
+isn't yet defined everywhere it should be.
+
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/starfire.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
+index 4adf124..a4f2bd5 100644
+--- a/drivers/net/starfire.c
++++ b/drivers/net/starfire.c
+@@ -148,7 +148,7 @@ static int full_duplex[MAX_UNITS] = {0, };
+ * This SUCKS.
+ * We need a much better method to determine if dma_addr_t is 64-bit.
+ */
+-#if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__alpha__) || defined(__mips64__) || (defined(__mips__) && defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)) || (defined(__powerpc64__) || defined(CONFIG_PHYS_64BIT))
++#if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__alpha__) || (defined(CONFIG_MIPS) && ((defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)) || defined(CONFIG_64BIT))) || (defined(__powerpc64__) || defined(CONFIG_PHYS_64BIT))
+ /* 64-bit dma_addr_t */
+ #define ADDR_64BITS /* This chip uses 64 bit addresses. */
+ #define netdrv_addr_t __le64
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0043-drivers-atm-atmtcp.c-add-missing-atm_dev_put.patch b/extras/recipes-kernel/linux/linux-omap/linus/0043-drivers-atm-atmtcp.c-add-missing-atm_dev_put.patch
new file mode 100644
index 00000000..20077bf9
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0043-drivers-atm-atmtcp.c-add-missing-atm_dev_put.patch
@@ -0,0 +1,50 @@
+From 0af81f1e48cd0f4a1cdce5939408e1d9ad508190 Mon Sep 17 00:00:00 2001
+From: Julia Lawall <julia@diku.dk>
+Date: Wed, 29 Dec 2010 04:01:03 +0000
+Subject: [PATCH 43/65] drivers/atm/atmtcp.c: add missing atm_dev_put
+
+The earlier call to atm_dev_lookup increases the reference count of dev,
+so decrease it on the way out.
+
+The semantic match that finds this problem is as follows:
+(http://coccinelle.lip6.fr/)
+
+// <smpl>
+@@
+expression x, E;
+constant C;
+@@
+
+x = atm_dev_lookup(...);
+... when != false x != NULL
+ when != true x == NULL
+ when != \(E = x\|x = E\)
+ when != atm_dev_put(dev);
+*return -C;
+// </smpl>
+
+Signed-off-by: Julia Lawall <julia@diku.dk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/atm/atmtcp.c | 5 ++++-
+ 1 files changed, 4 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c
+index 2b464b6..0b06250 100644
+--- a/drivers/atm/atmtcp.c
++++ b/drivers/atm/atmtcp.c
+@@ -392,7 +392,10 @@ static int atmtcp_attach(struct atm_vcc *vcc,int itf)
+ atm_dev_put(dev);
+ return -EMEDIUMTYPE;
+ }
+- if (PRIV(dev)->vcc) return -EBUSY;
++ if (PRIV(dev)->vcc) {
++ atm_dev_put(dev);
++ return -EBUSY;
++ }
+ }
+ else {
+ int error;
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0044-KVM-i8259-initialize-isr_ack.patch b/extras/recipes-kernel/linux/linux-omap/linus/0044-KVM-i8259-initialize-isr_ack.patch
new file mode 100644
index 00000000..0f47f868
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0044-KVM-i8259-initialize-isr_ack.patch
@@ -0,0 +1,32 @@
+From 1e144569ab9d311fa5e08efc9a7fb35853d697d9 Mon Sep 17 00:00:00 2001
+From: Avi Kivity <avi@redhat.com>
+Date: Fri, 31 Dec 2010 10:52:15 +0200
+Subject: [PATCH 44/65] KVM: i8259: initialize isr_ack
+
+isr_ack is never initialized. So, until the first PIC reset, interrupts
+may fail to be injected. This can cause Windows XP to fail to boot, as
+reported in the fallout from the fix to
+https://bugzilla.kernel.org/show_bug.cgi?id=21962.
+
+Reported-and-tested-by: Nicolas Prochazka <prochazka.nicolas@gmail.com>
+Signed-off-by: Avi Kivity <avi@redhat.com>
+---
+ arch/x86/kvm/i8259.c | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c
+index f628234..3cece05 100644
+--- a/arch/x86/kvm/i8259.c
++++ b/arch/x86/kvm/i8259.c
+@@ -575,6 +575,8 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm)
+ s->pics[1].elcr_mask = 0xde;
+ s->pics[0].pics_state = s;
+ s->pics[1].pics_state = s;
++ s->pics[0].isr_ack = 0xff;
++ s->pics[1].isr_ack = 0xff;
+
+ /*
+ * Initialize PIO device
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0045-hwmon-s3c-hwmon-Fix-compilation.patch b/extras/recipes-kernel/linux/linux-omap/linus/0045-hwmon-s3c-hwmon-Fix-compilation.patch
new file mode 100644
index 00000000..c322f9c9
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0045-hwmon-s3c-hwmon-Fix-compilation.patch
@@ -0,0 +1,37 @@
+From cdca50978acd2a0be9ef675b8cdd3b77fadab492 Mon Sep 17 00:00:00 2001
+From: Maurus Cuelenaere <mcuelenaere@gmail.com>
+Date: Sun, 2 Jan 2011 14:48:16 -0500
+Subject: [PATCH 45/65] hwmon: (s3c-hwmon) Fix compilation
+
+The owner field was removed from struct attribute in
+6fd69dc578fa0b1bbc3aad70ae3af9a137211707, so don't assign it anymore.
+
+Signed-off-by: Maurus Cuelenaere <mcuelenaere@gmail.com>
+Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
+---
+ drivers/hwmon/s3c-hwmon.c | 2 --
+ 1 files changed, 0 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c
+index 05248f2..92b42db 100644
+--- a/drivers/hwmon/s3c-hwmon.c
++++ b/drivers/hwmon/s3c-hwmon.c
+@@ -234,7 +234,6 @@ static int s3c_hwmon_create_attr(struct device *dev,
+ attr->index = channel;
+ attr->dev_attr.attr.name = attrs->in_name;
+ attr->dev_attr.attr.mode = S_IRUGO;
+- attr->dev_attr.attr.owner = THIS_MODULE;
+ attr->dev_attr.show = s3c_hwmon_ch_show;
+
+ ret = device_create_file(dev, &attr->dev_attr);
+@@ -252,7 +251,6 @@ static int s3c_hwmon_create_attr(struct device *dev,
+ attr->index = channel;
+ attr->dev_attr.attr.name = attrs->label_name;
+ attr->dev_attr.attr.mode = S_IRUGO;
+- attr->dev_attr.attr.owner = THIS_MODULE;
+ attr->dev_attr.show = s3c_hwmon_label_show;
+
+ ret = device_create_file(dev, &attr->dev_attr);
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0046-watchdog-Improve-initialisation-error-message-and-do.patch b/extras/recipes-kernel/linux/linux-omap/linus/0046-watchdog-Improve-initialisation-error-message-and-do.patch
new file mode 100644
index 00000000..b490dc07
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0046-watchdog-Improve-initialisation-error-message-and-do.patch
@@ -0,0 +1,58 @@
+From 358160309eeeb8e29b74240874267ea9f7e43d36 Mon Sep 17 00:00:00 2001
+From: Ben Hutchings <ben@decadent.org.uk>
+Date: Sun, 2 Jan 2011 23:02:42 +0000
+Subject: [PATCH 46/65] watchdog: Improve initialisation error message and documentation
+
+The error message 'NMI watchdog failed to create perf event...'
+does not make it clear that this is a fatal error for the
+watchdog. It also currently prints the error value as a
+pointer, rather than extracting the error code with PTR_ERR().
+Fix that.
+
+Add a note to the description of the 'nowatchdog' kernel
+parameter to associate it with this message.
+
+Reported-by: Cesare Leonardi <celeonar@gmail.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: 599368@bugs.debian.org
+Cc: 608138@bugs.debian.org
+Cc: Don Zickus <dzickus@redhat.com>
+Cc: Frederic Weisbecker <fweisbec@gmail.com>
+Cc: <stable@kernel.org> # .37.x and later
+LKML-Reference: <1294009362.3167.126.camel@localhost>
+Signed-off-by: Ingo Molnar <mingo@elte.hu>
+---
+ Documentation/kernel-parameters.txt | 2 +-
+ kernel/watchdog.c | 3 ++-
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
+index 8b61c93..01ece1b 100644
+--- a/Documentation/kernel-parameters.txt
++++ b/Documentation/kernel-parameters.txt
+@@ -1759,7 +1759,7 @@ and is between 256 and 4096 characters. It is defined in the file
+
+ nousb [USB] Disable the USB subsystem
+
+- nowatchdog [KNL] Disable the lockup detector.
++ nowatchdog [KNL] Disable the lockup detector (NMI watchdog).
+
+ nowb [ARM]
+
+diff --git a/kernel/watchdog.c b/kernel/watchdog.c
+index 6e3c41a..5b08215 100644
+--- a/kernel/watchdog.c
++++ b/kernel/watchdog.c
+@@ -364,7 +364,8 @@ static int watchdog_nmi_enable(int cpu)
+ goto out_save;
+ }
+
+- printk(KERN_ERR "NMI watchdog failed to create perf event on cpu%i: %p\n", cpu, event);
++ printk(KERN_ERR "NMI watchdog disabled for cpu%i: unable to create perf event: %ld\n",
++ cpu, PTR_ERR(event));
+ return PTR_ERR(event);
+
+ /* success path */
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0047-ARM-6605-1-Add-missing-include-asm-memory.h.patch b/extras/recipes-kernel/linux/linux-omap/linus/0047-ARM-6605-1-Add-missing-include-asm-memory.h.patch
new file mode 100644
index 00000000..1b083882
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0047-ARM-6605-1-Add-missing-include-asm-memory.h.patch
@@ -0,0 +1,42 @@
+From ff3df95843c9713d7b7247c461b955b1f794db76 Mon Sep 17 00:00:00 2001
+From: Axel Lin <axel.lin@gmail.com>
+Date: Mon, 3 Jan 2011 02:26:53 +0100
+Subject: [PATCH 47/65] ARM: 6605/1: Add missing include "asm/memory.h"
+
+This patch fixes below build error by adding the missing asm/memory.h,
+which is needed for arch_is_coherent().
+
+$ make pxa3xx_defconfig; make
+ CC init/do_mounts_rd.o
+In file included from include/linux/list_bl.h:5,
+ from include/linux/rculist_bl.h:7,
+ from include/linux/dcache.h:7,
+ from include/linux/fs.h:381,
+ from init/do_mounts_rd.c:3:
+include/linux/bit_spinlock.h: In function 'bit_spin_unlock':
+include/linux/bit_spinlock.h:61: error: implicit declaration of function 'arch_is_coherent'
+make[1]: *** [init/do_mounts_rd.o] Error 1
+make: *** [init] Error 2
+
+Signed-off-by: Axel Lin <axel.lin@gmail.com>
+Acked-by: Peter Huewe <peterhuewe@gmx.de>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ arch/arm/include/asm/system.h | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
+index 1120f18..8002594 100644
+--- a/arch/arm/include/asm/system.h
++++ b/arch/arm/include/asm/system.h
+@@ -150,6 +150,7 @@ extern unsigned int user_debug;
+ #define rmb() dmb()
+ #define wmb() mb()
+ #else
++#include <asm/memory.h>
+ #define mb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
+ #define rmb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
+ #define wmb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0048-mv_xor-fix-race-in-tasklet-function.patch b/extras/recipes-kernel/linux/linux-omap/linus/0048-mv_xor-fix-race-in-tasklet-function.patch
new file mode 100644
index 00000000..6c1d8467
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0048-mv_xor-fix-race-in-tasklet-function.patch
@@ -0,0 +1,31 @@
+From b4c914578637d1d92b92842c50b02a98f2a7357d Mon Sep 17 00:00:00 2001
+From: Saeed Bishara <saeed@marvell.com>
+Date: Tue, 21 Dec 2010 16:53:39 +0200
+Subject: [PATCH 48/65] mv_xor: fix race in tasklet function
+
+use mv_xor_slot_cleanup() instead of __mv_xor_slot_cleanup() as the former function
+aquires the spin lock that needed to protect the drivers data.
+
+Cc: <stable@kernel.org>
+Signed-off-by: Saeed Bishara <saeed@marvell.com>
+Signed-off-by: Dan Williams <dan.j.williams@intel.com>
+---
+ drivers/dma/mv_xor.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
+index 411d5bf..a25f5f6 100644
+--- a/drivers/dma/mv_xor.c
++++ b/drivers/dma/mv_xor.c
+@@ -449,7 +449,7 @@ mv_xor_slot_cleanup(struct mv_xor_chan *mv_chan)
+ static void mv_xor_tasklet(unsigned long data)
+ {
+ struct mv_xor_chan *chan = (struct mv_xor_chan *) data;
+- __mv_xor_slot_cleanup(chan);
++ mv_xor_slot_cleanup(chan);
+ }
+
+ static struct mv_xor_desc_slot *
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0049-dmaengine-provide-dummy-functions-for-DMA_ENGINE-n.patch b/extras/recipes-kernel/linux/linux-omap/linus/0049-dmaengine-provide-dummy-functions-for-DMA_ENGINE-n.patch
new file mode 100644
index 00000000..a5a0850c
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0049-dmaengine-provide-dummy-functions-for-DMA_ENGINE-n.patch
@@ -0,0 +1,55 @@
+From 8948bfb494b67389d7ea6249b3d6e765f4500d88 Mon Sep 17 00:00:00 2001
+From: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+Date: Wed, 22 Dec 2010 14:46:46 +0100
+Subject: [PATCH 49/65] dmaengine: provide dummy functions for DMA_ENGINE=n
+
+This lets drivers, optionally using the dmaengine, build with DMA_ENGINE
+unselected.
+
+Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+Signed-off-by: Dan Williams <dan.j.williams@intel.com>
+---
+ include/linux/dmaengine.h | 13 ++++++++++---
+ 1 files changed, 10 insertions(+), 3 deletions(-)
+
+diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
+index 9d8688b..8cd00ad 100644
+--- a/include/linux/dmaengine.h
++++ b/include/linux/dmaengine.h
+@@ -824,6 +824,8 @@ enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie);
+ #ifdef CONFIG_DMA_ENGINE
+ enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx);
+ void dma_issue_pending_all(void);
++struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, void *fn_param);
++void dma_release_channel(struct dma_chan *chan);
+ #else
+ static inline enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx)
+ {
+@@ -831,7 +833,14 @@ static inline enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descript
+ }
+ static inline void dma_issue_pending_all(void)
+ {
+- do { } while (0);
++}
++static inline struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask,
++ dma_filter_fn fn, void *fn_param)
++{
++ return NULL;
++}
++static inline void dma_release_channel(struct dma_chan *chan)
++{
+ }
+ #endif
+
+@@ -842,8 +851,6 @@ void dma_async_device_unregister(struct dma_device *device);
+ void dma_run_dependencies(struct dma_async_tx_descriptor *tx);
+ struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type);
+ #define dma_request_channel(mask, x, y) __dma_request_channel(&(mask), x, y)
+-struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, void *fn_param);
+-void dma_release_channel(struct dma_chan *chan);
+
+ /* --- Helper iov-locking functions --- */
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0050-cx25840-Prevent-device-probe-failure-due-to-volume-c.patch b/extras/recipes-kernel/linux/linux-omap/linus/0050-cx25840-Prevent-device-probe-failure-due-to-volume-c.patch
new file mode 100644
index 00000000..b1b84018
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0050-cx25840-Prevent-device-probe-failure-due-to-volume-c.patch
@@ -0,0 +1,52 @@
+From 99ce7fb9211326fed836b7dee035f8a4b1df0250 Mon Sep 17 00:00:00 2001
+From: Andy Walls <awalls@md.metrocast.net>
+Date: Sun, 5 Dec 2010 19:42:30 -0300
+Subject: [PATCH 50/65] cx25840: Prevent device probe failure due to volume control ERANGE error
+
+This patch fixes a regression that crept into 2.6.36.
+
+The volume control scale in the cx25840 driver has an unusual mapping
+from register values to v4l2 volume control values. Enforce the mapping
+limits, so that the default volume control setting does not fall out of
+bounds to prevent the cx25840 module device probe from failing.
+
+Signed-off-by: Andy Walls <awalls@md.metrocast.net>
+Cc: Hans Verkuil <hverkuil@xs4all.nl>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+---
+ drivers/media/video/cx25840/cx25840-core.c | 19 +++++++++++++++++--
+ 1 files changed, 17 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
+index dfb198d..f164618 100644
+--- a/drivers/media/video/cx25840/cx25840-core.c
++++ b/drivers/media/video/cx25840/cx25840-core.c
+@@ -1989,8 +1989,23 @@ static int cx25840_probe(struct i2c_client *client,
+ v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
+ V4L2_CID_HUE, -128, 127, 1, 0);
+ if (!is_cx2583x(state)) {
+- default_volume = 228 - cx25840_read(client, 0x8d4);
+- default_volume = ((default_volume / 2) + 23) << 9;
++ default_volume = cx25840_read(client, 0x8d4);
++ /*
++ * Enforce the legacy PVR-350/MSP3400 to PVR-150/CX25843 volume
++ * scale mapping limits to avoid -ERANGE errors when
++ * initializing the volume control
++ */
++ if (default_volume > 228) {
++ /* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */
++ default_volume = 228;
++ cx25840_write(client, 0x8d4, 228);
++ }
++ else if (default_volume < 20) {
++ /* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */
++ default_volume = 20;
++ cx25840_write(client, 0x8d4, 20);
++ }
++ default_volume = (((228 - default_volume) >> 1) + 23) << 9;
+
+ state->volume = v4l2_ctrl_new_std(&state->hdl,
+ &cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME,
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0051-wm8775-Revert-changeset-fcb9757333-to-avoid-a-regres.patch b/extras/recipes-kernel/linux/linux-omap/linus/0051-wm8775-Revert-changeset-fcb9757333-to-avoid-a-regres.patch
new file mode 100644
index 00000000..792fe440
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0051-wm8775-Revert-changeset-fcb9757333-to-avoid-a-regres.patch
@@ -0,0 +1,518 @@
+From 2d2e6426126f420da1df0e4c2b37069e00aefdb8 Mon Sep 17 00:00:00 2001
+From: Mauro Carvalho Chehab <mchehab@redhat.com>
+Date: Mon, 3 Jan 2011 09:09:56 -0200
+Subject: [PATCH 51/65] wm8775: Revert changeset fcb9757333 to avoid a regression
+
+It seems that cx88 and ivtv use wm8775 on some different modes. The
+patch that added support for a board with wm8775 broke ivtv boards with
+this device. As we're too close to release 2.6.37, let's just revert
+it.
+
+Reported-by: Andy Walls <awalls@md.metrocast.net>
+Reported-by: Eric Sharkey <eric@lisaneric.org>
+Reported-by: Auric <auric@aanet.com.au>
+Reported by: David Gesswein <djg@pdp8online.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+---
+ drivers/media/video/cx88/cx88-alsa.c | 99 ++++---------------------------
+ drivers/media/video/cx88/cx88-cards.c | 7 ++
+ drivers/media/video/cx88/cx88-video.c | 27 +--------
+ drivers/media/video/cx88/cx88.h | 6 +-
+ drivers/media/video/wm8775.c | 104 ++++++++++++--------------------
+ include/media/wm8775.h | 3 -
+ 6 files changed, 61 insertions(+), 185 deletions(-)
+
+diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
+index 4aaa47c..54b7fcd 100644
+--- a/drivers/media/video/cx88/cx88-alsa.c
++++ b/drivers/media/video/cx88/cx88-alsa.c
+@@ -40,7 +40,6 @@
+ #include <sound/control.h>
+ #include <sound/initval.h>
+ #include <sound/tlv.h>
+-#include <media/wm8775.h>
+
+ #include "cx88.h"
+ #include "cx88-reg.h"
+@@ -587,47 +586,26 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,
+ int left, right, v, b;
+ int changed = 0;
+ u32 old;
+- struct v4l2_control client_ctl;
+-
+- /* Pass volume & balance onto any WM8775 */
+- if (value->value.integer.value[0] >= value->value.integer.value[1]) {
+- v = value->value.integer.value[0] << 10;
+- b = value->value.integer.value[0] ?
+- (0x8000 * value->value.integer.value[1]) / value->value.integer.value[0] :
+- 0x8000;
+- } else {
+- v = value->value.integer.value[1] << 10;
+- b = value->value.integer.value[1] ?
+- 0xffff - (0x8000 * value->value.integer.value[0]) / value->value.integer.value[1] :
+- 0x8000;
+- }
+- client_ctl.value = v;
+- client_ctl.id = V4L2_CID_AUDIO_VOLUME;
+- call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
+-
+- client_ctl.value = b;
+- client_ctl.id = V4L2_CID_AUDIO_BALANCE;
+- call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
+
+ left = value->value.integer.value[0] & 0x3f;
+ right = value->value.integer.value[1] & 0x3f;
+ b = right - left;
+ if (b < 0) {
+- v = 0x3f - left;
+- b = (-b) | 0x40;
++ v = 0x3f - left;
++ b = (-b) | 0x40;
+ } else {
+- v = 0x3f - right;
++ v = 0x3f - right;
+ }
+ /* Do we really know this will always be called with IRQs on? */
+ spin_lock_irq(&chip->reg_lock);
+ old = cx_read(AUD_VOL_CTL);
+ if (v != (old & 0x3f)) {
+- cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, (old & ~0x3f) | v);
+- changed = 1;
++ cx_write(AUD_VOL_CTL, (old & ~0x3f) | v);
++ changed = 1;
+ }
+- if ((cx_read(AUD_BAL_CTL) & 0x7f) != b) {
+- cx_write(AUD_BAL_CTL, b);
+- changed = 1;
++ if (cx_read(AUD_BAL_CTL) != b) {
++ cx_write(AUD_BAL_CTL, b);
++ changed = 1;
+ }
+ spin_unlock_irq(&chip->reg_lock);
+
+@@ -640,7 +618,7 @@ static const struct snd_kcontrol_new snd_cx88_volume = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+- .name = "Analog-TV Volume",
++ .name = "Playback Volume",
+ .info = snd_cx88_volume_info,
+ .get = snd_cx88_volume_get,
+ .put = snd_cx88_volume_put,
+@@ -671,14 +649,7 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,
+ vol = cx_read(AUD_VOL_CTL);
+ if (value->value.integer.value[0] != !(vol & bit)) {
+ vol ^= bit;
+- cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol);
+- /* Pass mute onto any WM8775 */
+- if ((1<<6) == bit) {
+- struct v4l2_control client_ctl;
+- client_ctl.value = 0 != (vol & bit);
+- client_ctl.id = V4L2_CID_AUDIO_MUTE;
+- call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
+- }
++ cx_write(AUD_VOL_CTL, vol);
+ ret = 1;
+ }
+ spin_unlock_irq(&chip->reg_lock);
+@@ -687,7 +658,7 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,
+
+ static const struct snd_kcontrol_new snd_cx88_dac_switch = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+- .name = "Audio-Out Switch",
++ .name = "Playback Switch",
+ .info = snd_ctl_boolean_mono_info,
+ .get = snd_cx88_switch_get,
+ .put = snd_cx88_switch_put,
+@@ -696,49 +667,13 @@ static const struct snd_kcontrol_new snd_cx88_dac_switch = {
+
+ static const struct snd_kcontrol_new snd_cx88_source_switch = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+- .name = "Analog-TV Switch",
++ .name = "Capture Switch",
+ .info = snd_ctl_boolean_mono_info,
+ .get = snd_cx88_switch_get,
+ .put = snd_cx88_switch_put,
+ .private_value = (1<<6),
+ };
+
+-static int snd_cx88_alc_get(struct snd_kcontrol *kcontrol,
+- struct snd_ctl_elem_value *value)
+-{
+- snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+- struct cx88_core *core = chip->core;
+- struct v4l2_control client_ctl;
+-
+- client_ctl.id = V4L2_CID_AUDIO_LOUDNESS;
+- call_hw(core, WM8775_GID, core, g_ctrl, &client_ctl);
+- value->value.integer.value[0] = client_ctl.value ? 1 : 0;
+-
+- return 0;
+-}
+-
+-static int snd_cx88_alc_put(struct snd_kcontrol *kcontrol,
+- struct snd_ctl_elem_value *value)
+-{
+- snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+- struct cx88_core *core = chip->core;
+- struct v4l2_control client_ctl;
+-
+- client_ctl.value = 0 != value->value.integer.value[0];
+- client_ctl.id = V4L2_CID_AUDIO_LOUDNESS;
+- call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
+-
+- return 0;
+-}
+-
+-static struct snd_kcontrol_new snd_cx88_alc_switch = {
+- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+- .name = "Line-In ALC Switch",
+- .info = snd_ctl_boolean_mono_info,
+- .get = snd_cx88_alc_get,
+- .put = snd_cx88_alc_put,
+-};
+-
+ /****************************************************************************
+ Basic Flow for Sound Devices
+ ****************************************************************************/
+@@ -860,7 +795,6 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
+ {
+ struct snd_card *card;
+ snd_cx88_card_t *chip;
+- struct v4l2_subdev *sd;
+ int err;
+
+ if (devno >= SNDRV_CARDS)
+@@ -896,15 +830,6 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
+ if (err < 0)
+ goto error;
+
+- /* If there's a wm8775 then add a Line-In ALC switch */
+- list_for_each_entry(sd, &chip->core->v4l2_dev.subdevs, list) {
+- if (WM8775_GID == sd->grp_id) {
+- snd_ctl_add(card, snd_ctl_new1(&snd_cx88_alc_switch,
+- chip));
+- break;
+- }
+- }
+-
+ strcpy (card->driver, "CX88x");
+ sprintf(card->shortname, "Conexant CX%x", pci->device);
+ sprintf(card->longname, "%s at %#llx",
+diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
+index 9b9e169..0ccc2af 100644
+--- a/drivers/media/video/cx88/cx88-cards.c
++++ b/drivers/media/video/cx88/cx88-cards.c
+@@ -1007,15 +1007,22 @@ static const struct cx88_board cx88_boards[] = {
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
++ .audio_chip = V4L2_IDENT_WM8775,
+ .input = {{
+ .type = CX88_VMUX_DVB,
+ .vmux = 0,
++ /* 2: Line-In */
++ .audioroute = 2,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
++ /* 2: Line-In */
++ .audioroute = 2,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
++ /* 2: Line-In */
++ .audioroute = 2,
+ }},
+ .mpeg = CX88_MPEG_DVB,
+ },
+diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
+index 62cea95..d9249e5 100644
+--- a/drivers/media/video/cx88/cx88-video.c
++++ b/drivers/media/video/cx88/cx88-video.c
+@@ -40,7 +40,6 @@
+ #include "cx88.h"
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-ioctl.h>
+-#include <media/wm8775.h>
+
+ MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
+ MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+@@ -977,7 +976,6 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)
+ const struct cx88_ctrl *c = NULL;
+ u32 value,mask;
+ int i;
+- struct v4l2_control client_ctl;
+
+ for (i = 0; i < CX8800_CTLS; i++) {
+ if (cx8800_ctls[i].v.id == ctl->id) {
+@@ -991,27 +989,6 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)
+ ctl->value = c->v.minimum;
+ if (ctl->value > c->v.maximum)
+ ctl->value = c->v.maximum;
+-
+- /* Pass changes onto any WM8775 */
+- client_ctl.id = ctl->id;
+- switch (ctl->id) {
+- case V4L2_CID_AUDIO_MUTE:
+- client_ctl.value = ctl->value;
+- break;
+- case V4L2_CID_AUDIO_VOLUME:
+- client_ctl.value = (ctl->value) ?
+- (0x90 + ctl->value) << 8 : 0;
+- break;
+- case V4L2_CID_AUDIO_BALANCE:
+- client_ctl.value = ctl->value << 9;
+- break;
+- default:
+- client_ctl.id = 0;
+- break;
+- }
+- if (client_ctl.id)
+- call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
+-
+ mask=c->mask;
+ switch (ctl->id) {
+ case V4L2_CID_AUDIO_BALANCE:
+@@ -1558,9 +1535,7 @@ static int radio_queryctrl (struct file *file, void *priv,
+ if (c->id < V4L2_CID_BASE ||
+ c->id >= V4L2_CID_LASTP1)
+ return -EINVAL;
+- if (c->id == V4L2_CID_AUDIO_MUTE ||
+- c->id == V4L2_CID_AUDIO_VOLUME ||
+- c->id == V4L2_CID_AUDIO_BALANCE) {
++ if (c->id == V4L2_CID_AUDIO_MUTE) {
+ for (i = 0; i < CX8800_CTLS; i++) {
+ if (cx8800_ctls[i].v.id == c->id)
+ break;
+diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
+index e8c732e..c9981e7 100644
+--- a/drivers/media/video/cx88/cx88.h
++++ b/drivers/media/video/cx88/cx88.h
+@@ -398,19 +398,17 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev)
+ return container_of(v4l2_dev, struct cx88_core, v4l2_dev);
+ }
+
+-#define call_hw(core, grpid, o, f, args...) \
++#define call_all(core, o, f, args...) \
+ do { \
+ if (!core->i2c_rc) { \
+ if (core->gate_ctrl) \
+ core->gate_ctrl(core, 1); \
+- v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \
++ v4l2_device_call_all(&core->v4l2_dev, 0, o, f, ##args); \
+ if (core->gate_ctrl) \
+ core->gate_ctrl(core, 0); \
+ } \
+ } while (0)
+
+-#define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args)
+-
+ struct cx8800_dev;
+ struct cx8802_dev;
+
+diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
+index 1355256..fe8ef64 100644
+--- a/drivers/media/video/wm8775.c
++++ b/drivers/media/video/wm8775.c
+@@ -35,7 +35,6 @@
+ #include <media/v4l2-device.h>
+ #include <media/v4l2-chip-ident.h>
+ #include <media/v4l2-ctrls.h>
+-#include <media/wm8775.h>
+
+ MODULE_DESCRIPTION("wm8775 driver");
+ MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
+@@ -51,16 +50,10 @@ enum {
+ TOT_REGS
+ };
+
+-#define ALC_HOLD 0x85 /* R17: use zero cross detection, ALC hold time 42.6 ms */
+-#define ALC_EN 0x100 /* R17: ALC enable */
+-
+ struct wm8775_state {
+ struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
+ struct v4l2_ctrl *mute;
+- struct v4l2_ctrl *vol;
+- struct v4l2_ctrl *bal;
+- struct v4l2_ctrl *loud;
+ u8 input; /* Last selected input (0-0xf) */
+ };
+
+@@ -92,30 +85,6 @@ static int wm8775_write(struct v4l2_subdev *sd, int reg, u16 val)
+ return -1;
+ }
+
+-static void wm8775_set_audio(struct v4l2_subdev *sd, int quietly)
+-{
+- struct wm8775_state *state = to_state(sd);
+- u8 vol_l, vol_r;
+- int muted = 0 != state->mute->val;
+- u16 volume = (u16)state->vol->val;
+- u16 balance = (u16)state->bal->val;
+-
+- /* normalize ( 65535 to 0 -> 255 to 0 (+24dB to -103dB) ) */
+- vol_l = (min(65536 - balance, 32768) * volume) >> 23;
+- vol_r = (min(balance, (u16)32768) * volume) >> 23;
+-
+- /* Mute */
+- if (muted || quietly)
+- wm8775_write(sd, R21, 0x0c0 | state->input);
+-
+- wm8775_write(sd, R14, vol_l | 0x100); /* 0x100= Left channel ADC zero cross enable */
+- wm8775_write(sd, R15, vol_r | 0x100); /* 0x100= Right channel ADC zero cross enable */
+-
+- /* Un-mute */
+- if (!muted)
+- wm8775_write(sd, R21, state->input);
+-}
+-
+ static int wm8775_s_routing(struct v4l2_subdev *sd,
+ u32 input, u32 output, u32 config)
+ {
+@@ -133,26 +102,25 @@ static int wm8775_s_routing(struct v4l2_subdev *sd,
+ state->input = input;
+ if (!v4l2_ctrl_g_ctrl(state->mute))
+ return 0;
+- if (!v4l2_ctrl_g_ctrl(state->vol))
+- return 0;
+- if (!v4l2_ctrl_g_ctrl(state->bal))
+- return 0;
+- wm8775_set_audio(sd, 1);
++ wm8775_write(sd, R21, 0x0c0);
++ wm8775_write(sd, R14, 0x1d4);
++ wm8775_write(sd, R15, 0x1d4);
++ wm8775_write(sd, R21, 0x100 + state->input);
+ return 0;
+ }
+
+ static int wm8775_s_ctrl(struct v4l2_ctrl *ctrl)
+ {
+ struct v4l2_subdev *sd = to_sd(ctrl);
++ struct wm8775_state *state = to_state(sd);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+- case V4L2_CID_AUDIO_VOLUME:
+- case V4L2_CID_AUDIO_BALANCE:
+- wm8775_set_audio(sd, 0);
+- return 0;
+- case V4L2_CID_AUDIO_LOUDNESS:
+- wm8775_write(sd, R17, (ctrl->val ? ALC_EN : 0) | ALC_HOLD);
++ wm8775_write(sd, R21, 0x0c0);
++ wm8775_write(sd, R14, 0x1d4);
++ wm8775_write(sd, R15, 0x1d4);
++ if (!ctrl->val)
++ wm8775_write(sd, R21, 0x100 + state->input);
+ return 0;
+ }
+ return -EINVAL;
+@@ -176,7 +144,16 @@ static int wm8775_log_status(struct v4l2_subdev *sd)
+
+ static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
+ {
+- wm8775_set_audio(sd, 0);
++ struct wm8775_state *state = to_state(sd);
++
++ /* If I remove this, then it can happen that I have no
++ sound the first time I tune from static to a valid channel.
++ It's difficult to reproduce and is almost certainly related
++ to the zero cross detect circuit. */
++ wm8775_write(sd, R21, 0x0c0);
++ wm8775_write(sd, R14, 0x1d4);
++ wm8775_write(sd, R15, 0x1d4);
++ wm8775_write(sd, R21, 0x100 + state->input);
+ return 0;
+ }
+
+@@ -226,7 +203,6 @@ static int wm8775_probe(struct i2c_client *client,
+ {
+ struct wm8775_state *state;
+ struct v4l2_subdev *sd;
+- int err;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+@@ -240,21 +216,15 @@ static int wm8775_probe(struct i2c_client *client,
+ return -ENOMEM;
+ sd = &state->sd;
+ v4l2_i2c_subdev_init(sd, client, &wm8775_ops);
+- sd->grp_id = WM8775_GID; /* subdev group id */
+ state->input = 2;
+
+- v4l2_ctrl_handler_init(&state->hdl, 4);
++ v4l2_ctrl_handler_init(&state->hdl, 1);
+ state->mute = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+- state->vol = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
+- V4L2_CID_AUDIO_VOLUME, 0, 65535, (65535+99)/100, 0xCF00); /* 0dB*/
+- state->bal = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
+- V4L2_CID_AUDIO_BALANCE, 0, 65535, (65535+99)/100, 32768);
+- state->loud = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
+- V4L2_CID_AUDIO_LOUDNESS, 0, 1, 1, 1);
+ sd->ctrl_handler = &state->hdl;
+- err = state->hdl.error;
+- if (err) {
++ if (state->hdl.error) {
++ int err = state->hdl.error;
++
+ v4l2_ctrl_handler_free(&state->hdl);
+ kfree(state);
+ return err;
+@@ -266,25 +236,29 @@ static int wm8775_probe(struct i2c_client *client,
+ wm8775_write(sd, R23, 0x000);
+ /* Disable zero cross detect timeout */
+ wm8775_write(sd, R7, 0x000);
+- /* HPF enable, I2S mode, 24-bit */
+- wm8775_write(sd, R11, 0x022);
++ /* Left justified, 24-bit mode */
++ wm8775_write(sd, R11, 0x021);
+ /* Master mode, clock ratio 256fs */
+ wm8775_write(sd, R12, 0x102);
+ /* Powered up */
+ wm8775_write(sd, R13, 0x000);
+- /* ALC stereo, ALC target level -5dB FS, ALC max gain +8dB */
+- wm8775_write(sd, R16, 0x1bb);
+- /* Set ALC mode and hold time */
+- wm8775_write(sd, R17, (state->loud->val ? ALC_EN : 0) | ALC_HOLD);
++ /* ADC gain +2.5dB, enable zero cross */
++ wm8775_write(sd, R14, 0x1d4);
++ /* ADC gain +2.5dB, enable zero cross */
++ wm8775_write(sd, R15, 0x1d4);
++ /* ALC Stereo, ALC target level -1dB FS max gain +8dB */
++ wm8775_write(sd, R16, 0x1bf);
++ /* Enable gain control, use zero cross detection,
++ ALC hold time 42.6 ms */
++ wm8775_write(sd, R17, 0x185);
+ /* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */
+ wm8775_write(sd, R18, 0x0a2);
+ /* Enable noise gate, threshold -72dBfs */
+ wm8775_write(sd, R19, 0x005);
+- /* Transient window 4ms, ALC min gain -5dB */
+- wm8775_write(sd, R20, 0x0fb);
+-
+- wm8775_set_audio(sd, 1); /* set volume/mute/mux */
+-
++ /* Transient window 4ms, lower PGA gain limit -1dB */
++ wm8775_write(sd, R20, 0x07a);
++ /* LRBOTH = 1, use input 2. */
++ wm8775_write(sd, R21, 0x102);
+ return 0;
+ }
+
+diff --git a/include/media/wm8775.h b/include/media/wm8775.h
+index a1c4d41..60739c5 100644
+--- a/include/media/wm8775.h
++++ b/include/media/wm8775.h
+@@ -32,7 +32,4 @@
+ #define WM8775_AIN3 4
+ #define WM8775_AIN4 8
+
+-/* subdev group ID */
+-#define WM8775_GID (1 << 0)
+-
+ #endif
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0052-em28xx-radio_fops-should-also-use-unlocked_ioctl.patch b/extras/recipes-kernel/linux/linux-omap/linus/0052-em28xx-radio_fops-should-also-use-unlocked_ioctl.patch
new file mode 100644
index 00000000..f8070990
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0052-em28xx-radio_fops-should-also-use-unlocked_ioctl.patch
@@ -0,0 +1,31 @@
+From 002eb3b2ab46fef443a2e40c52255e1c30b83704 Mon Sep 17 00:00:00 2001
+From: Hans Verkuil <hverkuil@xs4all.nl>
+Date: Sat, 18 Dec 2010 09:59:51 -0300
+Subject: [PATCH 52/65] em28xx: radio_fops should also use unlocked_ioctl
+
+em28xx uses core assisted locking, so it shouldn't use .ioctl.
+The .ioctl callback was replaced by .unlocked_ioctl for video nodes,
+but not for radio nodes. This is now corrected.
+
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+---
+ drivers/media/video/em28xx/em28xx-video.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
+index 908e3bc..2c30072 100644
+--- a/drivers/media/video/em28xx/em28xx-video.c
++++ b/drivers/media/video/em28xx/em28xx-video.c
+@@ -2377,7 +2377,7 @@ static const struct v4l2_file_operations radio_fops = {
+ .owner = THIS_MODULE,
+ .open = em28xx_v4l2_open,
+ .release = em28xx_v4l2_close,
+- .ioctl = video_ioctl2,
++ .unlocked_ioctl = video_ioctl2,
+ };
+
+ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0053-arch-x86-oprofile-op_model_amd.c-Perform-initialisat.patch b/extras/recipes-kernel/linux/linux-omap/linus/0053-arch-x86-oprofile-op_model_amd.c-Perform-initialisat.patch
new file mode 100644
index 00000000..dc5522d0
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0053-arch-x86-oprofile-op_model_amd.c-Perform-initialisat.patch
@@ -0,0 +1,81 @@
+From b376276870006eabba46427b79a3f3be70b3e3ea Mon Sep 17 00:00:00 2001
+From: Robert Richter <robert.richter@amd.com>
+Date: Mon, 3 Jan 2011 12:15:14 +0100
+Subject: [PATCH 53/65] arch/x86/oprofile/op_model_amd.c: Perform initialisation on a single CPU
+
+Disable preemption in init_ibs(). The function only checks the
+ibs capabilities and sets up pci devices (if necessary). It runs
+only on one cpu but operates with the local APIC and some MSRs,
+thus it is better to disable preemption.
+
+[ 7.034377] BUG: using smp_processor_id() in preemptible [00000000] code: modprobe/483
+[ 7.034385] caller is setup_APIC_eilvt+0x155/0x180
+[ 7.034389] Pid: 483, comm: modprobe Not tainted 2.6.37-rc1-20101110+ #1
+[ 7.034392] Call Trace:
+[ 7.034400] [<ffffffff812a2b72>] debug_smp_processor_id+0xd2/0xf0
+[ 7.034404] [<ffffffff8101e985>] setup_APIC_eilvt+0x155/0x180
+[ ... ]
+
+Addresses https://bugzilla.kernel.org/show_bug.cgi?id=22812
+
+Reported-by: <atswartz@gmail.com>
+Signed-off-by: Robert Richter <robert.richter@amd.com>
+Cc: oprofile-list@lists.sourceforge.net <oprofile-list@lists.sourceforge.net>
+Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
+Cc: Frederic Weisbecker <fweisbec@gmail.com>
+Cc: Rafael J. Wysocki <rjw@sisk.pl>
+Cc: Dan Carpenter <error27@gmail.com>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Cc: <stable@kernel.org> [2.6.37.x]
+LKML-Reference: <20110103111514.GM4739@erda.amd.com>
+[ small cleanups ]
+Signed-off-by: Ingo Molnar <mingo@elte.hu>
+---
+ arch/x86/oprofile/op_model_amd.c | 24 ++++++++++++++++--------
+ 1 files changed, 16 insertions(+), 8 deletions(-)
+
+diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c
+index a011bcc..7d90d47 100644
+--- a/arch/x86/oprofile/op_model_amd.c
++++ b/arch/x86/oprofile/op_model_amd.c
+@@ -630,21 +630,29 @@ static int __init_ibs_nmi(void)
+ return 0;
+ }
+
+-/* initialize the APIC for the IBS interrupts if available */
++/*
++ * check and reserve APIC extended interrupt LVT offset for IBS if
++ * available
++ *
++ * init_ibs() preforms implicitly cpu-local operations, so pin this
++ * thread to its current CPU
++ */
++
+ static void init_ibs(void)
+ {
+- ibs_caps = get_ibs_caps();
++ preempt_disable();
+
++ ibs_caps = get_ibs_caps();
+ if (!ibs_caps)
+- return;
++ goto out;
+
+- if (__init_ibs_nmi()) {
++ if (__init_ibs_nmi() < 0)
+ ibs_caps = 0;
+- return;
+- }
++ else
++ printk(KERN_INFO "oprofile: AMD IBS detected (0x%08x)\n", ibs_caps);
+
+- printk(KERN_INFO "oprofile: AMD IBS detected (0x%08x)\n",
+- (unsigned)ibs_caps);
++out:
++ preempt_enable();
+ }
+
+ static int (*create_arch_files)(struct super_block *sb, struct dentry *root);
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0054-perf-Fix-callchain-hit-bad-cast-on-ascii-display.patch b/extras/recipes-kernel/linux/linux-omap/linus/0054-perf-Fix-callchain-hit-bad-cast-on-ascii-display.patch
new file mode 100644
index 00000000..09ed27c3
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0054-perf-Fix-callchain-hit-bad-cast-on-ascii-display.patch
@@ -0,0 +1,39 @@
+From ef44b2900e7bfd255e56ae9bd2ec03d2c13b780c Mon Sep 17 00:00:00 2001
+From: Frederic Weisbecker <fweisbec@gmail.com>
+Date: Mon, 3 Jan 2011 16:13:11 +0100
+Subject: [PATCH 54/65] perf: Fix callchain hit bad cast on ascii display
+
+ipchain__fprintf_graph() casts the number of hits in a branch as an
+int, which means we lose its highests bits.
+
+This results in meaningless number of callchain hits in perf.data
+that have a high number of hits recorded, typically those that have
+callchain branches hits appearing more than INT_MAX. This happens
+easily as those are pondered by the event period.
+
+Reported-by: Nick Piggin <npiggin@kernel.dk>
+Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
+Cc: Ingo Molnar <mingo@elte.hu>
+Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
+Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
+Cc: Paul Mackerras <paulus@samba.org>
+---
+ tools/perf/util/hist.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
+index 2022e87..76bcc35 100644
+--- a/tools/perf/util/hist.c
++++ b/tools/perf/util/hist.c
+@@ -356,7 +356,7 @@ static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
+
+ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
+ int depth, int depth_mask, int period,
+- u64 total_samples, int hits,
++ u64 total_samples, u64 hits,
+ int left_margin)
+ {
+ int i;
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0055-ARM-it8152-add-IT8152_LAST_IRQ-definition-to-fix-bui.patch b/extras/recipes-kernel/linux/linux-omap/linus/0055-ARM-it8152-add-IT8152_LAST_IRQ-definition-to-fix-bui.patch
new file mode 100644
index 00000000..9a1f006b
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0055-ARM-it8152-add-IT8152_LAST_IRQ-definition-to-fix-bui.patch
@@ -0,0 +1,40 @@
+From 83c04c29567a2f57c4881c8c11bce2bd4bc0b0ab Mon Sep 17 00:00:00 2001
+From: Mike Rapoport <mike@compulab.co.il>
+Date: Wed, 29 Dec 2010 09:06:26 +0200
+Subject: [PATCH 55/65] ARM: it8152: add IT8152_LAST_IRQ definition to fix build error
+
+The commit 6ac6b817f3f4c23c5febd960d8deb343e13af5f3 (ARM: pxa: encode
+IRQ number into .nr_irqs) removed definition of ITE_LAST_IRQ which
+caused the following build error:
+
+CC arch/arm/common/it8152.o
+arch/arm/common/it8152.c: In function 'it8152_init_irq':
+arch/arm/common/it8152.c:86: error: 'IT8152_LAST_IRQ' undeclared (first use in this function)
+arch/arm/common/it8152.c:86: error: (Each undeclared identifier is reported only once
+arch/arm/common/it8152.c:86: error: for each function it appears in.)
+make[2]: *** [arch/arm/common/it8152.o] Error 1
+
+Defining the IT8152_LAST_IRQ in the arch/arm/include/hardware/it8152.c
+fixes the build.
+
+Signed-off-by: Mike Rapoport <mike@compulab.co.il>
+Signed-off-by: Eric Miao <eric.y.miao@gmail.com>
+---
+ arch/arm/include/asm/hardware/it8152.h | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/include/asm/hardware/it8152.h b/arch/arm/include/asm/hardware/it8152.h
+index 21fa272..b2f95c7 100644
+--- a/arch/arm/include/asm/hardware/it8152.h
++++ b/arch/arm/include/asm/hardware/it8152.h
+@@ -76,6 +76,7 @@ extern unsigned long it8152_base_address;
+ IT8152_PD_IRQ(0) Audio controller (ACR)
+ */
+ #define IT8152_IRQ(x) (IRQ_BOARD_START + (x))
++#define IT8152_LAST_IRQ (IRQ_BOARD_START + 40)
+
+ /* IRQ-sources in 3 groups - local devices, LPC (serial), and external PCI */
+ #define IT8152_LD_IRQ_COUNT 9
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0056-ARM-pxa-fix-page-table-corruption-on-resume.patch b/extras/recipes-kernel/linux/linux-omap/linus/0056-ARM-pxa-fix-page-table-corruption-on-resume.patch
new file mode 100644
index 00000000..5ae9609e
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0056-ARM-pxa-fix-page-table-corruption-on-resume.patch
@@ -0,0 +1,46 @@
+From b7072ddc2682868372d060e1e25447e5c1aee007 Mon Sep 17 00:00:00 2001
+From: Aric D. Blumer <aric@sdgsystems.com>
+Date: Wed, 29 Dec 2010 11:18:29 -0500
+Subject: [PATCH 56/65] ARM: pxa: fix page table corruption on resume
+
+Before this patch, the following error would sometimes occur after a
+resume on pxa3xx:
+
+ /path/to/mm/memory.c:144: bad pmd 8040542e.
+
+The problem was that a temporary page table mapping was being improperly
+restored.
+
+The PXA3xx resume code creates a temporary mapping of resume_turn_on_mmu
+to avoid a prefetch abort. The pxa3xx_resume_after_mmu code requires
+that the r1 register holding the address of this mapping not be
+modified, however, resume_turn_on_mmu does modify it. It is mostly
+correct in that r1 receives the base table address, but it may also
+get other bits in 13:0. This results in pxa3xx_resume_after_mmu
+restoring the original mapping to the wrong place, corrupting memory
+and leaving the temporary mapping in place.
+
+Signed-off-by: Matt Reimer <mreimer@sdgsystems.com>
+Signed-off-by: Eric Miao <eric.y.miao@gmail.com>
+---
+ arch/arm/mach-pxa/sleep.S | 4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S
+index 52c30b0..ae00811 100644
+--- a/arch/arm/mach-pxa/sleep.S
++++ b/arch/arm/mach-pxa/sleep.S
+@@ -353,8 +353,8 @@ resume_turn_on_mmu:
+
+ @ Let us ensure we jump to resume_after_mmu only when the mcr above
+ @ actually took effect. They call it the "cpwait" operation.
+- mrc p15, 0, r1, c2, c0, 0 @ queue a dependency on CP15
+- sub pc, r2, r1, lsr #32 @ jump to virtual addr
++ mrc p15, 0, r0, c2, c0, 0 @ queue a dependency on CP15
++ sub pc, r2, r0, lsr #32 @ jump to virtual addr
+ nop
+ nop
+ nop
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0057-atl1-fix-oops-when-changing-tx-rx-ring-params.patch b/extras/recipes-kernel/linux/linux-omap/linus/0057-atl1-fix-oops-when-changing-tx-rx-ring-params.patch
new file mode 100644
index 00000000..9db691b1
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0057-atl1-fix-oops-when-changing-tx-rx-ring-params.patch
@@ -0,0 +1,63 @@
+From f14284bb4ad057377b4944bb3985352fe1079c60 Mon Sep 17 00:00:00 2001
+From: J. K. Cliburn <jcliburn@gmail.com>
+Date: Sat, 1 Jan 2011 05:02:12 +0000
+Subject: [PATCH 57/65] atl1: fix oops when changing tx/rx ring params
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Commit 3f5a2a713aad28480d86b0add00c68484b54febc zeroes out the statistics
+message block (SMB) and coalescing message block (CMB) when adapter ring
+resources are freed. This is desirable behavior, but, as a side effect,
+the commit leads to an oops when atl1_set_ringparam() attempts to alter
+the number of rx or tx elements in the ring buffer (by using ethtool
+-G, for example). We don't want SMB or CMB to change during this
+operation.
+
+Modify atl1_set_ringparam() to preserve SMB and CMB when changing ring
+parameters.
+
+Cc: stable@kernel.org
+Signed-off-by: Jay Cliburn <jcliburn@gmail.com>
+Reported-by: Tõnu Raitviir <jussuf@linux.ee>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/atlx/atl1.c | 10 ++++++++++
+ 1 files changed, 10 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c
+index 5336310..3acf512 100644
+--- a/drivers/net/atlx/atl1.c
++++ b/drivers/net/atlx/atl1.c
+@@ -3504,6 +3504,8 @@ static int atl1_set_ringparam(struct net_device *netdev,
+ struct atl1_rfd_ring rfd_old, rfd_new;
+ struct atl1_rrd_ring rrd_old, rrd_new;
+ struct atl1_ring_header rhdr_old, rhdr_new;
++ struct atl1_smb smb;
++ struct atl1_cmb cmb;
+ int err;
+
+ tpd_old = adapter->tpd_ring;
+@@ -3544,11 +3546,19 @@ static int atl1_set_ringparam(struct net_device *netdev,
+ adapter->rrd_ring = rrd_old;
+ adapter->tpd_ring = tpd_old;
+ adapter->ring_header = rhdr_old;
++ /*
++ * Save SMB and CMB, since atl1_free_ring_resources
++ * will clear them.
++ */
++ smb = adapter->smb;
++ cmb = adapter->cmb;
+ atl1_free_ring_resources(adapter);
+ adapter->rfd_ring = rfd_new;
+ adapter->rrd_ring = rrd_new;
+ adapter->tpd_ring = tpd_new;
+ adapter->ring_header = rhdr_new;
++ adapter->smb = smb;
++ adapter->cmb = cmb;
+
+ err = atl1_up(adapter);
+ if (err)
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0058-bridge-fix-br_multicast_ipv6_rcv-for-paged-skbs.patch b/extras/recipes-kernel/linux/linux-omap/linus/0058-bridge-fix-br_multicast_ipv6_rcv-for-paged-skbs.patch
new file mode 100644
index 00000000..857f506f
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0058-bridge-fix-br_multicast_ipv6_rcv-for-paged-skbs.patch
@@ -0,0 +1,157 @@
+From 87bd79394bd7f4b7e01199421aae0df5fb1910d0 Mon Sep 17 00:00:00 2001
+From: Tomas Winkler <tomas.winkler@intel.com>
+Date: Mon, 3 Jan 2011 11:26:08 -0800
+Subject: [PATCH 58/65] bridge: fix br_multicast_ipv6_rcv for paged skbs
+
+use pskb_may_pull to access ipv6 header correctly for paged skbs
+It was omitted in the bridge code leading to crash in blind
+__skb_pull
+
+since the skb is cloned undonditionally we also simplify the
+the exit path
+
+this fixes bug https://bugzilla.kernel.org/show_bug.cgi?id=25202
+
+Dec 15 14:36:40 User-PC hostapd: wlan0: STA 00:15:00:60:5d:34 IEEE 802.11: authenticated
+Dec 15 14:36:40 User-PC hostapd: wlan0: STA 00:15:00:60:5d:34 IEEE 802.11: associated (aid 2)
+Dec 15 14:36:40 User-PC hostapd: wlan0: STA 00:15:00:60:5d:34 RADIUS: starting accounting session 4D0608A3-00000005
+Dec 15 14:36:41 User-PC kernel: [175576.120287] ------------[ cut here ]------------
+Dec 15 14:36:41 User-PC kernel: [175576.120452] kernel BUG at include/linux/skbuff.h:1178!
+Dec 15 14:36:41 User-PC kernel: [175576.120609] invalid opcode: 0000 [#1] SMP
+Dec 15 14:36:41 User-PC kernel: [175576.120749] last sysfs file: /sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/uevent
+Dec 15 14:36:41 User-PC kernel: [175576.121035] Modules linked in: approvals binfmt_misc bridge stp llc parport_pc ppdev arc4 iwlagn snd_hda_codec_realtek iwlcore i915 snd_hda_intel mac80211 joydev snd_hda_codec snd_hwdep snd_pcm snd_seq_midi drm_kms_helper snd_rawmidi drm snd_seq_midi_event snd_seq snd_timer snd_seq_device cfg80211 eeepc_wmi usbhid psmouse intel_agp i2c_algo_bit intel_gtt uvcvideo agpgart videodev sparse_keymap snd shpchp v4l1_compat lp hid video serio_raw soundcore output snd_page_alloc ahci libahci atl1c
+Dec 15 14:36:41 User-PC kernel: [175576.122712]
+Dec 15 14:36:41 User-PC kernel: [175576.122769] Pid: 0, comm: kworker/0:0 Tainted: G W 2.6.37-rc5-wl+ #3 1015PE/1016P
+Dec 15 14:36:41 User-PC kernel: [175576.123012] EIP: 0060:[<f83edd65>] EFLAGS: 00010283 CPU: 1
+Dec 15 14:36:41 User-PC kernel: [175576.123193] EIP is at br_multicast_rcv+0xc95/0xe1c [bridge]
+Dec 15 14:36:41 User-PC kernel: [175576.123362] EAX: 0000001c EBX: f5626318 ECX: 00000000 EDX: 00000000
+Dec 15 14:36:41 User-PC kernel: [175576.123550] ESI: ec512262 EDI: f5626180 EBP: f60b5ca0 ESP: f60b5bd8
+Dec 15 14:36:41 User-PC kernel: [175576.123737] DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
+Dec 15 14:36:41 User-PC kernel: [175576.123902] Process kworker/0:0 (pid: 0, ti=f60b4000 task=f60a8000 task.ti=f60b0000)
+Dec 15 14:36:41 User-PC kernel: [175576.124137] Stack:
+Dec 15 14:36:41 User-PC kernel: [175576.124181] ec556500 f6d06800 f60b5be8 c01087d8 ec512262 00000030 00000024 f5626180
+Dec 15 14:36:41 User-PC kernel: [175576.124181] f572c200 ef463440 f5626300 3affffff f6d06dd0 e60766a4 000000c4 f6d06860
+Dec 15 14:36:41 User-PC kernel: [175576.124181] ffffffff ec55652c 00000001 f6d06844 f60b5c64 c0138264 c016e451 c013e47d
+Dec 15 14:36:41 User-PC kernel: [175576.124181] Call Trace:
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c01087d8>] ? sched_clock+0x8/0x10
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c0138264>] ? enqueue_entity+0x174/0x440
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c016e451>] ? sched_clock_cpu+0x131/0x190
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c013e47d>] ? select_task_rq_fair+0x2ad/0x730
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c0524fc1>] ? nf_iterate+0x71/0x90
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<f83e4914>] ? br_handle_frame_finish+0x184/0x220 [bridge]
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<f83e4790>] ? br_handle_frame_finish+0x0/0x220 [bridge]
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<f83e46e9>] ? br_handle_frame+0x189/0x230 [bridge]
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<f83e4790>] ? br_handle_frame_finish+0x0/0x220 [bridge]
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<f83e4560>] ? br_handle_frame+0x0/0x230 [bridge]
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c04ff026>] ? __netif_receive_skb+0x1b6/0x5b0
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c04f7a30>] ? skb_copy_bits+0x110/0x210
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c0503a7f>] ? netif_receive_skb+0x6f/0x80
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<f82cb74c>] ? ieee80211_deliver_skb+0x8c/0x1a0 [mac80211]
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<f82cc836>] ? ieee80211_rx_handlers+0xeb6/0x1aa0 [mac80211]
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c04ff1f0>] ? __netif_receive_skb+0x380/0x5b0
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c016e242>] ? sched_clock_local+0xb2/0x190
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c012b688>] ? default_spin_lock_flags+0x8/0x10
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c05d83df>] ? _raw_spin_lock_irqsave+0x2f/0x50
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<f82cd621>] ? ieee80211_prepare_and_rx_handle+0x201/0xa90 [mac80211]
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<f82ce154>] ? ieee80211_rx+0x2a4/0x830 [mac80211]
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<f815a8d6>] ? iwl_update_stats+0xa6/0x2a0 [iwlcore]
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<f8499212>] ? iwlagn_rx_reply_rx+0x292/0x3b0 [iwlagn]
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c05d83df>] ? _raw_spin_lock_irqsave+0x2f/0x50
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<f8483697>] ? iwl_rx_handle+0xe7/0x350 [iwlagn]
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<f8486ab7>] ? iwl_irq_tasklet+0xf7/0x5c0 [iwlagn]
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c01aece1>] ? __rcu_process_callbacks+0x201/0x2d0
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c0150d05>] ? tasklet_action+0xc5/0x100
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c0150a07>] ? __do_softirq+0x97/0x1d0
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c05d910c>] ? nmi_stack_correct+0x2f/0x34
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c0150970>] ? __do_softirq+0x0/0x1d0
+Dec 15 14:36:41 User-PC kernel: [175576.124181] <IRQ>
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c01508f5>] ? irq_exit+0x65/0x70
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c05df062>] ? do_IRQ+0x52/0xc0
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c01036b0>] ? common_interrupt+0x30/0x38
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c03a1fc2>] ? intel_idle+0xc2/0x160
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c04daebb>] ? cpuidle_idle_call+0x6b/0x100
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c0101dea>] ? cpu_idle+0x8a/0xf0
+Dec 15 14:36:41 User-PC kernel: [175576.124181] [<c05d2702>] ? start_secondary+0x1e8/0x1ee
+
+Cc: David Miller <davem@davemloft.net>
+Cc: Johannes Berg <johannes@sipsolutions.net>
+Cc: Stephen Hemminger <shemminger@vyatta.com>
+Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ net/bridge/br_multicast.c | 28 ++++++++++++++++++----------
+ 1 files changed, 18 insertions(+), 10 deletions(-)
+
+diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
+index f19e347..543b326 100644
+--- a/net/bridge/br_multicast.c
++++ b/net/bridge/br_multicast.c
+@@ -1430,7 +1430,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
+ struct net_bridge_port *port,
+ struct sk_buff *skb)
+ {
+- struct sk_buff *skb2 = skb;
++ struct sk_buff *skb2;
+ struct ipv6hdr *ip6h;
+ struct icmp6hdr *icmp6h;
+ u8 nexthdr;
+@@ -1469,15 +1469,15 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
+ if (!skb2)
+ return -ENOMEM;
+
++ err = -EINVAL;
++ if (!pskb_may_pull(skb2, offset + sizeof(struct icmp6hdr)))
++ goto out;
++
+ len -= offset - skb_network_offset(skb2);
+
+ __skb_pull(skb2, offset);
+ skb_reset_transport_header(skb2);
+
+- err = -EINVAL;
+- if (!pskb_may_pull(skb2, sizeof(*icmp6h)))
+- goto out;
+-
+ icmp6h = icmp6_hdr(skb2);
+
+ switch (icmp6h->icmp6_type) {
+@@ -1516,7 +1516,12 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
+ switch (icmp6h->icmp6_type) {
+ case ICMPV6_MGM_REPORT:
+ {
+- struct mld_msg *mld = (struct mld_msg *)icmp6h;
++ struct mld_msg *mld;
++ if (!pskb_may_pull(skb2, sizeof(*mld))) {
++ err = -EINVAL;
++ goto out;
++ }
++ mld = (struct mld_msg *)skb_transport_header(skb2);
+ BR_INPUT_SKB_CB(skb2)->mrouters_only = 1;
+ err = br_ip6_multicast_add_group(br, port, &mld->mld_mca);
+ break;
+@@ -1529,15 +1534,18 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
+ break;
+ case ICMPV6_MGM_REDUCTION:
+ {
+- struct mld_msg *mld = (struct mld_msg *)icmp6h;
++ struct mld_msg *mld;
++ if (!pskb_may_pull(skb2, sizeof(*mld))) {
++ err = -EINVAL;
++ goto out;
++ }
++ mld = (struct mld_msg *)skb_transport_header(skb2);
+ br_ip6_multicast_leave_group(br, port, &mld->mld_mca);
+ }
+ }
+
+ out:
+- __skb_push(skb2, offset);
+- if (skb2 != skb)
+- kfree_skb(skb2);
++ kfree_skb(skb2);
+ return err;
+ }
+ #endif
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0059-name_to_dev_t-must-not-call-__init-code.patch b/extras/recipes-kernel/linux/linux-omap/linus/0059-name_to_dev_t-must-not-call-__init-code.patch
new file mode 100644
index 00000000..26915acc
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0059-name_to_dev_t-must-not-call-__init-code.patch
@@ -0,0 +1,31 @@
+From edb8dd77b87534a3cc6bf4e2a234216d2cc68f89 Mon Sep 17 00:00:00 2001
+From: Jan Beulich <JBeulich@novell.com>
+Date: Mon, 3 Jan 2011 15:07:02 +0000
+Subject: [PATCH 59/65] name_to_dev_t() must not call __init code
+
+The function can't be __init itself (being called from some sysfs
+handler), and hence none of the functions it calls can be either.
+
+Signed-off-by: Jan Beulich <jbeulich@novell.com>
+Acked-by: Randy Dunlap <randy.dunlap@oracle.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+---
+ init/do_mounts.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/init/do_mounts.c b/init/do_mounts.c
+index 830aaec..2b54bef 100644
+--- a/init/do_mounts.c
++++ b/init/do_mounts.c
+@@ -93,7 +93,7 @@ no_match:
+ *
+ * Returns the matching dev_t on success or 0 on failure.
+ */
+-static dev_t __init devt_from_partuuid(char *uuid_str)
++static dev_t devt_from_partuuid(char *uuid_str)
+ {
+ dev_t res = 0;
+ struct device *dev = NULL;
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0060-bridge-stp-ensure-mac-header-is-set.patch b/extras/recipes-kernel/linux/linux-omap/linus/0060-bridge-stp-ensure-mac-header-is-set.patch
new file mode 100644
index 00000000..ad0b8e1b
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0060-bridge-stp-ensure-mac-header-is-set.patch
@@ -0,0 +1,38 @@
+From ff26fe4db962b41b794fb81518b8e407093239d9 Mon Sep 17 00:00:00 2001
+From: Florian Westphal <fw@strlen.de>
+Date: Mon, 3 Jan 2011 04:16:28 +0000
+Subject: [PATCH 60/65] bridge: stp: ensure mac header is set
+
+commit bf9ae5386bca8836c16e69ab8fdbe46767d7452a
+(llc: use dev_hard_header) removed the
+skb_reset_mac_header call from llc_mac_hdr_init.
+
+This seems fine itself, but br_send_bpdu() invokes ebtables LOCAL_OUT.
+
+We oops in ebt_basic_match() because it assumes eth_hdr(skb) returns
+a meaningful result.
+
+Cc: acme@ghostprotocols.net
+References: https://bugzilla.kernel.org/show_bug.cgi?id=24532
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ net/bridge/br_stp_bpdu.c | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c
+index 35cf270..e3d7aef 100644
+--- a/net/bridge/br_stp_bpdu.c
++++ b/net/bridge/br_stp_bpdu.c
+@@ -50,6 +50,8 @@ static void br_send_bpdu(struct net_bridge_port *p,
+
+ llc_mac_hdr_init(skb, p->dev->dev_addr, p->br->group_addr);
+
++ skb_reset_mac_header(skb);
++
+ NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
+ dev_queue_xmit);
+ }
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0061-ima-fix-add-LSM-rule-bug.patch b/extras/recipes-kernel/linux/linux-omap/linus/0061-ima-fix-add-LSM-rule-bug.patch
new file mode 100644
index 00000000..5c37ce35
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0061-ima-fix-add-LSM-rule-bug.patch
@@ -0,0 +1,64 @@
+From 497d2c1cfa523a66bfea594791d8f2a50e5bb0aa Mon Sep 17 00:00:00 2001
+From: Mimi Zohar <zohar@linux.vnet.ibm.com>
+Date: Mon, 3 Jan 2011 14:59:10 -0800
+Subject: [PATCH 61/65] ima: fix add LSM rule bug
+
+If security_filter_rule_init() doesn't return a rule, then not everything
+is as fine as the return code implies.
+
+This bug only occurs when the LSM (eg. SELinux) is disabled at runtime.
+
+Adding an empty LSM rule causes ima_match_rules() to always succeed,
+ignoring any remaining rules.
+
+ default IMA TCB policy:
+ # PROC_SUPER_MAGIC
+ dont_measure fsmagic=0x9fa0
+ # SYSFS_MAGIC
+ dont_measure fsmagic=0x62656572
+ # DEBUGFS_MAGIC
+ dont_measure fsmagic=0x64626720
+ # TMPFS_MAGIC
+ dont_measure fsmagic=0x01021994
+ # SECURITYFS_MAGIC
+ dont_measure fsmagic=0x73636673
+
+ < LSM specific rule >
+ dont_measure obj_type=var_log_t
+
+ measure func=BPRM_CHECK
+ measure func=FILE_MMAP mask=MAY_EXEC
+ measure func=FILE_CHECK mask=MAY_READ uid=0
+
+Thus without the patch, with the boot parameters 'tcb selinux=0', adding
+the above 'dont_measure obj_type=var_log_t' rule to the default IMA TCB
+measurement policy, would result in nothing being measured. The patch
+prevents the default TCB policy from being replaced.
+
+Signed-off-by: Mimi Zohar <zohar@us.ibm.com>
+Cc: James Morris <jmorris@namei.org>
+Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
+Cc: David Safford <safford@watson.ibm.com>
+Cc: <stable@kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+---
+ security/integrity/ima/ima_policy.c | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
+index aef8c0a..d661afb 100644
+--- a/security/integrity/ima/ima_policy.c
++++ b/security/integrity/ima/ima_policy.c
+@@ -253,6 +253,8 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry,
+ result = security_filter_rule_init(entry->lsm[lsm_rule].type,
+ Audit_equal, args,
+ &entry->lsm[lsm_rule].rule);
++ if (!entry->lsm[lsm_rule].rule)
++ return -EINVAL;
+ return result;
+ }
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0062-arch-mn10300-kernel-irq.c-fix-build.patch b/extras/recipes-kernel/linux/linux-omap/linus/0062-arch-mn10300-kernel-irq.c-fix-build.patch
new file mode 100644
index 00000000..ecbbaa02
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0062-arch-mn10300-kernel-irq.c-fix-build.patch
@@ -0,0 +1,31 @@
+From 942dd5c14797f41c9e6d960ae95940ccdb7cb044 Mon Sep 17 00:00:00 2001
+From: Andrew Morton <akpm@linux-foundation.org>
+Date: Mon, 3 Jan 2011 14:59:11 -0800
+Subject: [PATCH 62/65] arch/mn10300/kernel/irq.c: fix build
+
+Addresses https://bugzilla.kernel.org/show_bug.cgi?id=25702
+
+Reported-by: Martin Ettl <ettl.martin@gmx.de>
+Cc: David Howells <dhowells@redhat.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+---
+ arch/mn10300/kernel/irq.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/arch/mn10300/kernel/irq.c b/arch/mn10300/kernel/irq.c
+index c2e4459..ac11754 100644
+--- a/arch/mn10300/kernel/irq.c
++++ b/arch/mn10300/kernel/irq.c
+@@ -459,7 +459,7 @@ void migrate_irqs(void)
+ tmp = CROSS_GxICR(irq, new);
+
+ x &= GxICR_LEVEL | GxICR_ENABLE;
+- if (GxICR(irq) & GxICR_REQUEST) {
++ if (GxICR(irq) & GxICR_REQUEST)
+ x |= GxICR_REQUEST | GxICR_DETECT;
+ CROSS_GxICR(irq, new) = x;
+ tmp = CROSS_GxICR(irq, new);
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0063-remove-trim_fs-method-from-Documentation-filesystems.patch b/extras/recipes-kernel/linux/linux-omap/linus/0063-remove-trim_fs-method-from-Documentation-filesystems.patch
new file mode 100644
index 00000000..d7e9481b
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0063-remove-trim_fs-method-from-Documentation-filesystems.patch
@@ -0,0 +1,38 @@
+From 012cfd55bb9075c4697cc068ba0a8c0d0069433a Mon Sep 17 00:00:00 2001
+From: Christoph Hellwig <hch@lst.de>
+Date: Tue, 4 Jan 2011 07:14:24 +0100
+Subject: [PATCH 63/65] remove trim_fs method from Documentation/filesystems/Locking
+
+The ->trim_fs has been removed meanwhile, so remove it from the documentation
+as well.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Reported-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+---
+ Documentation/filesystems/Locking | 2 --
+ 1 files changed, 0 insertions(+), 2 deletions(-)
+
+diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
+index 7686e76..33fa3e5 100644
+--- a/Documentation/filesystems/Locking
++++ b/Documentation/filesystems/Locking
+@@ -115,7 +115,6 @@ prototypes:
+ ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
+ ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
+ int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t);
+- int (*trim_fs) (struct super_block *, struct fstrim_range *);
+
+ locking rules:
+ All may block [not true, see below]
+@@ -138,7 +137,6 @@ show_options: no (namespace_sem)
+ quota_read: no (see below)
+ quota_write: no (see below)
+ bdev_try_to_free_page: no (see below)
+-trim_fs: no
+
+ ->statfs() has s_umount (shared) when called by ustat(2) (native or
+ compat), but that's an accident of bad API; s_umount is used to pin
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0064-ipv4-route.c-respect-prefsrc-for-local-routes.patch b/extras/recipes-kernel/linux/linux-omap/linus/0064-ipv4-route.c-respect-prefsrc-for-local-routes.patch
new file mode 100644
index 00000000..56e00911
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0064-ipv4-route.c-respect-prefsrc-for-local-routes.patch
@@ -0,0 +1,57 @@
+From 1e3d23ed2eae8473568b34fdc323d2fec679616b Mon Sep 17 00:00:00 2001
+From: Joel Sing <jsing@google.com>
+Date: Mon, 3 Jan 2011 20:24:20 +0000
+Subject: [PATCH 64/65] ipv4/route.c: respect prefsrc for local routes
+
+The preferred source address is currently ignored for local routes,
+which results in all local connections having a src address that is the
+same as the local dst address. Fix this by respecting the preferred source
+address when it is provided for local routes.
+
+This bug can be demonstrated as follows:
+
+ # ifconfig dummy0 192.168.0.1
+ # ip route show table local | grep local.*dummy0
+ local 192.168.0.1 dev dummy0 proto kernel scope host src 192.168.0.1
+ # ip route change table local local 192.168.0.1 dev dummy0 \
+ proto kernel scope host src 127.0.0.1
+ # ip route show table local | grep local.*dummy0
+ local 192.168.0.1 dev dummy0 proto kernel scope host src 127.0.0.1
+
+We now establish a local connection and verify the source IP
+address selection:
+
+ # nc -l 192.168.0.1 3128 &
+ # nc 192.168.0.1 3128 &
+ # netstat -ant | grep 192.168.0.1:3128.*EST
+ tcp 0 0 192.168.0.1:3128 192.168.0.1:33228 ESTABLISHED
+ tcp 0 0 192.168.0.1:33228 192.168.0.1:3128 ESTABLISHED
+
+Signed-off-by: Joel Sing <jsing@google.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ net/ipv4/route.c | 8 ++++++--
+ 1 files changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/net/ipv4/route.c b/net/ipv4/route.c
+index df948b0..93bfd95 100644
+--- a/net/ipv4/route.c
++++ b/net/ipv4/route.c
+@@ -2649,8 +2649,12 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp,
+ }
+
+ if (res.type == RTN_LOCAL) {
+- if (!fl.fl4_src)
+- fl.fl4_src = fl.fl4_dst;
++ if (!fl.fl4_src) {
++ if (res.fi->fib_prefsrc)
++ fl.fl4_src = res.fi->fib_prefsrc;
++ else
++ fl.fl4_src = fl.fl4_dst;
++ }
+ dev_out = net->loopback_dev;
+ fl.oif = dev_out->ifindex;
+ res.fi = NULL;
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/linus/0065-Linux-2.6.37.patch b/extras/recipes-kernel/linux/linux-omap/linus/0065-Linux-2.6.37.patch
new file mode 100644
index 00000000..f4f6c6b1
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/linus/0065-Linux-2.6.37.patch
@@ -0,0 +1,25 @@
+From 52aefa299da0c025c4e521f2a40a89c01aad5a17 Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Tue, 4 Jan 2011 16:50:19 -0800
+Subject: [PATCH 65/65] Linux 2.6.37
+
+---
+ Makefile | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/Makefile b/Makefile
+index e7c41f1..74b2555 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ VERSION = 2
+ PATCHLEVEL = 6
+ SUBLEVEL = 37
+-EXTRAVERSION = -rc8
++EXTRAVERSION =
+ NAME = Flesh-Eating Bats with Fangs
+
+ # *DOCUMENTATION*
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0001-v4l-Share-code-between-video_usercopy-and-video_ioct.patch b/extras/recipes-kernel/linux/linux-omap/media/0001-v4l-Share-code-between-video_usercopy-and-video_ioct.patch
new file mode 100644
index 00000000..f2120201
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0001-v4l-Share-code-between-video_usercopy-and-video_ioct.patch
@@ -0,0 +1,297 @@
+From d71c2e533be956a95e4ddde8b87f657ada3c9de3 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Mon, 12 Jul 2010 16:09:41 +0200
+Subject: [PATCH 01/43] v4l: Share code between video_usercopy and video_ioctl2
+
+The two functions are mostly identical. They handle the copy_from_user
+and copy_to_user operations related with V4L2 ioctls and call the real
+ioctl handler.
+
+Create a __video_usercopy function that implements the core of
+video_usercopy and video_ioctl2, and call that function from both.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ drivers/media/video/v4l2-ioctl.c | 218 ++++++++++++-------------------------
+ 1 files changed, 71 insertions(+), 147 deletions(-)
+
+diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
+index dd9283f..1e01554 100644
+--- a/drivers/media/video/v4l2-ioctl.c
++++ b/drivers/media/video/v4l2-ioctl.c
+@@ -374,35 +374,62 @@ video_fix_command(unsigned int cmd)
+ }
+ #endif
+
+-/*
+- * Obsolete usercopy function - Should be removed soon
+- */
+-long
+-video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
++/* In some cases, only a few fields are used as input, i.e. when the app sets
++ * "index" and then the driver fills in the rest of the structure for the thing
++ * with that index. We only need to copy up the first non-input field. */
++static unsigned long cmd_input_size(unsigned int cmd)
++{
++ /* Size of structure up to and including 'field' */
++#define CMDINSIZE(cmd, type, field) \
++ case VIDIOC_##cmd: \
++ return offsetof(struct v4l2_##type, field) + \
++ sizeof(((struct v4l2_##type *)0)->field);
++
++ switch (cmd) {
++ CMDINSIZE(ENUM_FMT, fmtdesc, type);
++ CMDINSIZE(G_FMT, format, type);
++ CMDINSIZE(QUERYBUF, buffer, type);
++ CMDINSIZE(G_PARM, streamparm, type);
++ CMDINSIZE(ENUMSTD, standard, index);
++ CMDINSIZE(ENUMINPUT, input, index);
++ CMDINSIZE(G_CTRL, control, id);
++ CMDINSIZE(G_TUNER, tuner, index);
++ CMDINSIZE(QUERYCTRL, queryctrl, id);
++ CMDINSIZE(QUERYMENU, querymenu, index);
++ CMDINSIZE(ENUMOUTPUT, output, index);
++ CMDINSIZE(G_MODULATOR, modulator, index);
++ CMDINSIZE(G_FREQUENCY, frequency, tuner);
++ CMDINSIZE(CROPCAP, cropcap, type);
++ CMDINSIZE(G_CROP, crop, type);
++ CMDINSIZE(ENUMAUDIO, audio, index);
++ CMDINSIZE(ENUMAUDOUT, audioout, index);
++ CMDINSIZE(ENCODER_CMD, encoder_cmd, flags);
++ CMDINSIZE(TRY_ENCODER_CMD, encoder_cmd, flags);
++ CMDINSIZE(G_SLICED_VBI_CAP, sliced_vbi_cap, type);
++ CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format);
++ CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height);
++ default:
++ return _IOC_SIZE(cmd);
++ }
++}
++
++static long
++__video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+ v4l2_kioctl func)
+ {
+ char sbuf[128];
+ void *mbuf = NULL;
+- void *parg = NULL;
++ void *parg = (void *)arg;
+ long err = -EINVAL;
+ int is_ext_ctrl;
+ size_t ctrls_size = 0;
+ void __user *user_ptr = NULL;
+
+-#ifdef __OLD_VIDIOC_
+- cmd = video_fix_command(cmd);
+-#endif
+ is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
+ cmd == VIDIOC_TRY_EXT_CTRLS);
+
+ /* Copy arguments into temp kernel buffer */
+- switch (_IOC_DIR(cmd)) {
+- case _IOC_NONE:
+- parg = NULL;
+- break;
+- case _IOC_READ:
+- case _IOC_WRITE:
+- case (_IOC_WRITE | _IOC_READ):
++ if (_IOC_DIR(cmd) != _IOC_NONE) {
+ if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+ parg = sbuf;
+ } else {
+@@ -414,11 +441,21 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+ }
+
+ err = -EFAULT;
+- if (_IOC_DIR(cmd) & _IOC_WRITE)
+- if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
++ if (_IOC_DIR(cmd) & _IOC_WRITE) {
++ unsigned long n = cmd_input_size(cmd);
++
++ if (copy_from_user(parg, (void __user *)arg, n))
+ goto out;
+- break;
++
++ /* zero out anything we don't copy from userspace */
++ if (n < _IOC_SIZE(cmd))
++ memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n);
++ } else {
++ /* read-only ioctl */
++ memset(parg, 0, _IOC_SIZE(cmd));
++ }
+ }
++
+ if (is_ext_ctrl) {
+ struct v4l2_ext_controls *p = parg;
+
+@@ -440,7 +477,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+ }
+ }
+
+- /* call driver */
++ /* Handles IOCTL */
+ err = func(file, cmd, parg);
+ if (err == -ENOIOCTLCMD)
+ err = -EINVAL;
+@@ -469,6 +506,19 @@ out:
+ kfree(mbuf);
+ return err;
+ }
++
++/*
++ * Obsolete usercopy function - Should be removed soon
++ */
++long
++video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
++ v4l2_kioctl func)
++{
++#ifdef __OLD_VIDIOC_
++ cmd = video_fix_command(cmd);
++#endif
++ return __video_usercopy(file, cmd, arg, func);
++}
+ EXPORT_SYMBOL(video_usercopy);
+
+ static void dbgbuf(unsigned int cmd, struct video_device *vfd,
+@@ -2041,138 +2091,12 @@ static long __video_do_ioctl(struct file *file,
+ return ret;
+ }
+
+-/* In some cases, only a few fields are used as input, i.e. when the app sets
+- * "index" and then the driver fills in the rest of the structure for the thing
+- * with that index. We only need to copy up the first non-input field. */
+-static unsigned long cmd_input_size(unsigned int cmd)
+-{
+- /* Size of structure up to and including 'field' */
+-#define CMDINSIZE(cmd, type, field) \
+- case VIDIOC_##cmd: \
+- return offsetof(struct v4l2_##type, field) + \
+- sizeof(((struct v4l2_##type *)0)->field);
+-
+- switch (cmd) {
+- CMDINSIZE(ENUM_FMT, fmtdesc, type);
+- CMDINSIZE(G_FMT, format, type);
+- CMDINSIZE(QUERYBUF, buffer, type);
+- CMDINSIZE(G_PARM, streamparm, type);
+- CMDINSIZE(ENUMSTD, standard, index);
+- CMDINSIZE(ENUMINPUT, input, index);
+- CMDINSIZE(G_CTRL, control, id);
+- CMDINSIZE(G_TUNER, tuner, index);
+- CMDINSIZE(QUERYCTRL, queryctrl, id);
+- CMDINSIZE(QUERYMENU, querymenu, index);
+- CMDINSIZE(ENUMOUTPUT, output, index);
+- CMDINSIZE(G_MODULATOR, modulator, index);
+- CMDINSIZE(G_FREQUENCY, frequency, tuner);
+- CMDINSIZE(CROPCAP, cropcap, type);
+- CMDINSIZE(G_CROP, crop, type);
+- CMDINSIZE(ENUMAUDIO, audio, index);
+- CMDINSIZE(ENUMAUDOUT, audioout, index);
+- CMDINSIZE(ENCODER_CMD, encoder_cmd, flags);
+- CMDINSIZE(TRY_ENCODER_CMD, encoder_cmd, flags);
+- CMDINSIZE(G_SLICED_VBI_CAP, sliced_vbi_cap, type);
+- CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format);
+- CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height);
+- default:
+- return _IOC_SIZE(cmd);
+- }
+-}
+-
+ long video_ioctl2(struct file *file,
+ unsigned int cmd, unsigned long arg)
+ {
+- char sbuf[128];
+- void *mbuf = NULL;
+- void *parg = (void *)arg;
+- long err = -EINVAL;
+- int is_ext_ctrl;
+- size_t ctrls_size = 0;
+- void __user *user_ptr = NULL;
+-
+ #ifdef __OLD_VIDIOC_
+ cmd = video_fix_command(cmd);
+ #endif
+- is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
+- cmd == VIDIOC_TRY_EXT_CTRLS);
+-
+- /* Copy arguments into temp kernel buffer */
+- if (_IOC_DIR(cmd) != _IOC_NONE) {
+- if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+- parg = sbuf;
+- } else {
+- /* too big to allocate from stack */
+- mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
+- if (NULL == mbuf)
+- return -ENOMEM;
+- parg = mbuf;
+- }
+-
+- err = -EFAULT;
+- if (_IOC_DIR(cmd) & _IOC_WRITE) {
+- unsigned long n = cmd_input_size(cmd);
+-
+- if (copy_from_user(parg, (void __user *)arg, n))
+- goto out;
+-
+- /* zero out anything we don't copy from userspace */
+- if (n < _IOC_SIZE(cmd))
+- memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n);
+- } else {
+- /* read-only ioctl */
+- memset(parg, 0, _IOC_SIZE(cmd));
+- }
+- }
+-
+- if (is_ext_ctrl) {
+- struct v4l2_ext_controls *p = parg;
+-
+- /* In case of an error, tell the caller that it wasn't
+- a specific control that caused it. */
+- p->error_idx = p->count;
+- user_ptr = (void __user *)p->controls;
+- if (p->count) {
+- ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
+- /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
+- mbuf = kmalloc(ctrls_size, GFP_KERNEL);
+- err = -ENOMEM;
+- if (NULL == mbuf)
+- goto out_ext_ctrl;
+- err = -EFAULT;
+- if (copy_from_user(mbuf, user_ptr, ctrls_size))
+- goto out_ext_ctrl;
+- p->controls = mbuf;
+- }
+- }
+-
+- /* Handles IOCTL */
+- err = __video_do_ioctl(file, cmd, parg);
+- if (err == -ENOIOCTLCMD)
+- err = -EINVAL;
+- if (is_ext_ctrl) {
+- struct v4l2_ext_controls *p = parg;
+-
+- p->controls = (void *)user_ptr;
+- if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
+- err = -EFAULT;
+- goto out_ext_ctrl;
+- }
+- if (err < 0)
+- goto out;
+-
+-out_ext_ctrl:
+- /* Copy results into user buffer */
+- switch (_IOC_DIR(cmd)) {
+- case _IOC_READ:
+- case (_IOC_WRITE | _IOC_READ):
+- if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
+- err = -EFAULT;
+- break;
+- }
+-
+-out:
+- kfree(mbuf);
+- return err;
++ return __video_usercopy(file, cmd, arg, __video_do_ioctl);
+ }
+ EXPORT_SYMBOL(video_ioctl2);
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0002-v4l-subdev-Don-t-require-core-operations.patch b/extras/recipes-kernel/linux/linux-omap/media/0002-v4l-subdev-Don-t-require-core-operations.patch
new file mode 100644
index 00000000..c53c18e4
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0002-v4l-subdev-Don-t-require-core-operations.patch
@@ -0,0 +1,31 @@
+From e501e49dfa290479eaf23fcc5bd0623102220e0c Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Mon, 31 May 2010 11:33:06 +0300
+Subject: [PATCH 02/43] v4l: subdev: Don't require core operations
+
+There's no reason to require subdevices to implement the core
+operations. Remove the check for non-NULL core operations when
+initializing the subdev.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ include/media/v4l2-subdev.h | 3 +--
+ 1 files changed, 1 insertions(+), 2 deletions(-)
+
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index b0316a7..b636444 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -466,8 +466,7 @@ static inline void v4l2_subdev_init(struct v4l2_subdev *sd,
+ const struct v4l2_subdev_ops *ops)
+ {
+ INIT_LIST_HEAD(&sd->list);
+- /* ops->core MUST be set */
+- BUG_ON(!ops || !ops->core);
++ BUG_ON(!ops);
+ sd->ops = ops;
+ sd->v4l2_dev = NULL;
+ sd->flags = 0;
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0003-v4l-subdev-Merge-v4l2_i2c_new_subdev_cfg-and-v4l2_i2.patch b/extras/recipes-kernel/linux/linux-omap/media/0003-v4l-subdev-Merge-v4l2_i2c_new_subdev_cfg-and-v4l2_i2.patch
new file mode 100644
index 00000000..6cca7eaa
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0003-v4l-subdev-Merge-v4l2_i2c_new_subdev_cfg-and-v4l2_i2.patch
@@ -0,0 +1,132 @@
+From 2c7009851d70caeb91ac806b133b7d77c5c2ca19 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Thu, 8 Jul 2010 12:01:09 +0200
+Subject: [PATCH 03/43] v4l: subdev: Merge v4l2_i2c_new_subdev_cfg and v4l2_i2c_new_subdev
+
+v4l2_i2c_new_subdev is a thin wrapper around v4l2_i2c_new_subdev_cfg,
+which is itself a wrapper around v4l2_i2c_new_subdev_board.
+
+The intermediate v4l2_i2c_new_subdev_cfg function is called directly by
+the ivtv and cafe-ccic drivers only. Merge it with v4l2_i2c_new_subdev
+and use v4l2_i2c_new_subdev_board in the ivtv and cafe-ccic drivers.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ drivers/media/video/cafe_ccic.c | 11 +++++++++--
+ drivers/media/video/ivtv/ivtv-i2c.c | 11 +++++++++--
+ drivers/media/video/v4l2-common.c | 7 ++-----
+ include/media/v4l2-common.h | 13 +------------
+ 4 files changed, 21 insertions(+), 21 deletions(-)
+
+diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
+index 0dfff50..6e23add 100644
+--- a/drivers/media/video/cafe_ccic.c
++++ b/drivers/media/video/cafe_ccic.c
+@@ -1992,6 +1992,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
+ {
+ int ret;
+ struct cafe_camera *cam;
++ struct i2c_board_info info;
+ struct ov7670_config sensor_cfg = {
+ /* This controller only does SMBUS */
+ .use_smbus = true,
+@@ -2065,8 +2066,14 @@ static int cafe_pci_probe(struct pci_dev *pdev,
+ sensor_cfg.clock_speed = 45;
+
+ cam->sensor_addr = 0x42;
+- cam->sensor = v4l2_i2c_new_subdev_cfg(&cam->v4l2_dev, &cam->i2c_adapter,
+- "ov7670", 0, &sensor_cfg, cam->sensor_addr, NULL);
++
++ memset(&info, 0, sizeof(info));
++ strlcpy(info.type, "ov7670", sizeof(info.type));
++ info.addr = cam->sensor_addr;
++ info.platform_data = &sensor_cfg;
++
++ cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev,
++ &cam->i2c_adapter, &info, NULL);
+ if (cam->sensor == NULL) {
+ ret = -ENODEV;
+ goto out_smbus;
+diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
+index 665191c..6651a6c 100644
+--- a/drivers/media/video/ivtv/ivtv-i2c.c
++++ b/drivers/media/video/ivtv/ivtv-i2c.c
+@@ -267,10 +267,17 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
+ adap, type, 0, I2C_ADDRS(hw_addrs[idx]));
+ } else if (hw == IVTV_HW_CX25840) {
+ struct cx25840_platform_data pdata;
++ struct i2c_board_info info;
+
+ pdata.pvr150_workaround = itv->pvr150_workaround;
+- sd = v4l2_i2c_new_subdev_cfg(&itv->v4l2_dev,
+- adap, type, 0, &pdata, hw_addrs[idx], NULL);
++
++ memset(&info, 0, sizeof(info));
++ strlcpy(info.type, type, sizeof(info.type));
++ info.addr = hw_addrs[idx];
++ info.platform_data = &pdata;
++
++ sd = v4l2_i2c_new_subdev_board(&itv->v4l2_dev, adap, &info,
++ NULL);
+ } else {
+ sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
+ adap, type, hw_addrs[idx], NULL);
+diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
+index b5eb1f3..e007e61 100644
+--- a/drivers/media/video/v4l2-common.c
++++ b/drivers/media/video/v4l2-common.c
+@@ -428,9 +428,8 @@ error:
+ }
+ EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board);
+
+-struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
++struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
+ struct i2c_adapter *adapter, const char *client_type,
+- int irq, void *platform_data,
+ u8 addr, const unsigned short *probe_addrs)
+ {
+ struct i2c_board_info info;
+@@ -440,12 +439,10 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
+ memset(&info, 0, sizeof(info));
+ strlcpy(info.type, client_type, sizeof(info.type));
+ info.addr = addr;
+- info.irq = irq;
+- info.platform_data = platform_data;
+
+ return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, probe_addrs);
+ }
+-EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_cfg);
++EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev);
+
+ /* Return i2c client address of v4l2_subdev. */
+ unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd)
+diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
+index 239125a..565fb32 100644
+--- a/include/media/v4l2-common.h
++++ b/include/media/v4l2-common.h
+@@ -138,21 +138,10 @@ struct v4l2_subdev_ops;
+
+ /* Load an i2c module and return an initialized v4l2_subdev struct.
+ The client_type argument is the name of the chip that's on the adapter. */
+-struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
++struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
+ struct i2c_adapter *adapter, const char *client_type,
+- int irq, void *platform_data,
+ u8 addr, const unsigned short *probe_addrs);
+
+-/* Load an i2c module and return an initialized v4l2_subdev struct.
+- The client_type argument is the name of the chip that's on the adapter. */
+-static inline struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
+- struct i2c_adapter *adapter, const char *client_type,
+- u8 addr, const unsigned short *probe_addrs)
+-{
+- return v4l2_i2c_new_subdev_cfg(v4l2_dev, adapter, client_type, 0, NULL,
+- addr, probe_addrs);
+-}
+-
+ struct i2c_board_info;
+
+ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0004-v4l-subdev-Add-device-node-support.patch b/extras/recipes-kernel/linux/linux-omap/media/0004-v4l-subdev-Add-device-node-support.patch
new file mode 100644
index 00000000..8fe2a9d6
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0004-v4l-subdev-Add-device-node-support.patch
@@ -0,0 +1,615 @@
+From e5b8af4e36ca5e922dd2b881d6c215e9d4d30a6f Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:38:49 +0100
+Subject: [PATCH 04/43] v4l: subdev: Add device node support
+
+Create a device node named subdevX for every registered subdev.
+
+As the device node is registered before the subdev core::s_config
+function is called, return -EGAIN on open until initialization
+completes.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Vimarsh Zutshi <vimarsh.zutshi@nokia.com>
+---
+ Documentation/video4linux/v4l2-framework.txt | 18 +++++++
+ drivers/media/radio/radio-si4713.c | 2 +-
+ drivers/media/video/Makefile | 2 +-
+ drivers/media/video/cafe_ccic.c | 2 +-
+ drivers/media/video/davinci/vpfe_capture.c | 2 +-
+ drivers/media/video/davinci/vpif_capture.c | 2 +-
+ drivers/media/video/davinci/vpif_display.c | 2 +-
+ drivers/media/video/ivtv/ivtv-i2c.c | 2 +-
+ drivers/media/video/s5p-fimc/fimc-capture.c | 2 +-
+ drivers/media/video/sh_vou.c | 2 +-
+ drivers/media/video/soc_camera.c | 2 +-
+ drivers/media/video/v4l2-common.c | 15 +++++-
+ drivers/media/video/v4l2-dev.c | 27 ++++------
+ drivers/media/video/v4l2-device.c | 24 +++++++++-
+ drivers/media/video/v4l2-ioctl.c | 2 +-
+ drivers/media/video/v4l2-subdev.c | 66 ++++++++++++++++++++++++++
+ include/media/v4l2-common.h | 5 +-
+ include/media/v4l2-dev.h | 18 ++++++-
+ include/media/v4l2-ioctl.h | 3 +
+ include/media/v4l2-subdev.h | 16 ++++++-
+ 20 files changed, 176 insertions(+), 38 deletions(-)
+ create mode 100644 drivers/media/video/v4l2-subdev.c
+
+diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
+index f22f35c..4c9185a 100644
+--- a/Documentation/video4linux/v4l2-framework.txt
++++ b/Documentation/video4linux/v4l2-framework.txt
+@@ -319,6 +319,24 @@ controlled through GPIO pins. This distinction is only relevant when setting
+ up the device, but once the subdev is registered it is completely transparent.
+
+
++V4L2 sub-device userspace API
++-----------------------------
++
++Beside exposing a kernel API through the v4l2_subdev_ops structure, V4L2
++sub-devices can also be controlled directly by userspace applications.
++
++When a sub-device is registered, a device node named v4l-subdevX can be created
++in /dev. If the sub-device supports direct userspace configuration it must set
++the V4L2_SUBDEV_FL_HAS_DEVNODE flag before being registered.
++
++For I2C and SPI sub-devices, the v4l2_device driver can disable registration of
++the device node if it wants to control the sub-device on its own. In that case
++it must set the v4l2_i2c_new_subdev_board or v4l2_spi_new_subdev enable_devnode
++argument to 0. Setting the argument to 1 will only enable device node
++registration if the sub-device driver has set the V4L2_SUBDEV_FL_HAS_DEVNODE
++flag.
++
++
+ I2C sub-device drivers
+ ----------------------
+
+diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c
+index 726d367..f7c942f 100644
+--- a/drivers/media/radio/radio-si4713.c
++++ b/drivers/media/radio/radio-si4713.c
+@@ -293,7 +293,7 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
+ }
+
+ sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter,
+- pdata->subdev_board_info, NULL);
++ pdata->subdev_board_info, NULL, 0);
+ if (!sd) {
+ dev_err(&pdev->dev, "Cannot get v4l2 subdevice\n");
+ rval = -ENODEV;
+diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
+index af79d47..adc1bd5 100644
+--- a/drivers/media/video/Makefile
++++ b/drivers/media/video/Makefile
+@@ -11,7 +11,7 @@ stkwebcam-objs := stk-webcam.o stk-sensor.o
+ omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o
+
+ videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
+- v4l2-event.o v4l2-ctrls.o
++ v4l2-event.o v4l2-ctrls.o v4l2-subdev.o
+
+ # V4L2 core modules
+
+diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
+index 6e23add..f932da1 100644
+--- a/drivers/media/video/cafe_ccic.c
++++ b/drivers/media/video/cafe_ccic.c
+@@ -2073,7 +2073,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
+ info.platform_data = &sensor_cfg;
+
+ cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev,
+- &cam->i2c_adapter, &info, NULL);
++ &cam->i2c_adapter, &info, NULL, 0);
+ if (cam->sensor == NULL) {
+ ret = -ENODEV;
+ goto out_smbus;
+diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c
+index 7333a9b..bfc2a47 100644
+--- a/drivers/media/video/davinci/vpfe_capture.c
++++ b/drivers/media/video/davinci/vpfe_capture.c
+@@ -1987,7 +1987,7 @@ static __init int vpfe_probe(struct platform_device *pdev)
+ v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev,
+ i2c_adap,
+ &sdinfo->board_info,
+- NULL);
++ NULL, 0);
+ if (vpfe_dev->sd[i]) {
+ v4l2_info(&vpfe_dev->v4l2_dev,
+ "v4l2 sub device %s registered\n",
+diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c
+index 193abab..d2228e0 100644
+--- a/drivers/media/video/davinci/vpif_capture.c
++++ b/drivers/media/video/davinci/vpif_capture.c
+@@ -2014,7 +2014,7 @@ static __init int vpif_probe(struct platform_device *pdev)
+ v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
+ i2c_adap,
+ &subdevdata->board_info,
+- NULL);
++ NULL, 0);
+
+ if (!vpif_obj.sd[i]) {
+ vpif_err("Error registering v4l2 subdevice\n");
+diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c
+index 412c65d..060c049 100644
+--- a/drivers/media/video/davinci/vpif_display.c
++++ b/drivers/media/video/davinci/vpif_display.c
+@@ -1555,7 +1555,7 @@ static __init int vpif_probe(struct platform_device *pdev)
+ vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
+ i2c_adap,
+ &subdevdata[i].board_info,
+- NULL);
++ NULL, 0);
+ if (!vpif_obj.sd[i]) {
+ vpif_err("Error registering v4l2 subdevice\n");
+ goto probe_subdev_out;
+diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
+index 6651a6c..3d3b62d 100644
+--- a/drivers/media/video/ivtv/ivtv-i2c.c
++++ b/drivers/media/video/ivtv/ivtv-i2c.c
+@@ -277,7 +277,7 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
+ info.platform_data = &pdata;
+
+ sd = v4l2_i2c_new_subdev_board(&itv->v4l2_dev, adap, &info,
+- NULL);
++ NULL, 0);
+ } else {
+ sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
+ adap, type, hw_addrs[idx], NULL);
+diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
+index 2f50080..b237daa 100644
+--- a/drivers/media/video/s5p-fimc/fimc-capture.c
++++ b/drivers/media/video/s5p-fimc/fimc-capture.c
+@@ -44,7 +44,7 @@ static struct v4l2_subdev *fimc_subdev_register(struct fimc_dev *fimc,
+ return ERR_PTR(-ENOMEM);
+
+ sd = v4l2_i2c_new_subdev_board(&vid_cap->v4l2_dev, i2c_adap,
+- isp_info->board_info, NULL);
++ isp_info->board_info, NULL, 0);
+ if (!sd) {
+ v4l2_err(&vid_cap->v4l2_dev, "failed to acquire subdev\n");
+ return NULL;
+diff --git a/drivers/media/video/sh_vou.c b/drivers/media/video/sh_vou.c
+index 07cf0c6..c50f0f5 100644
+--- a/drivers/media/video/sh_vou.c
++++ b/drivers/media/video/sh_vou.c
+@@ -1409,7 +1409,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev)
+ goto ereset;
+
+ subdev = v4l2_i2c_new_subdev_board(&vou_dev->v4l2_dev, i2c_adap,
+- vou_pdata->board_info, NULL);
++ vou_pdata->board_info, NULL, 0);
+ if (!subdev) {
+ ret = -ENOMEM;
+ goto ei2cnd;
+diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
+index 052bd6d..5afb601 100644
+--- a/drivers/media/video/soc_camera.c
++++ b/drivers/media/video/soc_camera.c
+@@ -896,7 +896,7 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
+ icl->board_info->platform_data = icd;
+
+ subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
+- icl->board_info, NULL);
++ icl->board_info, NULL, 0);
+ if (!subdev)
+ goto ei2cnd;
+
+diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
+index e007e61..ffee794 100644
+--- a/drivers/media/video/v4l2-common.c
++++ b/drivers/media/video/v4l2-common.c
+@@ -369,7 +369,7 @@ EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init);
+ /* Load an i2c sub-device. */
+ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
+ struct i2c_adapter *adapter, struct i2c_board_info *info,
+- const unsigned short *probe_addrs)
++ const unsigned short *probe_addrs, int enable_devnode)
+ {
+ struct v4l2_subdev *sd = NULL;
+ struct i2c_client *client;
+@@ -399,9 +399,12 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
+ if (!try_module_get(client->driver->driver.owner))
+ goto error;
+ sd = i2c_get_clientdata(client);
++ if (!enable_devnode)
++ sd->flags &= ~V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ /* Register with the v4l2_device which increases the module's
+ use count as well. */
++ sd->initialized = 0;
+ if (v4l2_device_register_subdev(v4l2_dev, sd))
+ sd = NULL;
+ /* Decrease the module use count to match the first try_module_get. */
+@@ -416,6 +419,8 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
+ if (err && err != -ENOIOCTLCMD) {
+ v4l2_device_unregister_subdev(sd);
+ sd = NULL;
++ } else {
++ sd->initialized = 1;
+ }
+ }
+
+@@ -440,7 +445,8 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
+ strlcpy(info.type, client_type, sizeof(info.type));
+ info.addr = addr;
+
+- return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, probe_addrs);
++ return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, probe_addrs,
++ 0);
+ }
+ EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev);
+
+@@ -510,7 +516,8 @@ void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi,
+ EXPORT_SYMBOL_GPL(v4l2_spi_subdev_init);
+
+ struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev,
+- struct spi_master *master, struct spi_board_info *info)
++ struct spi_master *master, struct spi_board_info *info,
++ int enable_devnode)
+ {
+ struct v4l2_subdev *sd = NULL;
+ struct spi_device *spi = NULL;
+@@ -529,6 +536,8 @@ struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev,
+ goto error;
+
+ sd = spi_get_drvdata(spi);
++ if (!enable_devnode)
++ sd->flags &= ~V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ /* Register with the v4l2_device which increases the module's
+ use count as well. */
+diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
+index 359e232..f22bd41 100644
+--- a/drivers/media/video/v4l2-dev.c
++++ b/drivers/media/video/v4l2-dev.c
+@@ -408,13 +408,14 @@ static int get_index(struct video_device *vdev)
+ }
+
+ /**
+- * video_register_device - register video4linux devices
++ * __video_register_device - register video4linux devices
+ * @vdev: video device structure we want to register
+ * @type: type of device to register
+ * @nr: which device node number (0 == /dev/video0, 1 == /dev/video1, ...
+ * -1 == first free)
+ * @warn_if_nr_in_use: warn if the desired device node number
+ * was already in use and another number was chosen instead.
++ * @owner: module that owns the video device node
+ *
+ * The registration code assigns minor numbers and device node numbers
+ * based on the requested type and registers the new device node with
+@@ -431,9 +432,11 @@ static int get_index(struct video_device *vdev)
+ * %VFL_TYPE_VBI - Vertical blank data (undecoded)
+ *
+ * %VFL_TYPE_RADIO - A radio card
++ *
++ * %VFL_TYPE_SUBDEV - A subdevice
+ */
+-static int __video_register_device(struct video_device *vdev, int type, int nr,
+- int warn_if_nr_in_use)
++int __video_register_device(struct video_device *vdev, int type, int nr,
++ int warn_if_nr_in_use, struct module *owner)
+ {
+ int i = 0;
+ int ret;
+@@ -466,6 +469,9 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
+ case VFL_TYPE_RADIO:
+ name_base = "radio";
+ break;
++ case VFL_TYPE_SUBDEV:
++ name_base = "v4l-subdev";
++ break;
+ default:
+ printk(KERN_ERR "%s called with unknown type: %d\n",
+ __func__, type);
+@@ -549,7 +555,7 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
+ goto cleanup;
+ }
+ vdev->cdev->ops = &v4l2_fops;
+- vdev->cdev->owner = vdev->fops->owner;
++ vdev->cdev->owner = owner;
+ ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: cdev_add failed\n", __func__);
+@@ -598,18 +604,7 @@ cleanup:
+ vdev->minor = -1;
+ return ret;
+ }
+-
+-int video_register_device(struct video_device *vdev, int type, int nr)
+-{
+- return __video_register_device(vdev, type, nr, 1);
+-}
+-EXPORT_SYMBOL(video_register_device);
+-
+-int video_register_device_no_warn(struct video_device *vdev, int type, int nr)
+-{
+- return __video_register_device(vdev, type, nr, 0);
+-}
+-EXPORT_SYMBOL(video_register_device_no_warn);
++EXPORT_SYMBOL(__video_register_device);
+
+ /**
+ * video_unregister_device - unregister a video4linux device
+diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
+index 7fe6f92..97e84df 100644
+--- a/drivers/media/video/v4l2-device.c
++++ b/drivers/media/video/v4l2-device.c
+@@ -117,24 +117,43 @@ EXPORT_SYMBOL_GPL(v4l2_device_unregister);
+ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
+ struct v4l2_subdev *sd)
+ {
++ struct video_device *vdev;
+ int err;
+
+ /* Check for valid input */
+ if (v4l2_dev == NULL || sd == NULL || !sd->name[0])
+ return -EINVAL;
++
+ /* Warn if we apparently re-register a subdev */
+ WARN_ON(sd->v4l2_dev != NULL);
++
+ if (!try_module_get(sd->owner))
+ return -ENODEV;
++
+ /* This just returns 0 if either of the two args is NULL */
+ err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler);
+ if (err)
+ return err;
++
+ sd->v4l2_dev = v4l2_dev;
+ spin_lock(&v4l2_dev->lock);
+ list_add_tail(&sd->list, &v4l2_dev->subdevs);
+ spin_unlock(&v4l2_dev->lock);
+- return 0;
++
++ /* Register the device node. */
++ vdev = &sd->devnode;
++ strlcpy(vdev->name, sd->name, sizeof(vdev->name));
++ vdev->parent = v4l2_dev->dev;
++ vdev->fops = &v4l2_subdev_fops;
++ vdev->release = video_device_release_empty;
++ if (sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE) {
++ err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
++ sd->owner);
++ if (err < 0)
++ v4l2_device_unregister_subdev(sd);
++ }
++
++ return err;
+ }
+ EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
+
+@@ -143,10 +162,13 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
+ /* return if it isn't registered */
+ if (sd == NULL || sd->v4l2_dev == NULL)
+ return;
++
+ spin_lock(&sd->v4l2_dev->lock);
+ list_del(&sd->list);
+ spin_unlock(&sd->v4l2_dev->lock);
+ sd->v4l2_dev = NULL;
++
+ module_put(sd->owner);
++ video_unregister_device(&sd->devnode);
+ }
+ EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
+diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
+index 1e01554..4137e4c 100644
+--- a/drivers/media/video/v4l2-ioctl.c
++++ b/drivers/media/video/v4l2-ioctl.c
+@@ -413,7 +413,7 @@ static unsigned long cmd_input_size(unsigned int cmd)
+ }
+ }
+
+-static long
++long
+ __video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+ v4l2_kioctl func)
+ {
+diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
+new file mode 100644
+index 0000000..00bd4b1
+--- /dev/null
++++ b/drivers/media/video/v4l2-subdev.c
+@@ -0,0 +1,66 @@
++/*
++ * V4L2 subdevice support.
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ *
++ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/types.h>
++#include <linux/ioctl.h>
++#include <linux/videodev2.h>
++
++#include <media/v4l2-device.h>
++#include <media/v4l2-ioctl.h>
++
++static int subdev_open(struct file *file)
++{
++ struct video_device *vdev = video_devdata(file);
++ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
++
++ if (!sd->initialized)
++ return -EAGAIN;
++
++ return 0;
++}
++
++static int subdev_close(struct file *file)
++{
++ return 0;
++}
++
++static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
++{
++ switch (cmd) {
++ default:
++ return -ENOIOCTLCMD;
++ }
++
++ return 0;
++}
++
++static long subdev_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ return __video_usercopy(file, cmd, arg, subdev_do_ioctl);
++}
++
++const struct v4l2_file_operations v4l2_subdev_fops = {
++ .owner = THIS_MODULE,
++ .open = subdev_open,
++ .unlocked_ioctl = subdev_ioctl,
++ .release = subdev_close,
++};
+diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
+index 565fb32..ef8965d 100644
+--- a/include/media/v4l2-common.h
++++ b/include/media/v4l2-common.h
+@@ -146,7 +146,7 @@ struct i2c_board_info;
+
+ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
+ struct i2c_adapter *adapter, struct i2c_board_info *info,
+- const unsigned short *probe_addrs);
++ const unsigned short *probe_addrs, int enable_devnode);
+
+ /* Initialize an v4l2_subdev with data from an i2c_client struct */
+ void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
+@@ -179,7 +179,8 @@ struct spi_device;
+ /* Load an spi module and return an initialized v4l2_subdev struct.
+ The client_type argument is the name of the chip that's on the adapter. */
+ struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev,
+- struct spi_master *master, struct spi_board_info *info);
++ struct spi_master *master, struct spi_board_info *info,
++ int enable_devnode);
+
+ /* Initialize an v4l2_subdev with data from an spi_device struct */
+ void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi,
+diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
+index 15802a0..4fe6831 100644
+--- a/include/media/v4l2-dev.h
++++ b/include/media/v4l2-dev.h
+@@ -21,7 +21,8 @@
+ #define VFL_TYPE_GRABBER 0
+ #define VFL_TYPE_VBI 1
+ #define VFL_TYPE_RADIO 2
+-#define VFL_TYPE_MAX 3
++#define VFL_TYPE_SUBDEV 3
++#define VFL_TYPE_MAX 4
+
+ struct v4l2_ioctl_callbacks;
+ struct video_device;
+@@ -102,15 +103,26 @@ struct video_device
+ /* dev to video-device */
+ #define to_video_device(cd) container_of(cd, struct video_device, dev)
+
++int __must_check __video_register_device(struct video_device *vdev, int type,
++ int nr, int warn_if_nr_in_use, struct module *owner);
++
+ /* Register video devices. Note that if video_register_device fails,
+ the release() callback of the video_device structure is *not* called, so
+ the caller is responsible for freeing any data. Usually that means that
+ you call video_device_release() on failure. */
+-int __must_check video_register_device(struct video_device *vdev, int type, int nr);
++static inline int __must_check video_register_device(struct video_device *vdev,
++ int type, int nr)
++{
++ return __video_register_device(vdev, type, nr, 1, vdev->fops->owner);
++}
+
+ /* Same as video_register_device, but no warning is issued if the desired
+ device node number was already in use. */
+-int __must_check video_register_device_no_warn(struct video_device *vdev, int type, int nr);
++static inline int __must_check video_register_device_no_warn(
++ struct video_device *vdev, int type, int nr)
++{
++ return __video_register_device(vdev, type, nr, 0, vdev->fops->owner);
++}
+
+ /* Unregister video devices. Will do nothing if vdev == NULL or
+ video_is_registered() returns false. */
+diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
+index 06daa6e..abb64d0 100644
+--- a/include/media/v4l2-ioctl.h
++++ b/include/media/v4l2-ioctl.h
+@@ -316,6 +316,9 @@ extern long v4l2_compat_ioctl32(struct file *file, unsigned int cmd,
+ unsigned long arg);
+ #endif
+
++extern long __video_usercopy(struct file *file, unsigned int cmd,
++ unsigned long arg, v4l2_kioctl func);
++
+ /* Include support for obsoleted stuff */
+ extern long video_usercopy(struct file *file, unsigned int cmd,
+ unsigned long arg, v4l2_kioctl func);
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index b636444..de181db 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -22,6 +22,7 @@
+ #define _V4L2_SUBDEV_H
+
+ #include <media/v4l2-common.h>
++#include <media/v4l2-dev.h>
+ #include <media/v4l2-mediabus.h>
+
+ /* generic v4l2_device notify callback notification values */
+@@ -418,9 +419,11 @@ struct v4l2_subdev_ops {
+ #define V4L2_SUBDEV_NAME_SIZE 32
+
+ /* Set this flag if this subdev is a i2c device. */
+-#define V4L2_SUBDEV_FL_IS_I2C (1U << 0)
++#define V4L2_SUBDEV_FL_IS_I2C (1U << 0)
+ /* Set this flag if this subdev is a spi device. */
+-#define V4L2_SUBDEV_FL_IS_SPI (1U << 1)
++#define V4L2_SUBDEV_FL_IS_SPI (1U << 1)
++/* Set this flag if this subdev needs a device node. */
++#define V4L2_SUBDEV_FL_HAS_DEVNODE (1U << 2)
+
+ /* Each instance of a subdev driver should create this struct, either
+ stand-alone or embedded in a larger struct.
+@@ -440,8 +443,16 @@ struct v4l2_subdev {
+ /* pointer to private data */
+ void *dev_priv;
+ void *host_priv;
++ /* subdev device node */
++ struct video_device devnode;
++ unsigned int initialized;
+ };
+
++#define vdev_to_v4l2_subdev(vdev) \
++ container_of(vdev, struct v4l2_subdev, devnode)
++
++extern const struct v4l2_file_operations v4l2_subdev_fops;
++
+ static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p)
+ {
+ sd->dev_priv = p;
+@@ -474,6 +485,7 @@ static inline void v4l2_subdev_init(struct v4l2_subdev *sd,
+ sd->grp_id = 0;
+ sd->dev_priv = NULL;
+ sd->host_priv = NULL;
++ sd->initialized = 1;
+ }
+
+ /* Call an ops of a v4l2_subdev, doing the right checks against
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0005-v4l-subdev-Uninline-the-v4l2_subdev_init-function.patch b/extras/recipes-kernel/linux/linux-omap/media/0005-v4l-subdev-Uninline-the-v4l2_subdev_init-function.patch
new file mode 100644
index 00000000..a4e45e61
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0005-v4l-subdev-Uninline-the-v4l2_subdev_init-function.patch
@@ -0,0 +1,103 @@
+From 7acd77b0cdf013213a6513a75ee5bc2c3e92e1a1 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:38:52 +0100
+Subject: [PATCH 05/43] v4l: subdev: Uninline the v4l2_subdev_init function
+
+The function isn't small or performance sensitive enough to be inlined.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ drivers/media/video/v4l2-subdev.c | 42 +++++++++++++++++++++++++-----------
+ include/media/v4l2-subdev.h | 16 +------------
+ 2 files changed, 31 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
+index 00bd4b1..0deff78 100644
+--- a/drivers/media/video/v4l2-subdev.c
++++ b/drivers/media/video/v4l2-subdev.c
+@@ -1,22 +1,23 @@
+ /*
+- * V4L2 subdevice support.
++ * V4L2 sub-device
+ *
+- * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2010 Nokia Corporation
+ *
+- * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation.
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
+ *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
+ *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+ #include <linux/types.h>
+@@ -64,3 +65,18 @@ const struct v4l2_file_operations v4l2_subdev_fops = {
+ .unlocked_ioctl = subdev_ioctl,
+ .release = subdev_close,
+ };
++
++void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
++{
++ INIT_LIST_HEAD(&sd->list);
++ BUG_ON(!ops);
++ sd->ops = ops;
++ sd->v4l2_dev = NULL;
++ sd->flags = 0;
++ sd->name[0] = '\0';
++ sd->grp_id = 0;
++ sd->dev_priv = NULL;
++ sd->host_priv = NULL;
++ sd->initialized = 1;
++}
++EXPORT_SYMBOL(v4l2_subdev_init);
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index de181db..90022f5 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -473,20 +473,8 @@ static inline void *v4l2_get_subdev_hostdata(const struct v4l2_subdev *sd)
+ return sd->host_priv;
+ }
+
+-static inline void v4l2_subdev_init(struct v4l2_subdev *sd,
+- const struct v4l2_subdev_ops *ops)
+-{
+- INIT_LIST_HEAD(&sd->list);
+- BUG_ON(!ops);
+- sd->ops = ops;
+- sd->v4l2_dev = NULL;
+- sd->flags = 0;
+- sd->name[0] = '\0';
+- sd->grp_id = 0;
+- sd->dev_priv = NULL;
+- sd->host_priv = NULL;
+- sd->initialized = 1;
+-}
++void v4l2_subdev_init(struct v4l2_subdev *sd,
++ const struct v4l2_subdev_ops *ops);
+
+ /* Call an ops of a v4l2_subdev, doing the right checks against
+ NULL pointers.
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0006-v4l-subdev-Control-ioctls-support.patch b/extras/recipes-kernel/linux/linux-omap/media/0006-v4l-subdev-Control-ioctls-support.patch
new file mode 100644
index 00000000..218f3469
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0006-v4l-subdev-Control-ioctls-support.patch
@@ -0,0 +1,88 @@
+From dd0b366441249eb10daa2275e968431507f8d0d5 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:39:54 +0100
+Subject: [PATCH 06/43] v4l: subdev: Control ioctls support
+
+Pass the control-related ioctls to the subdev driver through the control
+framework.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ Documentation/video4linux/v4l2-framework.txt | 16 ++++++++++++++++
+ drivers/media/video/v4l2-subdev.c | 25 +++++++++++++++++++++++++
+ 2 files changed, 41 insertions(+), 0 deletions(-)
+
+diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
+index 4c9185a..f683f63 100644
+--- a/Documentation/video4linux/v4l2-framework.txt
++++ b/Documentation/video4linux/v4l2-framework.txt
+@@ -336,6 +336,22 @@ argument to 0. Setting the argument to 1 will only enable device node
+ registration if the sub-device driver has set the V4L2_SUBDEV_FL_HAS_DEVNODE
+ flag.
+
++The device node handles a subset of the V4L2 API.
++
++VIDIOC_QUERYCTRL
++VIDIOC_QUERYMENU
++VIDIOC_G_CTRL
++VIDIOC_S_CTRL
++VIDIOC_G_EXT_CTRLS
++VIDIOC_S_EXT_CTRLS
++VIDIOC_TRY_EXT_CTRLS
++
++ The controls ioctls are identical to the ones defined in V4L2. They
++ behave identically, with the only exception that they deal only with
++ controls implemented in the sub-device. Depending on the driver, those
++ controls can be also be accessed through one (or several) V4L2 device
++ nodes.
++
+
+ I2C sub-device drivers
+ ----------------------
+diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
+index 0deff78..fc57ce7 100644
+--- a/drivers/media/video/v4l2-subdev.c
++++ b/drivers/media/video/v4l2-subdev.c
+@@ -24,6 +24,7 @@
+ #include <linux/ioctl.h>
+ #include <linux/videodev2.h>
+
++#include <media/v4l2-ctrls.h>
+ #include <media/v4l2-device.h>
+ #include <media/v4l2-ioctl.h>
+
+@@ -45,7 +46,31 @@ static int subdev_close(struct file *file)
+
+ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+ {
++ struct video_device *vdev = video_devdata(file);
++ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
++
+ switch (cmd) {
++ case VIDIOC_QUERYCTRL:
++ return v4l2_subdev_queryctrl(sd, arg);
++
++ case VIDIOC_QUERYMENU:
++ return v4l2_subdev_querymenu(sd, arg);
++
++ case VIDIOC_G_CTRL:
++ return v4l2_subdev_g_ctrl(sd, arg);
++
++ case VIDIOC_S_CTRL:
++ return v4l2_subdev_s_ctrl(sd, arg);
++
++ case VIDIOC_G_EXT_CTRLS:
++ return v4l2_subdev_g_ext_ctrls(sd, arg);
++
++ case VIDIOC_S_EXT_CTRLS:
++ return v4l2_subdev_s_ext_ctrls(sd, arg);
++
++ case VIDIOC_TRY_EXT_CTRLS:
++ return v4l2_subdev_try_ext_ctrls(sd, arg);
++
+ default:
+ return -ENOIOCTLCMD;
+ }
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0007-v4l-subdev-Events-support.patch b/extras/recipes-kernel/linux/linux-omap/media/0007-v4l-subdev-Events-support.patch
new file mode 100644
index 00000000..cb02f498
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0007-v4l-subdev-Events-support.patch
@@ -0,0 +1,223 @@
+From 127fac73175e73c509ba203717be618a611294cd Mon Sep 17 00:00:00 2001
+From: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+Date: Wed, 3 Mar 2010 17:49:38 +0200
+Subject: [PATCH 07/43] v4l: subdev: Events support
+
+Provide v4l2_subdevs with v4l2_event support. Subdev drivers only need very
+little to support events.
+
+Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+Signed-off-by: David Cohen <david.cohen@nokia.com>
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ Documentation/video4linux/v4l2-framework.txt | 18 ++++++
+ drivers/media/video/v4l2-subdev.c | 75 +++++++++++++++++++++++++-
+ include/media/v4l2-subdev.h | 10 ++++
+ 3 files changed, 102 insertions(+), 1 deletions(-)
+
+diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
+index f683f63..4db1def 100644
+--- a/Documentation/video4linux/v4l2-framework.txt
++++ b/Documentation/video4linux/v4l2-framework.txt
+@@ -352,6 +352,24 @@ VIDIOC_TRY_EXT_CTRLS
+ controls can be also be accessed through one (or several) V4L2 device
+ nodes.
+
++VIDIOC_DQEVENT
++VIDIOC_SUBSCRIBE_EVENT
++VIDIOC_UNSUBSCRIBE_EVENT
++
++ The events ioctls are identical to the ones defined in V4L2. They
++ behave identically, with the only exception that they deal only with
++ events generated by the sub-device. Depending on the driver, those
++ events can also be reported by one (or several) V4L2 device nodes.
++
++ Sub-device drivers that want to use events need to set the
++ V4L2_SUBDEV_USES_EVENTS v4l2_subdev::flags and initialize
++ v4l2_subdev::nevents to events queue depth before registering the
++ sub-device. After registration events can be queued as usual on the
++ v4l2_subdev::devnode device node.
++
++ To properly support events, the poll() file operation is also
++ implemented.
++
+
+ I2C sub-device drivers
+ ----------------------
+diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
+index fc57ce7..fbccefd 100644
+--- a/drivers/media/video/v4l2-subdev.c
++++ b/drivers/media/video/v4l2-subdev.c
+@@ -20,27 +20,69 @@
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+-#include <linux/types.h>
+ #include <linux/ioctl.h>
++#include <linux/slab.h>
++#include <linux/types.h>
+ #include <linux/videodev2.h>
+
+ #include <media/v4l2-ctrls.h>
+ #include <media/v4l2-device.h>
+ #include <media/v4l2-ioctl.h>
++#include <media/v4l2-fh.h>
++#include <media/v4l2-event.h>
+
+ static int subdev_open(struct file *file)
+ {
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
++ struct v4l2_fh *vfh;
++ int ret;
+
+ if (!sd->initialized)
+ return -EAGAIN;
+
++ if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) {
++ vfh = kzalloc(sizeof(*vfh), GFP_KERNEL);
++ if (vfh == NULL)
++ return -ENOMEM;
++
++ ret = v4l2_fh_init(vfh, vdev);
++ if (ret)
++ goto err;
++
++ ret = v4l2_event_init(vfh);
++ if (ret)
++ goto err;
++
++ ret = v4l2_event_alloc(vfh, sd->nevents);
++ if (ret)
++ goto err;
++
++ v4l2_fh_add(vfh);
++ file->private_data = vfh;
++ }
++
+ return 0;
++
++err:
++ if (vfh != NULL) {
++ v4l2_fh_exit(vfh);
++ kfree(vfh);
++ }
++
++ return ret;
+ }
+
+ static int subdev_close(struct file *file)
+ {
++ struct v4l2_fh *vfh = file->private_data;
++
++ if (vfh != NULL) {
++ v4l2_fh_del(vfh);
++ v4l2_fh_exit(vfh);
++ kfree(vfh);
++ }
++
+ return 0;
+ }
+
+@@ -48,6 +90,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+ {
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
++ struct v4l2_fh *fh = file->private_data;
+
+ switch (cmd) {
+ case VIDIOC_QUERYCTRL:
+@@ -71,6 +114,18 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+ case VIDIOC_TRY_EXT_CTRLS:
+ return v4l2_subdev_try_ext_ctrls(sd, arg);
+
++ case VIDIOC_DQEVENT:
++ if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
++ return -ENOIOCTLCMD;
++
++ return v4l2_event_dequeue(fh, arg, file->f_flags & O_NONBLOCK);
++
++ case VIDIOC_SUBSCRIBE_EVENT:
++ return v4l2_subdev_call(sd, core, subscribe_event, fh, arg);
++
++ case VIDIOC_UNSUBSCRIBE_EVENT:
++ return v4l2_subdev_call(sd, core, unsubscribe_event, fh, arg);
++
+ default:
+ return -ENOIOCTLCMD;
+ }
+@@ -84,11 +139,29 @@ static long subdev_ioctl(struct file *file, unsigned int cmd,
+ return __video_usercopy(file, cmd, arg, subdev_do_ioctl);
+ }
+
++static unsigned int subdev_poll(struct file *file, poll_table *wait)
++{
++ struct video_device *vdev = video_devdata(file);
++ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
++ struct v4l2_fh *fh = file->private_data;
++
++ if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
++ return POLLERR;
++
++ poll_wait(file, &fh->events->wait, wait);
++
++ if (v4l2_event_pending(fh))
++ return POLLPRI;
++
++ return 0;
++}
++
+ const struct v4l2_file_operations v4l2_subdev_fops = {
+ .owner = THIS_MODULE,
+ .open = subdev_open,
+ .unlocked_ioctl = subdev_ioctl,
+ .release = subdev_close,
++ .poll = subdev_poll,
+ };
+
+ void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index 90022f5..68cbe48 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -37,6 +37,8 @@
+
+ struct v4l2_device;
+ struct v4l2_ctrl_handler;
++struct v4l2_event_subscription;
++struct v4l2_fh;
+ struct v4l2_subdev;
+ struct tuner_setup;
+
+@@ -165,6 +167,10 @@ struct v4l2_subdev_core_ops {
+ int (*s_power)(struct v4l2_subdev *sd, int on);
+ int (*interrupt_service_routine)(struct v4l2_subdev *sd,
+ u32 status, bool *handled);
++ int (*subscribe_event)(struct v4l2_subdev *sd, struct v4l2_fh *fh,
++ struct v4l2_event_subscription *sub);
++ int (*unsubscribe_event)(struct v4l2_subdev *sd, struct v4l2_fh *fh,
++ struct v4l2_event_subscription *sub);
+ };
+
+ /* s_mode: switch the tuner to a specific tuner mode. Replacement of s_radio.
+@@ -424,6 +430,8 @@ struct v4l2_subdev_ops {
+ #define V4L2_SUBDEV_FL_IS_SPI (1U << 1)
+ /* Set this flag if this subdev needs a device node. */
+ #define V4L2_SUBDEV_FL_HAS_DEVNODE (1U << 2)
++/* Set this flag if this subdev generates events. */
++#define V4L2_SUBDEV_FL_HAS_EVENTS (1U << 3)
+
+ /* Each instance of a subdev driver should create this struct, either
+ stand-alone or embedded in a larger struct.
+@@ -446,6 +454,8 @@ struct v4l2_subdev {
+ /* subdev device node */
+ struct video_device devnode;
+ unsigned int initialized;
++ /* number of events to be allocated on open */
++ unsigned int nevents;
+ };
+
+ #define vdev_to_v4l2_subdev(vdev) \
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0008-media-Media-device-node-support.patch b/extras/recipes-kernel/linux/linux-omap/media/0008-media-Media-device-node-support.patch
new file mode 100644
index 00000000..fd8b4952
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0008-media-Media-device-node-support.patch
@@ -0,0 +1,500 @@
+From 27c789f3ae1d24212355d10857efb2d406d0fedd Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:39:56 +0100
+Subject: [PATCH 08/43] media: Media device node support
+
+The media_devnode structure provides support for registering and
+unregistering character devices using a dynamic major number. Reference
+counting is handled internally, making device drivers easier to write
+without having to solve the open/disconnect race condition issue over
+and over again.
+
+The code is based on video/v4l2-dev.c.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ drivers/media/Kconfig | 13 ++
+ drivers/media/Makefile | 10 +-
+ drivers/media/media-devnode.c | 321 +++++++++++++++++++++++++++++++++++++++++
+ include/media/media-devnode.h | 97 +++++++++++++
+ 4 files changed, 439 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/media/media-devnode.c
+ create mode 100644 include/media/media-devnode.h
+
+diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
+index a28541b..6b946e6 100644
+--- a/drivers/media/Kconfig
++++ b/drivers/media/Kconfig
+@@ -14,6 +14,19 @@ if MEDIA_SUPPORT
+ comment "Multimedia core support"
+
+ #
++# Media controller
++#
++
++config MEDIA_CONTROLLER
++ bool "Media Controller API (EXPERIMENTAL)"
++ depends on EXPERIMENTAL
++ ---help---
++ Enable the media controller API used to query media devices internal
++ topology and configure it dynamically.
++
++ This API is mostly used by camera interfaces in embedded platforms.
++
++#
+ # V4L core and enabled API's
+ #
+
+diff --git a/drivers/media/Makefile b/drivers/media/Makefile
+index 499b081..3a08991 100644
+--- a/drivers/media/Makefile
++++ b/drivers/media/Makefile
+@@ -2,7 +2,13 @@
+ # Makefile for the kernel multimedia device drivers.
+ #
+
++media-objs := media-devnode.o
++
++ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
++ obj-$(CONFIG_MEDIA_SUPPORT) += media.o
++endif
++
+ obj-y += common/ IR/ video/
+
+-obj-$(CONFIG_VIDEO_DEV) += radio/
+-obj-$(CONFIG_DVB_CORE) += dvb/
++obj-$(CONFIG_VIDEO_DEV) += radio/
++obj-$(CONFIG_DVB_CORE) += dvb/
+diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
+new file mode 100644
+index 0000000..7804b70
+--- /dev/null
++++ b/drivers/media/media-devnode.c
+@@ -0,0 +1,321 @@
++/*
++ * Media device node
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ *
++ * Based on drivers/media/video/v4l2_dev.c code authored by
++ * Mauro Carvalho Chehab <mchehab@infradead.org> (version 2)
++ * Alan Cox, <alan@lxorguk.ukuu.org.uk> (version 1)
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ * --
++ *
++ * Generic media device node infrastructure to register and unregister
++ * character devices using a dynamic major number and proper reference
++ * counting.
++ */
++
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/kmod.h>
++#include <linux/slab.h>
++#include <linux/mm.h>
++#include <linux/smp_lock.h>
++#include <linux/string.h>
++#include <linux/types.h>
++#include <linux/uaccess.h>
++#include <asm/system.h>
++
++#include <media/media-devnode.h>
++
++#define MEDIA_NUM_DEVICES 256
++#define MEDIA_NAME "media"
++
++static dev_t media_dev_t;
++
++/*
++ * Active devices
++ */
++static DEFINE_MUTEX(media_devnode_lock);
++static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES);
++
++/* Called when the last user of the media device exits. */
++static void media_devnode_release(struct device *cd)
++{
++ struct media_devnode *mdev = to_media_devnode(cd);
++
++ mutex_lock(&media_devnode_lock);
++
++ /* Delete the cdev on this minor as well */
++ cdev_del(&mdev->cdev);
++
++ /* Mark device node number as free */
++ clear_bit(mdev->minor, media_devnode_nums);
++
++ mutex_unlock(&media_devnode_lock);
++
++ /* Release media_devnode and perform other cleanups as needed. */
++ if (mdev->release)
++ mdev->release(mdev);
++}
++
++static struct bus_type media_bus_type = {
++ .name = MEDIA_NAME,
++};
++
++static ssize_t media_read(struct file *filp, char __user *buf,
++ size_t sz, loff_t *off)
++{
++ struct media_devnode *mdev = media_devnode_data(filp);
++
++ if (!mdev->fops->read)
++ return -EINVAL;
++ if (!media_devnode_is_registered(mdev))
++ return -EIO;
++ return mdev->fops->read(filp, buf, sz, off);
++}
++
++static ssize_t media_write(struct file *filp, const char __user *buf,
++ size_t sz, loff_t *off)
++{
++ struct media_devnode *mdev = media_devnode_data(filp);
++
++ if (!mdev->fops->write)
++ return -EINVAL;
++ if (!media_devnode_is_registered(mdev))
++ return -EIO;
++ return mdev->fops->write(filp, buf, sz, off);
++}
++
++static unsigned int media_poll(struct file *filp,
++ struct poll_table_struct *poll)
++{
++ struct media_devnode *mdev = media_devnode_data(filp);
++
++ if (!media_devnode_is_registered(mdev))
++ return POLLERR | POLLHUP;
++ if (!mdev->fops->poll)
++ return DEFAULT_POLLMASK;
++ return mdev->fops->poll(filp, poll);
++}
++
++static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
++{
++ struct media_devnode *mdev = media_devnode_data(filp);
++
++ if (!mdev->fops->ioctl)
++ return -ENOTTY;
++
++ if (!media_devnode_is_registered(mdev))
++ return -EIO;
++
++ return mdev->fops->ioctl(filp, cmd, arg);
++}
++
++/* Override for the open function */
++static int media_open(struct inode *inode, struct file *filp)
++{
++ struct media_devnode *mdev;
++ int ret;
++
++ /* Check if the media device is available. This needs to be done with
++ * the media_devnode_lock held to prevent an open/unregister race:
++ * without the lock, the device could be unregistered and freed between
++ * the media_devnode_is_registered() and get_device() calls, leading to
++ * a crash.
++ */
++ mutex_lock(&media_devnode_lock);
++ mdev = container_of(inode->i_cdev, struct media_devnode, cdev);
++ /* return ENXIO if the media device has been removed
++ already or if it is not registered anymore. */
++ if (!media_devnode_is_registered(mdev)) {
++ mutex_unlock(&media_devnode_lock);
++ return -ENXIO;
++ }
++ /* and increase the device refcount */
++ get_device(&mdev->dev);
++ mutex_unlock(&media_devnode_lock);
++
++ filp->private_data = mdev;
++
++ if (mdev->fops->open) {
++ ret = mdev->fops->open(filp);
++ if (ret) {
++ put_device(&mdev->dev);
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
++/* Override for the release function */
++static int media_release(struct inode *inode, struct file *filp)
++{
++ struct media_devnode *mdev = media_devnode_data(filp);
++ int ret = 0;
++
++ if (mdev->fops->release)
++ mdev->fops->release(filp);
++
++ /* decrease the refcount unconditionally since the release()
++ return value is ignored. */
++ put_device(&mdev->dev);
++ filp->private_data = NULL;
++ return ret;
++}
++
++static const struct file_operations media_devnode_fops = {
++ .owner = THIS_MODULE,
++ .read = media_read,
++ .write = media_write,
++ .open = media_open,
++ .unlocked_ioctl = media_ioctl,
++ .release = media_release,
++ .poll = media_poll,
++ .llseek = no_llseek,
++};
++
++/**
++ * media_devnode_register - register a media device node
++ * @mdev: media device node structure we want to register
++ *
++ * The registration code assigns minor numbers and registers the new device node
++ * with the kernel. An error is returned if no free minor number can be found,
++ * or if the registration of the device node fails.
++ *
++ * Zero is returned on success.
++ *
++ * Note that if the media_devnode_register call fails, the release() callback of
++ * the media_devnode structure is *not* called, so the caller is responsible for
++ * freeing any data.
++ */
++int __must_check media_devnode_register(struct media_devnode *mdev)
++{
++ int minor;
++ int ret;
++
++ /* Part 1: Find a free minor number */
++ mutex_lock(&media_devnode_lock);
++ minor = find_next_zero_bit(media_devnode_nums, 0, MEDIA_NUM_DEVICES);
++ if (minor == MEDIA_NUM_DEVICES) {
++ mutex_unlock(&media_devnode_lock);
++ printk(KERN_ERR "could not get a free minor\n");
++ return -ENFILE;
++ }
++
++ set_bit(mdev->minor, media_devnode_nums);
++ mutex_unlock(&media_devnode_lock);
++
++ mdev->minor = minor;
++
++ /* Part 2: Initialize and register the character device */
++ cdev_init(&mdev->cdev, &media_devnode_fops);
++ mdev->cdev.owner = mdev->fops->owner;
++
++ ret = cdev_add(&mdev->cdev, MKDEV(MAJOR(media_dev_t), mdev->minor), 1);
++ if (ret < 0) {
++ printk(KERN_ERR "%s: cdev_add failed\n", __func__);
++ goto error;
++ }
++
++ /* Part 3: Register the media device */
++ mdev->dev.bus = &media_bus_type;
++ mdev->dev.devt = MKDEV(MAJOR(media_dev_t), mdev->minor);
++ mdev->dev.release = media_devnode_release;
++ if (mdev->parent)
++ mdev->dev.parent = mdev->parent;
++ dev_set_name(&mdev->dev, "media%d", mdev->minor);
++ ret = device_register(&mdev->dev);
++ if (ret < 0) {
++ printk(KERN_ERR "%s: device_register failed\n", __func__);
++ goto error;
++ }
++
++ /* Part 4: Activate this minor. The char device can now be used. */
++ set_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
++
++ return 0;
++
++error:
++ cdev_del(&mdev->cdev);
++ clear_bit(mdev->minor, media_devnode_nums);
++ return ret;
++}
++
++/**
++ * media_devnode_unregister - unregister a media device node
++ * @mdev: the device node to unregister
++ *
++ * This unregisters the passed device. Future open calls will be met with
++ * errors.
++ *
++ * This function can safely be called if the device node has never been
++ * registered or has already been unregistered.
++ */
++void media_devnode_unregister(struct media_devnode *mdev)
++{
++ /* Check if mdev was ever registered at all */
++ if (!media_devnode_is_registered(mdev))
++ return;
++
++ mutex_lock(&media_devnode_lock);
++ clear_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
++ mutex_unlock(&media_devnode_lock);
++ device_unregister(&mdev->dev);
++}
++
++/*
++ * Initialise media for linux
++ */
++static int __init media_devnode_init(void)
++{
++ int ret;
++
++ printk(KERN_INFO "Linux media interface: v0.10\n");
++ ret = alloc_chrdev_region(&media_dev_t, 0, MEDIA_NUM_DEVICES,
++ MEDIA_NAME);
++ if (ret < 0) {
++ printk(KERN_WARNING "media: unable to allocate major\n");
++ return ret;
++ }
++
++ ret = bus_register(&media_bus_type);
++ if (ret < 0) {
++ unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
++ printk(KERN_WARNING "media: bus_register failed\n");
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static void __exit media_devnode_exit(void)
++{
++ bus_unregister(&media_bus_type);
++ unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
++}
++
++module_init(media_devnode_init)
++module_exit(media_devnode_exit)
++
++MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
++MODULE_DESCRIPTION("Device node registration for media drivers");
++MODULE_LICENSE("GPL");
+diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h
+new file mode 100644
+index 0000000..01cd034
+--- /dev/null
++++ b/include/media/media-devnode.h
+@@ -0,0 +1,97 @@
++/*
++ * Media device node
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ * --
++ *
++ * Common functions for media-related drivers to register and unregister media
++ * device nodes.
++ */
++
++#ifndef _MEDIA_DEVNODE_H
++#define _MEDIA_DEVNODE_H
++
++#include <linux/poll.h>
++#include <linux/fs.h>
++#include <linux/device.h>
++#include <linux/cdev.h>
++
++/*
++ * Flag to mark the media_devnode struct as registered. Drivers must not touch
++ * this flag directly, it will be set and cleared by media_devnode_register and
++ * media_devnode_unregister.
++ */
++#define MEDIA_FLAG_REGISTERED 0
++
++struct media_file_operations {
++ struct module *owner;
++ ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
++ ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
++ unsigned int (*poll) (struct file *, struct poll_table_struct *);
++ long (*ioctl) (struct file *, unsigned int, unsigned long);
++ int (*open) (struct file *);
++ int (*release) (struct file *);
++};
++
++/**
++ * struct media_devnode - Media device node
++ * @parent: parent device
++ * @minor: device node minor number
++ * @flags: flags, combination of the MEDIA_FLAG_* constants
++ *
++ * This structure represents a media-related device node.
++ *
++ * The @parent is a physical device. It must be set by core or device drivers
++ * before registering the node.
++ */
++struct media_devnode {
++ /* device ops */
++ const struct media_file_operations *fops;
++
++ /* sysfs */
++ struct device dev; /* media device */
++ struct cdev cdev; /* character device */
++ struct device *parent; /* device parent */
++
++ /* device info */
++ int minor;
++ unsigned long flags; /* Use bitops to access flags */
++
++ /* callbacks */
++ void (*release)(struct media_devnode *mdev);
++};
++
++/* dev to media_devnode */
++#define to_media_devnode(cd) container_of(cd, struct media_devnode, dev)
++
++int __must_check media_devnode_register(struct media_devnode *mdev);
++void media_devnode_unregister(struct media_devnode *mdev);
++
++static inline struct media_devnode *media_devnode_data(struct file *filp)
++{
++ return filp->private_data;
++}
++
++static inline int media_devnode_is_registered(struct media_devnode *mdev)
++{
++ return test_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
++}
++
++#endif /* _MEDIA_DEVNODE_H */
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0009-media-Media-device.patch b/extras/recipes-kernel/linux/linux-omap/media/0009-media-Media-device.patch
new file mode 100644
index 00000000..d82c798e
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0009-media-Media-device.patch
@@ -0,0 +1,398 @@
+From 6bfbc237b86be01ad23b836ba047e76e23cc7a00 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:39:58 +0100
+Subject: [PATCH 09/43] media: Media device
+
+The media_device structure abstracts functions common to all kind of
+media devices (v4l2, dvb, alsa, ...). It manages media entities and
+offers a userspace API to discover and configure the media device
+internal topology.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ Documentation/ABI/testing/sysfs-bus-media | 6 ++
+ Documentation/DocBook/media-entities.tmpl | 2 +
+ Documentation/DocBook/media.tmpl | 3 +
+ Documentation/DocBook/v4l/media-controller.xml | 56 +++++++++++++
+ Documentation/media-framework.txt | 67 ++++++++++++++++
+ drivers/media/Makefile | 2 +-
+ drivers/media/media-device.c | 100 ++++++++++++++++++++++++
+ include/media/media-device.h | 69 ++++++++++++++++
+ 8 files changed, 304 insertions(+), 1 deletions(-)
+ create mode 100644 Documentation/ABI/testing/sysfs-bus-media
+ create mode 100644 Documentation/DocBook/v4l/media-controller.xml
+ create mode 100644 Documentation/media-framework.txt
+ create mode 100644 drivers/media/media-device.c
+ create mode 100644 include/media/media-device.h
+
+diff --git a/Documentation/ABI/testing/sysfs-bus-media b/Documentation/ABI/testing/sysfs-bus-media
+new file mode 100644
+index 0000000..7057e57
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-bus-media
+@@ -0,0 +1,6 @@
++What: /sys/bus/media/devices/.../model
++Date: January 2011
++Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ linux-media@vger.kernel.org
++Description: Contains the device model name in UTF-8. The device version is
++ is not be appended to the model name.
+diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
+index be34dcb..61d6f11 100644
+--- a/Documentation/DocBook/media-entities.tmpl
++++ b/Documentation/DocBook/media-entities.tmpl
+@@ -321,6 +321,8 @@
+ <!ENTITY sub-media-entities SYSTEM "media-entities.tmpl">
+ <!ENTITY sub-media-indices SYSTEM "media-indices.tmpl">
+
++<!ENTITY sub-media-controller SYSTEM "v4l/media-controller.xml">
++
+ <!-- Function Reference -->
+ <!ENTITY close SYSTEM "v4l/func-close.xml">
+ <!ENTITY ioctl SYSTEM "v4l/func-ioctl.xml">
+diff --git a/Documentation/DocBook/media.tmpl b/Documentation/DocBook/media.tmpl
+index f11048d..73464b0 100644
+--- a/Documentation/DocBook/media.tmpl
++++ b/Documentation/DocBook/media.tmpl
+@@ -106,6 +106,9 @@ Foundation. A copy of the license is included in the chapter entitled
+ &sub-remote_controllers;
+ </chapter>
+ </part>
++<part id="media_common">
++&sub-media-controller;
++</part>
+
+ &sub-fdl-appendix;
+
+diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml
+new file mode 100644
+index 0000000..253ddb4
+--- /dev/null
++++ b/Documentation/DocBook/v4l/media-controller.xml
+@@ -0,0 +1,56 @@
++<partinfo>
++ <authorgroup>
++ <author>
++ <firstname>Laurent</firstname>
++ <surname>Pinchart</surname>
++ <affiliation><address><email>laurent.pinchart@ideasonboard.com</email></address></affiliation>
++ <contrib>Initial version.</contrib>
++ </author>
++ </authorgroup>
++ <copyright>
++ <year>2010</year>
++ <holder>Laurent Pinchart</holder>
++ </copyright>
++
++ <revhistory>
++ <!-- Put document revisions here, newest first. -->
++ <revision>
++ <revnumber>1.0.0</revnumber>
++ <date>2010-11-10</date>
++ <authorinitials>lp</authorinitials>
++ <revremark>Initial revision</revremark>
++ </revision>
++ </revhistory>
++</partinfo>
++
++<title>Media Controller API</title>
++
++<chapter id="media_controller">
++ <title>Media Controller</title>
++
++ <section id="media-controller-intro">
++ <title>Introduction</title>
++ <para>Media devices increasingly handle multiple related functions. Many USB
++ cameras include microphones, video capture hardware can also output video,
++ or SoC camera interfaces also perform memory-to-memory operations similar to
++ video codecs.</para>
++ <para>Independent functions, even when implemented in the same hardware, can
++ be modelled as separate devices. A USB camera with a microphone will be
++ presented to userspace applications as V4L2 and ALSA capture devices. The
++ devices' relationships (when using a webcam, end-users shouldn't have to
++ manually select the associated USB microphone), while not made available
++ directly to applications by the drivers, can usually be retrieved from
++ sysfs.</para>
++ <para>With more and more advanced SoC devices being introduced, the current
++ approach will not scale. Device topologies are getting increasingly complex
++ and can't always be represented by a tree structure. Hardware blocks are
++ shared between different functions, creating dependencies between seemingly
++ unrelated devices.</para>
++ <para>Kernel abstraction APIs such as V4L2 and ALSA provide means for
++ applications to access hardware parameters. As newer hardware expose an
++ increasingly high number of those parameters, drivers need to guess what
++ applications really require based on limited information, thereby
++ implementing policies that belong to userspace.</para>
++ <para>The media controller API aims at solving those problems.</para>
++ </section>
++</chapter>
+diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
+new file mode 100644
+index 0000000..1844c3f
+--- /dev/null
++++ b/Documentation/media-framework.txt
+@@ -0,0 +1,67 @@
++Linux kernel media framework
++============================
++
++This document describes the Linux kernel media framework, its data structures,
++functions and their usage.
++
++
++Introduction
++------------
++
++The media controller API is documented in DocBook format in
++Documentation/DocBook/v4l/media-controller.xml. This document will focus on
++the kernel-side implementation of the media framework.
++
++
++Media device
++------------
++
++A media device is represented by a struct media_device instance, defined in
++include/media/media-device.h. Allocation of the structure is handled by the
++media device driver, usually by embedding the media_device instance in a
++larger driver-specific structure.
++
++Drivers register media device instances by calling
++
++ media_device_register(struct media_device *mdev);
++
++The caller is responsible for initializing the media_device structure before
++registration. The following fields must be set:
++
++ - dev must point to the parent device (usually a pci_dev, usb_interface or
++ platform_device instance).
++
++ - model must be filled with the device model name as a NUL-terminated UTF-8
++ string. The device/model revision must not be stored in this field.
++
++The following fields are optional:
++
++ - serial is a unique serial number stored as a NUL-terminated ASCII string.
++ The field is big enough to store a GUID in text form. If the hardware
++ doesn't provide a unique serial number this field must be left empty.
++
++ - bus_info represents the location of the device in the system as a
++ NUL-terminated ASCII string. For PCI/PCIe devices bus_info must be set to
++ "PCI:" (or "PCIe:") followed by the value of pci_name(). For USB devices,
++ the usb_make_path() function must be used. This field is used by
++ applications to distinguish between otherwise identical devices that don't
++ provide a serial number.
++
++ - hw_revision is the hardware device revision in a driver-specific format.
++ When possible the revision should be formatted with the KERNEL_VERSION
++ macro.
++
++ - driver_version is formatted with the KERNEL_VERSION macro. The version
++ minor must be incremented when new features are added to the userspace API
++ without breaking binary compatibility. The version major must be
++ incremented when binary compatibility is broken.
++
++Upon successful registration a character device named media[0-9]+ is created.
++The device major and minor numbers are dynamic. The model name is exported as
++a sysfs attribute.
++
++Drivers unregister media device instances by calling
++
++ media_device_unregister(struct media_device *mdev);
++
++Unregistering a media device that hasn't been registered is *NOT* safe.
+diff --git a/drivers/media/Makefile b/drivers/media/Makefile
+index 3a08991..019d3e0 100644
+--- a/drivers/media/Makefile
++++ b/drivers/media/Makefile
+@@ -2,7 +2,7 @@
+ # Makefile for the kernel multimedia device drivers.
+ #
+
+-media-objs := media-devnode.o
++media-objs := media-device.o media-devnode.o
+
+ ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
+ obj-$(CONFIG_MEDIA_SUPPORT) += media.o
+diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
+new file mode 100644
+index 0000000..57a9c6b
+--- /dev/null
++++ b/drivers/media/media-device.c
+@@ -0,0 +1,100 @@
++/*
++ * Media device
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/types.h>
++#include <linux/ioctl.h>
++
++#include <media/media-device.h>
++#include <media/media-devnode.h>
++
++static const struct media_file_operations media_device_fops = {
++ .owner = THIS_MODULE,
++};
++
++/* -----------------------------------------------------------------------------
++ * sysfs
++ */
++
++static ssize_t show_model(struct device *cd,
++ struct device_attribute *attr, char *buf)
++{
++ struct media_device *mdev = to_media_device(to_media_devnode(cd));
++
++ return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model);
++}
++
++static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
++
++/* -----------------------------------------------------------------------------
++ * Registration/unregistration
++ */
++
++static void media_device_release(struct media_devnode *mdev)
++{
++}
++
++/**
++ * media_device_register - register a media device
++ * @mdev: The media device
++ *
++ * The caller is responsible for initializing the media device before
++ * registration. The following fields must be set:
++ *
++ * - dev must point to the parent device
++ * - model must be filled with the device model name
++ */
++int __must_check media_device_register(struct media_device *mdev)
++{
++ int ret;
++
++ if (WARN_ON(mdev->dev == NULL || mdev->model[0] == 0))
++ return -EINVAL;
++
++ /* Register the device node. */
++ mdev->devnode.fops = &media_device_fops;
++ mdev->devnode.parent = mdev->dev;
++ mdev->devnode.release = media_device_release;
++ ret = media_devnode_register(&mdev->devnode);
++ if (ret < 0)
++ return ret;
++
++ ret = device_create_file(&mdev->devnode.dev, &dev_attr_model);
++ if (ret < 0) {
++ media_devnode_unregister(&mdev->devnode);
++ return ret;
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(media_device_register);
++
++/**
++ * media_device_unregister - unregister a media device
++ * @mdev: The media device
++ *
++ */
++void media_device_unregister(struct media_device *mdev)
++{
++ device_remove_file(&mdev->devnode.dev, &dev_attr_model);
++ media_devnode_unregister(&mdev->devnode);
++}
++EXPORT_SYMBOL_GPL(media_device_unregister);
+diff --git a/include/media/media-device.h b/include/media/media-device.h
+new file mode 100644
+index 0000000..e11f01a
+--- /dev/null
++++ b/include/media/media-device.h
+@@ -0,0 +1,69 @@
++/*
++ * Media device
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#ifndef _MEDIA_DEVICE_H
++#define _MEDIA_DEVICE_H
++
++#include <linux/device.h>
++#include <linux/list.h>
++
++#include <media/media-devnode.h>
++
++/**
++ * struct media_device - Media device
++ * @dev: Parent device
++ * @devnode: Media device node
++ * @model: Device model name
++ * @serial: Device serial number (optional)
++ * @bus_info: Unique and stable device location identifier
++ * @hw_revision: Hardware device revision
++ * @driver_version: Device driver version
++ *
++ * This structure represents an abstract high-level media device. It allows easy
++ * access to entities and provides basic media device-level support. The
++ * structure can be allocated directly or embedded in a larger structure.
++ *
++ * The parent @dev is a physical device. It must be set before registering the
++ * media device.
++ *
++ * @model is a descriptive model name exported through sysfs. It doesn't have to
++ * be unique.
++ */
++struct media_device {
++ /* dev->driver_data points to this struct. */
++ struct device *dev;
++ struct media_devnode devnode;
++
++ char model[32];
++ char serial[40];
++ char bus_info[32];
++ u32 hw_revision;
++ u32 driver_version;
++};
++
++/* media_devnode to media_device */
++#define to_media_device(node) container_of(node, struct media_device, devnode)
++
++int __must_check media_device_register(struct media_device *mdev);
++void media_device_unregister(struct media_device *mdev);
++
++#endif
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0010-media-Entities-pads-and-links.patch b/extras/recipes-kernel/linux/linux-omap/media/0010-media-Entities-pads-and-links.patch
new file mode 100644
index 00000000..be762331
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0010-media-Entities-pads-and-links.patch
@@ -0,0 +1,690 @@
+From b4697e5a8ad1e564ea378d435c2ce190318c1027 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:40:00 +0100
+Subject: [PATCH 10/43] media: Entities, pads and links
+
+As video hardware pipelines become increasingly complex and
+configurable, the current hardware description through v4l2 subdevices
+reaches its limits. In addition to enumerating and configuring
+subdevices, video camera drivers need a way to discover and modify at
+runtime how those subdevices are connected. This is done through new
+elements called entities, pads and links.
+
+An entity is a basic media hardware building block. It can correspond to
+a large variety of logical blocks such as physical hardware devices
+(CMOS sensor for instance), logical hardware devices (a building block
+in a System-on-Chip image processing pipeline), DMA channels or physical
+connectors.
+
+A pad is a connection endpoint through which an entity can interact with
+other entities. Data (not restricted to video) produced by an entity
+flows from the entity's output to one or more entity inputs. Pads should
+not be confused with physical pins at chip boundaries.
+
+A link is a point-to-point oriented connection between two pads, either
+on the same entity or on different entities. Data flows from a source
+pad to a sink pad.
+
+Links are stored in the source entity. To make backwards graph walk
+faster, a copy of all links is also stored in the sink entity. The copy
+is known as a backlink and is only used to help graph traversal.
+
+The entity API is made of three functions:
+
+- media_entity_init() initializes an entity. The caller must provide an
+array of pads as well as an estimated number of links. The links array
+is allocated dynamically and will be reallocated if it grows beyond the
+initial estimate.
+
+- media_entity_cleanup() frees resources allocated for an entity. It
+must be called during the cleanup phase after unregistering the entity
+and before freeing it.
+
+- media_entity_create_link() creates a link between two entities. An
+entry in the link array of each entity is allocated and stores pointers
+to source and sink pads.
+
+When a media device is unregistered, all its entities are unregistered
+automatically.
+
+The code is based on Hans Verkuil <hverkuil@xs4all.nl> initial work.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+---
+ Documentation/DocBook/v4l/media-controller.xml | 20 +++
+ Documentation/media-framework.txt | 151 ++++++++++++++++++++++++
+ drivers/media/Makefile | 2 +-
+ drivers/media/media-device.c | 56 +++++++++
+ drivers/media/media-entity.c | 147 +++++++++++++++++++++++
+ include/media/media-device.h | 19 +++
+ include/media/media-entity.h | 122 +++++++++++++++++++
+ 7 files changed, 516 insertions(+), 1 deletions(-)
+ create mode 100644 drivers/media/media-entity.c
+ create mode 100644 include/media/media-entity.h
+
+diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml
+index 253ddb4..f89228d 100644
+--- a/Documentation/DocBook/v4l/media-controller.xml
++++ b/Documentation/DocBook/v4l/media-controller.xml
+@@ -53,4 +53,24 @@
+ implementing policies that belong to userspace.</para>
+ <para>The media controller API aims at solving those problems.</para>
+ </section>
++
++ <section id="media-controller-model">
++ <title>Media device model</title>
++ <para>Discovering a device internal topology, and configuring it at runtime,
++ is one of the goals of the media controller API. To achieve this, hardware
++ devices are modelled as an oriented graph of building blocks called entities
++ connected through pads.</para>
++ <para>An entity is a basic media hardware or software building block. It can
++ correspond to a large variety of logical blocks such as physical hardware
++ devices (CMOS sensor for instance), logical hardware devices (a building
++ block in a System-on-Chip image processing pipeline), DMA channels or
++ physical connectors.</para>
++ <para>A pad is a connection endpoint through which an entity can interact
++ with other entities. Data (not restricted to video) produced by an entity
++ flows from the entity's output to one or more entity inputs. Pads should not
++ be confused with physical pins at chip boundaries.</para>
++ <para>A link is a point-to-point oriented connection between two pads,
++ either on the same entity or on different entities. Data flows from a source
++ pad to a sink pad.</para>
++ </section>
+ </chapter>
+diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
+index 1844c3f..b252cf9 100644
+--- a/Documentation/media-framework.txt
++++ b/Documentation/media-framework.txt
+@@ -13,6 +13,30 @@ Documentation/DocBook/v4l/media-controller.xml. This document will focus on
+ the kernel-side implementation of the media framework.
+
+
++Abstract media device model
++---------------------------
++
++Discovering a device internal topology, and configuring it at runtime, is one
++of the goals of the media framework. To achieve this, hardware devices are
++modeled as an oriented graph of building blocks called entities connected
++through pads.
++
++An entity is a basic media hardware building block. It can correspond to
++a large variety of logical blocks such as physical hardware devices
++(CMOS sensor for instance), logical hardware devices (a building block
++in a System-on-Chip image processing pipeline), DMA channels or physical
++connectors.
++
++A pad is a connection endpoint through which an entity can interact with
++other entities. Data (not restricted to video) produced by an entity
++flows from the entity's output to one or more entity inputs. Pads should
++not be confused with physical pins at chip boundaries.
++
++A link is a point-to-point oriented connection between two pads, either
++on the same entity or on different entities. Data flows from a source
++pad to a sink pad.
++
++
+ Media device
+ ------------
+
+@@ -65,3 +89,130 @@ Drivers unregister media device instances by calling
+ media_device_unregister(struct media_device *mdev);
+
+ Unregistering a media device that hasn't been registered is *NOT* safe.
++
++
++Entities, pads and links
++------------------------
++
++- Entities
++
++Entities are represented by a struct media_entity instance, defined in
++include/media/media-entity.h. The structure is usually embedded into a
++higher-level structure, such as a v4l2_subdev or video_device instance,
++although drivers can allocate entities directly.
++
++Drivers initialize entities by calling
++
++ media_entity_init(struct media_entity *entity, u16 num_pads,
++ struct media_pad *pads, u16 extra_links);
++
++The media_entity name, type, flags, revision and group_id fields can be
++initialized before or after calling media_entity_init. Entities embedded in
++higher-level standard structures can have some of those fields set by the
++higher-level framework.
++
++As the number of pads is known in advance, the pads array is not allocated
++dynamically but is managed by the entity driver. Most drivers will embed the
++pads array in a driver-specific structure, avoiding dynamic allocation.
++
++Drivers must set the direction of every pad in the pads array before calling
++media_entity_init. The function will initialize the other pads fields.
++
++Unlike the number of pads, the total number of links isn't always known in
++advance by the entity driver. As an initial estimate, media_entity_init
++pre-allocates a number of links equal to the number of pads plus an optional
++number of extra links. The links array will be reallocated if it grows beyond
++the initial estimate.
++
++Drivers register entities with a media device by calling
++
++ media_device_register_entity(struct media_device *mdev,
++ struct media_entity *entity);
++
++Entities are identified by a unique positive integer ID. Drivers can provide an
++ID by filling the media_entity id field prior to registration, or request the
++media controller framework to assign an ID automatically. Drivers that provide
++IDs manually must ensure that all IDs are unique. IDs are not guaranteed to be
++contiguous even when they are all assigned automatically by the framework.
++
++Drivers unregister entities by calling
++
++ media_device_unregister_entity(struct media_entity *entity);
++
++Unregistering an entity will not change the IDs of the other entities, and the
++ID will never be reused for a newly registered entity.
++
++When a media device is unregistered, all its entities are unregistered
++automatically. No manual entities unregistration is then required.
++
++Drivers free resources associated with an entity by calling
++
++ media_entity_cleanup(struct media_entity *entity);
++
++This function must be called during the cleanup phase after unregistering the
++entity. Note that the media_entity instance itself must be freed explicitly by
++the driver if required.
++
++Entities have flags that describe the entity capabilities and state.
++
++ MEDIA_ENT_FL_DEFAULT indicates the default entity for a given type.
++ This can be used to report the default audio and video devices or the
++ default camera sensor.
++
++Logical entity groups can be defined by setting the group ID of all member
++entities to the same non-zero value. An entity group serves no purpose in the
++kernel, but is reported to userspace during entities enumeration. The group_id
++field belongs to the media device driver and must not by touched by entity
++drivers.
++
++Media device drivers should define groups if several entities are logically
++bound together. Example usages include reporting
++
++ - ALSA, VBI and video nodes that carry the same media stream
++ - lens and flash controllers associated with a sensor
++
++- Pads
++
++Pads are represented by a struct media_pad instance, defined in
++include/media/media-entity.h. Each entity stores its pads in a pads array
++managed by the entity driver. Drivers usually embed the array in a
++driver-specific structure.
++
++Pads are identified by their entity and their 0-based index in the pads array.
++Both information are stored in the media_pad structure, making the media_pad
++pointer the canonical way to store and pass link references.
++
++Pads have flags that describe the pad capabilities and state.
++
++ MEDIA_PAD_FL_INPUT indicates that the pad supports sinking data.
++ MEDIA_PAD_FL_OUTPUT indicates that the pad supports sourcing data.
++
++One and only one of MEDIA_PAD_FL_INPUT and MEDIA_PAD_FL_OUTPUT must be set for
++each pad.
++
++- Links
++
++Links are represented by a struct media_link instance, defined in
++include/media/media-entity.h. Each entity stores all links originating at or
++targetting any of its pads in a links array. A given link is thus stored
++twice, once in the source entity and once in the target entity. The array is
++pre-allocated and grows dynamically as needed.
++
++Drivers create links by calling
++
++ media_entity_create_link(struct media_entity *source, u16 source_pad,
++ struct media_entity *sink, u16 sink_pad,
++ u32 flags);
++
++An entry in the link array of each entity is allocated and stores pointers
++to source and sink pads.
++
++Links have flags that describe the link capabilities and state.
++
++ MEDIA_LNK_FL_ENABLED indicates that the link is enabled and can be used
++ to transfer media data. When two or more links target a sink pad, only
++ one of them can be enabled at a time.
++ MEDIA_LNK_FL_IMMUTABLE indicates that the link enabled state can't be
++ modified at runtime. If MEDIA_LNK_FL_IMMUTABLE is set, then
++ MEDIA_LNK_FL_ENABLED must also be set since an immutable link is always
++ enabled.
+diff --git a/drivers/media/Makefile b/drivers/media/Makefile
+index 019d3e0..b890248 100644
+--- a/drivers/media/Makefile
++++ b/drivers/media/Makefile
+@@ -2,7 +2,7 @@
+ # Makefile for the kernel multimedia device drivers.
+ #
+
+-media-objs := media-device.o media-devnode.o
++media-objs := media-device.o media-devnode.o media-entity.o
+
+ ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
+ obj-$(CONFIG_MEDIA_SUPPORT) += media.o
+diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
+index 57a9c6b..b8a3ace 100644
+--- a/drivers/media/media-device.c
++++ b/drivers/media/media-device.c
+@@ -25,6 +25,7 @@
+
+ #include <media/media-device.h>
+ #include <media/media-devnode.h>
++#include <media/media-entity.h>
+
+ static const struct media_file_operations media_device_fops = {
+ .owner = THIS_MODULE,
+@@ -69,6 +70,10 @@ int __must_check media_device_register(struct media_device *mdev)
+ if (WARN_ON(mdev->dev == NULL || mdev->model[0] == 0))
+ return -EINVAL;
+
++ mdev->entity_id = 1;
++ INIT_LIST_HEAD(&mdev->entities);
++ spin_lock_init(&mdev->lock);
++
+ /* Register the device node. */
+ mdev->devnode.fops = &media_device_fops;
+ mdev->devnode.parent = mdev->dev;
+@@ -94,7 +99,58 @@ EXPORT_SYMBOL_GPL(media_device_register);
+ */
+ void media_device_unregister(struct media_device *mdev)
+ {
++ struct media_entity *entity;
++ struct media_entity *next;
++
++ list_for_each_entry_safe(entity, next, &mdev->entities, list)
++ media_device_unregister_entity(entity);
++
+ device_remove_file(&mdev->devnode.dev, &dev_attr_model);
+ media_devnode_unregister(&mdev->devnode);
+ }
+ EXPORT_SYMBOL_GPL(media_device_unregister);
++
++/**
++ * media_device_register_entity - Register an entity with a media device
++ * @mdev: The media device
++ * @entity: The entity
++ */
++int __must_check media_device_register_entity(struct media_device *mdev,
++ struct media_entity *entity)
++{
++ /* Warn if we apparently re-register an entity */
++ WARN_ON(entity->parent != NULL);
++ entity->parent = mdev;
++
++ spin_lock(&mdev->lock);
++ if (entity->id == 0)
++ entity->id = mdev->entity_id++;
++ else
++ mdev->entity_id = max(entity->id + 1, mdev->entity_id);
++ list_add_tail(&entity->list, &mdev->entities);
++ spin_unlock(&mdev->lock);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(media_device_register_entity);
++
++/**
++ * media_device_unregister_entity - Unregister an entity
++ * @entity: The entity
++ *
++ * If the entity has never been registered this function will return
++ * immediately.
++ */
++void media_device_unregister_entity(struct media_entity *entity)
++{
++ struct media_device *mdev = entity->parent;
++
++ if (mdev == NULL)
++ return;
++
++ spin_lock(&mdev->lock);
++ list_del(&entity->list);
++ spin_unlock(&mdev->lock);
++ entity->parent = NULL;
++}
++EXPORT_SYMBOL_GPL(media_device_unregister_entity);
+diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
+new file mode 100644
+index 0000000..e4ba2bc
+--- /dev/null
++++ b/drivers/media/media-entity.c
+@@ -0,0 +1,147 @@
++/*
++ * Media entity
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <media/media-entity.h>
++
++/**
++ * media_entity_init - Initialize a media entity
++ *
++ * @num_pads: Total number of input and output pads.
++ * @extra_links: Initial estimate of the number of extra links.
++ * @pads: Array of 'num_pads' pads.
++ *
++ * The total number of pads is an intrinsic property of entities known by the
++ * entity driver, while the total number of links depends on hardware design
++ * and is an extrinsic property unknown to the entity driver. However, in most
++ * use cases the entity driver can guess the number of links which can safely
++ * be assumed to be equal to or larger than the number of pads.
++ *
++ * For those reasons the links array can be preallocated based on the entity
++ * driver guess and will be reallocated later if extra links need to be
++ * created.
++ *
++ * This function allocates a links array with enough space to hold at least
++ * 'num_pads' + 'extra_links' elements. The media_entity::max_links field will
++ * be set to the number of allocated elements.
++ *
++ * The pads array is managed by the entity driver and passed to
++ * media_entity_init() where its pointer will be stored in the entity structure.
++ */
++int
++media_entity_init(struct media_entity *entity, u16 num_pads,
++ struct media_pad *pads, u16 extra_links)
++{
++ struct media_link *links;
++ unsigned int max_links = num_pads + extra_links;
++ unsigned int i;
++
++ links = kzalloc(max_links * sizeof(links[0]), GFP_KERNEL);
++ if (links == NULL)
++ return -ENOMEM;
++
++ entity->group_id = 0;
++ entity->max_links = max_links;
++ entity->num_links = 0;
++ entity->num_backlinks = 0;
++ entity->num_pads = num_pads;
++ entity->pads = pads;
++ entity->links = links;
++
++ for (i = 0; i < num_pads; i++) {
++ pads[i].entity = entity;
++ pads[i].index = i;
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(media_entity_init);
++
++void
++media_entity_cleanup(struct media_entity *entity)
++{
++ kfree(entity->links);
++}
++EXPORT_SYMBOL_GPL(media_entity_cleanup);
++
++static struct media_link *media_entity_add_link(struct media_entity *entity)
++{
++ if (entity->num_links >= entity->max_links) {
++ struct media_link *links = entity->links;
++ unsigned int max_links = entity->max_links + 2;
++ unsigned int i;
++
++ links = krealloc(links, max_links * sizeof(*links), GFP_KERNEL);
++ if (links == NULL)
++ return NULL;
++
++ for (i = 0; i < entity->num_links; i++)
++ links[i].reverse->reverse = &links[i];
++
++ entity->max_links = max_links;
++ entity->links = links;
++ }
++
++ return &entity->links[entity->num_links++];
++}
++
++int
++media_entity_create_link(struct media_entity *source, u16 source_pad,
++ struct media_entity *sink, u16 sink_pad, u32 flags)
++{
++ struct media_link *link;
++ struct media_link *backlink;
++
++ BUG_ON(source == NULL || sink == NULL);
++ BUG_ON(source_pad >= source->num_pads);
++ BUG_ON(sink_pad >= sink->num_pads);
++
++ link = media_entity_add_link(source);
++ if (link == NULL)
++ return -ENOMEM;
++
++ link->source = &source->pads[source_pad];
++ link->sink = &sink->pads[sink_pad];
++ link->flags = flags;
++
++ /* Create the backlink. Backlinks are used to help graph traversal and
++ * are not reported to userspace.
++ */
++ backlink = media_entity_add_link(sink);
++ if (backlink == NULL) {
++ source->num_links--;
++ return -ENOMEM;
++ }
++
++ backlink->source = &source->pads[source_pad];
++ backlink->sink = &sink->pads[sink_pad];
++ backlink->flags = flags;
++
++ link->reverse = backlink;
++ backlink->reverse = link;
++
++ sink->num_backlinks++;
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(media_entity_create_link);
+diff --git a/include/media/media-device.h b/include/media/media-device.h
+index e11f01a..0b1ecf5 100644
+--- a/include/media/media-device.h
++++ b/include/media/media-device.h
+@@ -25,8 +25,10 @@
+
+ #include <linux/device.h>
+ #include <linux/list.h>
++#include <linux/spinlock.h>
+
+ #include <media/media-devnode.h>
++#include <media/media-entity.h>
+
+ /**
+ * struct media_device - Media device
+@@ -37,6 +39,9 @@
+ * @bus_info: Unique and stable device location identifier
+ * @hw_revision: Hardware device revision
+ * @driver_version: Device driver version
++ * @entity_id: ID of the next entity to be registered
++ * @entities: List of registered entities
++ * @lock: Entities list lock
+ *
+ * This structure represents an abstract high-level media device. It allows easy
+ * access to entities and provides basic media device-level support. The
+@@ -58,6 +63,12 @@ struct media_device {
+ char bus_info[32];
+ u32 hw_revision;
+ u32 driver_version;
++
++ u32 entity_id;
++ struct list_head entities;
++
++ /* Protects the entities list */
++ spinlock_t lock;
+ };
+
+ /* media_devnode to media_device */
+@@ -66,4 +77,12 @@ struct media_device {
+ int __must_check media_device_register(struct media_device *mdev);
+ void media_device_unregister(struct media_device *mdev);
+
++int __must_check media_device_register_entity(struct media_device *mdev,
++ struct media_entity *entity);
++void media_device_unregister_entity(struct media_entity *entity);
++
++/* Iterate over all entities. */
++#define media_device_for_each_entity(entity, mdev) \
++ list_for_each_entry(entity, &(mdev)->entities, list)
++
+ #endif
+diff --git a/include/media/media-entity.h b/include/media/media-entity.h
+new file mode 100644
+index 0000000..7cf9135
+--- /dev/null
++++ b/include/media/media-entity.h
+@@ -0,0 +1,122 @@
++/*
++ * Media entity
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#ifndef _MEDIA_ENTITY_H
++#define _MEDIA_ENTITY_H
++
++#include <linux/list.h>
++
++#define MEDIA_ENT_TYPE_SHIFT 16
++#define MEDIA_ENT_TYPE_MASK 0x00ff0000
++#define MEDIA_ENT_SUBTYPE_MASK 0x0000ffff
++
++#define MEDIA_ENT_T_DEVNODE (1 << MEDIA_ENTITY_TYPE_SHIFT)
++#define MEDIA_ENT_T_DEVNODE_V4L (MEDIA_ENTITY_T_DEVNODE + 1)
++#define MEDIA_ENT_T_DEVNODE_FB (MEDIA_ENTITY_T_DEVNODE + 2)
++#define MEDIA_ENT_T_DEVNODE_ALSA (MEDIA_ENTITY_T_DEVNODE + 3)
++#define MEDIA_ENT_T_DEVNODE_DVB (MEDIA_ENTITY_T_DEVNODE + 4)
++
++#define MEDIA_ENT_T_V4L2_SUBDEV (2 << MEDIA_ENTITY_TYPE_SHIFT)
++#define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR (MEDIA_ENTITY_T_V4L2_SUBDEV + 1)
++#define MEDIA_ENT_T_V4L2_SUBDEV_FLASH (MEDIA_ENTITY_T_V4L2_SUBDEV + 2)
++#define MEDIA_ENT_T_V4L2_SUBDEV_LENS (MEDIA_ENTITY_T_V4L2_SUBDEV + 3)
++
++#define MEDIA_ENT_FL_DEFAULT (1 << 0)
++
++#define MEDIA_LNK_FL_ENABLED (1 << 0)
++#define MEDIA_LNK_FL_IMMUTABLE (1 << 1)
++
++#define MEDIA_PAD_FL_INPUT (1 << 0)
++#define MEDIA_PAD_FL_OUTPUT (1 << 1)
++
++struct media_link {
++ struct media_pad *source; /* Source pad */
++ struct media_pad *sink; /* Sink pad */
++ struct media_link *reverse; /* Link in the reverse direction */
++ unsigned long flags; /* Link flags (MEDIA_LNK_FL_*) */
++};
++
++struct media_pad {
++ struct media_entity *entity; /* Entity this pad belongs to */
++ u16 index; /* Pad index in the entity pads array */
++ unsigned long flags; /* Pad flags (MEDIA_PAD_FL_*) */
++};
++
++struct media_entity {
++ struct list_head list;
++ struct media_device *parent; /* Media device this entity belongs to*/
++ u32 id; /* Entity ID, unique in the parent media
++ * device context */
++ const char *name; /* Entity name */
++ u32 type; /* Entity type (MEDIA_ENT_T_*) */
++ u32 revision; /* Entity revision, driver specific */
++ unsigned long flags; /* Entity flags (MEDIA_ENT_FL_*) */
++ u32 group_id; /* Entity group ID */
++
++ u16 num_pads; /* Number of input and output pads */
++ u16 num_links; /* Number of existing links, both
++ * enabled and disabled */
++ u16 num_backlinks; /* Number of backlinks */
++ u16 max_links; /* Maximum number of links */
++
++ struct media_pad *pads; /* Pads array (num_pads elements) */
++ struct media_link *links; /* Links array (max_links elements)*/
++
++ union {
++ /* Node specifications */
++ struct {
++ u32 major;
++ u32 minor;
++ } v4l;
++ struct {
++ u32 major;
++ u32 minor;
++ } fb;
++ struct {
++ u32 card;
++ u32 device;
++ u32 subdevice;
++ } alsa;
++ int dvb;
++
++ /* Sub-device specifications */
++ /* Nothing needed yet */
++ };
++};
++
++static inline u32 media_entity_type(struct media_entity *entity)
++{
++ return entity->type & MEDIA_ENT_TYPE_MASK;
++}
++
++static inline u32 media_entity_subtype(struct media_entity *entity)
++{
++ return entity->type & MEDIA_ENT_SUBTYPE_MASK;
++}
++
++int media_entity_init(struct media_entity *entity, u16 num_pads,
++ struct media_pad *pads, u16 extra_links);
++void media_entity_cleanup(struct media_entity *entity);
++int media_entity_create_link(struct media_entity *source, u16 source_pad,
++ struct media_entity *sink, u16 sink_pad, u32 flags);
++
++#endif
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0011-media-Entity-graph-traversal.patch b/extras/recipes-kernel/linux/linux-omap/media/0011-media-Entity-graph-traversal.patch
new file mode 100644
index 00000000..15fc6123
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0011-media-Entity-graph-traversal.patch
@@ -0,0 +1,228 @@
+From 5b45472e8a692e6acea3cb6d601b44c17ea8d59e Mon Sep 17 00:00:00 2001
+From: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+Date: Sun, 7 Mar 2010 21:14:14 +0200
+Subject: [PATCH 11/43] media: Entity graph traversal
+
+Add media entity graph traversal. The traversal follows enabled links by
+depth first. Traversing graph backwards is prevented by comparing the next
+possible entity in the graph with the previous one. Multiply connected
+graphs are thus not supported.
+
+Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Vimarsh Zutshi <vimarsh.zutshi@nokia.com>
+---
+ Documentation/media-framework.txt | 42 +++++++++++++
+ drivers/media/media-entity.c | 115 +++++++++++++++++++++++++++++++++++++
+ include/media/media-entity.h | 15 +++++
+ 3 files changed, 172 insertions(+), 0 deletions(-)
+
+diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
+index b252cf9..88fe379 100644
+--- a/Documentation/media-framework.txt
++++ b/Documentation/media-framework.txt
+@@ -216,3 +216,45 @@ Links have flags that describe the link capabilities and state.
+ modified at runtime. If MEDIA_LNK_FL_IMMUTABLE is set, then
+ MEDIA_LNK_FL_ENABLED must also be set since an immutable link is always
+ enabled.
++
++
++Graph traversal
++---------------
++
++The media framework provides APIs to iterate over entities in a graph.
++
++To iterate over all entities belonging to a media device, drivers can use the
++media_device_for_each_entity macro, defined in include/media/media-device.h.
++
++ struct media_entity *entity;
++
++ media_device_for_each_entity(entity, mdev) {
++ /* entity will point to each entity in turn */
++ ...
++ }
++
++Drivers might also need to iterate over all entities in a graph that can be
++reached only through enabled links starting at a given entity. The media
++framework provides a depth-first graph traversal API for that purpose.
++
++Note that graphs with cycles (whether directed or undirected) are *NOT*
++supported by the graph traversal API. To prevent infinite loops, the graph
++traversal code limits the maximum depth to MEDIA_ENTITY_ENUM_MAX_DEPTH,
++currently defined as 16.
++
++Drivers initiate a graph traversal by calling
++
++ media_entity_graph_walk_start(struct media_entity_graph *graph,
++ struct media_entity *entity);
++
++The graph structure, provided by the caller, is initialized to start graph
++traversal at the given entity.
++
++Drivers can then retrieve the next entity by calling
++
++ media_entity_graph_walk_next(struct media_entity_graph *graph);
++
++When the graph traversal is complete the function will return NULL.
++
++Graph traversal can be interrupted at any moment. No cleanup function call is
++required and the graph structure can be freed normally.
+diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
+index e4ba2bc..a805f20 100644
+--- a/drivers/media/media-entity.c
++++ b/drivers/media/media-entity.c
+@@ -84,6 +84,121 @@ media_entity_cleanup(struct media_entity *entity)
+ }
+ EXPORT_SYMBOL_GPL(media_entity_cleanup);
+
++/* -----------------------------------------------------------------------------
++ * Graph traversal
++ */
++
++static struct media_entity *
++media_entity_other(struct media_entity *entity, struct media_link *link)
++{
++ if (link->source->entity == entity)
++ return link->sink->entity;
++ else
++ return link->source->entity;
++}
++
++/* push an entity to traversal stack */
++static void stack_push(struct media_entity_graph *graph,
++ struct media_entity *entity)
++{
++ if (graph->top == MEDIA_ENTITY_ENUM_MAX_DEPTH - 1) {
++ WARN_ON(1);
++ return;
++ }
++ graph->top++;
++ graph->stack[graph->top].link = 0;
++ graph->stack[graph->top].entity = entity;
++}
++
++static struct media_entity *stack_pop(struct media_entity_graph *graph)
++{
++ struct media_entity *entity;
++
++ entity = graph->stack[graph->top].entity;
++ graph->top--;
++
++ return entity;
++}
++
++#define stack_peek(en) ((en)->stack[(en)->top - 1].entity)
++#define link_top(en) ((en)->stack[(en)->top].link)
++#define stack_top(en) ((en)->stack[(en)->top].entity)
++
++/**
++ * media_entity_graph_walk_start - Start walking the media graph at a given entity
++ * @graph: Media graph structure that will be used to walk the graph
++ * @entity: Starting entity
++ *
++ * This function initializes the graph traversal structure to walk the entities
++ * graph starting at the given entity. The traversal structure must not be
++ * modified by the caller during graph traversal. When done the structure can
++ * safely be freed.
++ */
++void media_entity_graph_walk_start(struct media_entity_graph *graph,
++ struct media_entity *entity)
++{
++ graph->top = 0;
++ graph->stack[graph->top].entity = NULL;
++ stack_push(graph, entity);
++}
++EXPORT_SYMBOL_GPL(media_entity_graph_walk_start);
++
++/**
++ * media_entity_graph_walk_next - Get the next entity in the graph
++ * @graph: Media graph structure
++ *
++ * Perform a depth-first traversal of the given media entities graph.
++ *
++ * The graph structure must have been previously initialized with a call to
++ * media_entity_graph_walk_start().
++ *
++ * Return the next entity in the graph or NULL if the whole graph have been
++ * traversed.
++ */
++struct media_entity *
++media_entity_graph_walk_next(struct media_entity_graph *graph)
++{
++ if (stack_top(graph) == NULL)
++ return NULL;
++
++ /*
++ * Depth first search. Push entity to stack and continue from
++ * top of the stack until no more entities on the level can be
++ * found.
++ */
++ while (link_top(graph) < stack_top(graph)->num_links) {
++ struct media_entity *entity = stack_top(graph);
++ struct media_link *link = &entity->links[link_top(graph)];
++ struct media_entity *next;
++
++ /* The link is not enabled so we do not follow. */
++ if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
++ link_top(graph)++;
++ continue;
++ }
++
++ /* Get the entity in the other end of the link . */
++ next = media_entity_other(entity, link);
++
++ /* Was it the entity we came here from? */
++ if (next == stack_peek(graph)) {
++ link_top(graph)++;
++ continue;
++ }
++
++ /* Push the new entity to stack and start over. */
++ link_top(graph)++;
++ stack_push(graph, next);
++ }
++
++ return stack_pop(graph);
++}
++EXPORT_SYMBOL_GPL(media_entity_graph_walk_next);
++
++/* -----------------------------------------------------------------------------
++ * Links management
++ */
++
+ static struct media_link *media_entity_add_link(struct media_entity *entity)
+ {
+ if (entity->num_links >= entity->max_links) {
+diff --git a/include/media/media-entity.h b/include/media/media-entity.h
+index 7cf9135..b82f824 100644
+--- a/include/media/media-entity.h
++++ b/include/media/media-entity.h
+@@ -113,10 +113,25 @@ static inline u32 media_entity_subtype(struct media_entity *entity)
+ return entity->type & MEDIA_ENT_SUBTYPE_MASK;
+ }
+
++#define MEDIA_ENTITY_ENUM_MAX_DEPTH 16
++
++struct media_entity_graph {
++ struct {
++ struct media_entity *entity;
++ int link;
++ } stack[MEDIA_ENTITY_ENUM_MAX_DEPTH];
++ int top;
++};
++
+ int media_entity_init(struct media_entity *entity, u16 num_pads,
+ struct media_pad *pads, u16 extra_links);
+ void media_entity_cleanup(struct media_entity *entity);
+ int media_entity_create_link(struct media_entity *source, u16 source_pad,
+ struct media_entity *sink, u16 sink_pad, u32 flags);
+
++void media_entity_graph_walk_start(struct media_entity_graph *graph,
++ struct media_entity *entity);
++struct media_entity *
++media_entity_graph_walk_next(struct media_entity_graph *graph);
++
+ #endif
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0012-media-Entity-use-count.patch b/extras/recipes-kernel/linux/linux-omap/media/0012-media-Entity-use-count.patch
new file mode 100644
index 00000000..bc850e44
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0012-media-Entity-use-count.patch
@@ -0,0 +1,176 @@
+From 3be6a2d10ff0cad0b240c65054da28395b014f82 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Sun, 7 Mar 2010 20:04:59 +0200
+Subject: [PATCH 12/43] media: Entity use count
+
+Due to the wide differences between drivers regarding power management
+needs, the media controller does not implement power management.
+However, the media_entity structure includes a use_count field that
+media drivers can use to track the number of users of every entity for
+power management needs.
+
+The use_count field is owned by media drivers and must not be touched by
+entity drivers. Access to the field must be protected by the media
+device graph_mutex lock.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ Documentation/media-framework.txt | 13 ++++++++++
+ drivers/media/media-device.c | 1 +
+ drivers/media/media-entity.c | 46 +++++++++++++++++++++++++++++++++++++
+ include/media/media-device.h | 4 +++
+ include/media/media-entity.h | 5 ++++
+ 5 files changed, 69 insertions(+), 0 deletions(-)
+
+diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
+index 88fe379..9017a41 100644
+--- a/Documentation/media-framework.txt
++++ b/Documentation/media-framework.txt
+@@ -258,3 +258,16 @@ When the graph traversal is complete the function will return NULL.
+
+ Graph traversal can be interrupted at any moment. No cleanup function call is
+ required and the graph structure can be freed normally.
++
++
++Use count and power handling
++----------------------------
++
++Due to the wide differences between drivers regarding power management needs,
++the media controller does not implement power management. However, the
++media_entity structure includes a use_count field that media drivers can use to
++track the number of users of every entity for power management needs.
++
++The use_count field is owned by media drivers and must not be touched by entity
++drivers. Access to the field must be protected by the media device graph_mutex
++lock.
+diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
+index b8a3ace..e4c2157 100644
+--- a/drivers/media/media-device.c
++++ b/drivers/media/media-device.c
+@@ -73,6 +73,7 @@ int __must_check media_device_register(struct media_device *mdev)
+ mdev->entity_id = 1;
+ INIT_LIST_HEAD(&mdev->entities);
+ spin_lock_init(&mdev->lock);
++ mutex_init(&mdev->graph_mutex);
+
+ /* Register the device node. */
+ mdev->devnode.fops = &media_device_fops;
+diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
+index a805f20..fe6bfd2 100644
+--- a/drivers/media/media-entity.c
++++ b/drivers/media/media-entity.c
+@@ -23,6 +23,7 @@
+ #include <linux/module.h>
+ #include <linux/slab.h>
+ #include <media/media-entity.h>
++#include <media/media-device.h>
+
+ /**
+ * media_entity_init - Initialize a media entity
+@@ -196,6 +197,51 @@ media_entity_graph_walk_next(struct media_entity_graph *graph)
+ EXPORT_SYMBOL_GPL(media_entity_graph_walk_next);
+
+ /* -----------------------------------------------------------------------------
++ * Module use count
++ */
++
++/*
++ * media_entity_get - Get a reference to the parent module
++ * @entity: The entity
++ *
++ * Get a reference to the parent media device module.
++ *
++ * The function will return immediately if @entity is NULL.
++ *
++ * Return a pointer to the entity on success or NULL on failure.
++ */
++struct media_entity *media_entity_get(struct media_entity *entity)
++{
++ if (entity == NULL)
++ return NULL;
++
++ if (entity->parent->dev &&
++ !try_module_get(entity->parent->dev->driver->owner))
++ return NULL;
++
++ return entity;
++}
++EXPORT_SYMBOL_GPL(media_entity_get);
++
++/*
++ * media_entity_put - Release the reference to the parent module
++ * @entity: The entity
++ *
++ * Release the reference count acquired by media_entity_get().
++ *
++ * The function will return immediately if @entity is NULL.
++ */
++void media_entity_put(struct media_entity *entity)
++{
++ if (entity == NULL)
++ return;
++
++ if (entity->parent->dev)
++ module_put(entity->parent->dev->driver->owner);
++}
++EXPORT_SYMBOL_GPL(media_entity_put);
++
++/* -----------------------------------------------------------------------------
+ * Links management
+ */
+
+diff --git a/include/media/media-device.h b/include/media/media-device.h
+index 0b1ecf5..260d59c 100644
+--- a/include/media/media-device.h
++++ b/include/media/media-device.h
+@@ -25,6 +25,7 @@
+
+ #include <linux/device.h>
+ #include <linux/list.h>
++#include <linux/mutex.h>
+ #include <linux/spinlock.h>
+
+ #include <media/media-devnode.h>
+@@ -42,6 +43,7 @@
+ * @entity_id: ID of the next entity to be registered
+ * @entities: List of registered entities
+ * @lock: Entities list lock
++ * @graph_mutex: Entities graph operation lock
+ *
+ * This structure represents an abstract high-level media device. It allows easy
+ * access to entities and provides basic media device-level support. The
+@@ -69,6 +71,8 @@ struct media_device {
+
+ /* Protects the entities list */
+ spinlock_t lock;
++ /* Serializes graph operations. */
++ struct mutex graph_mutex;
+ };
+
+ /* media_devnode to media_device */
+diff --git a/include/media/media-entity.h b/include/media/media-entity.h
+index b82f824..114541a 100644
+--- a/include/media/media-entity.h
++++ b/include/media/media-entity.h
+@@ -81,6 +81,8 @@ struct media_entity {
+ struct media_pad *pads; /* Pads array (num_pads elements) */
+ struct media_link *links; /* Links array (max_links elements)*/
+
++ int use_count; /* Use count for the entity. */
++
+ union {
+ /* Node specifications */
+ struct {
+@@ -129,6 +131,9 @@ void media_entity_cleanup(struct media_entity *entity);
+ int media_entity_create_link(struct media_entity *source, u16 source_pad,
+ struct media_entity *sink, u16 sink_pad, u32 flags);
+
++struct media_entity *media_entity_get(struct media_entity *entity);
++void media_entity_put(struct media_entity *entity);
++
+ void media_entity_graph_walk_start(struct media_entity_graph *graph,
+ struct media_entity *entity);
+ struct media_entity *
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0013-media-Media-device-information-query.patch b/extras/recipes-kernel/linux/linux-omap/media/0013-media-Media-device-information-query.patch
new file mode 100644
index 00000000..bf9fcd97
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0013-media-Media-device-information-query.patch
@@ -0,0 +1,659 @@
+From cb6936ced565e168ac7f9be06dc3320733aac17f Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 18 Aug 2010 16:41:22 +0200
+Subject: [PATCH 13/43] media: Media device information query
+
+Create the following ioctl and implement it at the media device level to
+query device information.
+
+- MEDIA_IOC_DEVICE_INFO: Query media device information
+
+The ioctl and its data structure are defined in the new kernel header
+linux/media.h available to userspace applications.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ Documentation/DocBook/media-entities.tmpl | 12 ++
+ Documentation/DocBook/v4l/media-controller.xml | 10 ++
+ Documentation/DocBook/v4l/media-func-close.xml | 59 +++++++++
+ Documentation/DocBook/v4l/media-func-ioctl.xml | 116 +++++++++++++++++
+ Documentation/DocBook/v4l/media-func-open.xml | 94 ++++++++++++++
+ .../DocBook/v4l/media-ioc-device-info.xml | 132 ++++++++++++++++++++
+ drivers/media/media-device.c | 57 +++++++++
+ include/linux/Kbuild | 1 +
+ include/linux/media.h | 45 +++++++
+ 9 files changed, 526 insertions(+), 0 deletions(-)
+ create mode 100644 Documentation/DocBook/v4l/media-func-close.xml
+ create mode 100644 Documentation/DocBook/v4l/media-func-ioctl.xml
+ create mode 100644 Documentation/DocBook/v4l/media-func-open.xml
+ create mode 100644 Documentation/DocBook/v4l/media-ioc-device-info.xml
+ create mode 100644 include/linux/media.h
+
+diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
+index 61d6f11..6af3375 100644
+--- a/Documentation/DocBook/media-entities.tmpl
++++ b/Documentation/DocBook/media-entities.tmpl
+@@ -11,6 +11,10 @@
+ <!ENTITY func-select "<link linkend='func-select'><function>select()</function></link>">
+ <!ENTITY func-write "<link linkend='func-write'><function>write()</function></link>">
+
++<!ENTITY media-func-close "<link linkend='media-func-close'><function>close()</function></link>">
++<!ENTITY media-func-ioctl "<link linkend='media-func-ioctl'><function>ioctl()</function></link>">
++<!ENTITY media-func-open "<link linkend='media-func-open'><function>open()</function></link>">
++
+ <!-- Ioctls -->
+ <!ENTITY VIDIOC-CROPCAP "<link linkend='vidioc-cropcap'><constant>VIDIOC_CROPCAP</constant></link>">
+ <!ENTITY VIDIOC-DBG-G-CHIP-IDENT "<link linkend='vidioc-dbg-g-chip-ident'><constant>VIDIOC_DBG_G_CHIP_IDENT</constant></link>">
+@@ -87,6 +91,8 @@
+ <!ENTITY VIDIOC-TRY-FMT "<link linkend='vidioc-g-fmt'><constant>VIDIOC_TRY_FMT</constant></link>">
+ <!ENTITY VIDIOC-UNSUBSCRIBE-EVENT "<link linkend='vidioc-subscribe-event'><constant>VIDIOC_UNSUBSCRIBE_EVENT</constant></link>">
+
++<!ENTITY MEDIA-IOC-DEVICE-INFO "<link linkend='media-ioc-device-info'><constant>MEDIA_IOC_DEVICE_INFO</constant></link>">
++
+ <!-- Types -->
+ <!ENTITY v4l2-std-id "<link linkend='v4l2-std-id'>v4l2_std_id</link>">
+
+@@ -181,6 +187,8 @@
+ <!ENTITY v4l2-vbi-format "struct&nbsp;<link linkend='v4l2-vbi-format'>v4l2_vbi_format</link>">
+ <!ENTITY v4l2-window "struct&nbsp;<link linkend='v4l2-window'>v4l2_window</link>">
+
++<!ENTITY media-device-info "struct&nbsp;<link linkend='media-device-info'>media_device_info</link>">
++
+ <!-- Error Codes -->
+ <!ENTITY EACCES "<errorcode>EACCES</errorcode> error code">
+ <!ENTITY EAGAIN "<errorcode>EAGAIN</errorcode> error code">
+@@ -322,6 +330,10 @@
+ <!ENTITY sub-media-indices SYSTEM "media-indices.tmpl">
+
+ <!ENTITY sub-media-controller SYSTEM "v4l/media-controller.xml">
++<!ENTITY sub-media-open SYSTEM "v4l/media-func-open.xml">
++<!ENTITY sub-media-close SYSTEM "v4l/media-func-close.xml">
++<!ENTITY sub-media-ioctl SYSTEM "v4l/media-func-ioctl.xml">
++<!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml">
+
+ <!-- Function Reference -->
+ <!ENTITY close SYSTEM "v4l/func-close.xml">
+diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml
+index f89228d..a46b786 100644
+--- a/Documentation/DocBook/v4l/media-controller.xml
++++ b/Documentation/DocBook/v4l/media-controller.xml
+@@ -74,3 +74,13 @@
+ pad to a sink pad.</para>
+ </section>
+ </chapter>
++
++<appendix id="media-user-func">
++ <title>Function Reference</title>
++ <!-- Keep this alphabetically sorted. -->
++ &sub-media-open;
++ &sub-media-close;
++ &sub-media-ioctl;
++ <!-- All ioctls go here. -->
++ &sub-media-ioc-device-info;
++</appendix>
+diff --git a/Documentation/DocBook/v4l/media-func-close.xml b/Documentation/DocBook/v4l/media-func-close.xml
+new file mode 100644
+index 0000000..be149c8
+--- /dev/null
++++ b/Documentation/DocBook/v4l/media-func-close.xml
+@@ -0,0 +1,59 @@
++<refentry id="media-func-close">
++ <refmeta>
++ <refentrytitle>media close()</refentrytitle>
++ &manvol;
++ </refmeta>
++
++ <refnamediv>
++ <refname>media-close</refname>
++ <refpurpose>Close a media device</refpurpose>
++ </refnamediv>
++
++ <refsynopsisdiv>
++ <funcsynopsis>
++ <funcsynopsisinfo>#include &lt;unistd.h&gt;</funcsynopsisinfo>
++ <funcprototype>
++ <funcdef>int <function>close</function></funcdef>
++ <paramdef>int <parameter>fd</parameter></paramdef>
++ </funcprototype>
++ </funcsynopsis>
++ </refsynopsisdiv>
++
++ <refsect1>
++ <title>Arguments</title>
++
++ <variablelist>
++ <varlistentry>
++ <term><parameter>fd</parameter></term>
++ <listitem>
++ <para>&fd;</para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++
++ <refsect1>
++ <title>Description</title>
++
++ <para>Closes the media device. Resources associated with the file descriptor
++ are freed. The device configuration remain unchanged.</para>
++ </refsect1>
++
++ <refsect1>
++ <title>Return Value</title>
++
++ <para><function>close</function> returns 0 on success. On error, -1 is
++ returned, and <varname>errno</varname> is set appropriately. Possible error
++ codes are:</para>
++
++ <variablelist>
++ <varlistentry>
++ <term><errorcode>EBADF</errorcode></term>
++ <listitem>
++ <para><parameter>fd</parameter> is not a valid open file descriptor.
++ </para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++</refentry>
+diff --git a/Documentation/DocBook/v4l/media-func-ioctl.xml b/Documentation/DocBook/v4l/media-func-ioctl.xml
+new file mode 100644
+index 0000000..bda8604
+--- /dev/null
++++ b/Documentation/DocBook/v4l/media-func-ioctl.xml
+@@ -0,0 +1,116 @@
++<refentry id="media-func-ioctl">
++ <refmeta>
++ <refentrytitle>media ioctl()</refentrytitle>
++ &manvol;
++ </refmeta>
++
++ <refnamediv>
++ <refname>media-ioctl</refname>
++ <refpurpose>Control a media device</refpurpose>
++ </refnamediv>
++
++ <refsynopsisdiv>
++ <funcsynopsis>
++ <funcsynopsisinfo>#include &lt;sys/ioctl.h&gt;</funcsynopsisinfo>
++ <funcprototype>
++ <funcdef>int <function>ioctl</function></funcdef>
++ <paramdef>int <parameter>fd</parameter></paramdef>
++ <paramdef>int <parameter>request</parameter></paramdef>
++ <paramdef>void *<parameter>argp</parameter></paramdef>
++ </funcprototype>
++ </funcsynopsis>
++ </refsynopsisdiv>
++
++ <refsect1>
++ <title>Arguments</title>
++
++ <variablelist>
++ <varlistentry>
++ <term><parameter>fd</parameter></term>
++ <listitem>
++ <para>&fd;</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>request</parameter></term>
++ <listitem>
++ <para>Media ioctl request code as defined in the media.h header file,
++ for example MEDIA_IOC_SETUP_LINK.</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>argp</parameter></term>
++ <listitem>
++ <para>Pointer to a request-specific structure.</para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++
++ <refsect1>
++ <title>Description</title>
++ <para>The <function>ioctl()</function> function manipulates media device
++ parameters. The argument <parameter>fd</parameter> must be an open file
++ descriptor.</para>
++ <para>The ioctl <parameter>request</parameter> code specifies the media
++ function to be called. It has encoded in it whether the argument is an
++ input, output or read/write parameter, and the size of the argument
++ <parameter>argp</parameter> in bytes.</para>
++ <para>Macros and structures definitions specifying media ioctl requests and
++ their parameters are located in the media.h header file. All media ioctl
++ requests, their respective function and parameters are specified in
++ <xref linkend="media-user-func" />.</para>
++ </refsect1>
++
++ <refsect1>
++ <title>Return Value</title>
++
++ <para><function>ioctl()</function> returns <returnvalue>0</returnvalue> on
++ success. On failure, <returnvalue>-1</returnvalue> is returned, and the
++ <varname>errno</varname> variable is set appropriately. Generic error codes
++ are listed below, and request-specific error codes are listed in the
++ individual requests descriptions.</para>
++ <para>When an ioctl that takes an output or read/write parameter fails,
++ the parameter remains unmodified.</para>
++
++ <variablelist>
++ <varlistentry>
++ <term><errorcode>EBADF</errorcode></term>
++ <listitem>
++ <para><parameter>fd</parameter> is not a valid open file descriptor.
++ </para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><errorcode>EFAULT</errorcode></term>
++ <listitem>
++ <para><parameter>argp</parameter> references an inaccessible memory
++ area.</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><errorcode>EINVAL</errorcode></term>
++ <listitem>
++ <para>The <parameter>request</parameter> or the data pointed to by
++ <parameter>argp</parameter> is not valid. This is a very common error
++ code, see the individual ioctl requests listed in
++ <xref linkend="media-user-func" /> for actual causes.</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><errorcode>ENOMEM</errorcode></term>
++ <listitem>
++ <para>Insufficient kernel memory was available to complete the
++ request.</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><errorcode>ENOTTY</errorcode></term>
++ <listitem>
++ <para><parameter>fd</parameter> is not associated with a character
++ special device.</para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++</refentry>
+diff --git a/Documentation/DocBook/v4l/media-func-open.xml b/Documentation/DocBook/v4l/media-func-open.xml
+new file mode 100644
+index 0000000..f7df034
+--- /dev/null
++++ b/Documentation/DocBook/v4l/media-func-open.xml
+@@ -0,0 +1,94 @@
++<refentry id="media-func-open">
++ <refmeta>
++ <refentrytitle>media open()</refentrytitle>
++ &manvol;
++ </refmeta>
++
++ <refnamediv>
++ <refname>media-open</refname>
++ <refpurpose>Open a media device</refpurpose>
++ </refnamediv>
++
++ <refsynopsisdiv>
++ <funcsynopsis>
++ <funcsynopsisinfo>#include &lt;fcntl.h&gt;</funcsynopsisinfo>
++ <funcprototype>
++ <funcdef>int <function>open</function></funcdef>
++ <paramdef>const char *<parameter>device_name</parameter></paramdef>
++ <paramdef>int <parameter>flags</parameter></paramdef>
++ </funcprototype>
++ </funcsynopsis>
++ </refsynopsisdiv>
++
++ <refsect1>
++ <title>Arguments</title>
++
++ <variablelist>
++ <varlistentry>
++ <term><parameter>device_name</parameter></term>
++ <listitem>
++ <para>Device to be opened.</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>flags</parameter></term>
++ <listitem>
++ <para>Open flags. Access mode must be either <constant>O_RDONLY</constant>
++ or <constant>O_RDWR</constant>. Other flags have no effect.</para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++ <refsect1>
++ <title>Description</title>
++ <para>To open a media device applications call <function>open()</function>
++ with the desired device name. The function has no side effects; the device
++ configuration remain unchanged.</para>
++ <para>When the device is opened in read-only mode, attemps to modify its
++ configuration will result in an error, and <varname>errno</varname> will be
++ set to <errorcode>EBADF</errorcode>.</para>
++ </refsect1>
++ <refsect1>
++ <title>Return Value</title>
++
++ <para><function>open</function> returns the new file descriptor on success.
++ On error, -1 is returned, and <varname>errno</varname> is set appropriately.
++ Possible error codes are:</para>
++
++ <variablelist>
++ <varlistentry>
++ <term><errorcode>EACCES</errorcode></term>
++ <listitem>
++ <para>The requested access to the file is not allowed.</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><errorcode>EMFILE</errorcode></term>
++ <listitem>
++ <para>The process already has the maximum number of files open.
++ </para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><errorcode>ENFILE</errorcode></term>
++ <listitem>
++ <para>The system limit on the total number of open files has been
++ reached.</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><errorcode>ENOMEM</errorcode></term>
++ <listitem>
++ <para>Insufficient kernel memory was available.</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><errorcode>ENXIO</errorcode></term>
++ <listitem>
++ <para>No device corresponding to this device special file exists.
++ </para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++</refentry>
+diff --git a/Documentation/DocBook/v4l/media-ioc-device-info.xml b/Documentation/DocBook/v4l/media-ioc-device-info.xml
+new file mode 100644
+index 0000000..278a312
+--- /dev/null
++++ b/Documentation/DocBook/v4l/media-ioc-device-info.xml
+@@ -0,0 +1,132 @@
++<refentry id="media-ioc-device-info">
++ <refmeta>
++ <refentrytitle>ioctl MEDIA_IOC_DEVICE_INFO</refentrytitle>
++ &manvol;
++ </refmeta>
++
++ <refnamediv>
++ <refname>MEDIA_IOC_DEVICE_INFO</refname>
++ <refpurpose>Query device information</refpurpose>
++ </refnamediv>
++
++ <refsynopsisdiv>
++ <funcsynopsis>
++ <funcprototype>
++ <funcdef>int <function>ioctl</function></funcdef>
++ <paramdef>int <parameter>fd</parameter></paramdef>
++ <paramdef>int <parameter>request</parameter></paramdef>
++ <paramdef>struct media_device_info *<parameter>argp</parameter></paramdef>
++ </funcprototype>
++ </funcsynopsis>
++ </refsynopsisdiv>
++
++ <refsect1>
++ <title>Arguments</title>
++
++ <variablelist>
++ <varlistentry>
++ <term><parameter>fd</parameter></term>
++ <listitem>
++ <para>&fd;</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>request</parameter></term>
++ <listitem>
++ <para>MEDIA_IOC_DEVICE_INFO</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>argp</parameter></term>
++ <listitem>
++ <para></para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++
++ <refsect1>
++ <title>Description</title>
++
++ <para>All media devices must support the <constant>MEDIA_IOC_DEVICE_INFO</constant>
++ ioctl. To query device information, applications call the ioctl with a
++ pointer to a &media-device-info;. The driver fills the structure and returns
++ the information to the application.
++ The ioctl never fails.</para>
++
++ <table pgwide="1" frame="none" id="media-device-info">
++ <title>struct <structname>media_device_info</structname></title>
++ <tgroup cols="3">
++ &cs-str;
++ <tbody valign="top">
++ <row>
++ <entry>char</entry>
++ <entry><structfield>driver</structfield>[16]</entry>
++ <entry><para>Name of the driver implementing the media API as a
++ NUL-terminated ASCII string. The driver version is stored in the
++ <structfield>driver_version</structfield> field.</para>
++ <para>Driver specific applications can use this information to
++ verify the driver identity. It is also useful to work around
++ known bugs, or to identify drivers in error reports.</para></entry>
++ </row>
++ <row>
++ <entry>char</entry>
++ <entry><structfield>model</structfield>[32]</entry>
++ <entry>Device model name as a NUL-terminated UTF-8 string. The
++ device version is stored in the <structfield>device_version</structfield>
++ field and is not be appended to the model name.</entry>
++ </row>
++ <row>
++ <entry>char</entry>
++ <entry><structfield>serial</structfield>[40]</entry>
++ <entry>Serial number as a NUL-terminated ASCII string.</entry>
++ </row>
++ <row>
++ <entry>char</entry>
++ <entry><structfield>bus_info</structfield>[32]</entry>
++ <entry>Location of the device in the system as a NUL-terminated
++ ASCII string. This includes the bus type name (PCI, USB, ...) and a
++ bus-specific identifier.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>media_version</structfield></entry>
++ <entry>Media API version, formatted with the
++ <constant>KERNEL_VERSION()</constant> macro.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>hw_revision</structfield></entry>
++ <entry>Hardware device revision in a driver-specific format.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>media_version</structfield></entry>
++ <entry>Media device driver version, formatted with the
++ <constant>KERNEL_VERSION()</constant> macro. Together with the
++ <structfield>driver</structfield> field this identifies a particular
++ driver.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>reserved</structfield>[31]</entry>
++ <entry>Reserved for future extensions. Drivers and applications must
++ set this array to zero.</entry>
++ </row>
++ </tbody>
++ </tgroup>
++ </table>
++ <para>The <structfield>serial</structfield> and <structfield>bus_info</structfield>
++ fields can be used to distinguish between multiple instances of otherwise
++ identical hardware. The serial number takes precedence when provided and can
++ be assumed to be unique. If the serial number is an empty string, the
++ <structfield>bus_info</structfield> field can be used instead. The
++ <structfield>bus_info</structfield> field is guaranteed to be unique, but
++ can vary across reboots or device unplug/replug.</para>
++ </refsect1>
++
++ <refsect1>
++ <title>Return value</title>
++ <para>This function doesn't return specific error codes.</para>
++ </refsect1>
++</refentry>
+diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
+index e4c2157..5c745be 100644
+--- a/drivers/media/media-device.c
++++ b/drivers/media/media-device.c
+@@ -22,13 +22,70 @@
+
+ #include <linux/types.h>
+ #include <linux/ioctl.h>
++#include <linux/media.h>
+
+ #include <media/media-device.h>
+ #include <media/media-devnode.h>
+ #include <media/media-entity.h>
+
++/* -----------------------------------------------------------------------------
++ * Userspace API
++ */
++
++static int media_device_open(struct file *filp)
++{
++ return 0;
++}
++
++static int media_device_close(struct file *filp)
++{
++ return 0;
++}
++
++static int media_device_get_info(struct media_device *dev,
++ struct media_device_info __user *__info)
++{
++ struct media_device_info info;
++
++ memset(&info, 0, sizeof(info));
++
++ strlcpy(info.driver, dev->dev->driver->name, sizeof(info.driver));
++ strlcpy(info.model, dev->model, sizeof(info.model));
++ strlcpy(info.serial, dev->serial, sizeof(info.serial));
++ strlcpy(info.bus_info, dev->bus_info, sizeof(info.bus_info));
++
++ info.media_version = MEDIA_API_VERSION;
++ info.hw_revision = dev->hw_revision;
++ info.driver_version = dev->driver_version;
++
++ return copy_to_user(__info, &info, sizeof(*__info));
++}
++
++static long media_device_ioctl(struct file *filp, unsigned int cmd,
++ unsigned long arg)
++{
++ struct media_devnode *devnode = media_devnode_data(filp);
++ struct media_device *dev = to_media_device(devnode);
++ long ret;
++
++ switch (cmd) {
++ case MEDIA_IOC_DEVICE_INFO:
++ ret = media_device_get_info(dev,
++ (struct media_device_info __user *)arg);
++ break;
++
++ default:
++ ret = -ENOIOCTLCMD;
++ }
++
++ return ret;
++}
++
+ static const struct media_file_operations media_device_fops = {
+ .owner = THIS_MODULE,
++ .open = media_device_open,
++ .ioctl = media_device_ioctl,
++ .release = media_device_close,
+ };
+
+ /* -----------------------------------------------------------------------------
+diff --git a/include/linux/Kbuild b/include/linux/Kbuild
+index 97319a8..26e0a7f 100644
+--- a/include/linux/Kbuild
++++ b/include/linux/Kbuild
+@@ -228,6 +228,7 @@ header-y += magic.h
+ header-y += major.h
+ header-y += map_to_7segment.h
+ header-y += matroxfb.h
++header-y += media.h
+ header-y += mempolicy.h
+ header-y += meye.h
+ header-y += mii.h
+diff --git a/include/linux/media.h b/include/linux/media.h
+new file mode 100644
+index 0000000..4c52f08
+--- /dev/null
++++ b/include/linux/media.h
+@@ -0,0 +1,45 @@
++/*
++ * Multimedia device API
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#ifndef __LINUX_MEDIA_H
++#define __LINUX_MEDIA_H
++
++#include <linux/ioctl.h>
++#include <linux/types.h>
++#include <linux/version.h>
++
++#define MEDIA_API_VERSION KERNEL_VERSION(0, 1, 0)
++
++struct media_device_info {
++ char driver[16];
++ char model[32];
++ char serial[40];
++ char bus_info[32];
++ __u32 media_version;
++ __u32 hw_revision;
++ __u32 driver_version;
++ __u32 reserved[31];
++};
++
++#define MEDIA_IOC_DEVICE_INFO _IOWR('M', 1, struct media_device_info)
++
++#endif /* __LINUX_MEDIA_H */
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0014-media-Entities-pads-and-links-enumeration.patch b/extras/recipes-kernel/linux/linux-omap/media/0014-media-Entities-pads-and-links-enumeration.patch
new file mode 100644
index 00000000..cc9e8761
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0014-media-Entities-pads-and-links-enumeration.patch
@@ -0,0 +1,889 @@
+From d7784ca094970b836c99e5f2a6344811625753a3 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:40:01 +0100
+Subject: [PATCH 14/43] media: Entities, pads and links enumeration
+
+Create the following two ioctls and implement them at the media device
+level to enumerate entities, pads and links.
+
+- MEDIA_IOC_ENUM_ENTITIES: Enumerate entities and their properties
+- MEDIA_IOC_ENUM_LINKS: Enumerate all pads and links for a given entity
+
+Entity IDs can be non-contiguous. Userspace applications should
+enumerate entities using the MEDIA_ENT_ID_FLAG_NEXT flag. When the flag
+is set in the entity ID, the MEDIA_IOC_ENUM_ENTITIES will return the
+next entity with an ID bigger than the requested one.
+
+Only forward links that originate at one of the entity's source pads are
+returned during the enumeration process.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+---
+ Documentation/DocBook/media-entities.tmpl | 8 +
+ Documentation/DocBook/v4l/media-controller.xml | 2 +
+ .../DocBook/v4l/media-ioc-device-info.xml | 3 +-
+ .../DocBook/v4l/media-ioc-enum-entities.xml | 308 ++++++++++++++++++++
+ Documentation/DocBook/v4l/media-ioc-enum-links.xml | 202 +++++++++++++
+ drivers/media/media-device.c | 123 ++++++++
+ include/linux/media.h | 85 ++++++
+ include/media/media-entity.h | 24 +--
+ 8 files changed, 731 insertions(+), 24 deletions(-)
+ create mode 100644 Documentation/DocBook/v4l/media-ioc-enum-entities.xml
+ create mode 100644 Documentation/DocBook/v4l/media-ioc-enum-links.xml
+
+diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
+index 6af3375..6e7dae4 100644
+--- a/Documentation/DocBook/media-entities.tmpl
++++ b/Documentation/DocBook/media-entities.tmpl
+@@ -92,6 +92,8 @@
+ <!ENTITY VIDIOC-UNSUBSCRIBE-EVENT "<link linkend='vidioc-subscribe-event'><constant>VIDIOC_UNSUBSCRIBE_EVENT</constant></link>">
+
+ <!ENTITY MEDIA-IOC-DEVICE-INFO "<link linkend='media-ioc-device-info'><constant>MEDIA_IOC_DEVICE_INFO</constant></link>">
++<!ENTITY MEDIA-IOC-ENUM-ENTITIES "<link linkend='media-ioc-enum-entities'><constant>MEDIA_IOC_ENUM_ENTITIES</constant></link>">
++<!ENTITY MEDIA-IOC-ENUM-LINKS "<link linkend='media-ioc-enum-links'><constant>MEDIA_IOC_ENUM_LINKS</constant></link>">
+
+ <!-- Types -->
+ <!ENTITY v4l2-std-id "<link linkend='v4l2-std-id'>v4l2_std_id</link>">
+@@ -188,6 +190,10 @@
+ <!ENTITY v4l2-window "struct&nbsp;<link linkend='v4l2-window'>v4l2_window</link>">
+
+ <!ENTITY media-device-info "struct&nbsp;<link linkend='media-device-info'>media_device_info</link>">
++<!ENTITY media-entity-desc "struct&nbsp;<link linkend='media-entity-desc'>media_entity_desc</link>">
++<!ENTITY media-links-enum "struct&nbsp;<link linkend='media-links-enum'>media_links_enum</link>">
++<!ENTITY media-pad-desc "struct&nbsp;<link linkend='media-pad-desc'>media_pad_desc</link>">
++<!ENTITY media-link-desc "struct&nbsp;<link linkend='media-link-desc'>media_link_desc</link>">
+
+ <!-- Error Codes -->
+ <!ENTITY EACCES "<errorcode>EACCES</errorcode> error code">
+@@ -334,6 +340,8 @@
+ <!ENTITY sub-media-close SYSTEM "v4l/media-func-close.xml">
+ <!ENTITY sub-media-ioctl SYSTEM "v4l/media-func-ioctl.xml">
+ <!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml">
++<!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml">
++<!ENTITY sub-media-ioc-enum-links SYSTEM "v4l/media-ioc-enum-links.xml">
+
+ <!-- Function Reference -->
+ <!ENTITY close SYSTEM "v4l/func-close.xml">
+diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml
+index a46b786..2c4fd2b 100644
+--- a/Documentation/DocBook/v4l/media-controller.xml
++++ b/Documentation/DocBook/v4l/media-controller.xml
+@@ -83,4 +83,6 @@
+ &sub-media-ioctl;
+ <!-- All ioctls go here. -->
+ &sub-media-ioc-device-info;
++ &sub-media-ioc-enum-entities;
++ &sub-media-ioc-enum-links;
+ </appendix>
+diff --git a/Documentation/DocBook/v4l/media-ioc-device-info.xml b/Documentation/DocBook/v4l/media-ioc-device-info.xml
+index 278a312..1f32373 100644
+--- a/Documentation/DocBook/v4l/media-ioc-device-info.xml
++++ b/Documentation/DocBook/v4l/media-ioc-device-info.xml
+@@ -27,7 +27,8 @@
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+- <para>&fd;</para>
++ <para>File descriptor returned by
++ <link linkend='media-func-open'><function>open()</function></link>.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+diff --git a/Documentation/DocBook/v4l/media-ioc-enum-entities.xml b/Documentation/DocBook/v4l/media-ioc-enum-entities.xml
+new file mode 100644
+index 0000000..13d0cc4
+--- /dev/null
++++ b/Documentation/DocBook/v4l/media-ioc-enum-entities.xml
+@@ -0,0 +1,308 @@
++<refentry id="media-ioc-enum-entities">
++ <refmeta>
++ <refentrytitle>ioctl MEDIA_IOC_ENUM_ENTITIES</refentrytitle>
++ &manvol;
++ </refmeta>
++
++ <refnamediv>
++ <refname>MEDIA_IOC_ENUM_ENTITIES</refname>
++ <refpurpose>Enumerate entities and their properties</refpurpose>
++ </refnamediv>
++
++ <refsynopsisdiv>
++ <funcsynopsis>
++ <funcprototype>
++ <funcdef>int <function>ioctl</function></funcdef>
++ <paramdef>int <parameter>fd</parameter></paramdef>
++ <paramdef>int <parameter>request</parameter></paramdef>
++ <paramdef>struct media_entity_desc *<parameter>argp</parameter></paramdef>
++ </funcprototype>
++ </funcsynopsis>
++ </refsynopsisdiv>
++
++ <refsect1>
++ <title>Arguments</title>
++
++ <variablelist>
++ <varlistentry>
++ <term><parameter>fd</parameter></term>
++ <listitem>
++ <para>File descriptor returned by
++ <link linkend='media-func-open'><function>open()</function></link>.</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>request</parameter></term>
++ <listitem>
++ <para>MEDIA_IOC_ENUM_ENTITIES</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>argp</parameter></term>
++ <listitem>
++ <para></para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++
++ <refsect1>
++ <title>Description</title>
++ <para>To query the attributes of an entity, applications set the id field
++ of a &media-entity-desc; structure and call the MEDIA_IOC_ENUM_ENTITIES
++ ioctl with a pointer to this structure. The driver fills the rest of the
++ structure or returns an &EINVAL; when the id is invalid.</para>
++ <para>Entities can be enumerated by or'ing the id with the
++ <constant>MEDIA_ENT_ID_FLAG_NEXT</constant> flag. The driver will return
++ information about the entity with the smallest id strictly larger than the
++ requested one ('next entity'), or the &EINVAL; if there is none.</para>
++ <para>Entity IDs can be non-contiguous. Applications must
++ <emphasis>not</emphasis> try to enumerate entities by calling
++ MEDIA_IOC_ENUM_ENTITIES with increasing id's until they get an error.</para>
++ <para>Two or more entities that share a common non-zero
++ <structfield>group_id</structfield> value are considered as logically
++ grouped. Groups are used to report
++ <itemizedlist>
++ <listitem>ALSA, VBI and video nodes that carry the same media
++ stream</listitem>
++ <listitem>lens and flash controllers associated with a sensor</listitem>
++ </itemizedlist>
++ </para>
++
++ <table pgwide="1" frame="none" id="media-entity-desc">
++ <title>struct <structname>media_entity_desc</structname></title>
++ <tgroup cols="5">
++ <colspec colname="c1" />
++ <colspec colname="c2" />
++ <colspec colname="c3" />
++ <colspec colname="c4" />
++ <colspec colname="c5" />
++ <tbody valign="top">
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>id</structfield></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>Entity id, set by the application. When the id is or'ed with
++ <constant>MEDIA_ENT_ID_FLAG_NEXT</constant>, the driver clears the
++ flag and returns the first entity with a larger id.</entry>
++ </row>
++ <row>
++ <entry>char</entry>
++ <entry><structfield>name</structfield>[32]</entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>Entity name as an UTF-8 NULL-terminated string.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>type</structfield></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>Entity type, see <xref linkend="media-entity-type" /> for details.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>revision</structfield></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>Entity revision in a driver/hardware specific format.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>flags</structfield></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>Entity flags, see <xref linkend="media-entity-flag" /> for details.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>group_id</structfield></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>Entity group ID</entry>
++ </row>
++ <row>
++ <entry>__u16</entry>
++ <entry><structfield>pads</structfield></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>Number of pads</entry>
++ </row>
++ <row>
++ <entry>__u16</entry>
++ <entry><structfield>links</structfield></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>Total number of outbound links. Inbound links are not counted
++ in this field.</entry>
++ </row>
++ <row>
++ <entry>union</entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry>struct</entry>
++ <entry><structfield>v4l</structfield></entry>
++ <entry></entry>
++ <entry>Valid for V4L sub-devices and nodes only.</entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry>__u32</entry>
++ <entry><structfield>major</structfield></entry>
++ <entry>V4L device node major number. For V4L sub-devices with no
++ device node, set by the driver to 0.</entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry>__u32</entry>
++ <entry><structfield>minor</structfield></entry>
++ <entry>V4L device node minor number. For V4L sub-devices with no
++ device node, set by the driver to 0.</entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry>struct</entry>
++ <entry><structfield>fb</structfield></entry>
++ <entry></entry>
++ <entry>Valid for frame buffer nodes only.</entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry>__u32</entry>
++ <entry><structfield>major</structfield></entry>
++ <entry>Frame buffer device node major number.</entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry>__u32</entry>
++ <entry><structfield>minor</structfield></entry>
++ <entry>Frame buffer device node minor number.</entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry>struct</entry>
++ <entry><structfield>alsa</structfield></entry>
++ <entry></entry>
++ <entry>Valid for ALSA devices only.</entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry>__u32</entry>
++ <entry><structfield>card</structfield></entry>
++ <entry>ALSA card number</entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry>__u32</entry>
++ <entry><structfield>device</structfield></entry>
++ <entry>ALSA device number</entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry>__u32</entry>
++ <entry><structfield>subdevice</structfield></entry>
++ <entry>ALSA sub-device number</entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry>int</entry>
++ <entry><structfield>dvb</structfield></entry>
++ <entry></entry>
++ <entry>DVB card number</entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry>__u8</entry>
++ <entry><structfield>raw</structfield>[180]</entry>
++ <entry></entry>
++ <entry></entry>
++ </row>
++ </tbody>
++ </tgroup>
++ </table>
++
++ <table frame="none" pgwide="1" id="media-entity-type">
++ <title>Media entity types</title>
++ <tgroup cols="2">
++ <colspec colname="c1"/>
++ <colspec colname="c2"/>
++ <tbody valign="top">
++ <row>
++ <entry><constant>MEDIA_ENT_T_DEVNODE</constant></entry>
++ <entry>Unknown device node</entry>
++ </row>
++ <row>
++ <entry><constant>MEDIA_ENT_T_DEVNODE_V4L</constant></entry>
++ <entry>V4L video, radio or vbi device node</entry>
++ </row>
++ <row>
++ <entry><constant>MEDIA_ENT_T_DEVNODE_FB</constant></entry>
++ <entry>Frame buffer device node</entry>
++ </row>
++ <row>
++ <entry><constant>MEDIA_ENT_T_DEVNODE_ALSA</constant></entry>
++ <entry>ALSA card</entry>
++ </row>
++ <row>
++ <entry><constant>MEDIA_ENT_T_DEVNODE_DVB</constant></entry>
++ <entry>DVB card</entry>
++ </row>
++ <row>
++ <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV</constant></entry>
++ <entry>Unknown V4L sub-device</entry>
++ </row>
++ <row>
++ <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_SENSOR</constant></entry>
++ <entry>Video sensor</entry>
++ </row>
++ <row>
++ <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_FLASH</constant></entry>
++ <entry>Flash controller</entry>
++ </row>
++ <row>
++ <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_LENS</constant></entry>
++ <entry>Lens controller</entry>
++ </row>
++ </tbody>
++ </tgroup>
++ </table>
++
++ <table frame="none" pgwide="1" id="media-entity-flag">
++ <title>Media entity flags</title>
++ <tgroup cols="2">
++ <colspec colname="c1"/>
++ <colspec colname="c2"/>
++ <tbody valign="top">
++ <row>
++ <entry><constant>MEDIA_ENT_FL_DEFAULT</constant></entry>
++ <entry>Default entity for its type. Used to discover the default
++ audio, VBI and video devices, the default camera sensor, ...</entry>
++ </row>
++ </tbody>
++ </tgroup>
++ </table>
++ </refsect1>
++
++ <refsect1>
++ &return-value;
++
++ <variablelist>
++ <varlistentry>
++ <term><errorcode>EINVAL</errorcode></term>
++ <listitem>
++ <para>The &media-entity-desc; <structfield>id</structfield> references
++ a non-existing entity.</para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++</refentry>
+diff --git a/Documentation/DocBook/v4l/media-ioc-enum-links.xml b/Documentation/DocBook/v4l/media-ioc-enum-links.xml
+new file mode 100644
+index 0000000..daf0360
+--- /dev/null
++++ b/Documentation/DocBook/v4l/media-ioc-enum-links.xml
+@@ -0,0 +1,202 @@
++<refentry id="media-ioc-enum-links">
++ <refmeta>
++ <refentrytitle>ioctl MEDIA_IOC_ENUM_LINKS</refentrytitle>
++ &manvol;
++ </refmeta>
++
++ <refnamediv>
++ <refname>MEDIA_IOC_ENUM_LINKS</refname>
++ <refpurpose>Enumerate all pads and links for a given entity</refpurpose>
++ </refnamediv>
++
++ <refsynopsisdiv>
++ <funcsynopsis>
++ <funcprototype>
++ <funcdef>int <function>ioctl</function></funcdef>
++ <paramdef>int <parameter>fd</parameter></paramdef>
++ <paramdef>int <parameter>request</parameter></paramdef>
++ <paramdef>struct media_links_enum *<parameter>argp</parameter></paramdef>
++ </funcprototype>
++ </funcsynopsis>
++ </refsynopsisdiv>
++
++ <refsect1>
++ <title>Arguments</title>
++
++ <variablelist>
++ <varlistentry>
++ <term><parameter>fd</parameter></term>
++ <listitem>
++ <para>File descriptor returned by
++ <link linkend='media-func-open'><function>open()</function></link>.</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>request</parameter></term>
++ <listitem>
++ <para>MEDIA_IOC_ENUM_LINKS</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>argp</parameter></term>
++ <listitem>
++ <para></para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++
++ <refsect1>
++ <title>Description</title>
++
++ <para>To enumerate pads and/or links for a given entity, applications set
++ the entity field of a &media-links-enum; structure and initialize the
++ &media-pad-desc; and &media-link-desc; structure arrays pointed by the
++ <structfield>pads</structfield> and <structfield>links</structfield> fields.
++ They then call the MEDIA_IOC_ENUM_LINKS ioctl with a pointer to this
++ structure.</para>
++ <para>If the <structfield>pads</structfield> field is not NULL, the driver
++ fills the <structfield>pads</structfield> array with information about the
++ entity's pads. The array must have enough room to store all the entity's
++ pads. The number of pads can be retrieved with the &MEDIA-IOC-ENUM-ENTITIES;
++ ioctl.</para>
++ <para>If the <structfield>links</structfield> field is not NULL, the driver
++ fills the <structfield>links</structfield> array with information about the
++ entity's outbound links. The array must have enough room to store all the
++ entity's outbound links. The number of outbound links can be retrieved with
++ the &MEDIA-IOC-ENUM-ENTITIES; ioctl.</para>
++ <para>Only forward links that originate at one of the entity's source pads
++ are returned during the enumeration process.</para>
++
++ <table pgwide="1" frame="none" id="media-links-enum">
++ <title>struct <structname>media_links_enum</structname></title>
++ <tgroup cols="3">
++ &cs-str;
++ <tbody valign="top">
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>entity</structfield></entry>
++ <entry>Entity id, set by the application.</entry>
++ </row>
++ <row>
++ <entry>struct &media-pad-desc;</entry>
++ <entry>*<structfield>pads</structfield></entry>
++ <entry>Pointer to a pads array allocated by the application. Ignored
++ if NULL.</entry>
++ </row>
++ <row>
++ <entry>struct &media-link-desc;</entry>
++ <entry>*<structfield>links</structfield></entry>
++ <entry>Pointer to a links array allocated by the application. Ignored
++ if NULL.</entry>
++ </row>
++ </tbody>
++ </tgroup>
++ </table>
++
++ <table pgwide="1" frame="none" id="media-pad-desc">
++ <title>struct <structname>media_pad_desc</structname></title>
++ <tgroup cols="3">
++ &cs-str;
++ <tbody valign="top">
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>entity</structfield></entry>
++ <entry>ID of the entity this pad belongs to.</entry>
++ </row>
++ <row>
++ <entry>__u16</entry>
++ <entry><structfield>index</structfield></entry>
++ <entry>0-based pad index.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>flags</structfield></entry>
++ <entry>Pad flags, see <xref linkend="media-pad-flag" /> for more details.</entry>
++ </row>
++ </tbody>
++ </tgroup>
++ </table>
++
++ <table frame="none" pgwide="1" id="media-pad-flag">
++ <title>Media pad flags</title>
++ <tgroup cols="2">
++ <colspec colname="c1"/>
++ <colspec colname="c2"/>
++ <tbody valign="top">
++ <row>
++ <entry><constant>MEDIA_PAD_FL_INPUT</constant></entry>
++ <entry>Input pad, relative to the entity. Input pads sink data and
++ are targets of links.</entry>
++ </row>
++ <row>
++ <entry><constant>MEDIA_PAD_FL_OUTPUT</constant></entry>
++ <entry>Output pad, relative to the entity. Output pads source data
++ and are origins of links.</entry>
++ </row>
++ </tbody>
++ </tgroup>
++ </table>
++
++ <table pgwide="1" frame="none" id="media-link-desc">
++ <title>struct <structname>media_links_enum</structname></title>
++ <tgroup cols="3">
++ &cs-str;
++ <tbody valign="top">
++ <row>
++ <entry>struct &media-pad-desc;</entry>
++ <entry><structfield>source</structfield></entry>
++ <entry>Pad at the origin of this link.</entry>
++ </row>
++ <row>
++ <entry>struct &media-pad-desc;</entry>
++ <entry><structfield>sink</structfield></entry>
++ <entry>Pad at the target of this link.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>flags</structfield></entry>
++ <entry>Link flags, see <xref linkend="media-link-flag" /> for more details.</entry>
++ </row>
++ </tbody>
++ </tgroup>
++ </table>
++
++ <table frame="none" pgwide="1" id="media-link-flag">
++ <title>Media link flags</title>
++ <tgroup cols="2">
++ <colspec colname="c1"/>
++ <colspec colname="c2"/>
++ <tbody valign="top">
++ <row>
++ <entry><constant>MEDIA_LNK_FL_ENABLED</constant></entry>
++ <entry>The link is enabled and can be used to transfer media data.
++ When two or more links target a sink pad, only one of them can be
++ enabled at a time.</entry>
++ </row>
++ <row>
++ <entry><constant>MEDIA_LNK_FL_IMMUTABLE</constant></entry>
++ <entry>The link enabled state can't be modified at runtime. An
++ immutable link is always enabled.</entry>
++ </row>
++ </tbody>
++ </tgroup>
++ </table>
++ <para>One and only one of <constant>MEDIA_PAD_FL_INPUT</constant> and
++ <constant>MEDIA_PAD_FL_OUTPUT</constant> must be set for every pad.</para>
++ </refsect1>
++
++ <refsect1>
++ &return-value;
++
++ <variablelist>
++ <varlistentry>
++ <term><errorcode>EINVAL</errorcode></term>
++ <listitem>
++ <para>The &media-links-enum; <structfield>id</structfield> references
++ a non-existing entity.</para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++</refentry>
+diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
+index 5c745be..1f46acb 100644
+--- a/drivers/media/media-device.c
++++ b/drivers/media/media-device.c
+@@ -61,6 +61,117 @@ static int media_device_get_info(struct media_device *dev,
+ return copy_to_user(__info, &info, sizeof(*__info));
+ }
+
++static struct media_entity *find_entity(struct media_device *mdev, u32 id)
++{
++ struct media_entity *entity;
++ int next = id & MEDIA_ENT_ID_FLAG_NEXT;
++
++ id &= ~MEDIA_ENT_ID_FLAG_NEXT;
++
++ spin_lock(&mdev->lock);
++
++ media_device_for_each_entity(entity, mdev) {
++ if ((entity->id == id && !next) ||
++ (entity->id > id && next)) {
++ spin_unlock(&mdev->lock);
++ return entity;
++ }
++ }
++
++ spin_unlock(&mdev->lock);
++
++ return NULL;
++}
++
++static long media_device_enum_entities(struct media_device *mdev,
++ struct media_entity_desc __user *uent)
++{
++ struct media_entity *ent;
++ struct media_entity_desc u_ent;
++
++ if (copy_from_user(&u_ent.id, &uent->id, sizeof(u_ent.id)))
++ return -EFAULT;
++
++ ent = find_entity(mdev, u_ent.id);
++
++ if (ent == NULL)
++ return -EINVAL;
++
++ u_ent.id = ent->id;
++ u_ent.name[0] = '\0';
++ if (ent->name)
++ strlcpy(u_ent.name, ent->name, sizeof(u_ent.name));
++ u_ent.type = ent->type;
++ u_ent.revision = ent->revision;
++ u_ent.flags = ent->flags;
++ u_ent.group_id = ent->group_id;
++ u_ent.pads = ent->num_pads;
++ u_ent.links = ent->num_links - ent->num_backlinks;
++ u_ent.v4l.major = ent->v4l.major;
++ u_ent.v4l.minor = ent->v4l.minor;
++ if (copy_to_user(uent, &u_ent, sizeof(u_ent)))
++ return -EFAULT;
++ return 0;
++}
++
++static void media_device_kpad_to_upad(const struct media_pad *kpad,
++ struct media_pad_desc *upad)
++{
++ upad->entity = kpad->entity->id;
++ upad->index = kpad->index;
++ upad->flags = kpad->flags;
++}
++
++static long media_device_enum_links(struct media_device *mdev,
++ struct media_links_enum __user *ulinks)
++{
++ struct media_entity *entity;
++ struct media_links_enum links;
++
++ if (copy_from_user(&links, ulinks, sizeof(links)))
++ return -EFAULT;
++
++ entity = find_entity(mdev, links.entity);
++ if (entity == NULL)
++ return -EINVAL;
++
++ if (links.pads) {
++ unsigned int p;
++
++ for (p = 0; p < entity->num_pads; p++) {
++ struct media_pad_desc pad;
++ media_device_kpad_to_upad(&entity->pads[p], &pad);
++ if (copy_to_user(&links.pads[p], &pad, sizeof(pad)))
++ return -EFAULT;
++ }
++ }
++
++ if (links.links) {
++ struct media_link_desc __user *ulink;
++ unsigned int l;
++
++ for (l = 0, ulink = links.links; l < entity->num_links; l++) {
++ struct media_link_desc link;
++
++ /* Ignore backlinks. */
++ if (entity->links[l].source->entity != entity)
++ continue;
++
++ media_device_kpad_to_upad(entity->links[l].source,
++ &link.source);
++ media_device_kpad_to_upad(entity->links[l].sink,
++ &link.sink);
++ link.flags = entity->links[l].flags;
++ if (copy_to_user(ulink, &link, sizeof(*ulink)))
++ return -EFAULT;
++ ulink++;
++ }
++ }
++ if (copy_to_user(ulinks, &links, sizeof(*ulinks)))
++ return -EFAULT;
++ return 0;
++}
++
+ static long media_device_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+ {
+@@ -74,6 +185,18 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
+ (struct media_device_info __user *)arg);
+ break;
+
++ case MEDIA_IOC_ENUM_ENTITIES:
++ ret = media_device_enum_entities(dev,
++ (struct media_entity_desc __user *)arg);
++ break;
++
++ case MEDIA_IOC_ENUM_LINKS:
++ mutex_lock(&dev->graph_mutex);
++ ret = media_device_enum_links(dev,
++ (struct media_links_enum __user *)arg);
++ mutex_unlock(&dev->graph_mutex);
++ break;
++
+ default:
+ ret = -ENOIOCTLCMD;
+ }
+diff --git a/include/linux/media.h b/include/linux/media.h
+index 4c52f08..64c0313 100644
+--- a/include/linux/media.h
++++ b/include/linux/media.h
+@@ -40,6 +40,91 @@ struct media_device_info {
+ __u32 reserved[31];
+ };
+
++#define MEDIA_ENT_ID_FLAG_NEXT (1 << 31)
++
++#define MEDIA_ENT_TYPE_SHIFT 16
++#define MEDIA_ENT_TYPE_MASK 0x00ff0000
++#define MEDIA_ENT_SUBTYPE_MASK 0x0000ffff
++
++#define MEDIA_ENT_T_DEVNODE (1 << MEDIA_ENT_TYPE_SHIFT)
++#define MEDIA_ENT_T_DEVNODE_V4L (MEDIA_ENT_T_DEVNODE + 1)
++#define MEDIA_ENT_T_DEVNODE_FB (MEDIA_ENT_T_DEVNODE + 2)
++#define MEDIA_ENT_T_DEVNODE_ALSA (MEDIA_ENT_T_DEVNODE + 3)
++#define MEDIA_ENT_T_DEVNODE_DVB (MEDIA_ENT_T_DEVNODE + 4)
++
++#define MEDIA_ENT_T_V4L2_SUBDEV (2 << MEDIA_ENT_TYPE_SHIFT)
++#define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR (MEDIA_ENT_T_V4L2_SUBDEV + 1)
++#define MEDIA_ENT_T_V4L2_SUBDEV_FLASH (MEDIA_ENT_T_V4L2_SUBDEV + 2)
++#define MEDIA_ENT_T_V4L2_SUBDEV_LENS (MEDIA_ENT_T_V4L2_SUBDEV + 3)
++
++#define MEDIA_ENT_FL_DEFAULT (1 << 0)
++
++struct media_entity_desc {
++ __u32 id;
++ char name[32];
++ __u32 type;
++ __u32 revision;
++ __u32 flags;
++ __u32 group_id;
++ __u16 pads;
++ __u16 links;
++
++ __u32 reserved[4];
++
++ union {
++ /* Node specifications */
++ struct {
++ __u32 major;
++ __u32 minor;
++ } v4l;
++ struct {
++ __u32 major;
++ __u32 minor;
++ } fb;
++ struct {
++ __u32 card;
++ __u32 device;
++ __u32 subdevice;
++ } alsa;
++ int dvb;
++
++ /* Sub-device specifications */
++ /* Nothing needed yet */
++ __u8 raw[184];
++ };
++};
++
++#define MEDIA_PAD_FL_INPUT (1 << 0)
++#define MEDIA_PAD_FL_OUTPUT (1 << 1)
++
++struct media_pad_desc {
++ __u32 entity; /* entity ID */
++ __u16 index; /* pad index */
++ __u32 flags; /* pad flags */
++ __u32 reserved[2];
++};
++
++#define MEDIA_LNK_FL_ENABLED (1 << 0)
++#define MEDIA_LNK_FL_IMMUTABLE (1 << 1)
++
++struct media_link_desc {
++ struct media_pad_desc source;
++ struct media_pad_desc sink;
++ __u32 flags;
++ __u32 reserved[2];
++};
++
++struct media_links_enum {
++ __u32 entity;
++ /* Should have enough room for pads elements */
++ struct media_pad_desc __user *pads;
++ /* Should have enough room for links elements */
++ struct media_link_desc __user *links;
++ __u32 reserved[4];
++};
++
+ #define MEDIA_IOC_DEVICE_INFO _IOWR('M', 1, struct media_device_info)
++#define MEDIA_IOC_ENUM_ENTITIES _IOWR('M', 2, struct media_entity_desc)
++#define MEDIA_IOC_ENUM_LINKS _IOWR('M', 3, struct media_links_enum)
+
+ #endif /* __LINUX_MEDIA_H */
+diff --git a/include/media/media-entity.h b/include/media/media-entity.h
+index 114541a..0954490 100644
+--- a/include/media/media-entity.h
++++ b/include/media/media-entity.h
+@@ -24,29 +24,7 @@
+ #define _MEDIA_ENTITY_H
+
+ #include <linux/list.h>
+-
+-#define MEDIA_ENT_TYPE_SHIFT 16
+-#define MEDIA_ENT_TYPE_MASK 0x00ff0000
+-#define MEDIA_ENT_SUBTYPE_MASK 0x0000ffff
+-
+-#define MEDIA_ENT_T_DEVNODE (1 << MEDIA_ENTITY_TYPE_SHIFT)
+-#define MEDIA_ENT_T_DEVNODE_V4L (MEDIA_ENTITY_T_DEVNODE + 1)
+-#define MEDIA_ENT_T_DEVNODE_FB (MEDIA_ENTITY_T_DEVNODE + 2)
+-#define MEDIA_ENT_T_DEVNODE_ALSA (MEDIA_ENTITY_T_DEVNODE + 3)
+-#define MEDIA_ENT_T_DEVNODE_DVB (MEDIA_ENTITY_T_DEVNODE + 4)
+-
+-#define MEDIA_ENT_T_V4L2_SUBDEV (2 << MEDIA_ENTITY_TYPE_SHIFT)
+-#define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR (MEDIA_ENTITY_T_V4L2_SUBDEV + 1)
+-#define MEDIA_ENT_T_V4L2_SUBDEV_FLASH (MEDIA_ENTITY_T_V4L2_SUBDEV + 2)
+-#define MEDIA_ENT_T_V4L2_SUBDEV_LENS (MEDIA_ENTITY_T_V4L2_SUBDEV + 3)
+-
+-#define MEDIA_ENT_FL_DEFAULT (1 << 0)
+-
+-#define MEDIA_LNK_FL_ENABLED (1 << 0)
+-#define MEDIA_LNK_FL_IMMUTABLE (1 << 1)
+-
+-#define MEDIA_PAD_FL_INPUT (1 << 0)
+-#define MEDIA_PAD_FL_OUTPUT (1 << 1)
++#include <linux/media.h>
+
+ struct media_link {
+ struct media_pad *source; /* Source pad */
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0015-media-Links-setup.patch b/extras/recipes-kernel/linux/linux-omap/media/0015-media-Links-setup.patch
new file mode 100644
index 00000000..4ea39740
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0015-media-Links-setup.patch
@@ -0,0 +1,517 @@
+From 9991c219079532183cc33f16064f86680b80237c Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:40:03 +0100
+Subject: [PATCH 15/43] media: Links setup
+
+Create the following ioctl and implement it at the media device level to
+setup links.
+
+- MEDIA_IOC_SETUP_LINK: Modify the properties of a given link
+
+The only property that can currently be modified is the ENABLED link
+flag to enable/disable a link. Links marked with the IMMUTABLE link flag
+can not be enabled or disabled.
+
+Enabling or disabling a link has effects on entities' use count. Those
+changes are automatically propagated through the graph.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+---
+ Documentation/DocBook/media-entities.tmpl | 2 +
+ Documentation/DocBook/v4l/media-controller.xml | 1 +
+ Documentation/DocBook/v4l/media-ioc-setup-link.xml | 90 +++++++++++
+ Documentation/media-framework.txt | 42 ++++++
+ drivers/media/media-device.c | 45 ++++++
+ drivers/media/media-entity.c | 155 ++++++++++++++++++++
+ include/linux/media.h | 1 +
+ include/media/media-device.h | 3 +
+ include/media/media-entity.h | 17 ++
+ 9 files changed, 356 insertions(+), 0 deletions(-)
+ create mode 100644 Documentation/DocBook/v4l/media-ioc-setup-link.xml
+
+diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
+index 6e7dae4..679c585 100644
+--- a/Documentation/DocBook/media-entities.tmpl
++++ b/Documentation/DocBook/media-entities.tmpl
+@@ -94,6 +94,7 @@
+ <!ENTITY MEDIA-IOC-DEVICE-INFO "<link linkend='media-ioc-device-info'><constant>MEDIA_IOC_DEVICE_INFO</constant></link>">
+ <!ENTITY MEDIA-IOC-ENUM-ENTITIES "<link linkend='media-ioc-enum-entities'><constant>MEDIA_IOC_ENUM_ENTITIES</constant></link>">
+ <!ENTITY MEDIA-IOC-ENUM-LINKS "<link linkend='media-ioc-enum-links'><constant>MEDIA_IOC_ENUM_LINKS</constant></link>">
++<!ENTITY MEDIA-IOC-SETUP-LINK "<link linkend='media-ioc-setup-link'><constant>MEDIA_IOC_SETUP_LINK</constant></link>">
+
+ <!-- Types -->
+ <!ENTITY v4l2-std-id "<link linkend='v4l2-std-id'>v4l2_std_id</link>">
+@@ -342,6 +343,7 @@
+ <!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml">
+ <!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml">
+ <!ENTITY sub-media-ioc-enum-links SYSTEM "v4l/media-ioc-enum-links.xml">
++<!ENTITY sub-media-ioc-setup-link SYSTEM "v4l/media-ioc-setup-link.xml">
+
+ <!-- Function Reference -->
+ <!ENTITY close SYSTEM "v4l/func-close.xml">
+diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml
+index 2c4fd2b..2dc25e1 100644
+--- a/Documentation/DocBook/v4l/media-controller.xml
++++ b/Documentation/DocBook/v4l/media-controller.xml
+@@ -85,4 +85,5 @@
+ &sub-media-ioc-device-info;
+ &sub-media-ioc-enum-entities;
+ &sub-media-ioc-enum-links;
++ &sub-media-ioc-setup-link;
+ </appendix>
+diff --git a/Documentation/DocBook/v4l/media-ioc-setup-link.xml b/Documentation/DocBook/v4l/media-ioc-setup-link.xml
+new file mode 100644
+index 0000000..09ab3d2
+--- /dev/null
++++ b/Documentation/DocBook/v4l/media-ioc-setup-link.xml
+@@ -0,0 +1,90 @@
++<refentry id="media-ioc-setup-link">
++ <refmeta>
++ <refentrytitle>ioctl MEDIA_IOC_SETUP_LINK</refentrytitle>
++ &manvol;
++ </refmeta>
++
++ <refnamediv>
++ <refname>MEDIA_IOC_SETUP_LINK</refname>
++ <refpurpose>Modify the properties of a link</refpurpose>
++ </refnamediv>
++
++ <refsynopsisdiv>
++ <funcsynopsis>
++ <funcprototype>
++ <funcdef>int <function>ioctl</function></funcdef>
++ <paramdef>int <parameter>fd</parameter></paramdef>
++ <paramdef>int <parameter>request</parameter></paramdef>
++ <paramdef>struct media_link_desc *<parameter>argp</parameter></paramdef>
++ </funcprototype>
++ </funcsynopsis>
++ </refsynopsisdiv>
++
++ <refsect1>
++ <title>Arguments</title>
++
++ <variablelist>
++ <varlistentry>
++ <term><parameter>fd</parameter></term>
++ <listitem>
++ <para>File descriptor returned by
++ <link linkend='media-func-open'><function>open()</function></link>.</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>request</parameter></term>
++ <listitem>
++ <para>MEDIA_IOC_ENUM_LINKS</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>argp</parameter></term>
++ <listitem>
++ <para></para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++
++ <refsect1>
++ <title>Description</title>
++
++ <para>To change link properties applications fill a &media-link-desc; with
++ link identification information (source and sink pad) and the new requested
++ link flags. They then call the MEDIA_IOC_SETUP_LINK ioctl with a pointer to
++ that structure.</para>
++ <para>The only configurable property is the <constant>ENABLED</constant>
++ link flag to enable/disable a link. Links marked with the
++ <constant>IMMUTABLE</constant> link flag can not be enabled or disabled.
++ </para>
++ <para>Link configuration has no side effect on other links. If an enabled
++ link at the sink pad prevents the link from being enabled, the driver
++ returns with an &EBUSY;.</para>
++ <para>If the specified link can't be found the driver returns with an
++ &EINVAL;.</para>
++ </refsect1>
++
++ <refsect1>
++ &return-value;
++
++ <variablelist>
++ <varlistentry>
++ <term><errorcode>EBUSY</errorcode></term>
++ <listitem>
++ <para>The link properties can't be changed because the link is
++ currently busy. This can be caused, for instance, by an active media
++ stream (audio or video) on the link. The ioctl shouldn't be retried if
++ no other action is performed before to fix the problem.</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><errorcode>EINVAL</errorcode></term>
++ <listitem>
++ <para>The &media-link-desc; references a non-existing link, or the
++ link is immutable and an attempt to modify its configuration was made.
++ </para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++</refentry>
+diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
+index 9017a41..634845e 100644
+--- a/Documentation/media-framework.txt
++++ b/Documentation/media-framework.txt
+@@ -259,6 +259,16 @@ When the graph traversal is complete the function will return NULL.
+ Graph traversal can be interrupted at any moment. No cleanup function call is
+ required and the graph structure can be freed normally.
+
++Helper functions can be used to find a link between two given pads, or a pad
++connected to another pad through an enabled link
++
++ media_entity_find_link(struct media_pad *source,
++ struct media_pad *sink);
++
++ media_entity_remote_source(struct media_pad *pad);
++
++Refer to the kerneldoc documentation for more information.
++
+
+ Use count and power handling
+ ----------------------------
+@@ -271,3 +281,35 @@ track the number of users of every entity for power management needs.
+ The use_count field is owned by media drivers and must not be touched by entity
+ drivers. Access to the field must be protected by the media device graph_mutex
+ lock.
++
++
++Links setup
++-----------
++
++Link properties can be modified at runtime by calling
++
++ media_entity_setup_link(struct media_link *link, u32 flags);
++
++The flags argument contains the requested new link flags.
++
++The only configurable property is the ENABLED link flag to enable/disable a
++link. Links marked with the IMMUTABLE link flag can not be enabled or disabled.
++
++When a link is enabled or disabled, the media framework calls the
++link_setup operation for the two entities at the source and sink of the link,
++in that order. If the second link_setup call fails, another link_setup call is
++made on the first entity to restore the original link flags.
++
++Media device drivers can be notified of link setup operations by setting the
++media_device::link_notify pointer to a callback function. If provided, the
++notification callback will be called before enabling and after disabling
++links.
++
++Entity drivers must implement the link_setup operation if any of their links
++is non-immutable. The operation must either configure the hardware or store
++the configuration information to be applied later.
++
++Link configuration must not have any side effect on other links. If an enabled
++link at a sink pad prevents another link at the same pad from being disabled,
++the link_setup operation must return -EBUSY and can't implicitly disable the
++first enabled link.
+diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
+index 1f46acb..719deba 100644
+--- a/drivers/media/media-device.c
++++ b/drivers/media/media-device.c
+@@ -172,6 +172,44 @@ static long media_device_enum_links(struct media_device *mdev,
+ return 0;
+ }
+
++static long media_device_setup_link(struct media_device *mdev,
++ struct media_link_desc __user *_ulink)
++{
++ struct media_link *link = NULL;
++ struct media_link_desc ulink;
++ struct media_entity *source;
++ struct media_entity *sink;
++ int ret;
++
++ if (copy_from_user(&ulink, _ulink, sizeof(ulink)))
++ return -EFAULT;
++
++ /* Find the source and sink entities and link.
++ */
++ source = find_entity(mdev, ulink.source.entity);
++ sink = find_entity(mdev, ulink.sink.entity);
++
++ if (source == NULL || sink == NULL)
++ return -EINVAL;
++
++ if (ulink.source.index >= source->num_pads ||
++ ulink.sink.index >= sink->num_pads)
++ return -EINVAL;
++
++ link = media_entity_find_link(&source->pads[ulink.source.index],
++ &sink->pads[ulink.sink.index]);
++ if (link == NULL)
++ return -EINVAL;
++
++ /* Setup the link on both entities. */
++ ret = __media_entity_setup_link(link, ulink.flags);
++
++ if (copy_to_user(_ulink, &ulink, sizeof(ulink)))
++ return -EFAULT;
++
++ return ret;
++}
++
+ static long media_device_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+ {
+@@ -197,6 +235,13 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
+ mutex_unlock(&dev->graph_mutex);
+ break;
+
++ case MEDIA_IOC_SETUP_LINK:
++ mutex_lock(&dev->graph_mutex);
++ ret = media_device_setup_link(dev,
++ (struct media_link_desc __user *)arg);
++ mutex_unlock(&dev->graph_mutex);
++ break;
++
+ default:
+ ret = -ENOIOCTLCMD;
+ }
+diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
+index fe6bfd2..d703ce8 100644
+--- a/drivers/media/media-entity.c
++++ b/drivers/media/media-entity.c
+@@ -306,3 +306,158 @@ media_entity_create_link(struct media_entity *source, u16 source_pad,
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(media_entity_create_link);
++
++static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
++{
++ const u32 mask = MEDIA_LNK_FL_ENABLED;
++ int ret;
++
++ /* Notify both entities. */
++ ret = media_entity_call(link->source->entity, link_setup,
++ link->source, link->sink, flags);
++ if (ret < 0 && ret != -ENOIOCTLCMD)
++ return ret;
++
++ ret = media_entity_call(link->sink->entity, link_setup,
++ link->sink, link->source, flags);
++ if (ret < 0 && ret != -ENOIOCTLCMD) {
++ media_entity_call(link->source->entity, link_setup,
++ link->source, link->sink, link->flags);
++ return ret;
++ }
++
++ link->flags = (link->flags & ~mask) | (flags & mask);
++ link->reverse->flags = link->flags;
++
++ return 0;
++}
++
++/**
++ * __media_entity_setup_link - Configure a media link
++ * @link: The link being configured
++ * @flags: Link configuration flags
++ *
++ * The bulk of link setup is handled by the two entities connected through the
++ * link. This function notifies both entities of the link configuration change.
++ *
++ * If the link is immutable or if the current and new configuration are
++ * identical, return immediately.
++ *
++ * The user is expected to hold link->source->parent->mutex. If not,
++ * media_entity_setup_link() should be used instead.
++ */
++int __media_entity_setup_link(struct media_link *link, u32 flags)
++{
++ struct media_device *mdev;
++ struct media_entity *source, *sink;
++ int ret = -EBUSY;
++
++ if (link == NULL)
++ return -EINVAL;
++
++ if (link->flags & MEDIA_LNK_FL_IMMUTABLE)
++ return link->flags == flags ? 0 : -EINVAL;
++
++ if (link->flags == flags)
++ return 0;
++
++ source = link->source->entity;
++ sink = link->sink->entity;
++
++ mdev = source->parent;
++
++ if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) {
++ ret = mdev->link_notify(link->source, link->sink,
++ MEDIA_LNK_FL_ENABLED);
++ if (ret < 0)
++ return ret;
++ }
++
++ ret = __media_entity_setup_link_notify(link, flags);
++ if (ret < 0)
++ goto err;
++
++ if (!(flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify)
++ mdev->link_notify(link->source, link->sink, 0);
++
++ return 0;
++
++err:
++ if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify)
++ mdev->link_notify(link->source, link->sink, 0);
++
++ return ret;
++}
++
++int media_entity_setup_link(struct media_link *link, u32 flags)
++{
++ int ret;
++
++ mutex_lock(&link->source->entity->parent->graph_mutex);
++ ret = __media_entity_setup_link(link, flags);
++ mutex_unlock(&link->source->entity->parent->graph_mutex);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(media_entity_setup_link);
++
++/**
++ * media_entity_find_link - Find a link between two pads
++ * @source: Source pad
++ * @sink: Sink pad
++ *
++ * Return a pointer to the link between the two entities. If no such link
++ * exists, return NULL.
++ */
++struct media_link *
++media_entity_find_link(struct media_pad *source, struct media_pad *sink)
++{
++ struct media_link *link;
++ unsigned int i;
++
++ for (i = 0; i < source->entity->num_links; ++i) {
++ link = &source->entity->links[i];
++
++ if (link->source->entity == source->entity &&
++ link->source->index == source->index &&
++ link->sink->entity == sink->entity &&
++ link->sink->index == sink->index)
++ return link;
++ }
++
++ return NULL;
++}
++EXPORT_SYMBOL_GPL(media_entity_find_link);
++
++/**
++ * media_entity_remote_source - Find the source pad at the remote end of a link
++ * @pad: Sink pad at the local end of the link
++ *
++ * Search for a remote source pad connected to the given sink pad by iterating
++ * over all links originating or terminating at that pad until an enabled link
++ * is found.
++ *
++ * Return a pointer to the pad at the remote end of the first found enabled
++ * link, or NULL if no enabled link has been found.
++ */
++struct media_pad *media_entity_remote_source(struct media_pad *pad)
++{
++ unsigned int i;
++
++ for (i = 0; i < pad->entity->num_links; i++) {
++ struct media_link *link = &pad->entity->links[i];
++
++ if (!(link->flags & MEDIA_LNK_FL_ENABLED))
++ continue;
++
++ if (link->source == pad)
++ return link->sink;
++
++ if (link->sink == pad)
++ return link->source;
++ }
++
++ return NULL;
++
++}
++EXPORT_SYMBOL_GPL(media_entity_remote_source);
+diff --git a/include/linux/media.h b/include/linux/media.h
+index 64c0313..2f67ed2 100644
+--- a/include/linux/media.h
++++ b/include/linux/media.h
+@@ -126,5 +126,6 @@ struct media_links_enum {
+ #define MEDIA_IOC_DEVICE_INFO _IOWR('M', 1, struct media_device_info)
+ #define MEDIA_IOC_ENUM_ENTITIES _IOWR('M', 2, struct media_entity_desc)
+ #define MEDIA_IOC_ENUM_LINKS _IOWR('M', 3, struct media_links_enum)
++#define MEDIA_IOC_SETUP_LINK _IOWR('M', 4, struct media_link_desc)
+
+ #endif /* __LINUX_MEDIA_H */
+diff --git a/include/media/media-device.h b/include/media/media-device.h
+index 260d59c..ad93e66 100644
+--- a/include/media/media-device.h
++++ b/include/media/media-device.h
+@@ -73,6 +73,9 @@ struct media_device {
+ spinlock_t lock;
+ /* Serializes graph operations. */
+ struct mutex graph_mutex;
++
++ int (*link_notify)(struct media_pad *source,
++ struct media_pad *sink, u32 flags);
+ };
+
+ /* media_devnode to media_device */
+diff --git a/include/media/media-entity.h b/include/media/media-entity.h
+index 0954490..60fc7bd 100644
+--- a/include/media/media-entity.h
++++ b/include/media/media-entity.h
+@@ -39,6 +39,12 @@ struct media_pad {
+ unsigned long flags; /* Pad flags (MEDIA_PAD_FL_*) */
+ };
+
++struct media_entity_operations {
++ int (*link_setup)(struct media_entity *entity,
++ const struct media_pad *local,
++ const struct media_pad *remote, u32 flags);
++};
++
+ struct media_entity {
+ struct list_head list;
+ struct media_device *parent; /* Media device this entity belongs to*/
+@@ -59,6 +65,8 @@ struct media_entity {
+ struct media_pad *pads; /* Pads array (num_pads elements) */
+ struct media_link *links; /* Links array (max_links elements)*/
+
++ const struct media_entity_operations *ops; /* Entity operations */
++
+ int use_count; /* Use count for the entity. */
+
+ union {
+@@ -108,6 +116,11 @@ int media_entity_init(struct media_entity *entity, u16 num_pads,
+ void media_entity_cleanup(struct media_entity *entity);
+ int media_entity_create_link(struct media_entity *source, u16 source_pad,
+ struct media_entity *sink, u16 sink_pad, u32 flags);
++int __media_entity_setup_link(struct media_link *link, u32 flags);
++int media_entity_setup_link(struct media_link *link, u32 flags);
++struct media_link *media_entity_find_link(struct media_pad *source,
++ struct media_pad *sink);
++struct media_pad *media_entity_remote_source(struct media_pad *pad);
+
+ struct media_entity *media_entity_get(struct media_entity *entity);
+ void media_entity_put(struct media_entity *entity);
+@@ -117,4 +130,8 @@ void media_entity_graph_walk_start(struct media_entity_graph *graph,
+ struct media_entity *
+ media_entity_graph_walk_next(struct media_entity_graph *graph);
+
++#define media_entity_call(entity, operation, args...) \
++ (((entity)->ops && (entity)->ops->operation) ? \
++ (entity)->ops->operation((entity) , ##args) : -ENOIOCTLCMD)
++
+ #endif
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0016-media-Pipelines-and-media-streams.patch b/extras/recipes-kernel/linux/linux-omap/media/0016-media-Pipelines-and-media-streams.patch
new file mode 100644
index 00000000..969162f8
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0016-media-Pipelines-and-media-streams.patch
@@ -0,0 +1,259 @@
+From 4e07e9ada1b3baaec6d4948eccf3c0499e3228df Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 25 Aug 2010 15:00:41 +0300
+Subject: [PATCH 16/43] media: Pipelines and media streams
+
+Drivers often need to associate pipeline objects to entities, and to
+take stream state into account when configuring entities and links. The
+pipeline API helps drivers manage that information.
+
+When starting streaming, drivers call media_entity_pipeline_start(). The
+function marks all entities connected to the given entity through
+enabled links, either directly or indirectly, as streaming. Similarly,
+when stopping the stream, drivers call media_entity_pipeline_stop().
+
+The media_entity_pipeline_start() function takes a pointer to a media
+pipeline and stores it in every entity in the graph. Drivers should
+embed the media_pipeline structure in higher-level pipeline structures
+and can then access the pipeline through the media_entity structure.
+
+Link configuration will fail with -EBUSY by default if either end of the
+link is a streaming entity, unless the link is marked with the
+MEDIA_LNK_FL_DYNAMIC flag.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ Documentation/DocBook/v4l/media-ioc-enum-links.xml | 5 ++
+ Documentation/DocBook/v4l/media-ioc-setup-link.xml | 3 +
+ Documentation/media-framework.txt | 38 ++++++++++
+ drivers/media/media-entity.c | 73 ++++++++++++++++++++
+ include/linux/media.h | 1 +
+ include/media/media-entity.h | 10 +++
+ 6 files changed, 130 insertions(+), 0 deletions(-)
+
+diff --git a/Documentation/DocBook/v4l/media-ioc-enum-links.xml b/Documentation/DocBook/v4l/media-ioc-enum-links.xml
+index daf0360..b204bfb 100644
+--- a/Documentation/DocBook/v4l/media-ioc-enum-links.xml
++++ b/Documentation/DocBook/v4l/media-ioc-enum-links.xml
+@@ -179,6 +179,11 @@
+ <entry>The link enabled state can't be modified at runtime. An
+ immutable link is always enabled.</entry>
+ </row>
++ <row>
++ <entry><constant>MEDIA_LNK_FL_DYNAMIC</constant></entry>
++ <entry>The link enabled state can be modified during streaming. This
++ flag is set by drivers and is read-only for applications.</entry>
++ </row>
+ </tbody>
+ </tgroup>
+ </table>
+diff --git a/Documentation/DocBook/v4l/media-ioc-setup-link.xml b/Documentation/DocBook/v4l/media-ioc-setup-link.xml
+index 09ab3d2..2331e76 100644
+--- a/Documentation/DocBook/v4l/media-ioc-setup-link.xml
++++ b/Documentation/DocBook/v4l/media-ioc-setup-link.xml
+@@ -60,6 +60,9 @@
+ <para>Link configuration has no side effect on other links. If an enabled
+ link at the sink pad prevents the link from being enabled, the driver
+ returns with an &EBUSY;.</para>
++ <para>Only links marked with the <constant>DYNAMIC</constant> link flag can
++ be enabled/disabled while streaming media data. Attempting to enable or
++ disable a streaming non-dynamic link will return an &EBUSY;.</para>
+ <para>If the specified link can't be found the driver returns with an
+ &EINVAL;.</para>
+ </refsect1>
+diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
+index 634845e..435d0c4 100644
+--- a/Documentation/media-framework.txt
++++ b/Documentation/media-framework.txt
+@@ -313,3 +313,41 @@ Link configuration must not have any side effect on other links. If an enabled
+ link at a sink pad prevents another link at the same pad from being disabled,
+ the link_setup operation must return -EBUSY and can't implicitly disable the
+ first enabled link.
++
++
++Pipelines and media streams
++---------------------------
++
++When starting streaming, drivers must notify all entities in the pipeline to
++prevent link states from being modified during streaming by calling
++
++ media_entity_pipeline_start(struct media_entity *entity,
++ struct media_pipeline *pipe);
++
++The function will mark all entities connected to the given entity through
++enabled links, either directly or indirectly, as streaming.
++
++The media_pipeline instance pointed to by the pipe argument will be stored in
++every entity in the pipeline. Drivers should embed the media_pipeline structure
++in higher-level pipeline structures and can then access the pipeline through
++the media_entity pipe field.
++
++Calls to media_entity_pipeline_start() can be nested. The pipeline pointer must
++be identical for all nested calls to the function.
++
++When stopping the stream, drivers must notify the entities with
++
++ media_entity_pipeline_stop(struct media_entity *entity);
++
++If multiple calls to media_entity_pipeline_start() have been made the same
++number of media_entity_pipeline_stop() calls are required to stop streaming. The
++media_entity pipe field is reset to NULL on the last nested stop call.
++
++Link configuration will fail with -EBUSY by default if either end of the link is
++a streaming entity. Links that can be modified while streaming must be marked
++with the MEDIA_LNK_FL_DYNAMIC flag.
++
++If other operations need to be disallowed on streaming entities (such as
++changing entities configuration parameters) drivers can explictly check the
++media_entity stream_count field to find out if an entity is streaming. This
++operation must be done with the media_device graph_mutex held.
+diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
+index d703ce8..e63e089 100644
+--- a/drivers/media/media-entity.c
++++ b/drivers/media/media-entity.c
+@@ -197,6 +197,75 @@ media_entity_graph_walk_next(struct media_entity_graph *graph)
+ EXPORT_SYMBOL_GPL(media_entity_graph_walk_next);
+
+ /* -----------------------------------------------------------------------------
++ * Pipeline management
++ */
++
++/**
++ * media_entity_pipeline_start - Mark a pipeline as streaming
++ * @entity: Starting entity
++ * @pipe: Media pipeline to be assigned to all entities in the pipeline.
++ *
++ * Mark all entities connected to a given entity through enabled links, either
++ * directly or indirectly, as streaming. The given pipeline object is assigned to
++ * every entity in the pipeline and stored in the media_entity pipe field.
++ *
++ * Calls to this function can be nested, in which case the same number of
++ * media_entity_pipeline_stop() calls will be required to stop streaming. The
++ * pipeline pointer must be identical for all nested calls to
++ * media_entity_pipeline_start().
++ */
++void media_entity_pipeline_start(struct media_entity *entity,
++ struct media_pipeline *pipe)
++{
++ struct media_device *mdev = entity->parent;
++ struct media_entity_graph graph;
++
++ mutex_lock(&mdev->graph_mutex);
++
++ media_entity_graph_walk_start(&graph, entity);
++
++ while ((entity = media_entity_graph_walk_next(&graph))) {
++ entity->stream_count++;
++ WARN_ON(entity->pipe && entity->pipe != pipe);
++ entity->pipe = pipe;
++ }
++
++ mutex_unlock(&mdev->graph_mutex);
++}
++EXPORT_SYMBOL_GPL(media_entity_pipeline_start);
++
++/**
++ * media_entity_pipeline_stop - Mark a pipeline as not streaming
++ * @entity: Starting entity
++ *
++ * Mark all entities connected to a given entity through enabled links, either
++ * directly or indirectly, as not streaming. The media_entity pipe field is
++ * reset to NULL.
++ *
++ * If multiple calls to media_entity_pipeline_start() have been made, the same
++ * number of calls to this function are required to mark the pipeline as not
++ * streaming.
++ */
++void media_entity_pipeline_stop(struct media_entity *entity)
++{
++ struct media_device *mdev = entity->parent;
++ struct media_entity_graph graph;
++
++ mutex_lock(&mdev->graph_mutex);
++
++ media_entity_graph_walk_start(&graph, entity);
++
++ while ((entity = media_entity_graph_walk_next(&graph))) {
++ entity->stream_count--;
++ if (entity->stream_count == 0)
++ entity->pipe = NULL;
++ }
++
++ mutex_unlock(&mdev->graph_mutex);
++}
++EXPORT_SYMBOL_GPL(media_entity_pipeline_stop);
++
++/* -----------------------------------------------------------------------------
+ * Module use count
+ */
+
+@@ -364,6 +433,10 @@ int __media_entity_setup_link(struct media_link *link, u32 flags)
+ source = link->source->entity;
+ sink = link->sink->entity;
+
++ if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) &&
++ (source->stream_count || sink->stream_count))
++ return -EBUSY;
++
+ mdev = source->parent;
+
+ if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) {
+diff --git a/include/linux/media.h b/include/linux/media.h
+index 2f67ed2..29039e8 100644
+--- a/include/linux/media.h
++++ b/include/linux/media.h
+@@ -106,6 +106,7 @@ struct media_pad_desc {
+
+ #define MEDIA_LNK_FL_ENABLED (1 << 0)
+ #define MEDIA_LNK_FL_IMMUTABLE (1 << 1)
++#define MEDIA_LNK_FL_DYNAMIC (1 << 2)
+
+ struct media_link_desc {
+ struct media_pad_desc source;
+diff --git a/include/media/media-entity.h b/include/media/media-entity.h
+index 60fc7bd..450ba12 100644
+--- a/include/media/media-entity.h
++++ b/include/media/media-entity.h
+@@ -26,6 +26,9 @@
+ #include <linux/list.h>
+ #include <linux/media.h>
+
++struct media_pipeline {
++};
++
+ struct media_link {
+ struct media_pad *source; /* Source pad */
+ struct media_pad *sink; /* Sink pad */
+@@ -67,8 +70,11 @@ struct media_entity {
+
+ const struct media_entity_operations *ops; /* Entity operations */
+
++ int stream_count; /* Stream count for the entity. */
+ int use_count; /* Use count for the entity. */
+
++ struct media_pipeline *pipe; /* Pipeline this entity belongs to. */
++
+ union {
+ /* Node specifications */
+ struct {
+@@ -114,6 +120,7 @@ struct media_entity_graph {
+ int media_entity_init(struct media_entity *entity, u16 num_pads,
+ struct media_pad *pads, u16 extra_links);
+ void media_entity_cleanup(struct media_entity *entity);
++
+ int media_entity_create_link(struct media_entity *source, u16 source_pad,
+ struct media_entity *sink, u16 sink_pad, u32 flags);
+ int __media_entity_setup_link(struct media_link *link, u32 flags);
+@@ -129,6 +136,9 @@ void media_entity_graph_walk_start(struct media_entity_graph *graph,
+ struct media_entity *entity);
+ struct media_entity *
+ media_entity_graph_walk_next(struct media_entity_graph *graph);
++void media_entity_pipeline_start(struct media_entity *entity,
++ struct media_pipeline *pipe);
++void media_entity_pipeline_stop(struct media_entity *entity);
+
+ #define media_entity_call(entity, operation, args...) \
+ (((entity)->ops && (entity)->ops->operation) ? \
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0017-v4l-Add-a-media_device-pointer-to-the-v4l2_device-st.patch b/extras/recipes-kernel/linux/linux-omap/media/0017-v4l-Add-a-media_device-pointer-to-the-v4l2_device-st.patch
new file mode 100644
index 00000000..714c5a3b
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0017-v4l-Add-a-media_device-pointer-to-the-v4l2_device-st.patch
@@ -0,0 +1,115 @@
+From 56e006c01032f98483195e572700e17fb8aaa8b1 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:40:05 +0100
+Subject: [PATCH 17/43] v4l: Add a media_device pointer to the v4l2_device structure
+
+The pointer will later be used to register/unregister media entities
+when registering/unregistering a v4l2_subdev or a video_device.
+
+With the introduction of media devices, device drivers need to store a
+pointer to a driver-specific structure in the device's drvdata.
+v4l2_device can't claim ownership of the drvdata anymore.
+
+To maintain compatibility with drivers that rely on v4l2_device storing
+a pointer to itself in the device's drvdata, v4l2_device_register() will
+keep doing so if the drvdata is NULL.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ Documentation/video4linux/v4l2-framework.txt | 17 ++++++++++++-----
+ drivers/media/video/v4l2-device.c | 13 +++++++------
+ include/media/v4l2-device.h | 4 ++++
+ 3 files changed, 23 insertions(+), 11 deletions(-)
+
+diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
+index 4db1def..aeb2a22 100644
+--- a/Documentation/video4linux/v4l2-framework.txt
++++ b/Documentation/video4linux/v4l2-framework.txt
+@@ -83,11 +83,17 @@ You must register the device instance:
+
+ v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
+
+-Registration will initialize the v4l2_device struct and link dev->driver_data
+-to v4l2_dev. If v4l2_dev->name is empty then it will be set to a value derived
+-from dev (driver name followed by the bus_id, to be precise). If you set it
+-up before calling v4l2_device_register then it will be untouched. If dev is
+-NULL, then you *must* setup v4l2_dev->name before calling v4l2_device_register.
++Registration will initialize the v4l2_device struct. If the dev->driver_data
++field is NULL, it will be linked to v4l2_dev. Drivers that use the media
++device framework in addition to the V4L2 framework need to set
++dev->driver_data manually to point to the driver-specific device structure
++that embed the struct v4l2_device instance. This is achieved by a
++dev_set_drvdata() call before registering the V4L2 device instance.
++
++If v4l2_dev->name is empty then it will be set to a value derived from dev
++(driver name followed by the bus_id, to be precise). If you set it up before
++calling v4l2_device_register then it will be untouched. If dev is NULL, then
++you *must* setup v4l2_dev->name before calling v4l2_device_register.
+
+ You can use v4l2_device_set_name() to set the name based on a driver name and
+ a driver-global atomic_t instance. This will generate names like ivtv0, ivtv1,
+@@ -108,6 +114,7 @@ You unregister with:
+
+ v4l2_device_unregister(struct v4l2_device *v4l2_dev);
+
++If the dev->driver_data field points to v4l2_dev, it will be reset to NULL.
+ Unregistering will also automatically unregister all subdevs from the device.
+
+ If you have a hotpluggable device (e.g. a USB device), then when a disconnect
+diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
+index 97e84df..5c16a12 100644
+--- a/drivers/media/video/v4l2-device.c
++++ b/drivers/media/video/v4l2-device.c
+@@ -47,9 +47,8 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
+ if (!v4l2_dev->name[0])
+ snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",
+ dev->driver->name, dev_name(dev));
+- if (dev_get_drvdata(dev))
+- v4l2_warn(v4l2_dev, "Non-NULL drvdata on register\n");
+- dev_set_drvdata(dev, v4l2_dev);
++ if (!dev_get_drvdata(dev))
++ dev_set_drvdata(dev, v4l2_dev);
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(v4l2_device_register);
+@@ -72,10 +71,12 @@ EXPORT_SYMBOL_GPL(v4l2_device_set_name);
+
+ void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)
+ {
+- if (v4l2_dev->dev) {
++ if (v4l2_dev->dev == NULL)
++ return;
++
++ if (dev_get_drvdata(v4l2_dev->dev) == v4l2_dev)
+ dev_set_drvdata(v4l2_dev->dev, NULL);
+- v4l2_dev->dev = NULL;
+- }
++ v4l2_dev->dev = NULL;
+ }
+ EXPORT_SYMBOL_GPL(v4l2_device_disconnect);
+
+diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h
+index b16f307..759db73 100644
+--- a/include/media/v4l2-device.h
++++ b/include/media/v4l2-device.h
+@@ -21,6 +21,7 @@
+ #ifndef _V4L2_DEVICE_H
+ #define _V4L2_DEVICE_H
+
++#include <media/media-device.h>
+ #include <media/v4l2-subdev.h>
+
+ /* Each instance of a V4L2 device should create the v4l2_device struct,
+@@ -39,6 +40,9 @@ struct v4l2_device {
+ Note: dev might be NULL if there is no parent device
+ as is the case with e.g. ISA devices. */
+ struct device *dev;
++#if defined(CONFIG_MEDIA_CONTROLLER)
++ struct media_device *mdev;
++#endif
+ /* used to keep track of the registered subdevs */
+ struct list_head subdevs;
+ /* lock this struct; can be used by the driver as well if this
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0018-v4l-Make-video_device-inherit-from-media_entity.patch b/extras/recipes-kernel/linux/linux-omap/media/0018-v4l-Make-video_device-inherit-from-media_entity.patch
new file mode 100644
index 00000000..6417d1db
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0018-v4l-Make-video_device-inherit-from-media_entity.patch
@@ -0,0 +1,234 @@
+From e31cb57c733341b49256a47f086fa4cc1c1c56ac Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:40:10 +0100
+Subject: [PATCH 18/43] v4l: Make video_device inherit from media_entity
+
+V4L2 devices are media entities. As such they need to inherit from
+(include) the media_entity structure.
+
+When registering/unregistering the device, the media entity is
+automatically registered/unregistered. The entity is acquired on device
+open and released on device close.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+---
+ Documentation/video4linux/v4l2-framework.txt | 38 ++++++++++++++++++--
+ drivers/media/video/v4l2-dev.c | 49 +++++++++++++++++++++++--
+ include/media/v4l2-dev.h | 7 ++++
+ 3 files changed, 87 insertions(+), 7 deletions(-)
+
+diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
+index aeb2a22..f231bc2 100644
+--- a/Documentation/video4linux/v4l2-framework.txt
++++ b/Documentation/video4linux/v4l2-framework.txt
+@@ -71,6 +71,10 @@ sub-device instances, the video_device struct stores V4L2 device node data
+ and in the future a v4l2_fh struct will keep track of filehandle instances
+ (this is not yet implemented).
+
++The V4L2 framework also optionally integrates with the media framework. If a
++driver sets the struct v4l2_device mdev field, sub-devices and video nodes
++will automatically appear in the media framework as entities.
++
+
+ struct v4l2_device
+ ------------------
+@@ -84,11 +88,14 @@ You must register the device instance:
+ v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
+
+ Registration will initialize the v4l2_device struct. If the dev->driver_data
+-field is NULL, it will be linked to v4l2_dev. Drivers that use the media
+-device framework in addition to the V4L2 framework need to set
++field is NULL, it will be linked to v4l2_dev.
++
++Drivers that want integration with the media device framework need to set
+ dev->driver_data manually to point to the driver-specific device structure
+ that embed the struct v4l2_device instance. This is achieved by a
+-dev_set_drvdata() call before registering the V4L2 device instance.
++dev_set_drvdata() call before registering the V4L2 device instance. They must
++also set the struct v4l2_device mdev field to point to a properly initialized
++and registered media_device instance.
+
+ If v4l2_dev->name is empty then it will be set to a value derived from dev
+ (driver name followed by the bus_id, to be precise). If you set it up before
+@@ -532,6 +539,21 @@ If you use v4l2_ioctl_ops, then you should set either .unlocked_ioctl or
+ The v4l2_file_operations struct is a subset of file_operations. The main
+ difference is that the inode argument is omitted since it is never used.
+
++If integration with the media framework is needed, you must initialize the
++media_entity struct embedded in the video_device struct (entity field) by
++calling media_entity_init():
++
++ struct media_pad *pad = &my_vdev->pad;
++ int err;
++
++ err = media_entity_init(&vdev->entity, 1, pad, 0);
++
++The pads array must have been previously initialized. There is no need to
++manually set the struct media_entity type and name fields.
++
++A reference to the entity will be automatically acquired/released when the
++video device is opened/closed.
++
+ v4l2_file_operations and locking
+ --------------------------------
+
+@@ -561,6 +583,9 @@ for you.
+ return err;
+ }
+
++If the v4l2_device parent device has a non-NULL mdev field, the video device
++entity will be automatically registered with the media device.
++
+ Which device is registered depends on the type argument. The following
+ types exist:
+
+@@ -636,6 +661,13 @@ release, of course) will return an error as well.
+ When the last user of the video device node exits, then the vdev->release()
+ callback is called and you can do the final cleanup there.
+
++Don't forget to cleanup the media entity associated with the video device if
++it has been initialized:
++
++ media_entity_cleanup(&vdev->entity);
++
++This can be done from the release callback.
++
+
+ video_device helper functions
+ -----------------------------
+diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
+index f22bd41..f91348f 100644
+--- a/drivers/media/video/v4l2-dev.c
++++ b/drivers/media/video/v4l2-dev.c
+@@ -303,6 +303,9 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
+ static int v4l2_open(struct inode *inode, struct file *filp)
+ {
+ struct video_device *vdev;
++#if defined(CONFIG_MEDIA_CONTROLLER)
++ struct media_entity *entity = NULL;
++#endif
+ int ret = 0;
+
+ /* Check if the video device is available */
+@@ -316,6 +319,16 @@ static int v4l2_open(struct inode *inode, struct file *filp)
+ /* and increase the device refcount */
+ video_get(vdev);
+ mutex_unlock(&videodev_lock);
++#if defined(CONFIG_MEDIA_CONTROLLER)
++ if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) {
++ entity = media_entity_get(&vdev->entity);
++ if (!entity) {
++ ret = -EBUSY;
++ video_put(vdev);
++ return ret;
++ }
++ }
++#endif
+ if (vdev->fops->open) {
+ if (vdev->lock && mutex_lock_interruptible(vdev->lock)) {
+ ret = -ERESTARTSYS;
+@@ -331,8 +344,13 @@ static int v4l2_open(struct inode *inode, struct file *filp)
+
+ err:
+ /* decrease the refcount in case of an error */
+- if (ret)
++ if (ret) {
++#if defined(CONFIG_MEDIA_CONTROLLER)
++ if (vdev->v4l2_dev && vdev->v4l2_dev->mdev)
++ media_entity_put(entity);
++#endif
+ video_put(vdev);
++ }
+ return ret;
+ }
+
+@@ -349,7 +367,10 @@ static int v4l2_release(struct inode *inode, struct file *filp)
+ if (vdev->lock)
+ mutex_unlock(vdev->lock);
+ }
+-
++#if defined(CONFIG_MEDIA_CONTROLLER)
++ if (vdev->v4l2_dev && vdev->v4l2_dev->mdev)
++ media_entity_put(&vdev->entity);
++#endif
+ /* decrease the refcount unconditionally since the release()
+ return value is ignored. */
+ video_put(vdev);
+@@ -586,12 +607,27 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
+ if (nr != -1 && nr != vdev->num && warn_if_nr_in_use)
+ printk(KERN_WARNING "%s: requested %s%d, got %s\n", __func__,
+ name_base, nr, video_device_node_name(vdev));
+-
+- /* Part 5: Activate this minor. The char device can now be used. */
++#if defined(CONFIG_MEDIA_CONTROLLER)
++ /* Part 5: Register the entity. */
++ if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) {
++ vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
++ vdev->entity.name = vdev->name;
++ vdev->entity.v4l.major = VIDEO_MAJOR;
++ vdev->entity.v4l.minor = vdev->minor;
++ ret = media_device_register_entity(vdev->v4l2_dev->mdev,
++ &vdev->entity);
++ if (ret < 0)
++ printk(KERN_WARNING
++ "%s: media_device_register_entity failed\n",
++ __func__);
++ }
++#endif
++ /* Part 6: Activate this minor. The char device can now be used. */
+ set_bit(V4L2_FL_REGISTERED, &vdev->flags);
+ mutex_lock(&videodev_lock);
+ video_device[vdev->minor] = vdev;
+ mutex_unlock(&videodev_lock);
++
+ return 0;
+
+ cleanup:
+@@ -619,6 +655,11 @@ void video_unregister_device(struct video_device *vdev)
+ if (!vdev || !video_is_registered(vdev))
+ return;
+
++#if defined(CONFIG_MEDIA_CONTROLLER)
++ if (vdev->v4l2_dev && vdev->v4l2_dev->mdev)
++ media_device_unregister_entity(&vdev->entity);
++#endif
++
+ mutex_lock(&videodev_lock);
+ /* This must be in a critical section to prevent a race with v4l2_open.
+ * Once this bit has been cleared video_get may never be called again.
+diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
+index 4fe6831..51b2c51 100644
+--- a/include/media/v4l2-dev.h
++++ b/include/media/v4l2-dev.h
+@@ -16,6 +16,8 @@
+ #include <linux/mutex.h>
+ #include <linux/videodev2.h>
+
++#include <media/media-entity.h>
++
+ #define VIDEO_MAJOR 81
+
+ #define VFL_TYPE_GRABBER 0
+@@ -55,6 +57,9 @@ struct v4l2_file_operations {
+
+ struct video_device
+ {
++#if defined(CONFIG_MEDIA_CONTROLLER)
++ struct media_entity entity;
++#endif
+ /* device ops */
+ const struct v4l2_file_operations *fops;
+
+@@ -100,6 +105,8 @@ struct video_device
+ struct mutex *lock;
+ };
+
++#define media_entity_to_video_device(entity) \
++ container_of(entity, struct video_device, entity)
+ /* dev to video-device */
+ #define to_video_device(cd) container_of(cd, struct video_device, dev)
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0019-v4l-Make-v4l2_subdev-inherit-from-media_entity.patch b/extras/recipes-kernel/linux/linux-omap/media/0019-v4l-Make-v4l2_subdev-inherit-from-media_entity.patch
new file mode 100644
index 00000000..c7ae882a
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0019-v4l-Make-v4l2_subdev-inherit-from-media_entity.patch
@@ -0,0 +1,265 @@
+From ab4bf9e43078f79ba2b287e6dd6d6871901d0341 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:40:08 +0100
+Subject: [PATCH 19/43] v4l: Make v4l2_subdev inherit from media_entity
+
+V4L2 subdevices are media entities. As such they need to inherit from
+(include) the media_entity structure.
+
+When registering/unregistering the subdevice, the media entity is
+automatically registered/unregistered. The entity is acquired on device
+open and released on device close.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+---
+ Documentation/video4linux/v4l2-framework.txt | 23 ++++++++++++++
+ drivers/media/video/v4l2-device.c | 39 ++++++++++++++++++++----
+ drivers/media/video/v4l2-subdev.c | 41 ++++++++++++++++++++++++-
+ include/media/v4l2-subdev.h | 10 ++++++
+ 4 files changed, 104 insertions(+), 9 deletions(-)
+
+diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
+index f231bc2..d0fb880 100644
+--- a/Documentation/video4linux/v4l2-framework.txt
++++ b/Documentation/video4linux/v4l2-framework.txt
+@@ -268,6 +268,26 @@ A sub-device driver initializes the v4l2_subdev struct using:
+ Afterwards you need to initialize subdev->name with a unique name and set the
+ module owner. This is done for you if you use the i2c helper functions.
+
++If integration with the media framework is needed, you must initialize the
++media_entity struct embedded in the v4l2_subdev struct (entity field) by
++calling media_entity_init():
++
++ struct media_pad *pads = &my_sd->pads;
++ int err;
++
++ err = media_entity_init(&sd->entity, npads, pads, 0);
++
++The pads array must have been previously initialized. There is no need to
++manually set the struct media_entity type and name fields, but the revision
++field must be initialized if needed.
++
++A reference to the entity will be automatically acquired/released when the
++subdev device node (if any) is opened/closed.
++
++Don't forget to cleanup the media entity before the sub-device is destroyed:
++
++ media_entity_cleanup(&sd->entity);
++
+ A device (bridge) driver needs to register the v4l2_subdev with the
+ v4l2_device:
+
+@@ -277,6 +297,9 @@ This can fail if the subdev module disappeared before it could be registered.
+ After this function was called successfully the subdev->dev field points to
+ the v4l2_device.
+
++If the v4l2_device parent device has a non-NULL mdev field, the sub-device
++entity will be automatically registered with the media device.
++
+ You can unregister a sub-device using:
+
+ v4l2_device_unregister_subdev(sd);
+diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
+index 5c16a12..69cb429 100644
+--- a/drivers/media/video/v4l2-device.c
++++ b/drivers/media/video/v4l2-device.c
+@@ -116,8 +116,11 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
+ EXPORT_SYMBOL_GPL(v4l2_device_unregister);
+
+ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
+- struct v4l2_subdev *sd)
++ struct v4l2_subdev *sd)
+ {
++#if defined(CONFIG_MEDIA_CONTROLLER)
++ struct media_entity *entity = &sd->entity;
++#endif
+ struct video_device *vdev;
+ int err;
+
+@@ -135,7 +138,16 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
+ err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler);
+ if (err)
+ return err;
+-
++#if defined(CONFIG_MEDIA_CONTROLLER)
++ /* Register the entity. */
++ if (v4l2_dev->mdev) {
++ err = media_device_register_entity(v4l2_dev->mdev, entity);
++ if (err < 0) {
++ module_put(sd->owner);
++ return err;
++ }
++ }
++#endif
+ sd->v4l2_dev = v4l2_dev;
+ spin_lock(&v4l2_dev->lock);
+ list_add_tail(&sd->list, &v4l2_dev->subdevs);
+@@ -150,26 +162,39 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
+ if (sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE) {
+ err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
+ sd->owner);
+- if (err < 0)
++ if (err < 0) {
+ v4l2_device_unregister_subdev(sd);
++ return err;
++ }
+ }
+-
+- return err;
++#if defined(CONFIG_MEDIA_CONTROLLER)
++ entity->v4l.major = VIDEO_MAJOR;
++ entity->v4l.minor = vdev->minor;
++#endif
++ return 0;
+ }
+ EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
+
+ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
+ {
++ struct v4l2_device *v4l2_dev;
++
+ /* return if it isn't registered */
+ if (sd == NULL || sd->v4l2_dev == NULL)
+ return;
+
+- spin_lock(&sd->v4l2_dev->lock);
++ v4l2_dev = sd->v4l2_dev;
++
++ spin_lock(&v4l2_dev->lock);
+ list_del(&sd->list);
+- spin_unlock(&sd->v4l2_dev->lock);
++ spin_unlock(&v4l2_dev->lock);
+ sd->v4l2_dev = NULL;
+
+ module_put(sd->owner);
++#if defined(CONFIG_MEDIA_CONTROLLER)
++ if (v4l2_dev->mdev)
++ media_device_unregister_entity(&sd->entity);
++#endif
+ video_unregister_device(&sd->devnode);
+ }
+ EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
+diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
+index fbccefd..a49856a 100644
+--- a/drivers/media/video/v4l2-subdev.c
++++ b/drivers/media/video/v4l2-subdev.c
+@@ -35,7 +35,10 @@ static int subdev_open(struct file *file)
+ {
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+- struct v4l2_fh *vfh;
++#if defined(CONFIG_MEDIA_CONTROLLER)
++ struct media_entity *entity;
++#endif
++ struct v4l2_fh *vfh = NULL;
+ int ret;
+
+ if (!sd->initialized)
+@@ -61,11 +64,20 @@ static int subdev_open(struct file *file)
+ v4l2_fh_add(vfh);
+ file->private_data = vfh;
+ }
+-
++#if defined(CONFIG_MEDIA_CONTROLLER)
++ if (sd->v4l2_dev->mdev) {
++ entity = media_entity_get(&sd->entity);
++ if (!entity) {
++ ret = -EBUSY;
++ goto err;
++ }
++ }
++#endif
+ return 0;
+
+ err:
+ if (vfh != NULL) {
++ v4l2_fh_del(vfh);
+ v4l2_fh_exit(vfh);
+ kfree(vfh);
+ }
+@@ -75,8 +87,16 @@ err:
+
+ static int subdev_close(struct file *file)
+ {
++#if defined(CONFIG_MEDIA_CONTROLLER)
++ struct video_device *vdev = video_devdata(file);
++ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
++#endif
+ struct v4l2_fh *vfh = file->private_data;
+
++#if defined(CONFIG_MEDIA_CONTROLLER)
++ if (sd->v4l2_dev->mdev)
++ media_entity_put(&sd->entity);
++#endif
+ if (vfh != NULL) {
+ v4l2_fh_del(vfh);
+ v4l2_fh_exit(vfh);
+@@ -176,5 +196,22 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
+ sd->dev_priv = NULL;
+ sd->host_priv = NULL;
+ sd->initialized = 1;
++#if defined(CONFIG_MEDIA_CONTROLLER)
++ sd->entity.name = sd->name;
++ sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
++#endif
+ }
+ EXPORT_SYMBOL(v4l2_subdev_init);
++
++#if defined(CONFIG_MEDIA_CONTROLLER)
++int v4l2_subdev_set_power(struct media_entity *entity, int power)
++{
++ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
++
++ dev_dbg(entity->parent->dev,
++ "%s power%s\n", entity->name, power ? "on" : "off");
++
++ return v4l2_subdev_call(sd, core, s_power, power);
++}
++EXPORT_SYMBOL_GPL(v4l2_subdev_set_power);
++#endif
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index 68cbe48..7d55b0c 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -21,6 +21,7 @@
+ #ifndef _V4L2_SUBDEV_H
+ #define _V4L2_SUBDEV_H
+
++#include <media/media-entity.h>
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-dev.h>
+ #include <media/v4l2-mediabus.h>
+@@ -437,6 +438,9 @@ struct v4l2_subdev_ops {
+ stand-alone or embedded in a larger struct.
+ */
+ struct v4l2_subdev {
++#if defined(CONFIG_MEDIA_CONTROLLER)
++ struct media_entity entity;
++#endif
+ struct list_head list;
+ struct module *owner;
+ u32 flags;
+@@ -458,6 +462,8 @@ struct v4l2_subdev {
+ unsigned int nevents;
+ };
+
++#define media_entity_to_v4l2_subdev(ent) \
++ container_of(ent, struct v4l2_subdev, entity)
+ #define vdev_to_v4l2_subdev(vdev) \
+ container_of(vdev, struct v4l2_subdev, devnode)
+
+@@ -486,6 +492,10 @@ static inline void *v4l2_get_subdev_hostdata(const struct v4l2_subdev *sd)
+ void v4l2_subdev_init(struct v4l2_subdev *sd,
+ const struct v4l2_subdev_ops *ops);
+
++#if defined(CONFIG_MEDIA_CONTROLLER)
++int v4l2_subdev_set_power(struct media_entity *entity, int power);
++#endif
++
+ /* Call an ops of a v4l2_subdev, doing the right checks against
+ NULL pointers.
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0020-v4l-Move-the-media-v4l2-mediabus.h-header-to-include.patch b/extras/recipes-kernel/linux/linux-omap/media/0020-v4l-Move-the-media-v4l2-mediabus.h-header-to-include.patch
new file mode 100644
index 00000000..302fe532
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0020-v4l-Move-the-media-v4l2-mediabus.h-header-to-include.patch
@@ -0,0 +1,205 @@
+From 0d2a2247733eca8f357f5a93fcc357edbb941ec1 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Mon, 15 Mar 2010 23:33:31 +0100
+Subject: [PATCH 20/43] v4l: Move the media/v4l2-mediabus.h header to include/linux
+
+The header defines the v4l2_mbus_framefmt structure which will be used
+by the V4L2 subdevs userspace API.
+
+Change the type of the v4l2_mbus_framefmt::code field to __u32, as enum
+sizes can differ between different ABIs on the same architectures.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ include/linux/Kbuild | 1 +
+ include/linux/v4l2-mediabus.h | 78 +++++++++++++++++++++++++++++++++++++++++
+ include/media/soc_mediabus.h | 3 +-
+ include/media/v4l2-mediabus.h | 61 +-------------------------------
+ 4 files changed, 81 insertions(+), 62 deletions(-)
+ create mode 100644 include/linux/v4l2-mediabus.h
+
+diff --git a/include/linux/Kbuild b/include/linux/Kbuild
+index 26e0a7f..796e1d8 100644
+--- a/include/linux/Kbuild
++++ b/include/linux/Kbuild
+@@ -366,6 +366,7 @@ header-y += unistd.h
+ header-y += usbdevice_fs.h
+ header-y += utime.h
+ header-y += utsname.h
++header-y += v4l2-mediabus.h
+ header-y += veth.h
+ header-y += vhost.h
+ header-y += videodev.h
+diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
+new file mode 100644
+index 0000000..a62cd64
+--- /dev/null
++++ b/include/linux/v4l2-mediabus.h
+@@ -0,0 +1,78 @@
++/*
++ * Media Bus API header
++ *
++ * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef __LINUX_V4L2_MEDIABUS_H
++#define __LINUX_V4L2_MEDIABUS_H
++
++#include <linux/types.h>
++#include <linux/videodev2.h>
++
++/*
++ * These pixel codes uniquely identify data formats on the media bus. Mostly
++ * they correspond to similarly named V4L2_PIX_FMT_* formats, format 0 is
++ * reserved, V4L2_MBUS_FMT_FIXED shall be used by host-client pairs, where the
++ * data format is fixed. Additionally, "2X8" means that one pixel is transferred
++ * in two 8-bit samples, "BE" or "LE" specify in which order those samples are
++ * transferred over the bus: "LE" means that the least significant bits are
++ * transferred first, "BE" means that the most significant bits are transferred
++ * first, and "PADHI" and "PADLO" define which bits - low or high, in the
++ * incomplete high byte, are filled with padding bits.
++ */
++enum v4l2_mbus_pixelcode {
++ V4L2_MBUS_FMT_FIXED = 1,
++ V4L2_MBUS_FMT_YUYV8_2X8,
++ V4L2_MBUS_FMT_YVYU8_2X8,
++ V4L2_MBUS_FMT_UYVY8_2X8,
++ V4L2_MBUS_FMT_VYUY8_2X8,
++ V4L2_MBUS_FMT_YVYU10_2X10,
++ V4L2_MBUS_FMT_YUYV10_2X10,
++ V4L2_MBUS_FMT_YVYU10_1X20,
++ V4L2_MBUS_FMT_YUYV10_1X20,
++ V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
++ V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
++ V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
++ V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
++ V4L2_MBUS_FMT_RGB565_2X8_LE,
++ V4L2_MBUS_FMT_RGB565_2X8_BE,
++ V4L2_MBUS_FMT_BGR565_2X8_LE,
++ V4L2_MBUS_FMT_BGR565_2X8_BE,
++ V4L2_MBUS_FMT_SBGGR8_1X8,
++ V4L2_MBUS_FMT_SBGGR10_1X10,
++ V4L2_MBUS_FMT_GREY8_1X8,
++ V4L2_MBUS_FMT_Y10_1X10,
++ V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
++ V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
++ V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
++ V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
++ V4L2_MBUS_FMT_SGRBG8_1X8,
++ V4L2_MBUS_FMT_SBGGR12_1X12,
++ V4L2_MBUS_FMT_YUYV8_1_5X8,
++ V4L2_MBUS_FMT_YVYU8_1_5X8,
++ V4L2_MBUS_FMT_UYVY8_1_5X8,
++ V4L2_MBUS_FMT_VYUY8_1_5X8,
++};
++
++/**
++ * struct v4l2_mbus_framefmt - frame format on the media bus
++ * @width: frame width
++ * @height: frame height
++ * @code: data format code
++ * @field: used interlacing type
++ * @colorspace: colorspace of the data
++ */
++struct v4l2_mbus_framefmt {
++ __u32 width;
++ __u32 height;
++ __u32 code;
++ enum v4l2_field field;
++ enum v4l2_colorspace colorspace;
++};
++
++#endif
+diff --git a/include/media/soc_mediabus.h b/include/media/soc_mediabus.h
+index 037cd7b..6243147 100644
+--- a/include/media/soc_mediabus.h
++++ b/include/media/soc_mediabus.h
+@@ -12,8 +12,7 @@
+ #define SOC_MEDIABUS_H
+
+ #include <linux/videodev2.h>
+-
+-#include <media/v4l2-mediabus.h>
++#include <linux/v4l2-mediabus.h>
+
+ /**
+ * enum soc_mbus_packing - data packing types on the media-bus
+diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h
+index 8e65598..971c7fa 100644
+--- a/include/media/v4l2-mediabus.h
++++ b/include/media/v4l2-mediabus.h
+@@ -11,66 +11,7 @@
+ #ifndef V4L2_MEDIABUS_H
+ #define V4L2_MEDIABUS_H
+
+-/*
+- * These pixel codes uniquely identify data formats on the media bus. Mostly
+- * they correspond to similarly named V4L2_PIX_FMT_* formats, format 0 is
+- * reserved, V4L2_MBUS_FMT_FIXED shall be used by host-client pairs, where the
+- * data format is fixed. Additionally, "2X8" means that one pixel is transferred
+- * in two 8-bit samples, "BE" or "LE" specify in which order those samples are
+- * transferred over the bus: "LE" means that the least significant bits are
+- * transferred first, "BE" means that the most significant bits are transferred
+- * first, and "PADHI" and "PADLO" define which bits - low or high, in the
+- * incomplete high byte, are filled with padding bits.
+- */
+-enum v4l2_mbus_pixelcode {
+- V4L2_MBUS_FMT_FIXED = 1,
+- V4L2_MBUS_FMT_YUYV8_2X8,
+- V4L2_MBUS_FMT_YVYU8_2X8,
+- V4L2_MBUS_FMT_UYVY8_2X8,
+- V4L2_MBUS_FMT_VYUY8_2X8,
+- V4L2_MBUS_FMT_YVYU10_2X10,
+- V4L2_MBUS_FMT_YUYV10_2X10,
+- V4L2_MBUS_FMT_YVYU10_1X20,
+- V4L2_MBUS_FMT_YUYV10_1X20,
+- V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+- V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
+- V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+- V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
+- V4L2_MBUS_FMT_RGB565_2X8_LE,
+- V4L2_MBUS_FMT_RGB565_2X8_BE,
+- V4L2_MBUS_FMT_BGR565_2X8_LE,
+- V4L2_MBUS_FMT_BGR565_2X8_BE,
+- V4L2_MBUS_FMT_SBGGR8_1X8,
+- V4L2_MBUS_FMT_SBGGR10_1X10,
+- V4L2_MBUS_FMT_GREY8_1X8,
+- V4L2_MBUS_FMT_Y10_1X10,
+- V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
+- V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
+- V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
+- V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
+- V4L2_MBUS_FMT_SGRBG8_1X8,
+- V4L2_MBUS_FMT_SBGGR12_1X12,
+- V4L2_MBUS_FMT_YUYV8_1_5X8,
+- V4L2_MBUS_FMT_YVYU8_1_5X8,
+- V4L2_MBUS_FMT_UYVY8_1_5X8,
+- V4L2_MBUS_FMT_VYUY8_1_5X8,
+-};
+-
+-/**
+- * struct v4l2_mbus_framefmt - frame format on the media bus
+- * @width: frame width
+- * @height: frame height
+- * @code: data format code
+- * @field: used interlacing type
+- * @colorspace: colorspace of the data
+- */
+-struct v4l2_mbus_framefmt {
+- __u32 width;
+- __u32 height;
+- enum v4l2_mbus_pixelcode code;
+- enum v4l2_field field;
+- enum v4l2_colorspace colorspace;
+-};
++#include <linux/v4l2-mediabus.h>
+
+ static inline void v4l2_fill_pix_format(struct v4l2_pix_format *pix_fmt,
+ const struct v4l2_mbus_framefmt *mbus_fmt)
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0021-v4l-Replace-enums-with-fixed-sized-fields-in-public-.patch b/extras/recipes-kernel/linux/linux-omap/media/0021-v4l-Replace-enums-with-fixed-sized-fields-in-public-.patch
new file mode 100644
index 00000000..e04f4e2a
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0021-v4l-Replace-enums-with-fixed-sized-fields-in-public-.patch
@@ -0,0 +1,50 @@
+From fb1156d3125e36952f884b09afb9d0815ddeafd7 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 6 Oct 2010 08:30:26 +0200
+Subject: [PATCH 21/43] v4l: Replace enums with fixed-sized fields in public structure
+
+The v4l2_mbus_framefmt structure will be part of the public userspace
+API and used (albeit indirectly) as an ioctl argument. As such, its size
+must be fixed across userspace ABIs.
+
+Replace the v4l2_field and v4l2_colorspace enums by __u32 fields and add
+padding for future enhancements.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ include/linux/v4l2-mediabus.h | 17 +++++++++--------
+ 1 files changed, 9 insertions(+), 8 deletions(-)
+
+diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
+index a62cd64..feeb88c 100644
+--- a/include/linux/v4l2-mediabus.h
++++ b/include/linux/v4l2-mediabus.h
+@@ -63,16 +63,17 @@ enum v4l2_mbus_pixelcode {
+ * struct v4l2_mbus_framefmt - frame format on the media bus
+ * @width: frame width
+ * @height: frame height
+- * @code: data format code
+- * @field: used interlacing type
+- * @colorspace: colorspace of the data
++ * @code: data format code (from enum v4l2_mbus_pixelcode)
++ * @field: used interlacing type (from enum v4l2_field)
++ * @colorspace: colorspace of the data (from enum v4l2_colorspace)
+ */
+ struct v4l2_mbus_framefmt {
+- __u32 width;
+- __u32 height;
+- __u32 code;
+- enum v4l2_field field;
+- enum v4l2_colorspace colorspace;
++ __u32 width;
++ __u32 height;
++ __u32 code;
++ __u32 field;
++ __u32 colorspace;
++ __u32 reserved[7];
+ };
+
+ #endif
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0022-v4l-Rename-V4L2_MBUS_FMT_GREY8_1X8-to-V4L2_MBUS_FMT_.patch b/extras/recipes-kernel/linux/linux-omap/media/0022-v4l-Rename-V4L2_MBUS_FMT_GREY8_1X8-to-V4L2_MBUS_FMT_.patch
new file mode 100644
index 00000000..ffffd26a
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0022-v4l-Rename-V4L2_MBUS_FMT_GREY8_1X8-to-V4L2_MBUS_FMT_.patch
@@ -0,0 +1,154 @@
+From 0be9c8b998cef9ce650e1e53d12bb5a6d772d151 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Tue, 28 Sep 2010 12:01:44 +0200
+Subject: [PATCH 22/43] v4l: Rename V4L2_MBUS_FMT_GREY8_1X8 to V4L2_MBUS_FMT_Y8_1X8
+
+For consistency with the V4L2_MBUS_FMT_Y10_1X10 format.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ drivers/media/video/mt9m001.c | 2 +-
+ drivers/media/video/mt9v022.c | 4 ++--
+ drivers/media/video/ov6650.c | 10 +++++-----
+ drivers/media/video/sh_mobile_csi2.c | 6 +++---
+ drivers/media/video/soc_mediabus.c | 2 +-
+ include/linux/v4l2-mediabus.h | 2 +-
+ 6 files changed, 13 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
+index fcb4cd9..3aaedf6 100644
+--- a/drivers/media/video/mt9m001.c
++++ b/drivers/media/video/mt9m001.c
+@@ -79,7 +79,7 @@ static const struct mt9m001_datafmt mt9m001_colour_fmts[] = {
+ static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = {
+ /* Order important - see above */
+ {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
+- {V4L2_MBUS_FMT_GREY8_1X8, V4L2_COLORSPACE_JPEG},
++ {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
+ };
+
+ struct mt9m001 {
+diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
+index b96171c..56dd4fc 100644
+--- a/drivers/media/video/mt9v022.c
++++ b/drivers/media/video/mt9v022.c
+@@ -95,7 +95,7 @@ static const struct mt9v022_datafmt mt9v022_colour_fmts[] = {
+ static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = {
+ /* Order important - see above */
+ {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
+- {V4L2_MBUS_FMT_GREY8_1X8, V4L2_COLORSPACE_JPEG},
++ {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
+ };
+
+ struct mt9v022 {
+@@ -392,7 +392,7 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd,
+ * icd->try_fmt(), datawidth is from our supported format list
+ */
+ switch (mf->code) {
+- case V4L2_MBUS_FMT_GREY8_1X8:
++ case V4L2_MBUS_FMT_Y8_1X8:
+ case V4L2_MBUS_FMT_Y10_1X10:
+ if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
+ return -EINVAL;
+diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c
+index cf93de9..fe8e3eb 100644
+--- a/drivers/media/video/ov6650.c
++++ b/drivers/media/video/ov6650.c
+@@ -207,7 +207,7 @@ static enum v4l2_mbus_pixelcode ov6650_codes[] = {
+ V4L2_MBUS_FMT_YVYU8_2X8,
+ V4L2_MBUS_FMT_VYUY8_2X8,
+ V4L2_MBUS_FMT_SBGGR8_1X8,
+- V4L2_MBUS_FMT_GREY8_1X8,
++ V4L2_MBUS_FMT_Y8_1X8,
+ };
+
+ static const struct v4l2_queryctrl ov6650_controls[] = {
+@@ -800,7 +800,7 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
+
+ /* select color matrix configuration for given color encoding */
+ switch (code) {
+- case V4L2_MBUS_FMT_GREY8_1X8:
++ case V4L2_MBUS_FMT_Y8_1X8:
+ dev_dbg(&client->dev, "pixel format GREY8_1X8\n");
+ coma_mask |= COMA_RGB | COMA_WORD_SWAP | COMA_BYTE_SWAP;
+ coma_set |= COMA_BW;
+@@ -846,7 +846,7 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
+ }
+ priv->code = code;
+
+- if (code == V4L2_MBUS_FMT_GREY8_1X8 ||
++ if (code == V4L2_MBUS_FMT_Y8_1X8 ||
+ code == V4L2_MBUS_FMT_SBGGR8_1X8) {
+ coml_mask = COML_ONE_CHANNEL;
+ coml_set = 0;
+@@ -936,8 +936,8 @@ static int ov6650_try_fmt(struct v4l2_subdev *sd,
+
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_Y10_1X10:
+- mf->code = V4L2_MBUS_FMT_GREY8_1X8;
+- case V4L2_MBUS_FMT_GREY8_1X8:
++ mf->code = V4L2_MBUS_FMT_Y8_1X8;
++ case V4L2_MBUS_FMT_Y8_1X8:
+ case V4L2_MBUS_FMT_YVYU8_2X8:
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c
+index 84a6468..dd1b81b 100644
+--- a/drivers/media/video/sh_mobile_csi2.c
++++ b/drivers/media/video/sh_mobile_csi2.c
+@@ -56,7 +56,7 @@ static int sh_csi2_try_fmt(struct v4l2_subdev *sd,
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_UYVY8_2X8: /* YUV422 */
+ case V4L2_MBUS_FMT_YUYV8_1_5X8: /* YUV420 */
+- case V4L2_MBUS_FMT_GREY8_1X8: /* RAW8 */
++ case V4L2_MBUS_FMT_Y8_1X8: /* RAW8 */
+ case V4L2_MBUS_FMT_SBGGR8_1X8:
+ case V4L2_MBUS_FMT_SGRBG8_1X8:
+ break;
+@@ -67,7 +67,7 @@ static int sh_csi2_try_fmt(struct v4l2_subdev *sd,
+ break;
+ case SH_CSI2I:
+ switch (mf->code) {
+- case V4L2_MBUS_FMT_GREY8_1X8: /* RAW8 */
++ case V4L2_MBUS_FMT_Y8_1X8: /* RAW8 */
+ case V4L2_MBUS_FMT_SBGGR8_1X8:
+ case V4L2_MBUS_FMT_SGRBG8_1X8:
+ case V4L2_MBUS_FMT_SBGGR10_1X10: /* RAW10 */
+@@ -111,7 +111,7 @@ static int sh_csi2_s_fmt(struct v4l2_subdev *sd,
+ case V4L2_MBUS_FMT_RGB565_2X8_BE:
+ tmp |= 0x22; /* RGB565 */
+ break;
+- case V4L2_MBUS_FMT_GREY8_1X8:
++ case V4L2_MBUS_FMT_Y8_1X8:
+ case V4L2_MBUS_FMT_SBGGR8_1X8:
+ case V4L2_MBUS_FMT_SGRBG8_1X8:
+ tmp |= 0x2a; /* RAW8 */
+diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/video/soc_mediabus.c
+index 9139121..d9c297d 100644
+--- a/drivers/media/video/soc_mediabus.c
++++ b/drivers/media/video/soc_mediabus.c
+@@ -88,7 +88,7 @@ static const struct soc_mbus_pixelfmt mbus_fmt[] = {
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+- [MBUS_IDX(GREY8_1X8)] = {
++ [MBUS_IDX(Y8_1X8)] = {
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .name = "Grey",
+ .bits_per_sample = 8,
+diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
+index feeb88c..dc1d5c0 100644
+--- a/include/linux/v4l2-mediabus.h
++++ b/include/linux/v4l2-mediabus.h
+@@ -45,7 +45,7 @@ enum v4l2_mbus_pixelcode {
+ V4L2_MBUS_FMT_BGR565_2X8_BE,
+ V4L2_MBUS_FMT_SBGGR8_1X8,
+ V4L2_MBUS_FMT_SBGGR10_1X10,
+- V4L2_MBUS_FMT_GREY8_1X8,
++ V4L2_MBUS_FMT_Y8_1X8,
+ V4L2_MBUS_FMT_Y10_1X10,
+ V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
+ V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0023-v4l-Group-media-bus-pixel-codes-by-types-and-sort-th.patch b/extras/recipes-kernel/linux/linux-omap/media/0023-v4l-Group-media-bus-pixel-codes-by-types-and-sort-th.patch
new file mode 100644
index 00000000..aee5444a
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0023-v4l-Group-media-bus-pixel-codes-by-types-and-sort-th.patch
@@ -0,0 +1,112 @@
+From 9a13751e47503b4c966538e194a5027e5e7d9c5d Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 1 Sep 2010 17:58:22 +0200
+Subject: [PATCH 23/43] v4l: Group media bus pixel codes by types and sort them alphabetically
+
+Adding new pixel codes at the end of the enumeration will soon create a
+mess, so group the pixel codes by type and sort them by bus_width, bits
+per component, samples per pixel and order of subsamples.
+
+As the codes are part of the kernel ABI their value can't change when a
+new code is inserted in the enumeration, so they are given an explicit
+numerical value. When inserting a new pixel code developers must use and
+update the next free value.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ include/linux/v4l2-mediabus.h | 77 ++++++++++++++++++++++++----------------
+ 1 files changed, 46 insertions(+), 31 deletions(-)
+
+diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
+index dc1d5c0..cccfa34 100644
+--- a/include/linux/v4l2-mediabus.h
++++ b/include/linux/v4l2-mediabus.h
+@@ -24,39 +24,54 @@
+ * transferred first, "BE" means that the most significant bits are transferred
+ * first, and "PADHI" and "PADLO" define which bits - low or high, in the
+ * incomplete high byte, are filled with padding bits.
++ *
++ * The pixel codes are grouped by type, bus_width, bits per component, samples
++ * per pixel and order of subsamples. Numerical values are sorted using generic
++ * numerical sort order (8 thus comes before 10).
++ *
++ * As their value can't change when a new pixel code is inserted in the
++ * enumeration, the pixel codes are explicitly given a numerical value. The next
++ * free values for each category are listed below, update them when inserting
++ * new pixel codes.
+ */
+ enum v4l2_mbus_pixelcode {
+- V4L2_MBUS_FMT_FIXED = 1,
+- V4L2_MBUS_FMT_YUYV8_2X8,
+- V4L2_MBUS_FMT_YVYU8_2X8,
+- V4L2_MBUS_FMT_UYVY8_2X8,
+- V4L2_MBUS_FMT_VYUY8_2X8,
+- V4L2_MBUS_FMT_YVYU10_2X10,
+- V4L2_MBUS_FMT_YUYV10_2X10,
+- V4L2_MBUS_FMT_YVYU10_1X20,
+- V4L2_MBUS_FMT_YUYV10_1X20,
+- V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+- V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
+- V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+- V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
+- V4L2_MBUS_FMT_RGB565_2X8_LE,
+- V4L2_MBUS_FMT_RGB565_2X8_BE,
+- V4L2_MBUS_FMT_BGR565_2X8_LE,
+- V4L2_MBUS_FMT_BGR565_2X8_BE,
+- V4L2_MBUS_FMT_SBGGR8_1X8,
+- V4L2_MBUS_FMT_SBGGR10_1X10,
+- V4L2_MBUS_FMT_Y8_1X8,
+- V4L2_MBUS_FMT_Y10_1X10,
+- V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
+- V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
+- V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
+- V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
+- V4L2_MBUS_FMT_SGRBG8_1X8,
+- V4L2_MBUS_FMT_SBGGR12_1X12,
+- V4L2_MBUS_FMT_YUYV8_1_5X8,
+- V4L2_MBUS_FMT_YVYU8_1_5X8,
+- V4L2_MBUS_FMT_UYVY8_1_5X8,
+- V4L2_MBUS_FMT_VYUY8_1_5X8,
++ V4L2_MBUS_FMT_FIXED = 0x0001,
++
++ /* RGB - next is 0x1009 */
++ V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE = 0x1001,
++ V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE = 0x1002,
++ V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE = 0x1003,
++ V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE = 0x1004,
++ V4L2_MBUS_FMT_BGR565_2X8_BE = 0x1005,
++ V4L2_MBUS_FMT_BGR565_2X8_LE = 0x1006,
++ V4L2_MBUS_FMT_RGB565_2X8_BE = 0x1007,
++ V4L2_MBUS_FMT_RGB565_2X8_LE = 0x1008,
++
++ /* YUV (including grey) - next is 0x200f */
++ V4L2_MBUS_FMT_Y8_1X8 = 0x2001,
++ V4L2_MBUS_FMT_UYVY8_1_5X8 = 0x2002,
++ V4L2_MBUS_FMT_VYUY8_1_5X8 = 0x2003,
++ V4L2_MBUS_FMT_YUYV8_1_5X8 = 0x2004,
++ V4L2_MBUS_FMT_YVYU8_1_5X8 = 0x2005,
++ V4L2_MBUS_FMT_UYVY8_2X8 = 0x2006,
++ V4L2_MBUS_FMT_VYUY8_2X8 = 0x2007,
++ V4L2_MBUS_FMT_YUYV8_2X8 = 0x2008,
++ V4L2_MBUS_FMT_YVYU8_2X8 = 0x2009,
++ V4L2_MBUS_FMT_Y10_1X10 = 0x200a,
++ V4L2_MBUS_FMT_YUYV10_2X10 = 0x200b,
++ V4L2_MBUS_FMT_YVYU10_2X10 = 0x200c,
++ V4L2_MBUS_FMT_YUYV10_1X20 = 0x200d,
++ V4L2_MBUS_FMT_YVYU10_1X20 = 0x200e,
++
++ /* Bayer - next is 0x3009 */
++ V4L2_MBUS_FMT_SBGGR8_1X8 = 0x3001,
++ V4L2_MBUS_FMT_SGRBG8_1X8 = 0x3002,
++ V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE = 0x3003,
++ V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE = 0x3004,
++ V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE = 0x3005,
++ V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE = 0x3006,
++ V4L2_MBUS_FMT_SBGGR10_1X10 = 0x3007,
++ V4L2_MBUS_FMT_SBGGR12_1X12 = 0x3008,
+ };
+
+ /**
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0024-v4l-Create-v4l2-subdev-file-handle-structure.patch b/extras/recipes-kernel/linux/linux-omap/media/0024-v4l-Create-v4l2-subdev-file-handle-structure.patch
new file mode 100644
index 00000000..726af5d0
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0024-v4l-Create-v4l2-subdev-file-handle-structure.patch
@@ -0,0 +1,243 @@
+From 47f7677adda05f6d85a35047c4aac940c46a123c Mon Sep 17 00:00:00 2001
+From: Stanimir Varbanov <svarbanov@mm-sol.com>
+Date: Fri, 21 May 2010 12:04:24 +0300
+Subject: [PATCH 24/43] v4l: Create v4l2 subdev file handle structure
+
+Used for storing subdev information per file handle and hold V4L2 file
+handle.
+
+Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
+Signed-off-by: Antti Koskipaa <antti.koskipaa@nokia.com>
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ drivers/media/Kconfig | 9 ++++
+ drivers/media/video/v4l2-subdev.c | 85 +++++++++++++++++++++++++------------
+ include/media/v4l2-subdev.h | 29 +++++++++++++
+ 3 files changed, 96 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
+index 6b946e6..eaf4734 100644
+--- a/drivers/media/Kconfig
++++ b/drivers/media/Kconfig
+@@ -82,6 +82,15 @@ config VIDEO_V4L1_COMPAT
+
+ If you are unsure as to whether this is required, answer Y.
+
++config VIDEO_V4L2_SUBDEV_API
++ bool "V4L2 sub-device userspace API (EXPERIMENTAL)"
++ depends on VIDEO_DEV && MEDIA_CONTROLLER && EXPERIMENTAL
++ ---help---
++ Enables the V4L2 sub-device pad-level userspace API used to configure
++ video format, size and frame rate between hardware blocks.
++
++ This API is mostly used by camera interfaces in embedded platforms.
++
+ #
+ # DVB Core
+ #
+diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
+index a49856a..15449fc 100644
+--- a/drivers/media/video/v4l2-subdev.c
++++ b/drivers/media/video/v4l2-subdev.c
+@@ -31,39 +31,69 @@
+ #include <media/v4l2-fh.h>
+ #include <media/v4l2-event.h>
+
++static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
++{
++#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
++ /* Allocate try format and crop in the same memory block */
++ fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop))
++ * sd->entity.num_pads, GFP_KERNEL);
++ if (fh->try_fmt == NULL)
++ return -ENOMEM;
++
++ fh->try_crop = (struct v4l2_rect *)
++ (fh->try_fmt + sd->entity.num_pads);
++#endif
++ return 0;
++}
++
++static void subdev_fh_free(struct v4l2_subdev_fh *fh)
++{
++#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
++ kfree(fh->try_fmt);
++ fh->try_fmt = NULL;
++ fh->try_crop = NULL;
++#endif
++}
++
+ static int subdev_open(struct file *file)
+ {
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
++ struct v4l2_subdev_fh *subdev_fh;
+ #if defined(CONFIG_MEDIA_CONTROLLER)
+ struct media_entity *entity;
+ #endif
+- struct v4l2_fh *vfh = NULL;
+ int ret;
+
+ if (!sd->initialized)
+ return -EAGAIN;
+
+- if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) {
+- vfh = kzalloc(sizeof(*vfh), GFP_KERNEL);
+- if (vfh == NULL)
+- return -ENOMEM;
++ subdev_fh = kzalloc(sizeof(*subdev_fh), GFP_KERNEL);
++ if (subdev_fh == NULL)
++ return -ENOMEM;
+
+- ret = v4l2_fh_init(vfh, vdev);
+- if (ret)
+- goto err;
++ ret = subdev_fh_init(subdev_fh, sd);
++ if (ret) {
++ kfree(subdev_fh);
++ return ret;
++ }
++
++ ret = v4l2_fh_init(&subdev_fh->vfh, vdev);
++ if (ret)
++ goto err;
+
+- ret = v4l2_event_init(vfh);
++ if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) {
++ ret = v4l2_event_init(&subdev_fh->vfh);
+ if (ret)
+ goto err;
+
+- ret = v4l2_event_alloc(vfh, sd->nevents);
++ ret = v4l2_event_alloc(&subdev_fh->vfh, sd->nevents);
+ if (ret)
+ goto err;
+-
+- v4l2_fh_add(vfh);
+- file->private_data = vfh;
+ }
++
++ v4l2_fh_add(&subdev_fh->vfh);
++ file->private_data = &subdev_fh->vfh;
+ #if defined(CONFIG_MEDIA_CONTROLLER)
+ if (sd->v4l2_dev->mdev) {
+ entity = media_entity_get(&sd->entity);
+@@ -73,14 +103,14 @@ static int subdev_open(struct file *file)
+ }
+ }
+ #endif
++
+ return 0;
+
+ err:
+- if (vfh != NULL) {
+- v4l2_fh_del(vfh);
+- v4l2_fh_exit(vfh);
+- kfree(vfh);
+- }
++ v4l2_fh_del(&subdev_fh->vfh);
++ v4l2_fh_exit(&subdev_fh->vfh);
++ subdev_fh_free(subdev_fh);
++ kfree(subdev_fh);
+
+ return ret;
+ }
+@@ -92,16 +122,17 @@ static int subdev_close(struct file *file)
+ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+ #endif
+ struct v4l2_fh *vfh = file->private_data;
++ struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh);
+
+ #if defined(CONFIG_MEDIA_CONTROLLER)
+ if (sd->v4l2_dev->mdev)
+ media_entity_put(&sd->entity);
+ #endif
+- if (vfh != NULL) {
+- v4l2_fh_del(vfh);
+- v4l2_fh_exit(vfh);
+- kfree(vfh);
+- }
++ v4l2_fh_del(vfh);
++ v4l2_fh_exit(vfh);
++ subdev_fh_free(subdev_fh);
++ kfree(subdev_fh);
++ file->private_data = NULL;
+
+ return 0;
+ }
+@@ -110,7 +141,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+ {
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+- struct v4l2_fh *fh = file->private_data;
++ struct v4l2_fh *vfh = file->private_data;
+
+ switch (cmd) {
+ case VIDIOC_QUERYCTRL:
+@@ -138,13 +169,13 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+ if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
+ return -ENOIOCTLCMD;
+
+- return v4l2_event_dequeue(fh, arg, file->f_flags & O_NONBLOCK);
++ return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK);
+
+ case VIDIOC_SUBSCRIBE_EVENT:
+- return v4l2_subdev_call(sd, core, subscribe_event, fh, arg);
++ return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
+
+ case VIDIOC_UNSUBSCRIBE_EVENT:
+- return v4l2_subdev_call(sd, core, unsubscribe_event, fh, arg);
++ return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
+
+ default:
+ return -ENOIOCTLCMD;
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index 7d55b0c..f8704ff 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -24,6 +24,7 @@
+ #include <media/media-entity.h>
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-dev.h>
++#include <media/v4l2-fh.h>
+ #include <media/v4l2-mediabus.h>
+
+ /* generic v4l2_device notify callback notification values */
+@@ -467,6 +468,34 @@ struct v4l2_subdev {
+ #define vdev_to_v4l2_subdev(vdev) \
+ container_of(vdev, struct v4l2_subdev, devnode)
+
++/*
++ * Used for storing subdev information per file handle
++ */
++struct v4l2_subdev_fh {
++ struct v4l2_fh vfh;
++#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
++ struct v4l2_mbus_framefmt *try_fmt;
++ struct v4l2_rect *try_crop;
++#endif
++};
++
++#define to_v4l2_subdev_fh(fh) \
++ container_of(fh, struct v4l2_subdev_fh, vfh)
++
++#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
++static inline struct v4l2_mbus_framefmt *
++v4l2_subdev_get_try_format(struct v4l2_subdev_fh *fh, unsigned int pad)
++{
++ return &fh->try_fmt[pad];
++}
++
++static inline struct v4l2_rect *
++v4l2_subdev_get_try_crop(struct v4l2_subdev_fh *fh, unsigned int pad)
++{
++ return &fh->try_crop[pad];
++}
++#endif
++
+ extern const struct v4l2_file_operations v4l2_subdev_fops;
+
+ static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p)
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0025-v4l-subdev-Add-a-new-file-operations-class.patch b/extras/recipes-kernel/linux/linux-omap/media/0025-v4l-subdev-Add-a-new-file-operations-class.patch
new file mode 100644
index 00000000..cf631c88
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0025-v4l-subdev-Add-a-new-file-operations-class.patch
@@ -0,0 +1,93 @@
+From 4dc43ce10d8b66537a680635d4f2dbe0a1daa1d9 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Mon, 2 Aug 2010 00:05:09 +0200
+Subject: [PATCH 25/43] v4l: subdev: Add a new file operations class
+
+V4L2 sub-devices store pad formats and crop settings in the file handle.
+To let drivers initialize those settings properly, add a file::open
+operation that is called when the subdev is opened as well as a
+corresponding file::close operation.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ drivers/media/video/v4l2-subdev.c | 13 ++++++++++---
+ include/media/v4l2-subdev.h | 10 ++++++++++
+ 2 files changed, 20 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
+index 15449fc..0f904e2 100644
+--- a/drivers/media/video/v4l2-subdev.c
++++ b/drivers/media/video/v4l2-subdev.c
+@@ -61,7 +61,7 @@ static int subdev_open(struct file *file)
+ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+ struct v4l2_subdev_fh *subdev_fh;
+ #if defined(CONFIG_MEDIA_CONTROLLER)
+- struct media_entity *entity;
++ struct media_entity *entity = NULL;
+ #endif
+ int ret;
+
+@@ -104,9 +104,17 @@ static int subdev_open(struct file *file)
+ }
+ #endif
+
++ ret = v4l2_subdev_call(sd, file, open, subdev_fh);
++ if (ret < 0 && ret != -ENOIOCTLCMD)
++ goto err;
++
+ return 0;
+
+ err:
++#if defined(CONFIG_MEDIA_CONTROLLER)
++ if (entity)
++ media_entity_put(entity);
++#endif
+ v4l2_fh_del(&subdev_fh->vfh);
+ v4l2_fh_exit(&subdev_fh->vfh);
+ subdev_fh_free(subdev_fh);
+@@ -117,13 +125,12 @@ err:
+
+ static int subdev_close(struct file *file)
+ {
+-#if defined(CONFIG_MEDIA_CONTROLLER)
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+-#endif
+ struct v4l2_fh *vfh = file->private_data;
+ struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh);
+
++ v4l2_subdev_call(sd, file, close, subdev_fh);
+ #if defined(CONFIG_MEDIA_CONTROLLER)
+ if (sd->v4l2_dev->mdev)
+ media_entity_put(&sd->entity);
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index f8704ff..af704df 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -175,6 +175,15 @@ struct v4l2_subdev_core_ops {
+ struct v4l2_event_subscription *sub);
+ };
+
++/* open: called when the subdev device node is opened by an application.
++
++ close: called when the subdev device node is close.
++ */
++struct v4l2_subdev_file_ops {
++ int (*open)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
++ int (*close)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
++};
++
+ /* s_mode: switch the tuner to a specific tuner mode. Replacement of s_radio.
+
+ s_radio: v4l device was opened in Radio mode, to be replaced by s_mode.
+@@ -416,6 +425,7 @@ struct v4l2_subdev_ir_ops {
+
+ struct v4l2_subdev_ops {
+ const struct v4l2_subdev_core_ops *core;
++ const struct v4l2_subdev_file_ops *file;
+ const struct v4l2_subdev_tuner_ops *tuner;
+ const struct v4l2_subdev_audio_ops *audio;
+ const struct v4l2_subdev_video_ops *video;
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0026-v4l-v4l2_subdev-pad-level-operations.patch b/extras/recipes-kernel/linux/linux-omap/media/0026-v4l-v4l2_subdev-pad-level-operations.patch
new file mode 100644
index 00000000..63762451
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0026-v4l-v4l2_subdev-pad-level-operations.patch
@@ -0,0 +1,49 @@
+From 7a089b741d5c2ca3881d61e81971a1a0e464aa27 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:39:52 +0100
+Subject: [PATCH 26/43] v4l: v4l2_subdev pad-level operations
+
+Add a v4l2_subdev_pad_ops structure for the operations that need to be
+performed at the pad level such as format-related operations.
+
+Pad format-related operations use v4l2_mbus_framefmt instead of
+v4l2_format.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ include/media/v4l2-subdev.h | 5 +++++
+ 1 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index af704df..4f6ddba 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -42,6 +42,7 @@ struct v4l2_ctrl_handler;
+ struct v4l2_event_subscription;
+ struct v4l2_fh;
+ struct v4l2_subdev;
++struct v4l2_subdev_fh;
+ struct tuner_setup;
+
+ /* decode_vbi_line */
+@@ -423,6 +424,9 @@ struct v4l2_subdev_ir_ops {
+ struct v4l2_subdev_ir_parameters *params);
+ };
+
++struct v4l2_subdev_pad_ops {
++};
++
+ struct v4l2_subdev_ops {
+ const struct v4l2_subdev_core_ops *core;
+ const struct v4l2_subdev_file_ops *file;
+@@ -432,6 +436,7 @@ struct v4l2_subdev_ops {
+ const struct v4l2_subdev_vbi_ops *vbi;
+ const struct v4l2_subdev_ir_ops *ir;
+ const struct v4l2_subdev_sensor_ops *sensor;
++ const struct v4l2_subdev_pad_ops *pad;
+ };
+
+ #define V4L2_SUBDEV_NAME_SIZE 32
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0028-v4l-v4l2_subdev-userspace-format-API.patch b/extras/recipes-kernel/linux/linux-omap/media/0028-v4l-v4l2_subdev-userspace-format-API.patch
new file mode 100644
index 00000000..2b851d6f
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0028-v4l-v4l2_subdev-userspace-format-API.patch
@@ -0,0 +1,3546 @@
+From 58fa3ca8af541e6704ac11703fc3091d856e0700 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Tue, 16 Mar 2010 00:26:04 +0100
+Subject: [PATCH 28/43] v4l: v4l2_subdev userspace format API
+
+Add a userspace API to get, set and enumerate the media format on a
+subdev pad.
+
+The format at the output of a subdev usually depends on the format at
+its input(s). The try format operation is thus not suitable for probing
+format at individual pads, as it can't modify the device state and thus
+can't remember the format tried at the input to compute the output
+format.
+
+To fix the problem, pass an extra argument to the get/set format
+operations to select the 'try' or 'active' format.
+
+The try format is used when probing the subdev. Setting the try format
+must not change the device configuration but can store data for later
+reuse. Data storage is provided at the file-handle level so applications
+probing the subdev concurently won't interfere with each other.
+
+The active format is used when configuring the subdev. It's identical to
+the format handled by the usual get/set operations.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+---
+ Documentation/DocBook/Makefile | 5 +-
+ Documentation/DocBook/media-entities.tmpl | 16 +
+ Documentation/DocBook/v4l/dev-subdev.xml | 274 +++
+ Documentation/DocBook/v4l/subdev-formats.xml | 2416 ++++++++++++++++++++
+ Documentation/DocBook/v4l/v4l2.xml | 4 +
+ Documentation/DocBook/v4l/vidioc-streamon.xml | 9 +
+ .../DocBook/v4l/vidioc-subdev-enum-frame-size.xml | 148 ++
+ .../DocBook/v4l/vidioc-subdev-enum-mbus-code.xml | 113 +
+ Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml | 174 ++
+ drivers/media/video/v4l2-subdev.c | 49 +
+ include/linux/Kbuild | 1 +
+ include/linux/v4l2-subdev.h | 90 +
+ include/media/v4l2-subdev.h | 10 +
+ 13 files changed, 3308 insertions(+), 1 deletions(-)
+ create mode 100644 Documentation/DocBook/v4l/dev-subdev.xml
+ create mode 100644 Documentation/DocBook/v4l/subdev-formats.xml
+ create mode 100644 Documentation/DocBook/v4l/vidioc-subdev-enum-frame-size.xml
+ create mode 100644 Documentation/DocBook/v4l/vidioc-subdev-enum-mbus-code.xml
+ create mode 100644 Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml
+ create mode 100644 include/linux/v4l2-subdev.h
+
+diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
+index 8b6e00a..2deb069 100644
+--- a/Documentation/DocBook/Makefile
++++ b/Documentation/DocBook/Makefile
+@@ -53,7 +53,10 @@ MAN := $(patsubst %.xml, %.9, $(BOOKS))
+ mandocs: $(MAN)
+
+ build_images = mkdir -p $(objtree)/Documentation/DocBook/media/ && \
+- cp $(srctree)/Documentation/DocBook/dvb/*.png $(srctree)/Documentation/DocBook/v4l/*.gif $(objtree)/Documentation/DocBook/media/
++ cp $(srctree)/Documentation/DocBook/dvb/*.png \
++ $(srctree)/Documentation/DocBook/v4l/*.gif \
++ $(srctree)/Documentation/DocBook/v4l/*.png \
++ $(objtree)/Documentation/DocBook/media/
+
+ xmldoclinks:
+ ifneq ($(objtree),$(srctree))
+diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
+index 679c585..538f8fe 100644
+--- a/Documentation/DocBook/media-entities.tmpl
++++ b/Documentation/DocBook/media-entities.tmpl
+@@ -86,6 +86,10 @@
+ <!ENTITY VIDIOC-S-PRIORITY "<link linkend='vidioc-g-priority'><constant>VIDIOC_S_PRIORITY</constant></link>">
+ <!ENTITY VIDIOC-S-STD "<link linkend='vidioc-g-std'><constant>VIDIOC_S_STD</constant></link>">
+ <!ENTITY VIDIOC-S-TUNER "<link linkend='vidioc-g-tuner'><constant>VIDIOC_S_TUNER</constant></link>">
++<!ENTITY VIDIOC-SUBDEV-ENUM-FRAME-SIZE "<link linkend='vidioc-subdev-enum-frame-size'><constant>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</constant></link>">
++<!ENTITY VIDIOC-SUBDEV-ENUM-MBUS-CODE "<link linkend='vidioc-subdev-enum-mbus-code'><constant>VIDIOC_SUBDEV_ENUM_MBUS_CODE</constant></link>">
++<!ENTITY VIDIOC-SUBDEV-G-FMT "<link linkend='vidioc-subdev-g-fmt'><constant>VIDIOC_SUBDEV_G_FMT</constant></link>">
++<!ENTITY VIDIOC-SUBDEV-S-FMT "<link linkend='vidioc-subdev-g-fmt'><constant>VIDIOC_SUBDEV_S_FMT</constant></link>">
+ <!ENTITY VIDIOC-TRY-ENCODER-CMD "<link linkend='vidioc-encoder-cmd'><constant>VIDIOC_TRY_ENCODER_CMD</constant></link>">
+ <!ENTITY VIDIOC-TRY-EXT-CTRLS "<link linkend='vidioc-g-ext-ctrls'><constant>VIDIOC_TRY_EXT_CTRLS</constant></link>">
+ <!ENTITY VIDIOC-TRY-FMT "<link linkend='vidioc-g-fmt'><constant>VIDIOC_TRY_FMT</constant></link>">
+@@ -107,6 +111,7 @@
+ <!ENTITY v4l2-field "enum&nbsp;<link linkend='v4l2-field'>v4l2_field</link>">
+ <!ENTITY v4l2-frmivaltypes "enum&nbsp;<link linkend='v4l2-frmivaltypes'>v4l2_frmivaltypes</link>">
+ <!ENTITY v4l2-frmsizetypes "enum&nbsp;<link linkend='v4l2-frmsizetypes'>v4l2_frmsizetypes</link>">
++<!ENTITY v4l2-mbus-pixelcode "enum&nbsp;<link linkend='v4l2-mbus-pixelcode'>v4l2_mbus_pixelcode</link>">
+ <!ENTITY v4l2-memory "enum&nbsp;<link linkend='v4l2-memory'>v4l2_memory</link>">
+ <!ENTITY v4l2-mpeg-audio-ac3-bitrate "enum&nbsp;<link linkend='v4l2-mpeg-audio-ac3-bitrate'>v4l2_mpeg_audio_ac3_bitrate</link>">
+ <!ENTITY v4l2-mpeg-audio-crc "enum&nbsp;<link linkend='v4l2-mpeg-audio-crc'>v4l2_mpeg_audio_crc</link>">
+@@ -130,6 +135,7 @@
+ <!ENTITY v4l2-mpeg-video-encoding "enum&nbsp;<link linkend='v4l2-mpeg-video-encoding'>v4l2_mpeg_video_encoding</link>">
+ <!ENTITY v4l2-power-line-frequency "enum&nbsp;<link linkend='v4l2-power-line-frequency'>v4l2_power_line_frequency</link>">
+ <!ENTITY v4l2-priority "enum&nbsp;<link linkend='v4l2-priority'>v4l2_priority</link>">
++<!ENTITY v4l2-subdev-format-whence "enum&nbsp;<link linkend='v4l2-subdev-format-whence'>v4l2_subdev_format_whence</link>">
+ <!ENTITY v4l2-tuner-type "enum&nbsp;<link linkend='v4l2-tuner-type'>v4l2_tuner_type</link>">
+ <!ENTITY v4l2-preemphasis "enum&nbsp;<link linkend='v4l2-preemphasis'>v4l2_preemphasis</link>">
+
+@@ -171,6 +177,7 @@
+ <!ENTITY v4l2-hw-freq-seek "struct&nbsp;<link linkend='v4l2-hw-freq-seek'>v4l2_hw_freq_seek</link>">
+ <!ENTITY v4l2-input "struct&nbsp;<link linkend='v4l2-input'>v4l2_input</link>">
+ <!ENTITY v4l2-jpegcompression "struct&nbsp;<link linkend='v4l2-jpegcompression'>v4l2_jpegcompression</link>">
++<!ENTITY v4l2-mbus-framefmt "struct&nbsp;<link linkend='v4l2-mbus-framefmt'>v4l2_mbus_framefmt</link>">
+ <!ENTITY v4l2-modulator "struct&nbsp;<link linkend='v4l2-modulator'>v4l2_modulator</link>">
+ <!ENTITY v4l2-mpeg-vbi-fmt-ivtv "struct&nbsp;<link linkend='v4l2-mpeg-vbi-fmt-ivtv'>v4l2_mpeg_vbi_fmt_ivtv</link>">
+ <!ENTITY v4l2-output "struct&nbsp;<link linkend='v4l2-output'>v4l2_output</link>">
+@@ -183,6 +190,9 @@
+ <!ENTITY v4l2-sliced-vbi-cap "struct&nbsp;<link linkend='v4l2-sliced-vbi-cap'>v4l2_sliced_vbi_cap</link>">
+ <!ENTITY v4l2-sliced-vbi-data "struct&nbsp;<link linkend='v4l2-sliced-vbi-data'>v4l2_sliced_vbi_data</link>">
+ <!ENTITY v4l2-sliced-vbi-format "struct&nbsp;<link linkend='v4l2-sliced-vbi-format'>v4l2_sliced_vbi_format</link>">
++<!ENTITY v4l2-subdev-frame-size-enum "struct&nbsp;<link linkend='v4l2-subdev-frame-size-enum'>v4l2_subdev_frame_size_enum</link>">
++<!ENTITY v4l2-subdev-format "struct&nbsp;<link linkend='v4l2-subdev-format'>v4l2_subdev_format</link>">
++<!ENTITY v4l2-subdev-mbus-code-enum "struct&nbsp;<link linkend='v4l2-subdev-mbus-code-enum'>v4l2_subdev_mbus_code_enum</link>">
+ <!ENTITY v4l2-standard "struct&nbsp;<link linkend='v4l2-standard'>v4l2_standard</link>">
+ <!ENTITY v4l2-streamparm "struct&nbsp;<link linkend='v4l2-streamparm'>v4l2_streamparm</link>">
+ <!ENTITY v4l2-timecode "struct&nbsp;<link linkend='v4l2-timecode'>v4l2_timecode</link>">
+@@ -212,6 +222,7 @@
+ <!ENTITY ENXIO "<errorcode>ENXIO</errorcode> error code">
+ <!ENTITY EMFILE "<errorcode>EMFILE</errorcode> error code">
+ <!ENTITY EPERM "<errorcode>EPERM</errorcode> error code">
++<!ENTITY EPIPE "<errorcode>EPIPE</errorcode> error code">
+ <!ENTITY ERANGE "<errorcode>ERANGE</errorcode> error code">
+
+ <!-- Subsections -->
+@@ -230,6 +241,7 @@
+ <!ENTITY sub-dev-raw-vbi SYSTEM "v4l/dev-raw-vbi.xml">
+ <!ENTITY sub-dev-rds SYSTEM "v4l/dev-rds.xml">
+ <!ENTITY sub-dev-sliced-vbi SYSTEM "v4l/dev-sliced-vbi.xml">
++<!ENTITY sub-dev-subdev SYSTEM "v4l/dev-subdev.xml">
+ <!ENTITY sub-dev-teletext SYSTEM "v4l/dev-teletext.xml">
+ <!ENTITY sub-driver SYSTEM "v4l/driver.xml">
+ <!ENTITY sub-libv4l SYSTEM "v4l/libv4l.xml">
+@@ -313,6 +325,10 @@
+ <!ENTITY sub-reqbufs SYSTEM "v4l/vidioc-reqbufs.xml">
+ <!ENTITY sub-s-hw-freq-seek SYSTEM "v4l/vidioc-s-hw-freq-seek.xml">
+ <!ENTITY sub-streamon SYSTEM "v4l/vidioc-streamon.xml">
++<!ENTITY sub-subdev-enum-frame-size SYSTEM "v4l/vidioc-subdev-enum-frame-size.xml">
++<!ENTITY sub-subdev-enum-mbus-code SYSTEM "v4l/vidioc-subdev-enum-mbus-code.xml">
++<!ENTITY sub-subdev-formats SYSTEM "v4l/subdev-formats.xml">
++<!ENTITY sub-subdev-g-fmt SYSTEM "v4l/vidioc-subdev-g-fmt.xml">
+ <!ENTITY sub-capture-c SYSTEM "v4l/capture.c.xml">
+ <!ENTITY sub-keytable-c SYSTEM "v4l/keytable.c.xml">
+ <!ENTITY sub-v4l2grab-c SYSTEM "v4l/v4l2grab.c.xml">
+diff --git a/Documentation/DocBook/v4l/dev-subdev.xml b/Documentation/DocBook/v4l/dev-subdev.xml
+new file mode 100644
+index 0000000..12fdca4
+--- /dev/null
++++ b/Documentation/DocBook/v4l/dev-subdev.xml
+@@ -0,0 +1,274 @@
++ <title>Sub-device Interface</title>
++
++ <para>The complex nature of V4L2 devices, where hardware is often made of
++ several integrated circuits that need to interact with each other in a
++ controlled way, leads to complex V4L2 drivers. The drivers usually reflect
++ the hardware model in software, and model the different hardware components
++ as software blocks called sub-devices.</para>
++
++ <para>V4L2 sub-devices are usually kernel-only objects. If the V4L2 driver
++ implements the media device API, they will automatically inherit from media
++ entities. Applications will be able to enumerate the sub-devices and discover
++ the hardware topology using the media entities, pads and links enumeration
++ API.</para>
++
++ <para>In addition to make sub-devices discoverable, drivers can also choose
++ to make them directly configurable by applications. When both the sub-device
++ driver and the V4L2 device driver support this, sub-devices will feature a
++ character device node on which ioctls can be called to
++ <itemizedlist>
++ <listitem>query, read and write sub-devices controls</listitem>
++ <listitem>subscribe and unsubscribe to events and retrieve them</listitem>
++ <listitem>negotiate image formats on individual pads</listitem>
++ </itemizedlist>
++ </para>
++
++ <para>Sub-device character device nodes, conventionally named
++ <filename>/dev/v4l-subdev*</filename>, use major number 81.</para>
++
++ <section>
++ <title>Controls</title>
++ <para>Most V4L2 controls are implemented by sub-device hardware. Drivers
++ usually merge all controls and expose them through video device nodes.
++ Applications can control all sub-devices through a single interface.</para>
++
++ <para>Complex devices sometimes implement the same control in different
++ pieces of hardware. This situation is common in embedded platforms, where
++ both sensors and image processing hardware implement identical functions,
++ such as contrast adjustment, white balance or faulty pixels correction. As
++ the V4L2 controls API doesn't support several identical controls in a single
++ device, all but one of the identical controls are hidden.</para>
++
++ <para>Applications can access those hidden controls through the sub-device
++ node with the V4L2 control API described in <xref linkend="control" />. The
++ ioctls behave identically as when issued on V4L2 device nodes, with the
++ exception that they deal only with controls implemented in the sub-device.
++ </para>
++
++ <para>Depending on the driver, those controls might also be exposed through
++ one (or several) V4L2 device nodes.</para>
++ </section>
++
++ <section>
++ <title>Events</title>
++ <para>V4L2 sub-devices can notify applications of events as described in
++ <xref linkend="event" />. The API behaves identically as when used on V4L2
++ device nodes, with the exception that it only deals with events generated by
++ the sub-device. Depending on the driver, those events might also be reported
++ on one (or several) V4L2 device nodes.</para>
++ </section>
++
++ <section id="pad-level-formats">
++ <title>Pad-level Formats</title>
++
++ <warning>Pad-level formats are only applicable to very complex device that
++ need to expose low-level format configuration to user space. Generic V4L2
++ applications do <emphasis>not</emphasis> need to use the API described in
++ this section.</warning>
++
++ <note>For the purpose of this section, the term
++ <wordasword>format</wordasword> means the combination of media bus data
++ format, frame width and frame height.</note>
++
++ <para>Image formats are typically negotiated on video capture and output
++ devices using the <link linkend="crop">cropping and scaling</link> ioctls.
++ The driver is responsible for configuring every block in the video pipeline
++ according to the requested format at the pipeline input and/or
++ output.</para>
++
++ <para>For complex devices, such as often found in embedded systems,
++ identical image sizes at the output of a pipeline can be achieved using
++ different hardware configurations. One such exemple is shown on
++ <xref linkend="pipeline-scaling" xrefstyle="template: Figure %n" />, where
++ image scaling can be performed on both the video sensor and the host image
++ processing hardware.</para>
++
++ <figure id="pipeline-scaling">
++ <title>Image Format Negotation on Pipelines</title>
++ <mediaobject>
++ <imageobject>
++ <imagedata fileref="pipeline.pdf" format="PS" />
++ </imageobject>
++ <imageobject>
++ <imagedata fileref="pipeline.png" format="PNG" />
++ </imageobject>
++ <textobject>
++ <phrase>High quality and high speed pipeline configuration</phrase>
++ </textobject>
++ </mediaobject>
++ </figure>
++
++ <para>The sensor scaler is usually of less quality than the host scaler, but
++ scaling on the sensor is required to achieve higher frame rates. Depending
++ on the use case (quality vs. speed), the pipeline must be configured
++ differently. Applications need to configure the formats at every point in
++ the pipeline explicitly.</para>
++
++ <para>Drivers that implement the <link linkend="media-controller-intro">media
++ API</link> can expose pad-level image format configuration to applications.
++ When they do, applications can use the &VIDIOC-SUBDEV-G-FMT; and
++ &VIDIOC-SUBDEV-S-FMT; ioctls. to negotiate formats on a per-pad basis.</para>
++
++ <para>Applications are responsible for configuring coherent parameters on
++ the whole pipeline and making sure that connected pads have compatible
++ formats. The pipeline is checked for formats mismatch at &VIDIOC-STREAMON;
++ time, and an &EPIPE; is then returned if the configuration is
++ invalid.</para>
++
++ <para>Pad-level image format configuration support can be tested by calling
++ the &VIDIOC-SUBDEV-G-FMT; ioctl on pad 0. If the driver returns an &EINVAL;
++ pad-level format configuration is not supported by the sub-device.</para>
++
++ <section>
++ <title>Format Negotiation</title>
++
++ <para>Acceptable formats on pads can (and usually do) depend on a number
++ of external parameters, such as formats on other pads, active links, or
++ even controls. Finding a combination of formats on all pads in a video
++ pipeline, acceptable to both application and driver, can't rely on formats
++ enumeration only. A format negotiation mechanism is required.</para>
++
++ <para>Central to the format negotiation mechanism are the get/set format
++ operations. When called with the <structfield>which</structfield> argument
++ set to <constant>V4L2_SUBDEV_FORMAT_TRY</constant>, the
++ &VIDIOC-SUBDEV-G-FMT; and &VIDIOC-SUBDEV-S-FMT; ioctls operate on a set of
++ formats parameters that are not connected to the hardware configuration.
++ Modifying those 'try' formats leaves the device state untouched (this
++ applies to both the software state stored in the driver and the hardware
++ state stored in the device itself).</para>
++
++ <para>While not kept as part of the device state, try formats are stored
++ in the sub-device file handles. A &VIDIOC-SUBDEV-G-FMT; call will return
++ the last try format set <emphasis>on the same sub-device file
++ handle</emphasis>. Several applications querying the same sub-device at
++ the same time will thus not interact with each other.</para>
++
++ <para>To find out whether a particular format is supported by the device,
++ applications use the &VIDIOC-SUBDEV-S-FMT; ioctl. Drivers verify and, if
++ needed, change the requested <structfield>format</structfield> based on
++ device requirements and return the possibly modified value. Applications
++ can then choose to try a different format or accept the returned value and
++ continue.</para>
++
++ <para>Formats returned by the driver during a negotiation iteration are
++ guaranteed to be supported by the device. In particular, drivers guarantee
++ that a returned format will not be further changed if passed to an
++ &VIDIOC-SUBDEV-S-FMT; call as-is (as long as external parameters, such as
++ formats on other pads or links' configuration are not changed).</para>
++
++ <para>Drivers automatically propagate formats inside sub-devices. When a
++ try or active format is set on a pad, corresponding formats on other pads
++ of the same sub-device can be modified by the driver. Drivers are free to
++ modify formats as required by the device. However, they should comply with
++ the following rules when possible:
++ <itemizedlist>
++ <listitem>Formats should be propagated from sink pads to source pads.
++ Modifying a format on a source pad should not modify the format on any
++ sink pad.</listitem>
++ <listitem>Sub-devices that scale frames using variable scaling factors
++ should reset the scale factors to default values when sink pads formats
++ are modified. If the 1:1 scaling ratio is supported, this means that
++ source pads formats should be reset to the sink pads formats.</listitem>
++ </itemizedlist>
++ </para>
++
++ <para>Formats are not propagated across links, as that would involve
++ propagating them from one sub-device file handle to another. Applications
++ must then take care to configure both ends of every link explicitly with
++ compatible formats. Identical formats on the two ends of a link are
++ guaranteed to be compatible. Drivers are free to accept different formats
++ matching device requirements as being compatible.</para>
++
++ <para><xref linkend="sample-pipeline-config" xrefstyle="template:Table %n"/>
++ shows a sample configuration sequence for the pipeline described in
++ <xref linkend="pipeline-scaling" xrefstyle="template:Figure %n"/> (table
++ columns list entity names and pad numbers).</para>
++
++ <table pgwide="0" frame="none" id="sample-pipeline-config">
++ <title>Sample Pipeline Configuration</title>
++ <tgroup cols="3">
++ <colspec colname="what"/>
++ <colspec colname="sensor-0" />
++ <colspec colname="frontend-0" />
++ <colspec colname="frontend-1" />
++ <colspec colname="scaler-0" />
++ <colspec colname="scaler-1" />
++ <thead>
++ <row>
++ <entry></entry>
++ <entry>Sensor/0</entry>
++ <entry>Frontend/0</entry>
++ <entry>Frontend/1</entry>
++ <entry>Scaler/0</entry>
++ <entry>Scaler/1</entry>
++ </row>
++ </thead>
++ <tbody valign="top">
++ <row>
++ <entry>Initial state</entry>
++ <entry>2048x1536</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ </row>
++ <row>
++ <entry>Configure frontend input</entry>
++ <entry>2048x1536</entry>
++ <entry><emphasis>2048x1536</emphasis></entry>
++ <entry><emphasis>2046x1534</emphasis></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ </row>
++ <row>
++ <entry>Configure scaler input</entry>
++ <entry>2048x1536</entry>
++ <entry>2048x1536</entry>
++ <entry>2046x1534</entry>
++ <entry><emphasis>2046x1534</emphasis></entry>
++ <entry><emphasis>2046x1534</emphasis></entry>
++ </row>
++ <row>
++ <entry>Configure scaler output</entry>
++ <entry>2048x1536</entry>
++ <entry>2048x1536</entry>
++ <entry>2046x1534</entry>
++ <entry>2046x1534</entry>
++ <entry><emphasis>1280x960</emphasis></entry>
++ </row>
++ </tbody>
++ </tgroup>
++ </table>
++
++ <para>
++ <orderedlist>
++ <listitem>Initial state. The sensor output is set to its native 3MP
++ resolution. Resolutions on the host frontend and scaler input and output
++ pads are undefined.</listitem>
++ <listitem>The application configures the frontend input pad resolution to
++ 2048x1536. The driver propagates the format to the frontend output pad.
++ Note that the propagated output format can be different, as in this case,
++ than the input format, as the hardware might need to crop pixels (for
++ instance when converting a Bayer filter pattern to RGB or YUV).</listitem>
++ <listitem>The application configures the scaler input pad resolution to
++ 2046x1534 to match the frontend output resolution. The driver propagates
++ the format to the scaler output pad.</listitem>
++ <listitem>The application configures the scaler output pad resolution to
++ 1280x960.</listitem>
++ </orderedlist>
++ </para>
++
++ <para>When satisfied with the try results, applications can set the active
++ formats by setting the <structfield>which</structfield> argument to
++ <constant>V4L2_SUBDEV_FORMAT_TRY</constant>. Active formats are changed
++ exactly as try formats by drivers. To avoid modifying the hardware state
++ during format negotiation, applications should negotiate try formats first
++ and then modify the active settings using the try formats returned during
++ the last negotiation iteration. This guarantees that the active format
++ will be applied as-is by the driver without being modified.
++ </para>
++ </section>
++
++ </section>
++
++ &sub-subdev-formats;
+diff --git a/Documentation/DocBook/v4l/subdev-formats.xml b/Documentation/DocBook/v4l/subdev-formats.xml
+new file mode 100644
+index 0000000..0cae572
+--- /dev/null
++++ b/Documentation/DocBook/v4l/subdev-formats.xml
+@@ -0,0 +1,2416 @@
++<section id="v4l2-mbus-format">
++ <title>Media Bus Formats</title>
++
++ <table pgwide="1" frame="none" id="v4l2-mbus-framefmt">
++ <title>struct <structname>v4l2_mbus_framefmt</structname></title>
++ <tgroup cols="3">
++ &cs-str;
++ <tbody valign="top">
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>width</structfield></entry>
++ <entry>Image width, in pixels.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>height</structfield></entry>
++ <entry>Image height, in pixels.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>code</structfield></entry>
++ <entry>Format code, from &v4l2-mbus-pixelcode;.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>field</structfield></entry>
++ <entry>Field order, from &v4l2-field;. See
++ <xref linkend="field-order" /> for details.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>colorspace</structfield></entry>
++ <entry>Image colorspace, from &v4l2-colorspace;. See
++ <xref linkend="colorspaces" /> for details.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>reserved</structfield>[7]</entry>
++ <entry>Reserved for future extensions. Applications and drivers must
++ set the array to zero.</entry>
++ </row>
++ </tbody>
++ </tgroup>
++ </table>
++
++ <section id="v4l2-mbus-pixelcode">
++ <title>Media Bus Pixel Codes</title>
++
++ <para>The media bus pixel codes describe image formats as flowing over
++ physical busses (both between separate physical components and inside SoC
++ devices). This should not be confused with the V4L2 pixel formats that
++ describe, using four character codes, image formats as stored in memory.
++ </para>
++
++ <para>While there is a relationship between image formats on busses and
++ image formats in memory (a raw Bayer image won't be magically converted to
++ JPEG just by storing it to memory), there is no one-to-one correspondance
++ between them.</para>
++
++ <section>
++ <title>Packed RGB Formats</title>
++
++ <para>Those formats transfer pixel data as red, green and blue components.
++ The format code is made of the following information.
++ <itemizedlist>
++ <listitem>The red, green and blue components order code, as encoded in a
++ pixel sample. Possible values are RGB and BGR.</listitem>
++ <listitem>The number of bits per component, for each component. The values
++ can be different for all components. Common values are 555 and 565.
++ </listitem>
++ <listitem>The number of bus samples per pixel. Pixels that are wider than
++ the bus width must be transferred in multiple samples. Common values are
++ 1 and 2.</listitem>
++ <listitem>The bus width.</listitem>
++ <listitem>For formats where the total number of bits per pixel is smaller
++ than the number of bus samples per pixel times the bus width, a padding
++ value stating if the bytes are padded in their most high order bits
++ (PADHI) or low order bits (PADLO).</listitem>
++ <listitem>For formats where the number of bus samples per pixel is larger
++ than 1, an endianness value stating if the pixel is transferred MSB first
++ (BE) or LSB first (LE).</listitem>
++ </itemizedlist>
++ </para>
++
++ <para>For instance, a format where pixels are encoded as 5-bits red, 5-bits
++ green and 5-bit blue values padded on the high bit, transferred as 2 8-bit
++ samples per pixel with the most significant bits (padding, red and half of
++ the green value) transferred first will be named
++ <constant>V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE</constant>.
++ </para>
++
++ <para>The following tables list existing packet RGB formats.</para>
++
++ <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-rgb">
++ <title>RGB formats</title>
++ <tgroup cols="11">
++ <colspec colname="id" align="left" />
++ <colspec colname="code" align="center"/>
++ <colspec colname="bit" />
++ <colspec colnum="4" colname="b07" align="center" />
++ <colspec colnum="5" colname="b06" align="center" />
++ <colspec colnum="6" colname="b05" align="center" />
++ <colspec colnum="7" colname="b04" align="center" />
++ <colspec colnum="8" colname="b03" align="center" />
++ <colspec colnum="9" colname="b02" align="center" />
++ <colspec colnum="10" colname="b01" align="center" />
++ <colspec colnum="11" colname="b00" align="center" />
++ <spanspec namest="b07" nameend="b00" spanname="b0" />
++ <thead>
++ <row>
++ <entry>Identifier</entry>
++ <entry>Code</entry>
++ <entry></entry>
++ <entry spanname="b0">Data organization</entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry>Bit</entry>
++ <entry>7</entry>
++ <entry>6</entry>
++ <entry>5</entry>
++ <entry>4</entry>
++ <entry>3</entry>
++ <entry>2</entry>
++ <entry>1</entry>
++ <entry>0</entry>
++ </row>
++ </thead>
++ <tbody valign="top">
++ <row id="V4L2-MBUS-FMT-RGB444-2X8-PADHI-BE">
++ <entry>V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE</entry>
++ <entry>0x1001</entry>
++ <entry></entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>r<subscript>3</subscript></entry>
++ <entry>r<subscript>2</subscript></entry>
++ <entry>r<subscript>1</subscript></entry>
++ <entry>r<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>g<subscript>3</subscript></entry>
++ <entry>g<subscript>2</subscript></entry>
++ <entry>g<subscript>1</subscript></entry>
++ <entry>g<subscript>0</subscript></entry>
++ <entry>b<subscript>3</subscript></entry>
++ <entry>b<subscript>2</subscript></entry>
++ <entry>b<subscript>1</subscript></entry>
++ <entry>b<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-RGB444-2X8-PADHI-LE">
++ <entry>V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE</entry>
++ <entry>0x1002</entry>
++ <entry></entry>
++ <entry>g<subscript>3</subscript></entry>
++ <entry>g<subscript>2</subscript></entry>
++ <entry>g<subscript>1</subscript></entry>
++ <entry>g<subscript>0</subscript></entry>
++ <entry>b<subscript>3</subscript></entry>
++ <entry>b<subscript>2</subscript></entry>
++ <entry>b<subscript>1</subscript></entry>
++ <entry>b<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>r<subscript>3</subscript></entry>
++ <entry>r<subscript>2</subscript></entry>
++ <entry>r<subscript>1</subscript></entry>
++ <entry>r<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-RGB555-2X8-PADHI-BE">
++ <entry>V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE</entry>
++ <entry>0x1003</entry>
++ <entry></entry>
++ <entry>0</entry>
++ <entry>r<subscript>4</subscript></entry>
++ <entry>r<subscript>3</subscript></entry>
++ <entry>r<subscript>2</subscript></entry>
++ <entry>r<subscript>1</subscript></entry>
++ <entry>r<subscript>0</subscript></entry>
++ <entry>g<subscript>4</subscript></entry>
++ <entry>g<subscript>3</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>g<subscript>2</subscript></entry>
++ <entry>g<subscript>1</subscript></entry>
++ <entry>g<subscript>0</subscript></entry>
++ <entry>b<subscript>4</subscript></entry>
++ <entry>b<subscript>3</subscript></entry>
++ <entry>b<subscript>2</subscript></entry>
++ <entry>b<subscript>1</subscript></entry>
++ <entry>b<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-RGB555-2X8-PADHI-LE">
++ <entry>V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE</entry>
++ <entry>0x1004</entry>
++ <entry></entry>
++ <entry>g<subscript>2</subscript></entry>
++ <entry>g<subscript>1</subscript></entry>
++ <entry>g<subscript>0</subscript></entry>
++ <entry>b<subscript>4</subscript></entry>
++ <entry>b<subscript>3</subscript></entry>
++ <entry>b<subscript>2</subscript></entry>
++ <entry>b<subscript>1</subscript></entry>
++ <entry>b<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>0</entry>
++ <entry>r<subscript>4</subscript></entry>
++ <entry>r<subscript>3</subscript></entry>
++ <entry>r<subscript>2</subscript></entry>
++ <entry>r<subscript>1</subscript></entry>
++ <entry>r<subscript>0</subscript></entry>
++ <entry>g<subscript>4</subscript></entry>
++ <entry>g<subscript>3</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-BGR565-2X8-BE">
++ <entry>V4L2_MBUS_FMT_BGR565_2X8_BE</entry>
++ <entry>0x1005</entry>
++ <entry></entry>
++ <entry>b<subscript>4</subscript></entry>
++ <entry>b<subscript>3</subscript></entry>
++ <entry>b<subscript>2</subscript></entry>
++ <entry>b<subscript>1</subscript></entry>
++ <entry>b<subscript>0</subscript></entry>
++ <entry>g<subscript>5</subscript></entry>
++ <entry>g<subscript>4</subscript></entry>
++ <entry>g<subscript>3</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>g<subscript>2</subscript></entry>
++ <entry>g<subscript>1</subscript></entry>
++ <entry>g<subscript>0</subscript></entry>
++ <entry>r<subscript>4</subscript></entry>
++ <entry>r<subscript>3</subscript></entry>
++ <entry>r<subscript>2</subscript></entry>
++ <entry>r<subscript>1</subscript></entry>
++ <entry>r<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-BGR565-2X8-LE">
++ <entry>V4L2_MBUS_FMT_BGR565_2X8_LE</entry>
++ <entry>0x1006</entry>
++ <entry></entry>
++ <entry>g<subscript>2</subscript></entry>
++ <entry>g<subscript>1</subscript></entry>
++ <entry>g<subscript>0</subscript></entry>
++ <entry>r<subscript>4</subscript></entry>
++ <entry>r<subscript>3</subscript></entry>
++ <entry>r<subscript>2</subscript></entry>
++ <entry>r<subscript>1</subscript></entry>
++ <entry>r<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>b<subscript>4</subscript></entry>
++ <entry>b<subscript>3</subscript></entry>
++ <entry>b<subscript>2</subscript></entry>
++ <entry>b<subscript>1</subscript></entry>
++ <entry>b<subscript>0</subscript></entry>
++ <entry>g<subscript>5</subscript></entry>
++ <entry>g<subscript>4</subscript></entry>
++ <entry>g<subscript>3</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-RGB565-2X8-BE">
++ <entry>V4L2_MBUS_FMT_RGB565_2X8_BE</entry>
++ <entry>0x1007</entry>
++ <entry></entry>
++ <entry>r<subscript>4</subscript></entry>
++ <entry>r<subscript>3</subscript></entry>
++ <entry>r<subscript>2</subscript></entry>
++ <entry>r<subscript>1</subscript></entry>
++ <entry>r<subscript>0</subscript></entry>
++ <entry>g<subscript>5</subscript></entry>
++ <entry>g<subscript>4</subscript></entry>
++ <entry>g<subscript>3</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>g<subscript>2</subscript></entry>
++ <entry>g<subscript>1</subscript></entry>
++ <entry>g<subscript>0</subscript></entry>
++ <entry>b<subscript>4</subscript></entry>
++ <entry>b<subscript>3</subscript></entry>
++ <entry>b<subscript>2</subscript></entry>
++ <entry>b<subscript>1</subscript></entry>
++ <entry>b<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-RGB565-2X8-LE">
++ <entry>V4L2_MBUS_FMT_RGB565_2X8_LE</entry>
++ <entry>0x1008</entry>
++ <entry></entry>
++ <entry>g<subscript>2</subscript></entry>
++ <entry>g<subscript>1</subscript></entry>
++ <entry>g<subscript>0</subscript></entry>
++ <entry>b<subscript>4</subscript></entry>
++ <entry>b<subscript>3</subscript></entry>
++ <entry>b<subscript>2</subscript></entry>
++ <entry>b<subscript>1</subscript></entry>
++ <entry>b<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>r<subscript>4</subscript></entry>
++ <entry>r<subscript>3</subscript></entry>
++ <entry>r<subscript>2</subscript></entry>
++ <entry>r<subscript>1</subscript></entry>
++ <entry>r<subscript>0</subscript></entry>
++ <entry>g<subscript>5</subscript></entry>
++ <entry>g<subscript>4</subscript></entry>
++ <entry>g<subscript>3</subscript></entry>
++ </row>
++ </tbody>
++ </tgroup>
++ </table>
++ </section>
++
++ <section>
++ <title>Bayer Formats</title>
++
++ <para>Those formats transfer pixel data as red, green and blue components.
++ The format code is made of the following information.
++ <itemizedlist>
++ <listitem>The red, green and blue components order code, as encoded in a
++ pixel sample. The possible values are shown in <xref
++ linkend="bayer-patterns" />.</listitem>
++ <listitem>The number of bits per pixel component. All components are
++ transferred on the same number of bits. Common values are 8, 10 and 12.
++ </listitem>
++ <listitem>If the pixel components are DPCM-compressed, a mention of the
++ DPCM compression and the number of bits per compressed pixel component.
++ </listitem>
++ <listitem>The number of bus samples per pixel. Pixels that are wider than
++ the bus width must be transferred in multiple samples. Common values are
++ 1 and 2.</listitem>
++ <listitem>The bus width.</listitem>
++ <listitem>For formats where the total number of bits per pixel is smaller
++ than the number of bus samples per pixel times the bus width, a padding
++ value stating if the bytes are padded in their most high order bits
++ (PADHI) or low order bits (PADLO).</listitem>
++ <listitem>For formats where the number of bus samples per pixel is larger
++ than 1, an endianness value stating if the pixel is transferred MSB first
++ (BE) or LSB first (LE).</listitem>
++ </itemizedlist>
++ </para>
++
++ <para>For instance, a format with uncompressed 10-bit Bayer components
++ arranged in a red, green, green, blue pattern transferred as 2 8-bit
++ samples per pixel with the least significant bits transferred first will
++ be named <constant>V4L2_MBUS_FMT_SRGGB10_2X8_PADHI_LE</constant>.
++ </para>
++
++ <figure id="bayer-patterns">
++ <title>Bayer Patterns</title>
++ <mediaobject>
++ <imageobject>
++ <imagedata fileref="bayer.pdf" format="PS" />
++ </imageobject>
++ <imageobject>
++ <imagedata fileref="bayer.png" format="PNG" />
++ </imageobject>
++ <textobject>
++ <phrase>Bayer filter color patterns</phrase>
++ </textobject>
++ </mediaobject>
++ </figure>
++
++ <para>The following table lists existing packet Bayer formats. The data
++ organization is given as an example for the first pixel only.</para>
++
++ <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-bayer">
++ <title>Bayer Formats</title>
++ <tgroup cols="15">
++ <colspec colname="id" align="left" />
++ <colspec colname="code" align="center"/>
++ <colspec colname="bit" />
++ <colspec colnum="4" colname="b11" align="center" />
++ <colspec colnum="5" colname="b10" align="center" />
++ <colspec colnum="6" colname="b09" align="center" />
++ <colspec colnum="7" colname="b08" align="center" />
++ <colspec colnum="8" colname="b07" align="center" />
++ <colspec colnum="9" colname="b06" align="center" />
++ <colspec colnum="10" colname="b05" align="center" />
++ <colspec colnum="11" colname="b04" align="center" />
++ <colspec colnum="12" colname="b03" align="center" />
++ <colspec colnum="13" colname="b02" align="center" />
++ <colspec colnum="14" colname="b01" align="center" />
++ <colspec colnum="15" colname="b00" align="center" />
++ <spanspec namest="b11" nameend="b00" spanname="b0" />
++ <thead>
++ <row>
++ <entry>Identifier</entry>
++ <entry>Code</entry>
++ <entry></entry>
++ <entry spanname="b0">Data organization</entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry>Bit</entry>
++ <entry>11</entry>
++ <entry>10</entry>
++ <entry>9</entry>
++ <entry>8</entry>
++ <entry>7</entry>
++ <entry>6</entry>
++ <entry>5</entry>
++ <entry>4</entry>
++ <entry>3</entry>
++ <entry>2</entry>
++ <entry>1</entry>
++ <entry>0</entry>
++ </row>
++ </thead>
++ <tbody valign="top">
++ <row id="V4L2-MBUS-FMT-SBGGR8-1X8">
++ <entry>V4L2_MBUS_FMT_SBGGR8_1X8</entry>
++ <entry>0x3001</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>b<subscript>7</subscript></entry>
++ <entry>b<subscript>6</subscript></entry>
++ <entry>b<subscript>5</subscript></entry>
++ <entry>b<subscript>4</subscript></entry>
++ <entry>b<subscript>3</subscript></entry>
++ <entry>b<subscript>2</subscript></entry>
++ <entry>b<subscript>1</subscript></entry>
++ <entry>b<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-SGRBG8-1X8">
++ <entry>V4L2_MBUS_FMT_SGRBG8_1X8</entry>
++ <entry>0x3002</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>g<subscript>7</subscript></entry>
++ <entry>g<subscript>6</subscript></entry>
++ <entry>g<subscript>5</subscript></entry>
++ <entry>g<subscript>4</subscript></entry>
++ <entry>g<subscript>3</subscript></entry>
++ <entry>g<subscript>2</subscript></entry>
++ <entry>g<subscript>1</subscript></entry>
++ <entry>g<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-SBGGR10-DPCM8-1X8">
++ <entry>V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8</entry>
++ <entry>0x300b</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>b<subscript>7</subscript></entry>
++ <entry>b<subscript>6</subscript></entry>
++ <entry>b<subscript>5</subscript></entry>
++ <entry>b<subscript>4</subscript></entry>
++ <entry>b<subscript>3</subscript></entry>
++ <entry>b<subscript>2</subscript></entry>
++ <entry>b<subscript>1</subscript></entry>
++ <entry>b<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-SGBRG10-DPCM8-1X8">
++ <entry>V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8</entry>
++ <entry>0x300c</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>g<subscript>7</subscript></entry>
++ <entry>g<subscript>6</subscript></entry>
++ <entry>g<subscript>5</subscript></entry>
++ <entry>g<subscript>4</subscript></entry>
++ <entry>g<subscript>3</subscript></entry>
++ <entry>g<subscript>2</subscript></entry>
++ <entry>g<subscript>1</subscript></entry>
++ <entry>g<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-SGRBG10-DPCM8-1X8">
++ <entry>V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8</entry>
++ <entry>0x3009</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>g<subscript>7</subscript></entry>
++ <entry>g<subscript>6</subscript></entry>
++ <entry>g<subscript>5</subscript></entry>
++ <entry>g<subscript>4</subscript></entry>
++ <entry>g<subscript>3</subscript></entry>
++ <entry>g<subscript>2</subscript></entry>
++ <entry>g<subscript>1</subscript></entry>
++ <entry>g<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-SRGGB10-DPCM8-1X8">
++ <entry>V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8</entry>
++ <entry>0x300d</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>r<subscript>7</subscript></entry>
++ <entry>r<subscript>6</subscript></entry>
++ <entry>r<subscript>5</subscript></entry>
++ <entry>r<subscript>4</subscript></entry>
++ <entry>r<subscript>3</subscript></entry>
++ <entry>r<subscript>2</subscript></entry>
++ <entry>r<subscript>1</subscript></entry>
++ <entry>r<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADHI-BE">
++ <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE</entry>
++ <entry>0x3003</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>b<subscript>9</subscript></entry>
++ <entry>b<subscript>8</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>b<subscript>7</subscript></entry>
++ <entry>b<subscript>6</subscript></entry>
++ <entry>b<subscript>5</subscript></entry>
++ <entry>b<subscript>4</subscript></entry>
++ <entry>b<subscript>3</subscript></entry>
++ <entry>b<subscript>2</subscript></entry>
++ <entry>b<subscript>1</subscript></entry>
++ <entry>b<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADHI-LE">
++ <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE</entry>
++ <entry>0x3004</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>b<subscript>7</subscript></entry>
++ <entry>b<subscript>6</subscript></entry>
++ <entry>b<subscript>5</subscript></entry>
++ <entry>b<subscript>4</subscript></entry>
++ <entry>b<subscript>3</subscript></entry>
++ <entry>b<subscript>2</subscript></entry>
++ <entry>b<subscript>1</subscript></entry>
++ <entry>b<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>b<subscript>9</subscript></entry>
++ <entry>b<subscript>8</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADLO-BE">
++ <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE</entry>
++ <entry>0x3005</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>b<subscript>9</subscript></entry>
++ <entry>b<subscript>8</subscript></entry>
++ <entry>b<subscript>7</subscript></entry>
++ <entry>b<subscript>6</subscript></entry>
++ <entry>b<subscript>5</subscript></entry>
++ <entry>b<subscript>4</subscript></entry>
++ <entry>b<subscript>3</subscript></entry>
++ <entry>b<subscript>2</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>b<subscript>1</subscript></entry>
++ <entry>b<subscript>0</subscript></entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADLO-LE">
++ <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE</entry>
++ <entry>0x3006</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>b<subscript>1</subscript></entry>
++ <entry>b<subscript>0</subscript></entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ <entry>0</entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>b<subscript>9</subscript></entry>
++ <entry>b<subscript>8</subscript></entry>
++ <entry>b<subscript>7</subscript></entry>
++ <entry>b<subscript>6</subscript></entry>
++ <entry>b<subscript>5</subscript></entry>
++ <entry>b<subscript>4</subscript></entry>
++ <entry>b<subscript>3</subscript></entry>
++ <entry>b<subscript>2</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-SBGGR10-1X10">
++ <entry>V4L2_MBUS_FMT_SBGGR10_1X10</entry>
++ <entry>0x3007</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>b<subscript>9</subscript></entry>
++ <entry>b<subscript>8</subscript></entry>
++ <entry>b<subscript>7</subscript></entry>
++ <entry>b<subscript>6</subscript></entry>
++ <entry>b<subscript>5</subscript></entry>
++ <entry>b<subscript>4</subscript></entry>
++ <entry>b<subscript>3</subscript></entry>
++ <entry>b<subscript>2</subscript></entry>
++ <entry>b<subscript>1</subscript></entry>
++ <entry>b<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-SGBRG10-1X10">
++ <entry>V4L2_MBUS_FMT_SGBRG10_1X10</entry>
++ <entry>0x300e</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>g<subscript>9</subscript></entry>
++ <entry>g<subscript>8</subscript></entry>
++ <entry>g<subscript>7</subscript></entry>
++ <entry>g<subscript>6</subscript></entry>
++ <entry>g<subscript>5</subscript></entry>
++ <entry>g<subscript>4</subscript></entry>
++ <entry>g<subscript>3</subscript></entry>
++ <entry>g<subscript>2</subscript></entry>
++ <entry>g<subscript>1</subscript></entry>
++ <entry>g<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-SGRBG10-1X10">
++ <entry>V4L2_MBUS_FMT_SGRBG10_1X10</entry>
++ <entry>0x300a</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>g<subscript>9</subscript></entry>
++ <entry>g<subscript>8</subscript></entry>
++ <entry>g<subscript>7</subscript></entry>
++ <entry>g<subscript>6</subscript></entry>
++ <entry>g<subscript>5</subscript></entry>
++ <entry>g<subscript>4</subscript></entry>
++ <entry>g<subscript>3</subscript></entry>
++ <entry>g<subscript>2</subscript></entry>
++ <entry>g<subscript>1</subscript></entry>
++ <entry>g<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-SRGGB10-1X10">
++ <entry>V4L2_MBUS_FMT_SRGGB10_1X10</entry>
++ <entry>0x300f</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>r<subscript>9</subscript></entry>
++ <entry>r<subscript>8</subscript></entry>
++ <entry>r<subscript>7</subscript></entry>
++ <entry>r<subscript>6</subscript></entry>
++ <entry>r<subscript>5</subscript></entry>
++ <entry>r<subscript>4</subscript></entry>
++ <entry>r<subscript>3</subscript></entry>
++ <entry>r<subscript>2</subscript></entry>
++ <entry>r<subscript>1</subscript></entry>
++ <entry>r<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-SBGGR12-1X12">
++ <entry>V4L2_MBUS_FMT_SBGGR12_1X12</entry>
++ <entry>0x3008</entry>
++ <entry></entry>
++ <entry>b<subscript>11</subscript></entry>
++ <entry>b<subscript>10</subscript></entry>
++ <entry>b<subscript>9</subscript></entry>
++ <entry>b<subscript>8</subscript></entry>
++ <entry>b<subscript>7</subscript></entry>
++ <entry>b<subscript>6</subscript></entry>
++ <entry>b<subscript>5</subscript></entry>
++ <entry>b<subscript>4</subscript></entry>
++ <entry>b<subscript>3</subscript></entry>
++ <entry>b<subscript>2</subscript></entry>
++ <entry>b<subscript>1</subscript></entry>
++ <entry>b<subscript>0</subscript></entry>
++ </row>
++ </tbody>
++ </tgroup>
++ </table>
++ </section>
++
++ <section>
++ <title>Packed YUV Formats</title>
++
++ <para>Those data formats transfer pixel data as (possibly downsampled) Y, U
++ and V components. The format code is made of the following information.
++ <itemizedlist>
++ <listitem>The Y, U and V components order code, as transferred on the
++ bus. Possible values are YUYV, UYVY, YVYU and VYUY.</listitem>
++ <listitem>The number of bits per pixel component. All components are
++ transferred on the same number of bits. Common values are 8, 10 and 12.
++ </listitem>
++ <listitem>The number of bus samples per pixel. Pixels that are wider than
++ the bus width must be transferred in multiple samples. Common values are
++ 1, 1.5 (encoded as 1_5) and 2.</listitem>
++ <listitem>The bus width. When the bus width is larger than the number of
++ bits per pixel component, several components are packed in a single bus
++ sample. The components are ordered as specified by the order code, with
++ components on the left of the code transferred in the high order bits.
++ Common values are 8 and 16.
++ </listitem>
++ </itemizedlist>
++ </para>
++
++ <para>For instance, a format where pixels are encoded as 8-bit YUV values
++ downsampled to 4:2:2 and transferred as 2 8-bit bus samples per pixel in the
++ U, Y, V, Y order will be named <constant>V4L2_MBUS_FMT_UYVY8_2X8</constant>.
++ </para>
++
++ <para>The following table lisst existing packet YUV formats.</para>
++
++ <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-yuv8">
++ <title>YUV Formats</title>
++ <tgroup cols="23">
++ <colspec colname="id" align="left" />
++ <colspec colname="code" align="center"/>
++ <colspec colname="bit" />
++ <colspec colnum="4" colname="b19" align="center" />
++ <colspec colnum="5" colname="b18" align="center" />
++ <colspec colnum="6" colname="b17" align="center" />
++ <colspec colnum="7" colname="b16" align="center" />
++ <colspec colnum="8" colname="b15" align="center" />
++ <colspec colnum="9" colname="b14" align="center" />
++ <colspec colnum="10" colname="b13" align="center" />
++ <colspec colnum="11" colname="b12" align="center" />
++ <colspec colnum="12" colname="b11" align="center" />
++ <colspec colnum="13" colname="b10" align="center" />
++ <colspec colnum="14" colname="b09" align="center" />
++ <colspec colnum="15" colname="b08" align="center" />
++ <colspec colnum="16" colname="b07" align="center" />
++ <colspec colnum="17" colname="b06" align="center" />
++ <colspec colnum="18" colname="b05" align="center" />
++ <colspec colnum="19" colname="b04" align="center" />
++ <colspec colnum="20" colname="b03" align="center" />
++ <colspec colnum="21" colname="b02" align="center" />
++ <colspec colnum="22" colname="b01" align="center" />
++ <colspec colnum="23" colname="b00" align="center" />
++ <spanspec namest="b19" nameend="b00" spanname="b0" />
++ <thead>
++ <row>
++ <entry>Identifier</entry>
++ <entry>Code</entry>
++ <entry></entry>
++ <entry spanname="b0">Data organization</entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry>Bit</entry>
++ <entry>19</entry>
++ <entry>18</entry>
++ <entry>17</entry>
++ <entry>16</entry>
++ <entry>15</entry>
++ <entry>14</entry>
++ <entry>13</entry>
++ <entry>12</entry>
++ <entry>11</entry>
++ <entry>10</entry>
++ <entry>9</entry>
++ <entry>8</entry>
++ <entry>7</entry>
++ <entry>6</entry>
++ <entry>5</entry>
++ <entry>4</entry>
++ <entry>3</entry>
++ <entry>2</entry>
++ <entry>1</entry>
++ <entry>0</entry>
++ </row>
++ </thead>
++ <tbody valign="top">
++ <row id="V4L2-MBUS-FMT-Y8-1X8">
++ <entry>V4L2_MBUS_FMT_Y8_1X8</entry>
++ <entry>0x2001</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-UYVY8-1_5X8">
++ <entry>V4L2_MBUS_FMT_UYVY8_1_5X8</entry>
++ <entry>0x2002</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>u<subscript>7</subscript></entry>
++ <entry>u<subscript>6</subscript></entry>
++ <entry>u<subscript>5</subscript></entry>
++ <entry>u<subscript>4</subscript></entry>
++ <entry>u<subscript>3</subscript></entry>
++ <entry>u<subscript>2</subscript></entry>
++ <entry>u<subscript>1</subscript></entry>
++ <entry>u<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>v<subscript>7</subscript></entry>
++ <entry>v<subscript>6</subscript></entry>
++ <entry>v<subscript>5</subscript></entry>
++ <entry>v<subscript>4</subscript></entry>
++ <entry>v<subscript>3</subscript></entry>
++ <entry>v<subscript>2</subscript></entry>
++ <entry>v<subscript>1</subscript></entry>
++ <entry>v<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-VYUY8-1_5X8">
++ <entry>V4L2_MBUS_FMT_VYUY8_1_5X8</entry>
++ <entry>0x2003</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>v<subscript>7</subscript></entry>
++ <entry>v<subscript>6</subscript></entry>
++ <entry>v<subscript>5</subscript></entry>
++ <entry>v<subscript>4</subscript></entry>
++ <entry>v<subscript>3</subscript></entry>
++ <entry>v<subscript>2</subscript></entry>
++ <entry>v<subscript>1</subscript></entry>
++ <entry>v<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>u<subscript>7</subscript></entry>
++ <entry>u<subscript>6</subscript></entry>
++ <entry>u<subscript>5</subscript></entry>
++ <entry>u<subscript>4</subscript></entry>
++ <entry>u<subscript>3</subscript></entry>
++ <entry>u<subscript>2</subscript></entry>
++ <entry>u<subscript>1</subscript></entry>
++ <entry>u<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-YUYV8-1_5X8">
++ <entry>V4L2_MBUS_FMT_YUYV8_1_5X8</entry>
++ <entry>0x2004</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>u<subscript>7</subscript></entry>
++ <entry>u<subscript>6</subscript></entry>
++ <entry>u<subscript>5</subscript></entry>
++ <entry>u<subscript>4</subscript></entry>
++ <entry>u<subscript>3</subscript></entry>
++ <entry>u<subscript>2</subscript></entry>
++ <entry>u<subscript>1</subscript></entry>
++ <entry>u<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>v<subscript>7</subscript></entry>
++ <entry>v<subscript>6</subscript></entry>
++ <entry>v<subscript>5</subscript></entry>
++ <entry>v<subscript>4</subscript></entry>
++ <entry>v<subscript>3</subscript></entry>
++ <entry>v<subscript>2</subscript></entry>
++ <entry>v<subscript>1</subscript></entry>
++ <entry>v<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-YVYU8-1_5X8">
++ <entry>V4L2_MBUS_FMT_YVYU8_1_5X8</entry>
++ <entry>0x2005</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>v<subscript>7</subscript></entry>
++ <entry>v<subscript>6</subscript></entry>
++ <entry>v<subscript>5</subscript></entry>
++ <entry>v<subscript>4</subscript></entry>
++ <entry>v<subscript>3</subscript></entry>
++ <entry>v<subscript>2</subscript></entry>
++ <entry>v<subscript>1</subscript></entry>
++ <entry>v<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>u<subscript>7</subscript></entry>
++ <entry>u<subscript>6</subscript></entry>
++ <entry>u<subscript>5</subscript></entry>
++ <entry>u<subscript>4</subscript></entry>
++ <entry>u<subscript>3</subscript></entry>
++ <entry>u<subscript>2</subscript></entry>
++ <entry>u<subscript>1</subscript></entry>
++ <entry>u<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-UYVY8-2X8">
++ <entry>V4L2_MBUS_FMT_UYVY8_2X8</entry>
++ <entry>0x2006</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>u<subscript>7</subscript></entry>
++ <entry>u<subscript>6</subscript></entry>
++ <entry>u<subscript>5</subscript></entry>
++ <entry>u<subscript>4</subscript></entry>
++ <entry>u<subscript>3</subscript></entry>
++ <entry>u<subscript>2</subscript></entry>
++ <entry>u<subscript>1</subscript></entry>
++ <entry>u<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>v<subscript>7</subscript></entry>
++ <entry>v<subscript>6</subscript></entry>
++ <entry>v<subscript>5</subscript></entry>
++ <entry>v<subscript>4</subscript></entry>
++ <entry>v<subscript>3</subscript></entry>
++ <entry>v<subscript>2</subscript></entry>
++ <entry>v<subscript>1</subscript></entry>
++ <entry>v<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-VYUY8-2X8">
++ <entry>V4L2_MBUS_FMT_VYUY8_2X8</entry>
++ <entry>0x2007</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>v<subscript>7</subscript></entry>
++ <entry>v<subscript>6</subscript></entry>
++ <entry>v<subscript>5</subscript></entry>
++ <entry>v<subscript>4</subscript></entry>
++ <entry>v<subscript>3</subscript></entry>
++ <entry>v<subscript>2</subscript></entry>
++ <entry>v<subscript>1</subscript></entry>
++ <entry>v<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>u<subscript>7</subscript></entry>
++ <entry>u<subscript>6</subscript></entry>
++ <entry>u<subscript>5</subscript></entry>
++ <entry>u<subscript>4</subscript></entry>
++ <entry>u<subscript>3</subscript></entry>
++ <entry>u<subscript>2</subscript></entry>
++ <entry>u<subscript>1</subscript></entry>
++ <entry>u<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-YUYV8-2X8">
++ <entry>V4L2_MBUS_FMT_YUYV8_2X8</entry>
++ <entry>0x2008</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>u<subscript>7</subscript></entry>
++ <entry>u<subscript>6</subscript></entry>
++ <entry>u<subscript>5</subscript></entry>
++ <entry>u<subscript>4</subscript></entry>
++ <entry>u<subscript>3</subscript></entry>
++ <entry>u<subscript>2</subscript></entry>
++ <entry>u<subscript>1</subscript></entry>
++ <entry>u<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>v<subscript>7</subscript></entry>
++ <entry>v<subscript>6</subscript></entry>
++ <entry>v<subscript>5</subscript></entry>
++ <entry>v<subscript>4</subscript></entry>
++ <entry>v<subscript>3</subscript></entry>
++ <entry>v<subscript>2</subscript></entry>
++ <entry>v<subscript>1</subscript></entry>
++ <entry>v<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-YVYU8-2X8">
++ <entry>V4L2_MBUS_FMT_YVYU8_2X8</entry>
++ <entry>0x2009</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>v<subscript>7</subscript></entry>
++ <entry>v<subscript>6</subscript></entry>
++ <entry>v<subscript>5</subscript></entry>
++ <entry>v<subscript>4</subscript></entry>
++ <entry>v<subscript>3</subscript></entry>
++ <entry>v<subscript>2</subscript></entry>
++ <entry>v<subscript>1</subscript></entry>
++ <entry>v<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>u<subscript>7</subscript></entry>
++ <entry>u<subscript>6</subscript></entry>
++ <entry>u<subscript>5</subscript></entry>
++ <entry>u<subscript>4</subscript></entry>
++ <entry>u<subscript>3</subscript></entry>
++ <entry>u<subscript>2</subscript></entry>
++ <entry>u<subscript>1</subscript></entry>
++ <entry>u<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-Y10-1X10">
++ <entry>V4L2_MBUS_FMT_Y10_1X10</entry>
++ <entry>0x200a</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>9</subscript></entry>
++ <entry>y<subscript>8</subscript></entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-YUYV10-2X10">
++ <entry>V4L2_MBUS_FMT_YUYV10_2X10</entry>
++ <entry>0x200b</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>9</subscript></entry>
++ <entry>y<subscript>8</subscript></entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>u<subscript>9</subscript></entry>
++ <entry>u<subscript>8</subscript></entry>
++ <entry>u<subscript>7</subscript></entry>
++ <entry>u<subscript>6</subscript></entry>
++ <entry>u<subscript>5</subscript></entry>
++ <entry>u<subscript>4</subscript></entry>
++ <entry>u<subscript>3</subscript></entry>
++ <entry>u<subscript>2</subscript></entry>
++ <entry>u<subscript>1</subscript></entry>
++ <entry>u<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>9</subscript></entry>
++ <entry>y<subscript>8</subscript></entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>v<subscript>9</subscript></entry>
++ <entry>v<subscript>8</subscript></entry>
++ <entry>v<subscript>7</subscript></entry>
++ <entry>v<subscript>6</subscript></entry>
++ <entry>v<subscript>5</subscript></entry>
++ <entry>v<subscript>4</subscript></entry>
++ <entry>v<subscript>3</subscript></entry>
++ <entry>v<subscript>2</subscript></entry>
++ <entry>v<subscript>1</subscript></entry>
++ <entry>v<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-YVYU10-2X10">
++ <entry>V4L2_MBUS_FMT_YVYU10_2X10</entry>
++ <entry>0x200c</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>9</subscript></entry>
++ <entry>y<subscript>8</subscript></entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>v<subscript>9</subscript></entry>
++ <entry>v<subscript>8</subscript></entry>
++ <entry>v<subscript>7</subscript></entry>
++ <entry>v<subscript>6</subscript></entry>
++ <entry>v<subscript>5</subscript></entry>
++ <entry>v<subscript>4</subscript></entry>
++ <entry>v<subscript>3</subscript></entry>
++ <entry>v<subscript>2</subscript></entry>
++ <entry>v<subscript>1</subscript></entry>
++ <entry>v<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>9</subscript></entry>
++ <entry>y<subscript>8</subscript></entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>u<subscript>9</subscript></entry>
++ <entry>u<subscript>8</subscript></entry>
++ <entry>u<subscript>7</subscript></entry>
++ <entry>u<subscript>6</subscript></entry>
++ <entry>u<subscript>5</subscript></entry>
++ <entry>u<subscript>4</subscript></entry>
++ <entry>u<subscript>3</subscript></entry>
++ <entry>u<subscript>2</subscript></entry>
++ <entry>u<subscript>1</subscript></entry>
++ <entry>u<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-UYVY8-1X16">
++ <entry>V4L2_MBUS_FMT_UYVY8_1X16</entry>
++ <entry>0x200f</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>u<subscript>7</subscript></entry>
++ <entry>u<subscript>6</subscript></entry>
++ <entry>u<subscript>5</subscript></entry>
++ <entry>u<subscript>4</subscript></entry>
++ <entry>u<subscript>3</subscript></entry>
++ <entry>u<subscript>2</subscript></entry>
++ <entry>u<subscript>1</subscript></entry>
++ <entry>u<subscript>0</subscript></entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>v<subscript>7</subscript></entry>
++ <entry>v<subscript>6</subscript></entry>
++ <entry>v<subscript>5</subscript></entry>
++ <entry>v<subscript>4</subscript></entry>
++ <entry>v<subscript>3</subscript></entry>
++ <entry>v<subscript>2</subscript></entry>
++ <entry>v<subscript>1</subscript></entry>
++ <entry>v<subscript>0</subscript></entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-VYUY8-1X16">
++ <entry>V4L2_MBUS_FMT_VYUY8_1X16</entry>
++ <entry>0x2010</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>v<subscript>7</subscript></entry>
++ <entry>v<subscript>6</subscript></entry>
++ <entry>v<subscript>5</subscript></entry>
++ <entry>v<subscript>4</subscript></entry>
++ <entry>v<subscript>3</subscript></entry>
++ <entry>v<subscript>2</subscript></entry>
++ <entry>v<subscript>1</subscript></entry>
++ <entry>v<subscript>0</subscript></entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>u<subscript>7</subscript></entry>
++ <entry>u<subscript>6</subscript></entry>
++ <entry>u<subscript>5</subscript></entry>
++ <entry>u<subscript>4</subscript></entry>
++ <entry>u<subscript>3</subscript></entry>
++ <entry>u<subscript>2</subscript></entry>
++ <entry>u<subscript>1</subscript></entry>
++ <entry>u<subscript>0</subscript></entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-YUYV8-1X16">
++ <entry>V4L2_MBUS_FMT_YUYV8_1X16</entry>
++ <entry>0x2011</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ <entry>u<subscript>7</subscript></entry>
++ <entry>u<subscript>6</subscript></entry>
++ <entry>u<subscript>5</subscript></entry>
++ <entry>u<subscript>4</subscript></entry>
++ <entry>u<subscript>3</subscript></entry>
++ <entry>u<subscript>2</subscript></entry>
++ <entry>u<subscript>1</subscript></entry>
++ <entry>u<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ <entry>v<subscript>7</subscript></entry>
++ <entry>v<subscript>6</subscript></entry>
++ <entry>v<subscript>5</subscript></entry>
++ <entry>v<subscript>4</subscript></entry>
++ <entry>v<subscript>3</subscript></entry>
++ <entry>v<subscript>2</subscript></entry>
++ <entry>v<subscript>1</subscript></entry>
++ <entry>v<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-YVYU8-1X16">
++ <entry>V4L2_MBUS_FMT_YVYU8_1X16</entry>
++ <entry>0x2012</entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ <entry>v<subscript>7</subscript></entry>
++ <entry>v<subscript>6</subscript></entry>
++ <entry>v<subscript>5</subscript></entry>
++ <entry>v<subscript>4</subscript></entry>
++ <entry>v<subscript>3</subscript></entry>
++ <entry>v<subscript>2</subscript></entry>
++ <entry>v<subscript>1</subscript></entry>
++ <entry>v<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>-</entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ <entry>u<subscript>7</subscript></entry>
++ <entry>u<subscript>6</subscript></entry>
++ <entry>u<subscript>5</subscript></entry>
++ <entry>u<subscript>4</subscript></entry>
++ <entry>u<subscript>3</subscript></entry>
++ <entry>u<subscript>2</subscript></entry>
++ <entry>u<subscript>1</subscript></entry>
++ <entry>u<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-YUYV10-1X20">
++ <entry>V4L2_MBUS_FMT_YUYV10_1X20</entry>
++ <entry>0x200d</entry>
++ <entry></entry>
++ <entry>y<subscript>9</subscript></entry>
++ <entry>y<subscript>8</subscript></entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ <entry>u<subscript>9</subscript></entry>
++ <entry>u<subscript>8</subscript></entry>
++ <entry>u<subscript>7</subscript></entry>
++ <entry>u<subscript>6</subscript></entry>
++ <entry>u<subscript>5</subscript></entry>
++ <entry>u<subscript>4</subscript></entry>
++ <entry>u<subscript>3</subscript></entry>
++ <entry>u<subscript>2</subscript></entry>
++ <entry>u<subscript>1</subscript></entry>
++ <entry>u<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>y<subscript>9</subscript></entry>
++ <entry>y<subscript>8</subscript></entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ <entry>v<subscript>9</subscript></entry>
++ <entry>v<subscript>8</subscript></entry>
++ <entry>v<subscript>7</subscript></entry>
++ <entry>v<subscript>6</subscript></entry>
++ <entry>v<subscript>5</subscript></entry>
++ <entry>v<subscript>4</subscript></entry>
++ <entry>v<subscript>3</subscript></entry>
++ <entry>v<subscript>2</subscript></entry>
++ <entry>v<subscript>1</subscript></entry>
++ <entry>v<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-YVYU10-1X20">
++ <entry>V4L2_MBUS_FMT_YVYU10_1X20</entry>
++ <entry>0x200e</entry>
++ <entry></entry>
++ <entry>y<subscript>9</subscript></entry>
++ <entry>y<subscript>8</subscript></entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ <entry>v<subscript>9</subscript></entry>
++ <entry>v<subscript>8</subscript></entry>
++ <entry>v<subscript>7</subscript></entry>
++ <entry>v<subscript>6</subscript></entry>
++ <entry>v<subscript>5</subscript></entry>
++ <entry>v<subscript>4</subscript></entry>
++ <entry>v<subscript>3</subscript></entry>
++ <entry>v<subscript>2</subscript></entry>
++ <entry>v<subscript>1</subscript></entry>
++ <entry>v<subscript>0</subscript></entry>
++ </row>
++ <row>
++ <entry></entry>
++ <entry></entry>
++ <entry></entry>
++ <entry>y<subscript>9</subscript></entry>
++ <entry>y<subscript>8</subscript></entry>
++ <entry>y<subscript>7</subscript></entry>
++ <entry>y<subscript>6</subscript></entry>
++ <entry>y<subscript>5</subscript></entry>
++ <entry>y<subscript>4</subscript></entry>
++ <entry>y<subscript>3</subscript></entry>
++ <entry>y<subscript>2</subscript></entry>
++ <entry>y<subscript>1</subscript></entry>
++ <entry>y<subscript>0</subscript></entry>
++ <entry>u<subscript>9</subscript></entry>
++ <entry>u<subscript>8</subscript></entry>
++ <entry>u<subscript>7</subscript></entry>
++ <entry>u<subscript>6</subscript></entry>
++ <entry>u<subscript>5</subscript></entry>
++ <entry>u<subscript>4</subscript></entry>
++ <entry>u<subscript>3</subscript></entry>
++ <entry>u<subscript>2</subscript></entry>
++ <entry>u<subscript>1</subscript></entry>
++ <entry>u<subscript>0</subscript></entry>
++ </row>
++ </tbody>
++ </tgroup>
++ </table>
++ </section>
++ </section>
++</section>
+diff --git a/Documentation/DocBook/v4l/v4l2.xml b/Documentation/DocBook/v4l/v4l2.xml
+index 839e93e..695e3bf 100644
+--- a/Documentation/DocBook/v4l/v4l2.xml
++++ b/Documentation/DocBook/v4l/v4l2.xml
+@@ -410,6 +410,7 @@ and discussions on the V4L mailing list.</revremark>
+ <section id="radio"> &sub-dev-radio; </section>
+ <section id="rds"> &sub-dev-rds; </section>
+ <section id="event"> &sub-dev-event; </section>
++ <section id="subdev"> &sub-dev-subdev; </section>
+ </chapter>
+
+ <chapter id="driver">
+@@ -477,6 +478,9 @@ and discussions on the V4L mailing list.</revremark>
+ &sub-reqbufs;
+ &sub-s-hw-freq-seek;
+ &sub-streamon;
++ &sub-subdev-enum-frame-size;
++ &sub-subdev-enum-mbus-code;
++ &sub-subdev-g-fmt;
+ &sub-subscribe-event;
+ <!-- End of ioctls. -->
+ &sub-mmap;
+diff --git a/Documentation/DocBook/v4l/vidioc-streamon.xml b/Documentation/DocBook/v4l/vidioc-streamon.xml
+index e42bff1..75ed39b 100644
+--- a/Documentation/DocBook/v4l/vidioc-streamon.xml
++++ b/Documentation/DocBook/v4l/vidioc-streamon.xml
+@@ -93,6 +93,15 @@ synchronize with other events.</para>
+ been allocated (memory mapping) or enqueued (output) yet.</para>
+ </listitem>
+ </varlistentry>
++ <varlistentry>
++ <term><errorcode>EPIPE</errorcode></term>
++ <listitem>
++ <para>The driver implements <link
++ linkend="pad-level-formats">pad-level format configuration</link> and
++ the pipeline configuration is invalid.
++ </para>
++ </listitem>
++ </varlistentry>
+ </variablelist>
+ </refsect1>
+ </refentry>
+diff --git a/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-size.xml b/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-size.xml
+new file mode 100644
+index 0000000..209e983
+--- /dev/null
++++ b/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-size.xml
+@@ -0,0 +1,148 @@
++<refentry id="vidioc-subdev-enum-frame-size">
++ <refmeta>
++ <refentrytitle>ioctl VIDIOC_SUBDEV_ENUM_FRAME_SIZE</refentrytitle>
++ &manvol;
++ </refmeta>
++
++ <refnamediv>
++ <refname>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</refname>
++ <refpurpose>Enumerate media bus frame sizes</refpurpose>
++ </refnamediv>
++
++ <refsynopsisdiv>
++ <funcsynopsis>
++ <funcprototype>
++ <funcdef>int <function>ioctl</function></funcdef>
++ <paramdef>int <parameter>fd</parameter></paramdef>
++ <paramdef>int <parameter>request</parameter></paramdef>
++ <paramdef>struct v4l2_subdev_frame_size_enum *
++ <parameter>argp</parameter></paramdef>
++ </funcprototype>
++ </funcsynopsis>
++ </refsynopsisdiv>
++
++ <refsect1>
++ <title>Arguments</title>
++
++ <variablelist>
++ <varlistentry>
++ <term><parameter>fd</parameter></term>
++ <listitem>
++ <para>&fd;</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>request</parameter></term>
++ <listitem>
++ <para>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>argp</parameter></term>
++ <listitem>
++ <para></para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++
++ <refsect1>
++ <title>Description</title>
++
++ <para>This ioctl allows applications to enumerate all frame sizes
++ supported by a sub-device on the given pad for the given media bus format.
++ Supported formats can be retrieved with the &VIDIOC-SUBDEV-ENUM-MBUS-CODE;
++ ioctl.</para>
++
++ <para>To enumerate frame sizes applications initialize the
++ <structfield>pad</structfield>, <structfield>code</structfield> and
++ <structfield>index</structfield> fields of the
++ &v4l2-subdev-mbus-code-enum; and call the
++ <constant>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</constant> ioctl with a pointer to
++ the structure. Drivers fill the minimum and maximum frame sizes or return
++ an &EINVAL; if one of the input parameters is invalid.</para>
++
++ <para>Sub-devices that only support discrete frame sizes (such as most
++ sensors) will return one or more frame sizes with identical minimum and
++ maximum values.</para>
++
++ <para>Not all possible sizes in given [minimum, maximum] ranges need to be
++ supported. For instance, a scaler that uses a fixed-point scaling ratio
++ might not be able to produce every frame size between the minimum and
++ maximum values. Applications must use the &VIDIOC-SUBDEV-S-FMT; ioctl to
++ try the sub-device for an exact supported frame size.</para>
++
++ <para>Available frame sizes may depend on the current 'try' formats at other
++ pads of the sub-device, as well as on the current active links and the
++ current values of V4L2 controls. See &VIDIOC-SUBDEV-G-FMT; for more
++ information about try formats.</para>
++
++ <table pgwide="1" frame="none" id="v4l2-subdev-frame-size-enum">
++ <title>struct <structname>v4l2_subdev_frame_size_enum</structname></title>
++ <tgroup cols="3">
++ &cs-str;
++ <tbody valign="top">
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>index</structfield></entry>
++ <entry>Number of the format in the enumeration, set by the
++ application.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>pad</structfield></entry>
++ <entry>Pad number as reported by the media controller API.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>code</structfield></entry>
++ <entry>The media bus format code, as defined in
++ <xref linkend="v4l2-mbus-format" />.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>min_width</structfield></entry>
++ <entry>Minimum frame width, in pixels.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>max_width</structfield></entry>
++ <entry>Maximum frame width, in pixels.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>min_height</structfield></entry>
++ <entry>Minimum frame height, in pixels.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>max_height</structfield></entry>
++ <entry>Maximum frame height, in pixels.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>reserved</structfield>[9]</entry>
++ <entry>Reserved for future extensions. Applications and drivers must
++ set the array to zero.</entry>
++ </row>
++ </tbody>
++ </tgroup>
++ </table>
++ </refsect1>
++
++ <refsect1>
++ &return-value;
++
++ <variablelist>
++ <varlistentry>
++ <term><errorcode>EINVAL</errorcode></term>
++ <listitem>
++ <para>The &v4l2-subdev-frame-size-enum; <structfield>pad</structfield>
++ references a non-existing pad, the <structfield>code</structfield> is
++ invalid for the given pad or the <structfield>index</structfield>
++ field is out of bounds.</para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++</refentry>
+diff --git a/Documentation/DocBook/v4l/vidioc-subdev-enum-mbus-code.xml b/Documentation/DocBook/v4l/vidioc-subdev-enum-mbus-code.xml
+new file mode 100644
+index 0000000..763dbc7
+--- /dev/null
++++ b/Documentation/DocBook/v4l/vidioc-subdev-enum-mbus-code.xml
+@@ -0,0 +1,113 @@
++<refentry id="vidioc-subdev-enum-mbus-code">
++ <refmeta>
++ <refentrytitle>ioctl VIDIOC_SUBDEV_ENUM_MBUS_CODE</refentrytitle>
++ &manvol;
++ </refmeta>
++
++ <refnamediv>
++ <refname>VIDIOC_SUBDEV_ENUM_MBUS_CODE</refname>
++ <refpurpose>Enumerate media bus formats</refpurpose>
++ </refnamediv>
++
++ <refsynopsisdiv>
++ <funcsynopsis>
++ <funcprototype>
++ <funcdef>int <function>ioctl</function></funcdef>
++ <paramdef>int <parameter>fd</parameter></paramdef>
++ <paramdef>int <parameter>request</parameter></paramdef>
++ <paramdef>struct v4l2_subdev_mbus_code_enum *
++ <parameter>argp</parameter></paramdef>
++ </funcprototype>
++ </funcsynopsis>
++ </refsynopsisdiv>
++
++ <refsect1>
++ <title>Arguments</title>
++
++ <variablelist>
++ <varlistentry>
++ <term><parameter>fd</parameter></term>
++ <listitem>
++ <para>&fd;</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>request</parameter></term>
++ <listitem>
++ <para>VIDIOC_SUBDEV_ENUM_MBUS_CODE</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>argp</parameter></term>
++ <listitem>
++ <para></para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++
++ <refsect1>
++ <title>Description</title>
++
++ <para>To enumerate media bus formats available at a given sub-device pad
++ applications initialize the <structfield>pad</structfield> and
++ <structfield>index</structfield> fields of &v4l2-subdev-mbus-code-enum; and
++ call the <constant>VIDIOC_SUBDEV_ENUM_MBUS_CODE</constant> ioctl with a
++ pointer to this structure. Drivers fill the rest of the structure or return
++ an &EINVAL; if either the <structfield>pad</structfield> or
++ <structfield>index</structfield> are invalid. All media bus formats are
++ enumerable by beginning at index zero and incrementing by one until
++ <errorcode>EINVAL</errorcode> is returned.</para>
++
++ <para>Available media bus formats may depend on the current 'try' formats
++ at other pads of the sub-device, as well as on the current active links. See
++ &VIDIOC-SUBDEV-G-FMT; for more information about the try formats.</para>
++
++ <table pgwide="1" frame="none" id="v4l2-subdev-mbus-code-enum">
++ <title>struct <structname>v4l2_subdev_mbus_code_enum</structname></title>
++ <tgroup cols="3">
++ &cs-str;
++ <tbody valign="top">
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>pad</structfield></entry>
++ <entry>Pad number as reported by the media controller API.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>index</structfield></entry>
++ <entry>Number of the format in the enumeration, set by the
++ application.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>code</structfield></entry>
++ <entry>The media bus format code, as defined in
++ <xref linkend="v4l2-mbus-format" />.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>reserved</structfield>[9]</entry>
++ <entry>Reserved for future extensions. Applications and drivers must
++ set the array to zero.</entry>
++ </row>
++ </tbody>
++ </tgroup>
++ </table>
++ </refsect1>
++
++ <refsect1>
++ &return-value;
++
++ <variablelist>
++ <varlistentry>
++ <term><errorcode>EINVAL</errorcode></term>
++ <listitem>
++ <para>The &v4l2-subdev-mbus-code-enum; <structfield>pad</structfield>
++ references a non-existing pad, or the <structfield>index</structfield>
++ field is out of bounds.</para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++</refentry>
+diff --git a/Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml b/Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml
+new file mode 100644
+index 0000000..f06c41b
+--- /dev/null
++++ b/Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml
+@@ -0,0 +1,174 @@
++<refentry id="vidioc-subdev-g-fmt">
++ <refmeta>
++ <refentrytitle>ioctl VIDIOC_SUBDEV_G_FMT, VIDIOC_SUBDEV_S_FMT</refentrytitle>
++ &manvol;
++ </refmeta>
++
++ <refnamediv>
++ <refname>VIDIOC_SUBDEV_G_FMT</refname>
++ <refname>VIDIOC_SUBDEV_S_FMT</refname>
++ <refpurpose>Get or set the data format on a subdev pad</refpurpose>
++ </refnamediv>
++
++ <refsynopsisdiv>
++ <funcsynopsis>
++ <funcprototype>
++ <funcdef>int <function>ioctl</function></funcdef>
++ <paramdef>int <parameter>fd</parameter></paramdef>
++ <paramdef>int <parameter>request</parameter></paramdef>
++ <paramdef>struct v4l2_subdev_format *<parameter>argp</parameter>
++ </paramdef>
++ </funcprototype>
++ </funcsynopsis>
++ </refsynopsisdiv>
++
++ <refsect1>
++ <title>Arguments</title>
++
++ <variablelist>
++ <varlistentry>
++ <term><parameter>fd</parameter></term>
++ <listitem>
++ <para>&fd;</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>request</parameter></term>
++ <listitem>
++ <para>VIDIOC_SUBDEV_G_FMT, VIDIOC_SUBDEV_S_FMT</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>argp</parameter></term>
++ <listitem>
++ <para></para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++
++ <refsect1>
++ <title>Description</title>
++
++ <para>These ioctls are used to negotiate the frame format at specific
++ subdev pads in the image pipeline.</para>
++
++ <para>To retrieve the current format applications set the
++ <structfield>pad</structfield> field of a &v4l2-subdev-format; to the
++ desired pad number as reported by the media API and the
++ <structfield>which</structfield> field to
++ <constant>V4L2_SUBDEV_FORMAT_ACTIVE</constant>. When they call the
++ <constant>VIDIOC_SUBDEV_G_FMT</constant> ioctl with a pointer to this
++ structure the driver fills the members of the <structfield>format</structfield>
++ field.</para>
++
++ <para>To change the current format applications set both the
++ <structfield>pad</structfield> and <structfield>which</structfield> fields
++ and all members of the <structfield>format</structfield> field. When they
++ call the <constant>VIDIOC_SUBDEV_S_FMT</constant> ioctl with a pointer to this
++ structure the driver verifies the requested format, adjusts it based on the
++ hardware capabilities and configures the device. Upon return the
++ &v4l2-subdev-format; contains the current format as would be returned by a
++ <constant>VIDIOC_SUBDEV_G_FMT</constant> call.</para>
++
++ <para>Applications can query the device capabilities by setting the
++ <structfield>which</structfield> to
++ <constant>V4L2_SUBDEV_FORMAT_TRY</constant>. When set, 'try' formats are not
++ applied to the device by the driver, but are changed exactly as active
++ formats and stored in the sub-device file handle. Two applications querying
++ the same sub-device would thus not interact with each other.</para>
++
++ <para>For instance, to try a format at the output pad of a sub-device,
++ applications would first set the try format at the sub-device input with the
++ <constant>VIDIOC_SUBDEV_S_FMT</constant> ioctl. They would then either
++ retrieve the default format at the output pad with the
++ <constant>VIDIOC_SUBDEV_G_FMT</constant> ioctl, or set the desired output
++ pad format with the <constant>VIDIOC_SUBDEV_S_FMT</constant> ioctl and check
++ the returned value.</para>
++
++ <para>Try formats do not depend on active formats, but can depend on the
++ current links configuration or sub-device controls value. For instance, a
++ low-pass noise filter might crop pixels at the frame boundaries, modifying
++ its output frame size.</para>
++
++ <para>Drivers must not return an error solely because the requested format
++ doesn't match the device capabilities. They must instead modify the format
++ to match what the hardware can provide. The modified format should be as
++ close as possible to the original request.</para>
++
++ <table pgwide="1" frame="none" id="v4l2-subdev-format">
++ <title>struct <structname>v4l2_subdev_format</structname></title>
++ <tgroup cols="3">
++ &cs-str;
++ <tbody valign="top">
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>pad</structfield></entry>
++ <entry>Pad number as reported by the media controller API.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>which</structfield></entry>
++ <entry>Format to modified, from &v4l2-subdev-format-whence;.</entry>
++ </row>
++ <row>
++ <entry>&v4l2-mbus-framefmt;</entry>
++ <entry><structfield>format</structfield></entry>
++ <entry>Definition of an image format, see <xref
++ linkend="v4l2-mbus-framefmt" /> for details.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>reserved</structfield>[8]</entry>
++ <entry>Reserved for future extensions. Applications and drivers must
++ set the array to zero.</entry>
++ </row>
++ </tbody>
++ </tgroup>
++ </table>
++
++ <table pgwide="1" frame="none" id="v4l2-subdev-format-whence">
++ <title>enum <structname>v4l2_subdev_format_whence</structname></title>
++ <tgroup cols="3">
++ &cs-def;
++ <tbody valign="top">
++ <row>
++ <entry>V4L2_SUBDEV_FORMAT_TRY</entry>
++ <entry>0</entry>
++ <entry>Try formats, used for querying device capabilities.</entry>
++ </row>
++ <row>
++ <entry>V4L2_SUBDEV_FORMAT_ACTIVE</entry>
++ <entry>1</entry>
++ <entry>Active formats, applied to the hardware.</entry>
++ </row>
++ </tbody>
++ </tgroup>
++ </table>
++ </refsect1>
++
++ <refsect1>
++ &return-value;
++
++ <variablelist>
++ <varlistentry>
++ <term><errorcode>EBUSY</errorcode></term>
++ <listitem>
++ <para>The format can't be changed because the pad is currently busy.
++ This can be caused, for instance, by an active video stream on the
++ pad. The ioctl must not be retried without performing another action
++ to fix the problem first. Only returned by
++ <constant>VIDIOC_SUBDEV_S_FMT</constant></para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><errorcode>EINVAL</errorcode></term>
++ <listitem>
++ <para>The &v4l2-subdev-format; <structfield>pad</structfield>
++ references a non-existing pad, or the <structfield>which</structfield>
++ field references a non-existing format.</para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++</refentry>
+diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
+index 0f904e2..73aae00 100644
+--- a/drivers/media/video/v4l2-subdev.c
++++ b/drivers/media/video/v4l2-subdev.c
+@@ -149,6 +149,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+ struct v4l2_fh *vfh = file->private_data;
++#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
++ struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh);
++#endif
+
+ switch (cmd) {
+ case VIDIOC_QUERYCTRL:
+@@ -183,7 +186,53 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+
+ case VIDIOC_UNSUBSCRIBE_EVENT:
+ return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
++#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
++ case VIDIOC_SUBDEV_G_FMT: {
++ struct v4l2_subdev_format *format = arg;
++
++ if (format->which != V4L2_SUBDEV_FORMAT_TRY &&
++ format->which != V4L2_SUBDEV_FORMAT_ACTIVE)
++ return -EINVAL;
++
++ if (format->pad >= sd->entity.num_pads)
++ return -EINVAL;
++
++ return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh, format);
++ }
++
++ case VIDIOC_SUBDEV_S_FMT: {
++ struct v4l2_subdev_format *format = arg;
++
++ if (format->which != V4L2_SUBDEV_FORMAT_TRY &&
++ format->which != V4L2_SUBDEV_FORMAT_ACTIVE)
++ return -EINVAL;
++
++ if (format->pad >= sd->entity.num_pads)
++ return -EINVAL;
+
++ return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh, format);
++ }
++
++ case VIDIOC_SUBDEV_ENUM_MBUS_CODE: {
++ struct v4l2_subdev_mbus_code_enum *code = arg;
++
++ if (code->pad >= sd->entity.num_pads)
++ return -EINVAL;
++
++ return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh,
++ code);
++ }
++
++ case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: {
++ struct v4l2_subdev_frame_size_enum *fse = arg;
++
++ if (fse->pad >= sd->entity.num_pads)
++ return -EINVAL;
++
++ return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh,
++ fse);
++ }
++#endif
+ default:
+ return -ENOIOCTLCMD;
+ }
+diff --git a/include/linux/Kbuild b/include/linux/Kbuild
+index 796e1d8..c0db7f4 100644
+--- a/include/linux/Kbuild
++++ b/include/linux/Kbuild
+@@ -367,6 +367,7 @@ header-y += usbdevice_fs.h
+ header-y += utime.h
+ header-y += utsname.h
+ header-y += v4l2-mediabus.h
++header-y += v4l2-subdev.h
+ header-y += veth.h
+ header-y += vhost.h
+ header-y += videodev.h
+diff --git a/include/linux/v4l2-subdev.h b/include/linux/v4l2-subdev.h
+new file mode 100644
+index 0000000..38d0eda
+--- /dev/null
++++ b/include/linux/v4l2-subdev.h
+@@ -0,0 +1,90 @@
++/*
++ * V4L2 subdev userspace API
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#ifndef __LINUX_V4L2_SUBDEV_H
++#define __LINUX_V4L2_SUBDEV_H
++
++#include <linux/ioctl.h>
++#include <linux/types.h>
++#include <linux/v4l2-mediabus.h>
++
++/**
++ * enum v4l2_subdev_format_whence - Media bus format type
++ * @V4L2_SUBDEV_FORMAT_TRY: try format, for negotiation only
++ * @V4L2_SUBDEV_FORMAT_ACTIVE: active format, applied to the device
++ */
++enum v4l2_subdev_format_whence {
++ V4L2_SUBDEV_FORMAT_TRY = 0,
++ V4L2_SUBDEV_FORMAT_ACTIVE = 1,
++};
++
++/**
++ * struct v4l2_subdev_format - Pad-level media bus format
++ * @which: format type (from enum v4l2_subdev_format_whence)
++ * @pad: pad number, as reported by the media API
++ * @format: media bus format (format code and frame size)
++ */
++struct v4l2_subdev_format {
++ __u32 which;
++ __u32 pad;
++ struct v4l2_mbus_framefmt format;
++ __u32 reserved[8];
++};
++
++/**
++ * struct v4l2_subdev_mbus_code_enum - Media bus format enumeration
++ * @pad: pad number, as reported by the media API
++ * @index: format index during enumeration
++ * @code: format code (from enum v4l2_mbus_pixelcode)
++ */
++struct v4l2_subdev_mbus_code_enum {
++ __u32 pad;
++ __u32 index;
++ __u32 code;
++ __u32 reserved[9];
++};
++
++/**
++ * struct v4l2_subdev_frame_size_enum - Media bus format enumeration
++ * @pad: pad number, as reported by the media API
++ * @index: format index during enumeration
++ * @code: format code (from enum v4l2_mbus_pixelcode)
++ */
++struct v4l2_subdev_frame_size_enum {
++ __u32 index;
++ __u32 pad;
++ __u32 code;
++ __u32 min_width;
++ __u32 max_width;
++ __u32 min_height;
++ __u32 max_height;
++ __u32 reserved[9];
++};
++
++#define VIDIOC_SUBDEV_G_FMT _IOWR('V', 4, struct v4l2_subdev_format)
++#define VIDIOC_SUBDEV_S_FMT _IOWR('V', 5, struct v4l2_subdev_format)
++#define VIDIOC_SUBDEV_ENUM_MBUS_CODE \
++ _IOWR('V', 2, struct v4l2_subdev_mbus_code_enum)
++#define VIDIOC_SUBDEV_ENUM_FRAME_SIZE \
++ _IOWR('V', 74, struct v4l2_subdev_frame_size_enum)
++
++#endif
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index 4f6ddba..f5611c2 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -21,6 +21,7 @@
+ #ifndef _V4L2_SUBDEV_H
+ #define _V4L2_SUBDEV_H
+
++#include <linux/v4l2-subdev.h>
+ #include <media/media-entity.h>
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-dev.h>
+@@ -425,6 +426,15 @@ struct v4l2_subdev_ir_ops {
+ };
+
+ struct v4l2_subdev_pad_ops {
++ int (*enum_mbus_code)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_mbus_code_enum *code);
++ int (*enum_frame_size)(struct v4l2_subdev *sd,
++ struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_frame_size_enum *fse);
++ int (*get_fmt)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_format *format);
++ int (*set_fmt)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_format *format);
+ };
+
+ struct v4l2_subdev_ops {
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0029-v4l-v4l2_subdev-userspace-frame-interval-API.patch b/extras/recipes-kernel/linux/linux-omap/media/0029-v4l-v4l2_subdev-userspace-frame-interval-API.patch
new file mode 100644
index 00000000..8de33fdb
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0029-v4l-v4l2_subdev-userspace-frame-interval-API.patch
@@ -0,0 +1,479 @@
+From b137f96a198afb39c8457e2c5d28c1c4bca129a3 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 5 May 2010 16:38:35 +0200
+Subject: [PATCH 29/43] v4l: v4l2_subdev userspace frame interval API
+
+The three new ioctl VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL,
+VIDIOC_SUBDEV_G_FRAME_INTERVAL and VIDIOC_SUBDEV_S_FRAME_INTERVAL can be
+used to enumerate and configure a subdev's frame rate from userspace.
+
+Two new video::g/s_frame_interval subdev operations are introduced to
+support those ioctls. The existing video::g/s_parm operations are
+deprecated and shouldn't be used anymore.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+---
+ Documentation/DocBook/media-entities.tmpl | 6 +
+ Documentation/DocBook/v4l/v4l2.xml | 2 +
+ .../v4l/vidioc-subdev-enum-frame-interval.xml | 146 ++++++++++++++++++++
+ .../DocBook/v4l/vidioc-subdev-g-frame-interval.xml | 135 ++++++++++++++++++
+ drivers/media/video/v4l2-subdev.c | 16 ++
+ include/linux/v4l2-subdev.h | 36 +++++
+ include/media/v4l2-subdev.h | 7 +
+ 7 files changed, 348 insertions(+), 0 deletions(-)
+ create mode 100644 Documentation/DocBook/v4l/vidioc-subdev-enum-frame-interval.xml
+ create mode 100644 Documentation/DocBook/v4l/vidioc-subdev-g-frame-interval.xml
+
+diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
+index 538f8fe..4af3c2e 100644
+--- a/Documentation/DocBook/media-entities.tmpl
++++ b/Documentation/DocBook/media-entities.tmpl
+@@ -89,7 +89,9 @@
+ <!ENTITY VIDIOC-SUBDEV-ENUM-FRAME-SIZE "<link linkend='vidioc-subdev-enum-frame-size'><constant>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</constant></link>">
+ <!ENTITY VIDIOC-SUBDEV-ENUM-MBUS-CODE "<link linkend='vidioc-subdev-enum-mbus-code'><constant>VIDIOC_SUBDEV_ENUM_MBUS_CODE</constant></link>">
+ <!ENTITY VIDIOC-SUBDEV-G-FMT "<link linkend='vidioc-subdev-g-fmt'><constant>VIDIOC_SUBDEV_G_FMT</constant></link>">
++<!ENTITY VIDIOC-SUBDEV-G-FRAME-INTERVAL "<link linkend='vidioc-subdev-g-frame-interval'><constant>VIDIOC_SUBDEV_G_FRAME_INTERVAL</constant></link>">
+ <!ENTITY VIDIOC-SUBDEV-S-FMT "<link linkend='vidioc-subdev-g-fmt'><constant>VIDIOC_SUBDEV_S_FMT</constant></link>">
++<!ENTITY VIDIOC-SUBDEV-S-FRAME-INTERVAL "<link linkend='vidioc-subdev-g-frame-interval'><constant>VIDIOC_SUBDEV_S_FRAME_INTERVAL</constant></link>">
+ <!ENTITY VIDIOC-TRY-ENCODER-CMD "<link linkend='vidioc-encoder-cmd'><constant>VIDIOC_TRY_ENCODER_CMD</constant></link>">
+ <!ENTITY VIDIOC-TRY-EXT-CTRLS "<link linkend='vidioc-g-ext-ctrls'><constant>VIDIOC_TRY_EXT_CTRLS</constant></link>">
+ <!ENTITY VIDIOC-TRY-FMT "<link linkend='vidioc-g-fmt'><constant>VIDIOC_TRY_FMT</constant></link>">
+@@ -190,6 +192,8 @@
+ <!ENTITY v4l2-sliced-vbi-cap "struct&nbsp;<link linkend='v4l2-sliced-vbi-cap'>v4l2_sliced_vbi_cap</link>">
+ <!ENTITY v4l2-sliced-vbi-data "struct&nbsp;<link linkend='v4l2-sliced-vbi-data'>v4l2_sliced_vbi_data</link>">
+ <!ENTITY v4l2-sliced-vbi-format "struct&nbsp;<link linkend='v4l2-sliced-vbi-format'>v4l2_sliced_vbi_format</link>">
++<!ENTITY v4l2-subdev-frame-interval "struct&nbsp;<link linkend='v4l2-subdev-frame-interval'>v4l2_subdev_frame_interval</link>">
++<!ENTITY v4l2-subdev-frame-interval-enum "struct&nbsp;<link linkend='v4l2-subdev-frame-interval-enum'>v4l2_subdev_frame_interval_enum</link>">
+ <!ENTITY v4l2-subdev-frame-size-enum "struct&nbsp;<link linkend='v4l2-subdev-frame-size-enum'>v4l2_subdev_frame_size_enum</link>">
+ <!ENTITY v4l2-subdev-format "struct&nbsp;<link linkend='v4l2-subdev-format'>v4l2_subdev_format</link>">
+ <!ENTITY v4l2-subdev-mbus-code-enum "struct&nbsp;<link linkend='v4l2-subdev-mbus-code-enum'>v4l2_subdev_mbus_code_enum</link>">
+@@ -325,10 +329,12 @@
+ <!ENTITY sub-reqbufs SYSTEM "v4l/vidioc-reqbufs.xml">
+ <!ENTITY sub-s-hw-freq-seek SYSTEM "v4l/vidioc-s-hw-freq-seek.xml">
+ <!ENTITY sub-streamon SYSTEM "v4l/vidioc-streamon.xml">
++<!ENTITY sub-subdev-enum-frame-interval SYSTEM "v4l/vidioc-subdev-enum-frame-interval.xml">
+ <!ENTITY sub-subdev-enum-frame-size SYSTEM "v4l/vidioc-subdev-enum-frame-size.xml">
+ <!ENTITY sub-subdev-enum-mbus-code SYSTEM "v4l/vidioc-subdev-enum-mbus-code.xml">
+ <!ENTITY sub-subdev-formats SYSTEM "v4l/subdev-formats.xml">
+ <!ENTITY sub-subdev-g-fmt SYSTEM "v4l/vidioc-subdev-g-fmt.xml">
++<!ENTITY sub-subdev-g-frame-interval SYSTEM "v4l/vidioc-subdev-g-frame-interval.xml">
+ <!ENTITY sub-capture-c SYSTEM "v4l/capture.c.xml">
+ <!ENTITY sub-keytable-c SYSTEM "v4l/keytable.c.xml">
+ <!ENTITY sub-v4l2grab-c SYSTEM "v4l/v4l2grab.c.xml">
+diff --git a/Documentation/DocBook/v4l/v4l2.xml b/Documentation/DocBook/v4l/v4l2.xml
+index 695e3bf..e6225e0 100644
+--- a/Documentation/DocBook/v4l/v4l2.xml
++++ b/Documentation/DocBook/v4l/v4l2.xml
+@@ -478,9 +478,11 @@ and discussions on the V4L mailing list.</revremark>
+ &sub-reqbufs;
+ &sub-s-hw-freq-seek;
+ &sub-streamon;
++ &sub-subdev-enum-frame-interval;
+ &sub-subdev-enum-frame-size;
+ &sub-subdev-enum-mbus-code;
+ &sub-subdev-g-fmt;
++ &sub-subdev-g-frame-interval;
+ &sub-subscribe-event;
+ <!-- End of ioctls. -->
+ &sub-mmap;
+diff --git a/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-interval.xml b/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-interval.xml
+new file mode 100644
+index 0000000..bcea9d4
+--- /dev/null
++++ b/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-interval.xml
+@@ -0,0 +1,146 @@
++<refentry id="vidioc-subdev-enum-frame-interval">
++ <refmeta>
++ <refentrytitle>ioctl VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</refentrytitle>
++ &manvol;
++ </refmeta>
++
++ <refnamediv>
++ <refname>VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</refname>
++ <refpurpose>Enumerate frame intervals</refpurpose>
++ </refnamediv>
++
++ <refsynopsisdiv>
++ <funcsynopsis>
++ <funcprototype>
++ <funcdef>int <function>ioctl</function></funcdef>
++ <paramdef>int <parameter>fd</parameter></paramdef>
++ <paramdef>int <parameter>request</parameter></paramdef>
++ <paramdef>struct v4l2_subdev_frame_interval_enum *
++ <parameter>argp</parameter></paramdef>
++ </funcprototype>
++ </funcsynopsis>
++ </refsynopsisdiv>
++
++ <refsect1>
++ <title>Arguments</title>
++
++ <variablelist>
++ <varlistentry>
++ <term><parameter>fd</parameter></term>
++ <listitem>
++ <para>&fd;</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>request</parameter></term>
++ <listitem>
++ <para>VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>argp</parameter></term>
++ <listitem>
++ <para></para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++
++ <refsect1>
++ <title>Description</title>
++
++ <para>This ioctl lets applications enumerate available frame intervals on a
++ given sub-device pad. Frame intervals only makes sense for sub-devices that
++ can control the frame period on their own. This includes, for instance,
++ image sensors and TV tuners.</para>
++
++ <para>For the common use case of image sensors, the frame intervals
++ available on the sub-device output pad depend on the frame format and size
++ on the same pad. Applications must thus specify the desired format and size
++ when enumerating frame intervals.</para>
++
++ <para>To enumerate frame intervals applications initialize the
++ <structfield>index</structfield>, <structfield>pad</structfield>,
++ <structfield>code</structfield>, <structfield>width</structfield> and
++ <structfield>height</structfield> fields of
++ &v4l2-subdev-frame-interval-enum; and call the
++ <constant>VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</constant> ioctl with a pointer
++ to this structure. Drivers fill the rest of the structure or return
++ an &EINVAL; if one of the input fields is invalid. All frame intervals are
++ enumerable by beginning at index zero and incrementing by one until
++ <errorcode>EINVAL</errorcode> is returned.</para>
++
++ <para>Available frame intervals may depend on the current 'try' formats
++ at other pads of the sub-device, as well as on the current active links. See
++ &VIDIOC-SUBDEV-G-FMT; for more information about the try formats.</para>
++
++ <para>Sub-devices that support the frame interval enumeration ioctl should
++ implemented it on a single pad only. Its behaviour when supported on
++ multiple pads of the same sub-device is not defined.</para>
++
++ <table pgwide="1" frame="none" id="v4l2-subdev-frame-interval-enum">
++ <title>struct <structname>v4l2_subdev_frame_interval_enum</structname></title>
++ <tgroup cols="3">
++ &cs-str;
++ <tbody valign="top">
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>index</structfield></entry>
++ <entry>Number of the format in the enumeration, set by the
++ application.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>pad</structfield></entry>
++ <entry>Pad number as reported by the media controller API.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>code</structfield></entry>
++ <entry>The media bus format code, as defined in
++ <xref linkend="v4l2-mbus-format" />.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>width</structfield></entry>
++ <entry>Frame width, in pixels.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>height</structfield></entry>
++ <entry>Frame height, in pixels.</entry>
++ </row>
++ <row>
++ <entry>&v4l2-fract;</entry>
++ <entry><structfield>interval</structfield></entry>
++ <entry>Period, in seconds, between consecutive video frames.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>reserved</structfield>[9]</entry>
++ <entry>Reserved for future extensions. Applications and drivers must
++ set the array to zero.</entry>
++ </row>
++ </tbody>
++ </tgroup>
++ </table>
++ </refsect1>
++
++ <refsect1>
++ &return-value;
++
++ <variablelist>
++ <varlistentry>
++ <term><errorcode>EINVAL</errorcode></term>
++ <listitem>
++ <para>The &v4l2-subdev-frame-interval-enum;
++ <structfield>pad</structfield> references a non-existing pad, one of
++ the <structfield>code</structfield>, <structfield>width</structfield>
++ or <structfield>height</structfield> fields are invalid for the given
++ pad or the <structfield>index</structfield> field is out of bounds.
++ </para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++</refentry>
+diff --git a/Documentation/DocBook/v4l/vidioc-subdev-g-frame-interval.xml b/Documentation/DocBook/v4l/vidioc-subdev-g-frame-interval.xml
+new file mode 100644
+index 0000000..848ec78
+--- /dev/null
++++ b/Documentation/DocBook/v4l/vidioc-subdev-g-frame-interval.xml
+@@ -0,0 +1,135 @@
++<refentry id="vidioc-subdev-g-frame-interval">
++ <refmeta>
++ <refentrytitle>ioctl VIDIOC_SUBDEV_G_FRAME_INTERVAL, VIDIOC_SUBDEV_S_FRAME_INTERVAL</refentrytitle>
++ &manvol;
++ </refmeta>
++
++ <refnamediv>
++ <refname>VIDIOC_SUBDEV_G_FRAME_INTERVAL</refname>
++ <refname>VIDIOC_SUBDEV_S_FRAME_INTERVAL</refname>
++ <refpurpose>Get or set the frame interval on a subdev pad</refpurpose>
++ </refnamediv>
++
++ <refsynopsisdiv>
++ <funcsynopsis>
++ <funcprototype>
++ <funcdef>int <function>ioctl</function></funcdef>
++ <paramdef>int <parameter>fd</parameter></paramdef>
++ <paramdef>int <parameter>request</parameter></paramdef>
++ <paramdef>struct v4l2_subdev_frame_interval *<parameter>argp</parameter>
++ </paramdef>
++ </funcprototype>
++ </funcsynopsis>
++ </refsynopsisdiv>
++
++ <refsect1>
++ <title>Arguments</title>
++
++ <variablelist>
++ <varlistentry>
++ <term><parameter>fd</parameter></term>
++ <listitem>
++ <para>&fd;</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>request</parameter></term>
++ <listitem>
++ <para>VIDIOC_SUBDEV_G_FRAME_INTERVAL, VIDIOC_SUBDEV_S_FRAME_INTERVAL</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>argp</parameter></term>
++ <listitem>
++ <para></para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++
++ <refsect1>
++ <title>Description</title>
++
++ <para>These ioctls are used to get and set the frame interval at specific
++ subdev pads in the image pipeline. The frame interval only makes sense for
++ sub-devices that can control the frame period on their own. This includes,
++ for instance, image sensors and TV tuners. Sub-devices that don't support
++ frame intervals must not implement these ioctls.</para>
++
++ <para>To retrieve the current frame interval applications set the
++ <structfield>pad</structfield> field of a &v4l2-subdev-frame-interval; to
++ the desired pad number as reported by the media controller API. When they
++ call the <constant>VIDIOC_SUBDEV_G_FRAME_INTERVAL</constant> ioctl with a
++ pointer to this structure the driver fills the members of the
++ <structfield>interval</structfield> field.</para>
++
++ <para>To change the current frame interval applications set both the
++ <structfield>pad</structfield> field and all members of the
++ <structfield>interval</structfield> field. When they call the
++ <constant>VIDIOC_SUBDEV_S_FRAME_INTERVAL</constant> ioctl with a pointer to
++ this structure the driver verifies the requested interval, adjusts it based
++ on the hardware capabilities and configures the device. Upon return the
++ &v4l2-subdev-frame-interval; contains the current frame interval as would be
++ returned by a <constant>VIDIOC_SUBDEV_G_FRAME_INTERVAL</constant> call.
++ </para>
++
++ <para>Drivers must not return an error solely because the requested interval
++ doesn't match the device capabilities. They must instead modify the interval
++ to match what the hardware can provide. The modified interval should be as
++ close as possible to the original request.</para>
++
++ <para>Sub-devices that support the frame interval ioctls should implement
++ them on a single pad only. Their behaviour when supported on multiple pads
++ of the same sub-device is not defined.</para>
++
++ <table pgwide="1" frame="none" id="v4l2-subdev-frame-interval">
++ <title>struct <structname>v4l2_subdev_frame_interval</structname></title>
++ <tgroup cols="3">
++ &cs-str;
++ <tbody valign="top">
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>pad</structfield></entry>
++ <entry>Pad number as reported by the media controller API.</entry>
++ </row>
++ <row>
++ <entry>&v4l2-fract;</entry>
++ <entry><structfield>interval</structfield></entry>
++ <entry>Period, in seconds, between consecutive video frames.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>reserved</structfield>[9]</entry>
++ <entry>Reserved for future extensions. Applications and drivers must
++ set the array to zero.</entry>
++ </row>
++ </tbody>
++ </tgroup>
++ </table>
++ </refsect1>
++
++ <refsect1>
++ &return-value;
++
++ <variablelist>
++ <varlistentry>
++ <term><errorcode>EBUSY</errorcode></term>
++ <listitem>
++ <para>The frame interval can't be changed because the pad is currently
++ busy. This can be caused, for instance, by an active video stream on
++ the pad. The ioctl must not be retried without performing another
++ action to fix the problem first. Only returned by
++ <constant>VIDIOC_SUBDEV_S_FRAME_INTERVAL</constant></para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><errorcode>EINVAL</errorcode></term>
++ <listitem>
++ <para>The &v4l2-subdev-frame-interval; <structfield>pad</structfield>
++ references a non-existing pad, or the pad doesn't support frame
++ intervals.</para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++</refentry>
+diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
+index 73aae00..316a08a 100644
+--- a/drivers/media/video/v4l2-subdev.c
++++ b/drivers/media/video/v4l2-subdev.c
+@@ -232,6 +232,22 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+ return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh,
+ fse);
+ }
++
++ case VIDIOC_SUBDEV_G_FRAME_INTERVAL:
++ return v4l2_subdev_call(sd, video, g_frame_interval, arg);
++
++ case VIDIOC_SUBDEV_S_FRAME_INTERVAL:
++ return v4l2_subdev_call(sd, video, s_frame_interval, arg);
++
++ case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: {
++ struct v4l2_subdev_frame_interval_enum *fie = arg;
++
++ if (fie->pad >= sd->entity.num_pads)
++ return -EINVAL;
++
++ return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh,
++ fie);
++ }
+ #endif
+ default:
+ return -ENOIOCTLCMD;
+diff --git a/include/linux/v4l2-subdev.h b/include/linux/v4l2-subdev.h
+index 38d0eda..bf9f3e9 100644
+--- a/include/linux/v4l2-subdev.h
++++ b/include/linux/v4l2-subdev.h
+@@ -80,11 +80,47 @@ struct v4l2_subdev_frame_size_enum {
+ __u32 reserved[9];
+ };
+
++/**
++ * struct v4l2_subdev_frame_interval - Pad-level frame rate
++ * @pad: pad number, as reported by the media API
++ * @interval: frame interval in seconds
++ */
++struct v4l2_subdev_frame_interval {
++ __u32 pad;
++ struct v4l2_fract interval;
++ __u32 reserved[9];
++};
++
++/**
++ * struct v4l2_subdev_frame_interval_enum - Frame interval enumeration
++ * @pad: pad number, as reported by the media API
++ * @index: frame interval index during enumeration
++ * @code: format code (from enum v4l2_mbus_pixelcode)
++ * @width: frame width in pixels
++ * @height: frame height in pixels
++ * @interval: frame interval in seconds
++ */
++struct v4l2_subdev_frame_interval_enum {
++ __u32 index;
++ __u32 pad;
++ __u32 code;
++ __u32 width;
++ __u32 height;
++ struct v4l2_fract interval;
++ __u32 reserved[9];
++};
++
+ #define VIDIOC_SUBDEV_G_FMT _IOWR('V', 4, struct v4l2_subdev_format)
+ #define VIDIOC_SUBDEV_S_FMT _IOWR('V', 5, struct v4l2_subdev_format)
++#define VIDIOC_SUBDEV_G_FRAME_INTERVAL \
++ _IOWR('V', 21, struct v4l2_subdev_frame_interval)
++#define VIDIOC_SUBDEV_S_FRAME_INTERVAL \
++ _IOWR('V', 22, struct v4l2_subdev_frame_interval)
+ #define VIDIOC_SUBDEV_ENUM_MBUS_CODE \
+ _IOWR('V', 2, struct v4l2_subdev_mbus_code_enum)
+ #define VIDIOC_SUBDEV_ENUM_FRAME_SIZE \
+ _IOWR('V', 74, struct v4l2_subdev_frame_size_enum)
++#define VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL \
++ _IOWR('V', 75, struct v4l2_subdev_frame_interval_enum)
+
+ #endif
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index f5611c2..9c8bcd3 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -281,6 +281,10 @@ struct v4l2_subdev_video_ops {
+ int (*s_crop)(struct v4l2_subdev *sd, struct v4l2_crop *crop);
+ int (*g_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param);
+ int (*s_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param);
++ int (*g_frame_interval)(struct v4l2_subdev *sd,
++ struct v4l2_subdev_frame_interval *interval);
++ int (*s_frame_interval)(struct v4l2_subdev *sd,
++ struct v4l2_subdev_frame_interval *interval);
+ int (*enum_framesizes)(struct v4l2_subdev *sd, struct v4l2_frmsizeenum *fsize);
+ int (*enum_frameintervals)(struct v4l2_subdev *sd, struct v4l2_frmivalenum *fival);
+ int (*enum_dv_presets) (struct v4l2_subdev *sd,
+@@ -431,6 +435,9 @@ struct v4l2_subdev_pad_ops {
+ int (*enum_frame_size)(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_frame_size_enum *fse);
++ int (*enum_frame_interval)(struct v4l2_subdev *sd,
++ struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_frame_interval_enum *fie);
+ int (*get_fmt)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format);
+ int (*set_fmt)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0030-v4l-v4l2_subdev-userspace-crop-API.patch b/extras/recipes-kernel/linux/linux-omap/media/0030-v4l-v4l2_subdev-userspace-crop-API.patch
new file mode 100644
index 00000000..d1a3aae8
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0030-v4l-v4l2_subdev-userspace-crop-API.patch
@@ -0,0 +1,350 @@
+From 9e87e6d59dc364ec78717fb91cbe9bad7df14223 Mon Sep 17 00:00:00 2001
+From: Antti Koskipaa <antti.koskipaa@nokia.com>
+Date: Wed, 23 Jun 2010 11:03:42 +0300
+Subject: [PATCH 30/43] v4l: v4l2_subdev userspace crop API
+
+This patch adds the VIDIOC_SUBDEV_S_CROP and G_CROP ioctls to the
+userland API. CROPCAP is not implemented because it's redundant.
+
+Signed-off-by: Antti Koskipaa <antti.koskipaa@nokia.com>
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ Documentation/DocBook/media-entities.tmpl | 4 +
+ Documentation/DocBook/v4l/dev-subdev.xml | 33 +++++
+ Documentation/DocBook/v4l/v4l2.xml | 1 +
+ Documentation/DocBook/v4l/vidioc-subdev-g-crop.xml | 149 ++++++++++++++++++++
+ drivers/media/video/v4l2-subdev.c | 26 ++++
+ include/linux/v4l2-subdev.h | 15 ++
+ include/media/v4l2-subdev.h | 4 +
+ 7 files changed, 232 insertions(+), 0 deletions(-)
+ create mode 100644 Documentation/DocBook/v4l/vidioc-subdev-g-crop.xml
+
+diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
+index 4af3c2e..157d147 100644
+--- a/Documentation/DocBook/media-entities.tmpl
++++ b/Documentation/DocBook/media-entities.tmpl
+@@ -88,8 +88,10 @@
+ <!ENTITY VIDIOC-S-TUNER "<link linkend='vidioc-g-tuner'><constant>VIDIOC_S_TUNER</constant></link>">
+ <!ENTITY VIDIOC-SUBDEV-ENUM-FRAME-SIZE "<link linkend='vidioc-subdev-enum-frame-size'><constant>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</constant></link>">
+ <!ENTITY VIDIOC-SUBDEV-ENUM-MBUS-CODE "<link linkend='vidioc-subdev-enum-mbus-code'><constant>VIDIOC_SUBDEV_ENUM_MBUS_CODE</constant></link>">
++<!ENTITY VIDIOC-SUBDEV-G-CROP "<link linkend='vidioc-subdev-g-crop'><constant>VIDIOC_SUBDEV_G_CROP</constant></link>">
+ <!ENTITY VIDIOC-SUBDEV-G-FMT "<link linkend='vidioc-subdev-g-fmt'><constant>VIDIOC_SUBDEV_G_FMT</constant></link>">
+ <!ENTITY VIDIOC-SUBDEV-G-FRAME-INTERVAL "<link linkend='vidioc-subdev-g-frame-interval'><constant>VIDIOC_SUBDEV_G_FRAME_INTERVAL</constant></link>">
++<!ENTITY VIDIOC-SUBDEV-S-CROP "<link linkend='vidioc-subdev-g-crop'><constant>VIDIOC_SUBDEV_S_CROP</constant></link>">
+ <!ENTITY VIDIOC-SUBDEV-S-FMT "<link linkend='vidioc-subdev-g-fmt'><constant>VIDIOC_SUBDEV_S_FMT</constant></link>">
+ <!ENTITY VIDIOC-SUBDEV-S-FRAME-INTERVAL "<link linkend='vidioc-subdev-g-frame-interval'><constant>VIDIOC_SUBDEV_S_FRAME_INTERVAL</constant></link>">
+ <!ENTITY VIDIOC-TRY-ENCODER-CMD "<link linkend='vidioc-encoder-cmd'><constant>VIDIOC_TRY_ENCODER_CMD</constant></link>">
+@@ -195,6 +197,7 @@
+ <!ENTITY v4l2-subdev-frame-interval "struct&nbsp;<link linkend='v4l2-subdev-frame-interval'>v4l2_subdev_frame_interval</link>">
+ <!ENTITY v4l2-subdev-frame-interval-enum "struct&nbsp;<link linkend='v4l2-subdev-frame-interval-enum'>v4l2_subdev_frame_interval_enum</link>">
+ <!ENTITY v4l2-subdev-frame-size-enum "struct&nbsp;<link linkend='v4l2-subdev-frame-size-enum'>v4l2_subdev_frame_size_enum</link>">
++<!ENTITY v4l2-subdev-crop "struct&nbsp;<link linkend='v4l2-subdev-crop'>v4l2_subdev_crop</link>">
+ <!ENTITY v4l2-subdev-format "struct&nbsp;<link linkend='v4l2-subdev-format'>v4l2_subdev_format</link>">
+ <!ENTITY v4l2-subdev-mbus-code-enum "struct&nbsp;<link linkend='v4l2-subdev-mbus-code-enum'>v4l2_subdev_mbus_code_enum</link>">
+ <!ENTITY v4l2-standard "struct&nbsp;<link linkend='v4l2-standard'>v4l2_standard</link>">
+@@ -333,6 +336,7 @@
+ <!ENTITY sub-subdev-enum-frame-size SYSTEM "v4l/vidioc-subdev-enum-frame-size.xml">
+ <!ENTITY sub-subdev-enum-mbus-code SYSTEM "v4l/vidioc-subdev-enum-mbus-code.xml">
+ <!ENTITY sub-subdev-formats SYSTEM "v4l/subdev-formats.xml">
++<!ENTITY sub-subdev-g-crop SYSTEM "v4l/vidioc-subdev-g-crop.xml">
+ <!ENTITY sub-subdev-g-fmt SYSTEM "v4l/vidioc-subdev-g-fmt.xml">
+ <!ENTITY sub-subdev-g-frame-interval SYSTEM "v4l/vidioc-subdev-g-frame-interval.xml">
+ <!ENTITY sub-capture-c SYSTEM "v4l/capture.c.xml">
+diff --git a/Documentation/DocBook/v4l/dev-subdev.xml b/Documentation/DocBook/v4l/dev-subdev.xml
+index 12fdca4..a8da916 100644
+--- a/Documentation/DocBook/v4l/dev-subdev.xml
++++ b/Documentation/DocBook/v4l/dev-subdev.xml
+@@ -269,6 +269,39 @@
+ </para>
+ </section>
+
++ <section>
++ <title>Cropping and scaling</title>
++
++ <para>Many sub-devices support cropping frames on their input or output
++ pads (or possible even on both). Cropping is used to select the area of
++ interest in an image, typically on a video sensor or video decoder. It can
++ also be used as part of digital zoom implementations to select the area of
++ the image that will be scaled up.</para>
++
++ <para>Crop settings are defined by a crop rectangle and represented in a
++ &v4l2-rect; by the coordinates of the top left corner and the rectangle
++ size. Both the coordinates and sizes are expressed in pixels.</para>
++
++ <para>The crop rectangle is retrieved and set using the
++ &VIDIOC-SUBDEV-G-CROP; and &VIDIOC-SUBDEV-S-CROP; ioctls. Like for pad
++ formats, drivers store try and active crop rectangles. The format
++ negotiation mechanism applies to crop settings as well.</para>
++
++ <para>On input pads, cropping is applied relatively to the current pad
++ format. The pad format represents the image size as received by the
++ sub-device from the previous block in the pipeline, and the crop rectangle
++ represents the sub-image that will be transmitted further inside the
++ sub-device for processing. The crop rectangle be entirely containted
++ inside the input image size.</para>
++
++ <para>Input crop rectangle are reset to their default value when the input
++ image format is modified. Drivers should use the input image size as the
++ crop rectangle default value, but hardware requirements may prevent this.
++ </para>
++
++ <para>Cropping behaviour on output pads is not defined.</para>
++
++ </section>
+ </section>
+
+ &sub-subdev-formats;
+diff --git a/Documentation/DocBook/v4l/v4l2.xml b/Documentation/DocBook/v4l/v4l2.xml
+index e6225e0..5e640ca 100644
+--- a/Documentation/DocBook/v4l/v4l2.xml
++++ b/Documentation/DocBook/v4l/v4l2.xml
+@@ -481,6 +481,7 @@ and discussions on the V4L mailing list.</revremark>
+ &sub-subdev-enum-frame-interval;
+ &sub-subdev-enum-frame-size;
+ &sub-subdev-enum-mbus-code;
++ &sub-subdev-g-crop;
+ &sub-subdev-g-fmt;
+ &sub-subdev-g-frame-interval;
+ &sub-subscribe-event;
+diff --git a/Documentation/DocBook/v4l/vidioc-subdev-g-crop.xml b/Documentation/DocBook/v4l/vidioc-subdev-g-crop.xml
+new file mode 100644
+index 0000000..cef127f
+--- /dev/null
++++ b/Documentation/DocBook/v4l/vidioc-subdev-g-crop.xml
+@@ -0,0 +1,149 @@
++<refentry id="vidioc-subdev-g-crop">
++ <refmeta>
++ <refentrytitle>ioctl VIDIOC_SUBDEV_G_CROP, VIDIOC_SUBDEV_S_CROP</refentrytitle>
++ &manvol;
++ </refmeta>
++
++ <refnamediv>
++ <refname>VIDIOC_SUBDEV_G_CROP</refname>
++ <refname>VIDIOC_SUBDEV_S_CROP</refname>
++ <refpurpose>Get or set the crop rectangle on a subdev pad</refpurpose>
++ </refnamediv>
++
++ <refsynopsisdiv>
++ <funcsynopsis>
++ <funcprototype>
++ <funcdef>int <function>ioctl</function></funcdef>
++ <paramdef>int <parameter>fd</parameter></paramdef>
++ <paramdef>int <parameter>request</parameter></paramdef>
++ <paramdef>struct v4l2_subdev_crop *<parameter>argp</parameter></paramdef>
++ </funcprototype>
++ </funcsynopsis>
++ <funcsynopsis>
++ <funcprototype>
++ <funcdef>int <function>ioctl</function></funcdef>
++ <paramdef>int <parameter>fd</parameter></paramdef>
++ <paramdef>int <parameter>request</parameter></paramdef>
++ <paramdef>const struct v4l2_subdev_crop *<parameter>argp</parameter></paramdef>
++ </funcprototype>
++ </funcsynopsis>
++ </refsynopsisdiv>
++
++ <refsect1>
++ <title>Arguments</title>
++
++ <variablelist>
++ <varlistentry>
++ <term><parameter>fd</parameter></term>
++ <listitem>
++ <para>&fd;</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>request</parameter></term>
++ <listitem>
++ <para>VIDIOC_SUBDEV_G_CROP, VIDIOC_SUBDEV_S_CROP</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>argp</parameter></term>
++ <listitem>
++ <para></para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++
++ <refsect1>
++ <title>Description</title>
++
++ <para>To retrieve the current crop rectangle applications set the
++ <structfield>pad</structfield> field of a &v4l2-subdev-crop; to the
++ desired pad number as reported by the media API and the
++ <structfield>which</structfield> field to
++ <constant>V4L2_SUBDEV_FORMAT_ACTIVE</constant>. They then call the
++ <constant>VIDIOC_SUBDEV_G_CROP</constant> ioctl with a pointer to this
++ structure. The driver fills the members of the <structfield>rect</structfield>
++ field or returns &EINVAL; if the input arguments are invalid, or if cropping
++ is not supported on the given pad.</para>
++
++ <para>To change the current crop rectangle applications set both the
++ <structfield>pad</structfield> and <structfield>which</structfield> fields
++ and all members of the <structfield>rect</structfield> field. They then call
++ the <constant>VIDIOC_SUBDEV_S_CROP</constant> ioctl with a pointer to this
++ structure. The driver verifies the requested crop rectangle, adjusts it
++ based on the hardware capabilities and configures the device. Upon return
++ the &v4l2-subdev-crop; contains the current format as would be returned
++ by a <constant>VIDIOC_SUBDEV_G_CROP</constant> call.</para>
++
++ <para>Applications can query the device capabilities by setting the
++ <structfield>which</structfield> to
++ <constant>V4L2_SUBDEV_FORMAT_TRY</constant>. When set, 'try' crop
++ rectangles are not applied to the device by the driver, but are mangled
++ exactly as active crop rectangles and stored in the sub-device file handle.
++ Two applications querying the same sub-device would thus not interact with
++ each other.</para>
++
++ <para>Drivers must not return an error solely because the requested crop
++ rectangle doesn't match the device capabilities. They must instead modify
++ the rectangle to match what the hardware can provide. The modified format
++ should be as close as possible to the original request.</para>
++
++ <table pgwide="1" frame="none" id="v4l2-subdev-crop">
++ <title>struct <structname>v4l2_subdev_crop</structname></title>
++ <tgroup cols="3">
++ &cs-str;
++ <tbody valign="top">
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>pad</structfield></entry>
++ <entry>Pad number as reported by the media framework.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>which</structfield></entry>
++ <entry>Crop rectangle to get or set, from
++ &v4l2-subdev-format-whence;.</entry>
++ </row>
++ <row>
++ <entry>&v4l2-rect;</entry>
++ <entry><structfield>rect</structfield></entry>
++ <entry>Crop rectangle boundaries, in pixels.</entry>
++ </row>
++ <row>
++ <entry>__u32</entry>
++ <entry><structfield>reserved</structfield>[8]</entry>
++ <entry>Reserved for future extensions. Applications and drivers must
++ set the array to zero.</entry>
++ </row>
++ </tbody>
++ </tgroup>
++ </table>
++ </refsect1>
++
++ <refsect1>
++ &return-value;
++
++ <variablelist>
++ <varlistentry>
++ <term><errorcode>EBUSY</errorcode></term>
++ <listitem>
++ <para>The crop rectangle can't be changed because the pad is currently
++ busy. This can be caused, for instance, by an active video stream on
++ the pad. The ioctl must not be retried without performing another
++ action to fix the problem first. Only returned by
++ <constant>VIDIOC_SUBDEV_S_CROP</constant></para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><errorcode>EINVAL</errorcode></term>
++ <listitem>
++ <para>The &v4l2-subdev-crop; <structfield>pad</structfield>
++ references a non-existing pad, the <structfield>which</structfield>
++ field references a non-existing format, or cropping is not supported
++ on the given subdev pad.</para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++</refentry>
+diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
+index 316a08a..e706c4c 100644
+--- a/drivers/media/video/v4l2-subdev.c
++++ b/drivers/media/video/v4l2-subdev.c
+@@ -213,6 +213,32 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+ return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh, format);
+ }
+
++ case VIDIOC_SUBDEV_G_CROP: {
++ struct v4l2_subdev_crop *crop = arg;
++
++ if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
++ crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
++ return -EINVAL;
++
++ if (crop->pad >= sd->entity.num_pads)
++ return -EINVAL;
++
++ return v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop);
++ }
++
++ case VIDIOC_SUBDEV_S_CROP: {
++ struct v4l2_subdev_crop *crop = arg;
++
++ if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
++ crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
++ return -EINVAL;
++
++ if (crop->pad >= sd->entity.num_pads)
++ return -EINVAL;
++
++ return v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop);
++ }
++
+ case VIDIOC_SUBDEV_ENUM_MBUS_CODE: {
+ struct v4l2_subdev_mbus_code_enum *code = arg;
+
+diff --git a/include/linux/v4l2-subdev.h b/include/linux/v4l2-subdev.h
+index bf9f3e9..49ec1e0 100644
+--- a/include/linux/v4l2-subdev.h
++++ b/include/linux/v4l2-subdev.h
+@@ -51,6 +51,19 @@ struct v4l2_subdev_format {
+ };
+
+ /**
++ * struct v4l2_subdev_crop - Pad-level crop settings
++ * @which: format type (from enum v4l2_subdev_format_whence)
++ * @pad: pad number, as reported by the media API
++ * @rect: pad crop rectangle boundaries
++ */
++struct v4l2_subdev_crop {
++ __u32 which;
++ __u32 pad;
++ struct v4l2_rect rect;
++ __u32 reserved[8];
++};
++
++/**
+ * struct v4l2_subdev_mbus_code_enum - Media bus format enumeration
+ * @pad: pad number, as reported by the media API
+ * @index: format index during enumeration
+@@ -122,5 +135,7 @@ struct v4l2_subdev_frame_interval_enum {
+ _IOWR('V', 74, struct v4l2_subdev_frame_size_enum)
+ #define VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL \
+ _IOWR('V', 75, struct v4l2_subdev_frame_interval_enum)
++#define VIDIOC_SUBDEV_G_CROP _IOWR('V', 59, struct v4l2_subdev_crop)
++#define VIDIOC_SUBDEV_S_CROP _IOWR('V', 60, struct v4l2_subdev_crop)
+
+ #endif
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index 9c8bcd3..a02663e 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -442,6 +442,10 @@ struct v4l2_subdev_pad_ops {
+ struct v4l2_subdev_format *format);
+ int (*set_fmt)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format);
++ int (*set_crop)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_crop *crop);
++ int (*get_crop)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_crop *crop);
+ };
+
+ struct v4l2_subdev_ops {
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0031-v4l-subdev-Generic-ioctl-support.patch b/extras/recipes-kernel/linux/linux-omap/media/0031-v4l-subdev-Generic-ioctl-support.patch
new file mode 100644
index 00000000..d1bac037
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0031-v4l-subdev-Generic-ioctl-support.patch
@@ -0,0 +1,46 @@
+From 3378e81670a983f084f6d8e6be654234b258e482 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Fri, 26 Feb 2010 16:23:10 +0100
+Subject: [PATCH 31/43] v4l: subdev: Generic ioctl support
+
+Instead of returning an error when receiving an ioctl call with an
+unsupported command, forward the call to the subdev core::ioctl handler.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ Documentation/video4linux/v4l2-framework.txt | 5 +++++
+ drivers/media/video/v4l2-subdev.c | 2 +-
+ 2 files changed, 6 insertions(+), 1 deletions(-)
+
+diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
+index d0fb880..1bb5f22 100644
+--- a/Documentation/video4linux/v4l2-framework.txt
++++ b/Documentation/video4linux/v4l2-framework.txt
+@@ -407,6 +407,11 @@ VIDIOC_UNSUBSCRIBE_EVENT
+ To properly support events, the poll() file operation is also
+ implemented.
+
++Private ioctls
++
++ All ioctls not in the above list are passed directly to the sub-device
++ driver through the core::ioctl operation.
++
+
+ I2C sub-device drivers
+ ----------------------
+diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
+index e706c4c..1710a64 100644
+--- a/drivers/media/video/v4l2-subdev.c
++++ b/drivers/media/video/v4l2-subdev.c
+@@ -276,7 +276,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+ }
+ #endif
+ default:
+- return -ENOIOCTLCMD;
++ return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
+ }
+
+ return 0;
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0032-v4l-Add-subdev-sensor-g_skip_frames-operation.patch b/extras/recipes-kernel/linux/linux-omap/media/0032-v4l-Add-subdev-sensor-g_skip_frames-operation.patch
new file mode 100644
index 00000000..bbfe8470
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0032-v4l-Add-subdev-sensor-g_skip_frames-operation.patch
@@ -0,0 +1,35 @@
+From 80c35f54b7d24b5f05e1e510f87e2ad1b94efede Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Tue, 16 Nov 2010 06:21:06 +0200
+Subject: [PATCH 32/43] v4l: Add subdev sensor g_skip_frames operation
+
+Some buggy sensors generate corrupt frames when the stream is started.
+This new operation return the number of corrupt frames to skip when
+starting the stream.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ include/media/v4l2-subdev.h | 4 ++++
+ 1 files changed, 4 insertions(+), 0 deletions(-)
+
+diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
+index a02663e..181de59 100644
+--- a/include/media/v4l2-subdev.h
++++ b/include/media/v4l2-subdev.h
+@@ -352,9 +352,13 @@ struct v4l2_subdev_vbi_ops {
+ * This is needed for some sensors, which always corrupt
+ * several top lines of the output image, or which send their
+ * metadata in them.
++ * @g_skip_frames: number of frames to skip at stream start. This is needed for
++ * buggy sensors that generate faulty frames when they are
++ * turned on.
+ */
+ struct v4l2_subdev_sensor_ops {
+ int (*g_skip_top_lines)(struct v4l2_subdev *sd, u32 *lines);
++ int (*g_skip_frames)(struct v4l2_subdev *sd, u32 *frames);
+ };
+
+ /*
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0033-v4l-Include-linux-videodev2.h-in-media-v4l2-ctrls.h.patch b/extras/recipes-kernel/linux/linux-omap/media/0033-v4l-Include-linux-videodev2.h-in-media-v4l2-ctrls.h.patch
new file mode 100644
index 00000000..92dfe0d3
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0033-v4l-Include-linux-videodev2.h-in-media-v4l2-ctrls.h.patch
@@ -0,0 +1,27 @@
+From 70e40e24f3da31a0c29f6f6042da9a085aa9ba7f Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Fri, 19 Nov 2010 15:20:06 +0100
+Subject: [PATCH 33/43] v4l: Include linux/videodev2.h in media/v4l2-ctrls.h
+
+The later makes extensive use of structures defined in the former.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ include/media/v4l2-ctrls.h | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
+index 9b7bea9..3b133b7 100644
+--- a/include/media/v4l2-ctrls.h
++++ b/include/media/v4l2-ctrls.h
+@@ -23,6 +23,7 @@
+
+ #include <linux/list.h>
+ #include <linux/device.h>
++#include <linux/videodev2.h>
+
+ /* forward references */
+ struct v4l2_ctrl_handler;
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0034-v4l-Fix-a-use-before-set-in-the-control-framework.patch b/extras/recipes-kernel/linux/linux-omap/media/0034-v4l-Fix-a-use-before-set-in-the-control-framework.patch
new file mode 100644
index 00000000..adf8b4d4
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0034-v4l-Fix-a-use-before-set-in-the-control-framework.patch
@@ -0,0 +1,32 @@
+From d887b7e4224fa03f080ab6ede038eee8aac4c221 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Tue, 7 Dec 2010 12:57:25 +0100
+Subject: [PATCH 34/43] v4l: Fix a use-before-set in the control framework
+
+v4l2_queryctrl sets the step value based on the control type. That would
+be fine if it used the control type stored in the V4L2 kernel control
+object, not the one stored in the userspace ioctl structure that has
+just been memset to 0. Fix this.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Acked-by: Hans Verkuil <hverkuil@xs4all.nl>
+---
+ drivers/media/video/v4l2-ctrls.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
+index 9d2502c..5f74fec 100644
+--- a/drivers/media/video/v4l2-ctrls.c
++++ b/drivers/media/video/v4l2-ctrls.c
+@@ -1338,7 +1338,7 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
+ qc->minimum = ctrl->minimum;
+ qc->maximum = ctrl->maximum;
+ qc->default_value = ctrl->default_value;
+- if (qc->type == V4L2_CTRL_TYPE_MENU)
++ if (ctrl->type == V4L2_CTRL_TYPE_MENU)
+ qc->step = 1;
+ else
+ qc->step = ctrl->step;
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0035-v4l-Add-8-bit-YUYV-on-16-bit-bus-and-SGRBG10-media-b.patch b/extras/recipes-kernel/linux/linux-omap/media/0035-v4l-Add-8-bit-YUYV-on-16-bit-bus-and-SGRBG10-media-b.patch
new file mode 100644
index 00000000..8660a148
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0035-v4l-Add-8-bit-YUYV-on-16-bit-bus-and-SGRBG10-media-b.patch
@@ -0,0 +1,60 @@
+From 4ad2d8ab7eef4bc2a482c228f334cfbf30d71855 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 1 Sep 2010 17:59:36 +0200
+Subject: [PATCH 35/43] v4l: Add 8-bit YUYV on 16-bit bus and SGRBG10 media bus pixel codes
+
+Add the following media bus format code definitions:
+
+- V4L2_MBUS_FMT_SGRBG10_1X10 for 10-bit GRBG Bayer
+- V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8 for 10-bit DPCM compressed GRBG Bayer
+- V4L2_MBUS_FMT_YUYV16_1X16 for 8-bit YUYV on 16-bit bus
+- V4L2_MBUS_FMT_UYVY16_1X16 for 8-bit UYVY on 16-bit bus
+- V4L2_MBUS_FMT_YVYU16_1X16 for 8-bit YVYU on 16-bit bus
+- V4L2_MBUS_FMT_VYUY16_1X16 for 8-bit VYUY on 16-bit bus
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ include/linux/v4l2-mediabus.h | 10 ++++++++--
+ 1 files changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
+index cccfa34..c4caca3 100644
+--- a/include/linux/v4l2-mediabus.h
++++ b/include/linux/v4l2-mediabus.h
+@@ -47,7 +47,7 @@ enum v4l2_mbus_pixelcode {
+ V4L2_MBUS_FMT_RGB565_2X8_BE = 0x1007,
+ V4L2_MBUS_FMT_RGB565_2X8_LE = 0x1008,
+
+- /* YUV (including grey) - next is 0x200f */
++ /* YUV (including grey) - next is 0x2013 */
+ V4L2_MBUS_FMT_Y8_1X8 = 0x2001,
+ V4L2_MBUS_FMT_UYVY8_1_5X8 = 0x2002,
+ V4L2_MBUS_FMT_VYUY8_1_5X8 = 0x2003,
+@@ -60,17 +60,23 @@ enum v4l2_mbus_pixelcode {
+ V4L2_MBUS_FMT_Y10_1X10 = 0x200a,
+ V4L2_MBUS_FMT_YUYV10_2X10 = 0x200b,
+ V4L2_MBUS_FMT_YVYU10_2X10 = 0x200c,
++ V4L2_MBUS_FMT_UYVY8_1X16 = 0x200f,
++ V4L2_MBUS_FMT_VYUY8_1X16 = 0x2010,
++ V4L2_MBUS_FMT_YUYV8_1X16 = 0x2011,
++ V4L2_MBUS_FMT_YVYU8_1X16 = 0x2012,
+ V4L2_MBUS_FMT_YUYV10_1X20 = 0x200d,
+ V4L2_MBUS_FMT_YVYU10_1X20 = 0x200e,
+
+- /* Bayer - next is 0x3009 */
++ /* Bayer - next is 0x300b */
+ V4L2_MBUS_FMT_SBGGR8_1X8 = 0x3001,
+ V4L2_MBUS_FMT_SGRBG8_1X8 = 0x3002,
++ V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8 = 0x3009,
+ V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE = 0x3003,
+ V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE = 0x3004,
+ V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE = 0x3005,
+ V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE = 0x3006,
+ V4L2_MBUS_FMT_SBGGR10_1X10 = 0x3007,
++ V4L2_MBUS_FMT_SGRBG10_1X10 = 0x300a,
+ V4L2_MBUS_FMT_SBGGR12_1X12 = 0x3008,
+ };
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0036-v4l-Add-remaining-RAW10-patterns-w-DPCM-pixel-code-v.patch b/extras/recipes-kernel/linux/linux-omap/media/0036-v4l-Add-remaining-RAW10-patterns-w-DPCM-pixel-code-v.patch
new file mode 100644
index 00000000..ec6c332f
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0036-v4l-Add-remaining-RAW10-patterns-w-DPCM-pixel-code-v.patch
@@ -0,0 +1,48 @@
+From a63be84f54298581d51efb8a4745747ca17a9d0d Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Fri, 3 Sep 2010 10:47:25 +0200
+Subject: [PATCH 36/43] v4l: Add remaining RAW10 patterns w DPCM pixel code variants
+
+This adds following formats:
+- V4L2_MBUS_FMT_SRGGB10_1X10
+- V4L2_MBUS_FMT_SGBRG10_1X10
+- V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8
+- V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8
+- V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8
+
+Signed-off-by: Sergio Aguirre <saaguirre@ti.com>
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ include/linux/v4l2-mediabus.h | 7 ++++++-
+ 1 files changed, 6 insertions(+), 1 deletions(-)
+
+diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
+index c4caca3..5c64924 100644
+--- a/include/linux/v4l2-mediabus.h
++++ b/include/linux/v4l2-mediabus.h
+@@ -67,16 +67,21 @@ enum v4l2_mbus_pixelcode {
+ V4L2_MBUS_FMT_YUYV10_1X20 = 0x200d,
+ V4L2_MBUS_FMT_YVYU10_1X20 = 0x200e,
+
+- /* Bayer - next is 0x300b */
++ /* Bayer - next is 0x3010 */
+ V4L2_MBUS_FMT_SBGGR8_1X8 = 0x3001,
+ V4L2_MBUS_FMT_SGRBG8_1X8 = 0x3002,
++ V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8 = 0x300b,
++ V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8 = 0x300c,
+ V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8 = 0x3009,
++ V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8 = 0x300d,
+ V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE = 0x3003,
+ V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE = 0x3004,
+ V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE = 0x3005,
+ V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE = 0x3006,
+ V4L2_MBUS_FMT_SBGGR10_1X10 = 0x3007,
++ V4L2_MBUS_FMT_SGBRG10_1X10 = 0x300e,
+ V4L2_MBUS_FMT_SGRBG10_1X10 = 0x300a,
++ V4L2_MBUS_FMT_SRGGB10_1X10 = 0x300f,
+ V4L2_MBUS_FMT_SBGGR12_1X12 = 0x3008,
+ };
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0037-v4l-Add-missing-12-bits-bayer-media-bus-formats.patch b/extras/recipes-kernel/linux/linux-omap/media/0037-v4l-Add-missing-12-bits-bayer-media-bus-formats.patch
new file mode 100644
index 00000000..5644da5f
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0037-v4l-Add-missing-12-bits-bayer-media-bus-formats.patch
@@ -0,0 +1,105 @@
+From 6585f70cdd7cbe63e6618d06a10819d31c7009fe Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Thu, 23 Dec 2010 15:14:49 +0100
+Subject: [PATCH 37/43] v4l: Add missing 12 bits bayer media bus formats
+
+Add codes and documentation for the following media bus formats:
+
+- V4L2_MBUS_FMT_SGBRG12_1X12
+- V4L2_MBUS_FMT_SGRBG12_1X12
+- V4L2_MBUS_FMT_SRGGB12_1X12
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ Documentation/DocBook/v4l/subdev-formats.xml | 51 ++++++++++++++++++++++++++
+ include/linux/v4l2-mediabus.h | 5 ++-
+ 2 files changed, 55 insertions(+), 1 deletions(-)
+
+diff --git a/Documentation/DocBook/v4l/subdev-formats.xml b/Documentation/DocBook/v4l/subdev-formats.xml
+index 0cae572..2fed9be 100644
+--- a/Documentation/DocBook/v4l/subdev-formats.xml
++++ b/Documentation/DocBook/v4l/subdev-formats.xml
+@@ -490,6 +490,57 @@
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ </row>
++ <row id="V4L2-MBUS-FMT-SGBRG12-1X12">
++ <entry>V4L2_MBUS_FMT_SGBRG12_1X12</entry>
++ <entry>0x3010</entry>
++ <entry></entry>
++ <entry>g<subscript>11</subscript></entry>
++ <entry>g<subscript>10</subscript></entry>
++ <entry>g<subscript>9</subscript></entry>
++ <entry>g<subscript>8</subscript></entry>
++ <entry>g<subscript>7</subscript></entry>
++ <entry>g<subscript>6</subscript></entry>
++ <entry>g<subscript>5</subscript></entry>
++ <entry>g<subscript>4</subscript></entry>
++ <entry>g<subscript>3</subscript></entry>
++ <entry>g<subscript>2</subscript></entry>
++ <entry>g<subscript>1</subscript></entry>
++ <entry>g<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-SGRBG12-1X12">
++ <entry>V4L2_MBUS_FMT_SGRBG12_1X12</entry>
++ <entry>0x3011</entry>
++ <entry></entry>
++ <entry>g<subscript>11</subscript></entry>
++ <entry>g<subscript>10</subscript></entry>
++ <entry>g<subscript>9</subscript></entry>
++ <entry>g<subscript>8</subscript></entry>
++ <entry>g<subscript>7</subscript></entry>
++ <entry>g<subscript>6</subscript></entry>
++ <entry>g<subscript>5</subscript></entry>
++ <entry>g<subscript>4</subscript></entry>
++ <entry>g<subscript>3</subscript></entry>
++ <entry>g<subscript>2</subscript></entry>
++ <entry>g<subscript>1</subscript></entry>
++ <entry>g<subscript>0</subscript></entry>
++ </row>
++ <row id="V4L2-MBUS-FMT-SRGGB12-1X12">
++ <entry>V4L2_MBUS_FMT_SRGGB12_1X12</entry>
++ <entry>0x3012</entry>
++ <entry></entry>
++ <entry>r<subscript>11</subscript></entry>
++ <entry>r<subscript>10</subscript></entry>
++ <entry>r<subscript>9</subscript></entry>
++ <entry>r<subscript>8</subscript></entry>
++ <entry>r<subscript>7</subscript></entry>
++ <entry>r<subscript>6</subscript></entry>
++ <entry>r<subscript>5</subscript></entry>
++ <entry>r<subscript>4</subscript></entry>
++ <entry>r<subscript>3</subscript></entry>
++ <entry>r<subscript>2</subscript></entry>
++ <entry>r<subscript>1</subscript></entry>
++ <entry>r<subscript>0</subscript></entry>
++ </row>
+ <row id="V4L2-MBUS-FMT-SGBRG10-DPCM8-1X8">
+ <entry>V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8</entry>
+ <entry>0x300c</entry>
+diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
+index 5c64924..7054a7a 100644
+--- a/include/linux/v4l2-mediabus.h
++++ b/include/linux/v4l2-mediabus.h
+@@ -67,7 +67,7 @@ enum v4l2_mbus_pixelcode {
+ V4L2_MBUS_FMT_YUYV10_1X20 = 0x200d,
+ V4L2_MBUS_FMT_YVYU10_1X20 = 0x200e,
+
+- /* Bayer - next is 0x3010 */
++ /* Bayer - next is 0x3013 */
+ V4L2_MBUS_FMT_SBGGR8_1X8 = 0x3001,
+ V4L2_MBUS_FMT_SGRBG8_1X8 = 0x3002,
+ V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8 = 0x300b,
+@@ -83,6 +83,9 @@ enum v4l2_mbus_pixelcode {
+ V4L2_MBUS_FMT_SGRBG10_1X10 = 0x300a,
+ V4L2_MBUS_FMT_SRGGB10_1X10 = 0x300f,
+ V4L2_MBUS_FMT_SBGGR12_1X12 = 0x3008,
++ V4L2_MBUS_FMT_SGBRG12_1X12 = 0x3010,
++ V4L2_MBUS_FMT_SGRBG12_1X12 = 0x3011,
++ V4L2_MBUS_FMT_SRGGB12_1X12 = 0x3012,
+ };
+
+ /**
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0038-v4l-Add-12-bits-bayer-pixel-formats.patch b/extras/recipes-kernel/linux/linux-omap/media/0038-v4l-Add-12-bits-bayer-pixel-formats.patch
new file mode 100644
index 00000000..9deb0ee3
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0038-v4l-Add-12-bits-bayer-pixel-formats.patch
@@ -0,0 +1,35 @@
+From 859b5c38e30c3d41e7987a6bb46f7d062f7e02ad Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Thu, 23 Dec 2010 15:14:50 +0100
+Subject: [PATCH 38/43] v4l: Add 12 bits bayer pixel formats
+
+Add FCCs for the following pixel formats:
+
+- V4L2_PIX_FMT_SBGGR12
+- V4L2_PIX_FMT_SGBRG12
+- V4L2_PIX_FMT_SGRBG12
+- V4L2_PIX_FMT_SRGGB12
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ include/linux/videodev2.h | 4 ++++
+ 1 files changed, 4 insertions(+), 0 deletions(-)
+
+diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
+index 5f6f470..02da9e7 100644
+--- a/include/linux/videodev2.h
++++ b/include/linux/videodev2.h
+@@ -328,6 +328,10 @@ struct v4l2_pix_format {
+ #define V4L2_PIX_FMT_SGBRG10 v4l2_fourcc('G', 'B', '1', '0') /* 10 GBGB.. RGRG.. */
+ #define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0') /* 10 GRGR.. BGBG.. */
+ #define V4L2_PIX_FMT_SRGGB10 v4l2_fourcc('R', 'G', '1', '0') /* 10 RGRG.. GBGB.. */
++#define V4L2_PIX_FMT_SBGGR12 v4l2_fourcc('B', 'G', '1', '2') /* 12 BGBG.. GRGR.. */
++#define V4L2_PIX_FMT_SGBRG12 v4l2_fourcc('G', 'B', '1', '2') /* 12 GBGB.. RGRG.. */
++#define V4L2_PIX_FMT_SGRBG12 v4l2_fourcc('B', 'A', '1', '2') /* 12 GRGR.. BGBG.. */
++#define V4L2_PIX_FMT_SRGGB12 v4l2_fourcc('R', 'G', '1', '2') /* 12 RGRG.. GBGB.. */
+ /* 10bit raw bayer DPCM compressed to 8 bits */
+ #define V4L2_PIX_FMT_SGRBG10DPCM8 v4l2_fourcc('B', 'D', '1', '0')
+ /*
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0039-ARM-OMAP3-Update-Camera-ISP-definitions-for-OMAP3630.patch b/extras/recipes-kernel/linux/linux-omap/media/0039-ARM-OMAP3-Update-Camera-ISP-definitions-for-OMAP3630.patch
new file mode 100644
index 00000000..73f40d79
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0039-ARM-OMAP3-Update-Camera-ISP-definitions-for-OMAP3630.patch
@@ -0,0 +1,99 @@
+From 0fe8d5d2b4d1e48bf2ef9b5803636dc68c91b5f2 Mon Sep 17 00:00:00 2001
+From: Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
+Date: Tue, 2 Feb 2010 16:17:33 +0200
+Subject: [PATCH 39/43] ARM: OMAP3: Update Camera ISP definitions for OMAP3630
+
+Add new/changed base address definitions and resources for
+OMAP3630 ISP.
+
+The OMAP3430 CSI2PHY block is same as the OMAP3630 CSIPHY2
+block. But the later name is chosen as it gives more symmetry
+to the names.
+
+Signed-off-by: Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
+Signed-off-by: Vimarsh Zutshi <vimarsh.zutshi@nokia.com>
+Acked-by: Tony Lindgren <tony@atomide.com>
+---
+ arch/arm/mach-omap2/devices.c | 28 ++++++++++++++++++++++++----
+ arch/arm/plat-omap/include/plat/omap34xx.h | 16 ++++++++++++----
+ 2 files changed, 36 insertions(+), 8 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
+index 381f4eb..40c64b9 100644
+--- a/arch/arm/mach-omap2/devices.c
++++ b/arch/arm/mach-omap2/devices.c
+@@ -109,13 +109,33 @@ static struct resource omap3isp_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ {
+- .start = OMAP3430_ISP_CSI2A_BASE,
+- .end = OMAP3430_ISP_CSI2A_END,
++ .start = OMAP3430_ISP_CSI2A_REGS1_BASE,
++ .end = OMAP3430_ISP_CSI2A_REGS1_END,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+- .start = OMAP3430_ISP_CSI2PHY_BASE,
+- .end = OMAP3430_ISP_CSI2PHY_END,
++ .start = OMAP3430_ISP_CSIPHY2_BASE,
++ .end = OMAP3430_ISP_CSIPHY2_END,
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .start = OMAP3630_ISP_CSI2A_REGS2_BASE,
++ .end = OMAP3630_ISP_CSI2A_REGS2_END,
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .start = OMAP3630_ISP_CSI2C_REGS1_BASE,
++ .end = OMAP3630_ISP_CSI2C_REGS1_END,
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .start = OMAP3630_ISP_CSIPHY1_BASE,
++ .end = OMAP3630_ISP_CSIPHY1_END,
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .start = OMAP3630_ISP_CSI2C_REGS2_BASE,
++ .end = OMAP3630_ISP_CSI2C_REGS2_END,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+diff --git a/arch/arm/plat-omap/include/plat/omap34xx.h b/arch/arm/plat-omap/include/plat/omap34xx.h
+index 98fc8b4..b9e8588 100644
+--- a/arch/arm/plat-omap/include/plat/omap34xx.h
++++ b/arch/arm/plat-omap/include/plat/omap34xx.h
+@@ -56,8 +56,12 @@
+ #define OMAP3430_ISP_RESZ_BASE (OMAP3430_ISP_BASE + 0x1000)
+ #define OMAP3430_ISP_SBL_BASE (OMAP3430_ISP_BASE + 0x1200)
+ #define OMAP3430_ISP_MMU_BASE (OMAP3430_ISP_BASE + 0x1400)
+-#define OMAP3430_ISP_CSI2A_BASE (OMAP3430_ISP_BASE + 0x1800)
+-#define OMAP3430_ISP_CSI2PHY_BASE (OMAP3430_ISP_BASE + 0x1970)
++#define OMAP3430_ISP_CSI2A_REGS1_BASE (OMAP3430_ISP_BASE + 0x1800)
++#define OMAP3430_ISP_CSIPHY2_BASE (OMAP3430_ISP_BASE + 0x1970)
++#define OMAP3630_ISP_CSI2A_REGS2_BASE (OMAP3430_ISP_BASE + 0x19C0)
++#define OMAP3630_ISP_CSI2C_REGS1_BASE (OMAP3430_ISP_BASE + 0x1C00)
++#define OMAP3630_ISP_CSIPHY1_BASE (OMAP3430_ISP_BASE + 0x1D70)
++#define OMAP3630_ISP_CSI2C_REGS2_BASE (OMAP3430_ISP_BASE + 0x1DC0)
+
+ #define OMAP3430_ISP_END (OMAP3430_ISP_BASE + 0x06F)
+ #define OMAP3430_ISP_CBUFF_END (OMAP3430_ISP_CBUFF_BASE + 0x077)
+@@ -69,8 +73,12 @@
+ #define OMAP3430_ISP_RESZ_END (OMAP3430_ISP_RESZ_BASE + 0x0AB)
+ #define OMAP3430_ISP_SBL_END (OMAP3430_ISP_SBL_BASE + 0x0FB)
+ #define OMAP3430_ISP_MMU_END (OMAP3430_ISP_MMU_BASE + 0x06F)
+-#define OMAP3430_ISP_CSI2A_END (OMAP3430_ISP_CSI2A_BASE + 0x16F)
+-#define OMAP3430_ISP_CSI2PHY_END (OMAP3430_ISP_CSI2PHY_BASE + 0x007)
++#define OMAP3430_ISP_CSI2A_REGS1_END (OMAP3430_ISP_CSI2A_REGS1_BASE + 0x16F)
++#define OMAP3430_ISP_CSIPHY2_END (OMAP3430_ISP_CSIPHY2_BASE + 0x00B)
++#define OMAP3630_ISP_CSI2A_REGS2_END (OMAP3630_ISP_CSI2A_REGS2_BASE + 0x3F)
++#define OMAP3630_ISP_CSI2C_REGS1_END (OMAP3630_ISP_CSI2C_REGS1_BASE + 0x16F)
++#define OMAP3630_ISP_CSIPHY1_END (OMAP3630_ISP_CSIPHY1_BASE + 0x00B)
++#define OMAP3630_ISP_CSI2C_REGS2_END (OMAP3630_ISP_CSI2C_REGS2_BASE + 0x3F)
+
+ #define OMAP34XX_HSUSB_OTG_BASE (L4_34XX_BASE + 0xAB000)
+ #define OMAP34XX_USBTLL_BASE (L4_34XX_BASE + 0x62000)
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0040-omap3-Remove-unusued-ISP-CBUFF-resource.patch b/extras/recipes-kernel/linux/linux-omap/media/0040-omap3-Remove-unusued-ISP-CBUFF-resource.patch
new file mode 100644
index 00000000..d48e0e60
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0040-omap3-Remove-unusued-ISP-CBUFF-resource.patch
@@ -0,0 +1,32 @@
+From 70b39450b2de8e96504332730c9b00c663cfeaf9 Mon Sep 17 00:00:00 2001
+From: Sergio Aguirre <saaguirre@ti.com>
+Date: Mon, 15 Nov 2010 08:29:56 -0600
+Subject: [PATCH 40/43] omap3: Remove unusued ISP CBUFF resource
+
+The ISP CBUFF module isn't use, its resource isn't needed.
+
+Signed-off-by: Sergio Aguirre <saaguirre@ti.com>
+Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ arch/arm/mach-omap2/devices.c | 5 -----
+ 1 files changed, 0 insertions(+), 5 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
+index 40c64b9..60cb86f 100644
+--- a/arch/arm/mach-omap2/devices.c
++++ b/arch/arm/mach-omap2/devices.c
+@@ -69,11 +69,6 @@ static struct resource omap3isp_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ {
+- .start = OMAP3430_ISP_CBUFF_BASE,
+- .end = OMAP3430_ISP_CBUFF_END,
+- .flags = IORESOURCE_MEM,
+- },
+- {
+ .start = OMAP3430_ISP_CCP2_BASE,
+ .end = OMAP3430_ISP_CCP2_END,
+ .flags = IORESOURCE_MEM,
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0041-omap3-Add-function-to-register-omap3isp-platform-dev.patch b/extras/recipes-kernel/linux/linux-omap/media/0041-omap3-Add-function-to-register-omap3isp-platform-dev.patch
new file mode 100644
index 00000000..8bcbd73c
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0041-omap3-Add-function-to-register-omap3isp-platform-dev.patch
@@ -0,0 +1,91 @@
+From d59f7c080e1c0d35a71f788350b619e76cee5033 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Mon, 14 Dec 2009 13:09:07 +0200
+Subject: [PATCH 41/43] omap3: Add function to register omap3isp platform device structure
+
+The omap3isp platform device requires platform data. Instead of
+registering the device in omap2_init_devices(), export an
+omap3_init_camera() function to fill the device structure with the
+platform data pointer and register the device.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Acked-by: Tony Lindgren <tony@atomide.com>
+---
+ arch/arm/mach-omap2/devices.c | 20 +++++++++++---------
+ arch/arm/mach-omap2/devices.h | 17 +++++++++++++++++
+ 2 files changed, 28 insertions(+), 9 deletions(-)
+ create mode 100644 arch/arm/mach-omap2/devices.h
+
+diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
+index 60cb86f..9b243be 100644
+--- a/arch/arm/mach-omap2/devices.c
++++ b/arch/arm/mach-omap2/devices.c
+@@ -34,6 +34,8 @@
+ #include "mux.h"
+ #include "control.h"
+
++#include "devices.h"
++
+ #if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE)
+
+ static struct resource cam_resources[] = {
+@@ -59,8 +61,11 @@ static inline void omap_init_camera(void)
+ {
+ platform_device_register(&omap_cam_device);
+ }
+-
+-#elif defined(CONFIG_VIDEO_OMAP3) || defined(CONFIG_VIDEO_OMAP3_MODULE)
++#else
++static inline void omap_init_camera(void)
++{
++}
++#endif
+
+ static struct resource omap3isp_resources[] = {
+ {
+@@ -146,15 +151,12 @@ static struct platform_device omap3isp_device = {
+ .resource = omap3isp_resources,
+ };
+
+-static inline void omap_init_camera(void)
+-{
+- platform_device_register(&omap3isp_device);
+-}
+-#else
+-static inline void omap_init_camera(void)
++int omap3_init_camera(void *pdata)
+ {
++ omap3isp_device.dev.platform_data = pdata;
++ return platform_device_register(&omap3isp_device);
+ }
+-#endif
++EXPORT_SYMBOL_GPL(omap3_init_camera);
+
+ #if defined(CONFIG_OMAP_MBOX_FWK) || defined(CONFIG_OMAP_MBOX_FWK_MODULE)
+
+diff --git a/arch/arm/mach-omap2/devices.h b/arch/arm/mach-omap2/devices.h
+new file mode 100644
+index 0000000..12ddb8a
+--- /dev/null
++++ b/arch/arm/mach-omap2/devices.h
+@@ -0,0 +1,17 @@
++/*
++ * arch/arm/mach-omap2/devices.h
++ *
++ * OMAP2 platform device setup/initialization
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#ifndef __ARCH_ARM_MACH_OMAP_DEVICES_H
++#define __ARCH_ARM_MACH_OMAP_DEVICES_H
++
++int omap3_init_camera(void *pdata);
++
++#endif
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0042-omap2-Fix-camera-resources-for-multiomap.patch b/extras/recipes-kernel/linux/linux-omap/media/0042-omap2-Fix-camera-resources-for-multiomap.patch
new file mode 100644
index 00000000..273d6d05
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0042-omap2-Fix-camera-resources-for-multiomap.patch
@@ -0,0 +1,70 @@
+From 5cc262328a97b1d048ae42234909ac33c2fc342c Mon Sep 17 00:00:00 2001
+From: Sergio Aguirre <saaguirre@ti.com>
+Date: Mon, 15 Nov 2010 08:29:54 -0600
+Subject: [PATCH 42/43] omap2: Fix camera resources for multiomap
+
+Make sure the kernel can be compiled with both OMAP2 and OMAP3 camera
+support linked in, and give public symbols proper omap2/omap3 prefixes.
+
+Signed-off-by: Sergio Aguirre <saaguirre@ti.com>
+Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ arch/arm/mach-omap2/devices.c | 25 ++++++++++++-------------
+ 1 files changed, 12 insertions(+), 13 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
+index 9b243be..c132c65 100644
+--- a/arch/arm/mach-omap2/devices.c
++++ b/arch/arm/mach-omap2/devices.c
+@@ -38,7 +38,7 @@
+
+ #if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE)
+
+-static struct resource cam_resources[] = {
++static struct resource omap2cam_resources[] = {
+ {
+ .start = OMAP24XX_CAMERA_BASE,
+ .end = OMAP24XX_CAMERA_BASE + 0xfff,
+@@ -50,21 +50,12 @@ static struct resource cam_resources[] = {
+ }
+ };
+
+-static struct platform_device omap_cam_device = {
++static struct platform_device omap2cam_device = {
+ .name = "omap24xxcam",
+ .id = -1,
+- .num_resources = ARRAY_SIZE(cam_resources),
+- .resource = cam_resources,
++ .num_resources = ARRAY_SIZE(omap2cam_resources),
++ .resource = omap2cam_resources,
+ };
+-
+-static inline void omap_init_camera(void)
+-{
+- platform_device_register(&omap_cam_device);
+-}
+-#else
+-static inline void omap_init_camera(void)
+-{
+-}
+ #endif
+
+ static struct resource omap3isp_resources[] = {
+@@ -158,6 +149,14 @@ int omap3_init_camera(void *pdata)
+ }
+ EXPORT_SYMBOL_GPL(omap3_init_camera);
+
++static inline void omap_init_camera(void)
++{
++#if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE)
++ if (cpu_is_omap24xx())
++ platform_device_register(&omap2cam_device);
++#endif
++}
++
+ #if defined(CONFIG_OMAP_MBOX_FWK) || defined(CONFIG_OMAP_MBOX_FWK_MODULE)
+
+ #define MBOX_REG_SIZE 0x120
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0043-OMAP3-ISP-driver.patch b/extras/recipes-kernel/linux/linux-omap/media/0043-OMAP3-ISP-driver.patch
new file mode 100644
index 00000000..b4e97848
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0043-OMAP3-ISP-driver.patch
@@ -0,0 +1,21513 @@
+From f12978691d5189949c9296bceb43c5b272c9c03c Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Tue, 17 Feb 2009 09:23:45 -0600
+Subject: [PATCH 43/43] OMAP3 ISP driver
+
+Last 10 commits from upstream are
+
+omap3isp: Autoidle enabled for ISP
+omap3isp: enable AUTOIDLE through module parameter
+omap3isp: preview: Fix defect correct config function
+omap3isp: video: Replace BUG with WARN_ON in case of buffer queue error
+omap3isp: Add module device table
+omap3isp: csi2: Print registers on stream on
+v4l: OMAP3 ISP CCDC: Add support for 8bit greyscale sensors
+omap3isp: ccdc: Set default DC subtract value to 0
+omap3isp: Prefix all public symbols with omap3isp_
+omap3isp: Fix dependencies and mark as experimental
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Sakari Ailus <sakari.ailus@nokia.com>
+Signed-off-by: David Cohen <david.cohen@nokia.com>
+Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
+Signed-off-by: Vimarsh Zutshi <vimarsh.zutshi@nokia.com>
+Signed-off-by: Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
+Signed-off-by: Sergio Aguirre <saaguirre@ti.com>
+Signed-off-by: Antti Koskipaa <antti.koskipaa@nokia.com>
+Signed-off-by: Ivan T. Ivanov <iivanov@mm-sol.com>
+Signed-off-by: RaniSuneela <r-m@ti.com>
+Signed-off-by: Atanas Filipov <afilipov@mm-sol.com>
+Signed-off-by: Gjorgji Rosikopulos <grosikopulos@mm-sol.com>
+Signed-off-by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+Signed-off-by: Nayden Kanchev <nkanchev@mm-sol.com>
+Signed-off-by: Phil Carmody <ext-phil.2.carmody@nokia.com>
+Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
+Signed-off-by: Dominic Curran <dcurran@ti.com>
+Signed-off-by: Ilkka Myllyperkio <ilkka.myllyperkio@sofica.fi>
+Signed-off-by: Pallavi Kulkarni <p-kulkarni@ti.com>
+Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
+---
+ drivers/media/video/Kconfig | 13 +
+ drivers/media/video/Makefile | 2 +
+ drivers/media/video/isp/Makefile | 13 +
+ drivers/media/video/isp/cfa_coef_table.h | 601 +++++++
+ drivers/media/video/isp/gamma_table.h | 90 +
+ drivers/media/video/isp/isp.c | 2221 +++++++++++++++++++++++++
+ drivers/media/video/isp/isp.h | 427 +++++
+ drivers/media/video/isp/ispccdc.c | 2280 ++++++++++++++++++++++++++
+ drivers/media/video/isp/ispccdc.h | 223 +++
+ drivers/media/video/isp/ispccp2.c | 1189 ++++++++++++++
+ drivers/media/video/isp/ispccp2.h | 101 ++
+ drivers/media/video/isp/ispcsi2.c | 1332 +++++++++++++++
+ drivers/media/video/isp/ispcsi2.h | 169 ++
+ drivers/media/video/isp/ispcsiphy.c | 247 +++
+ drivers/media/video/isp/ispcsiphy.h | 74 +
+ drivers/media/video/isp/isph3a.h | 117 ++
+ drivers/media/video/isp/isph3a_aewb.c | 374 +++++
+ drivers/media/video/isp/isph3a_af.c | 429 +++++
+ drivers/media/video/isp/isphist.c | 520 ++++++
+ drivers/media/video/isp/isphist.h | 40 +
+ drivers/media/video/isp/isppreview.c | 2120 ++++++++++++++++++++++++
+ drivers/media/video/isp/isppreview.h | 214 +++
+ drivers/media/video/isp/ispqueue.c | 1136 +++++++++++++
+ drivers/media/video/isp/ispqueue.h | 185 +++
+ drivers/media/video/isp/ispreg.h | 1589 ++++++++++++++++++
+ drivers/media/video/isp/ispresizer.c | 1710 +++++++++++++++++++
+ drivers/media/video/isp/ispresizer.h | 150 ++
+ drivers/media/video/isp/ispstat.c | 1100 +++++++++++++
+ drivers/media/video/isp/ispstat.h | 169 ++
+ drivers/media/video/isp/ispvideo.c | 1264 ++++++++++++++
+ drivers/media/video/isp/ispvideo.h | 202 +++
+ drivers/media/video/isp/luma_enhance_table.h | 154 ++
+ drivers/media/video/isp/noise_filter_table.h | 90 +
+ include/linux/Kbuild | 1 +
+ include/linux/omap3isp.h | 631 +++++++
+ 35 files changed, 21177 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/media/video/isp/Makefile
+ create mode 100644 drivers/media/video/isp/cfa_coef_table.h
+ create mode 100644 drivers/media/video/isp/gamma_table.h
+ create mode 100644 drivers/media/video/isp/isp.c
+ create mode 100644 drivers/media/video/isp/isp.h
+ create mode 100644 drivers/media/video/isp/ispccdc.c
+ create mode 100644 drivers/media/video/isp/ispccdc.h
+ create mode 100644 drivers/media/video/isp/ispccp2.c
+ create mode 100644 drivers/media/video/isp/ispccp2.h
+ create mode 100644 drivers/media/video/isp/ispcsi2.c
+ create mode 100644 drivers/media/video/isp/ispcsi2.h
+ create mode 100644 drivers/media/video/isp/ispcsiphy.c
+ create mode 100644 drivers/media/video/isp/ispcsiphy.h
+ create mode 100644 drivers/media/video/isp/isph3a.h
+ create mode 100644 drivers/media/video/isp/isph3a_aewb.c
+ create mode 100644 drivers/media/video/isp/isph3a_af.c
+ create mode 100644 drivers/media/video/isp/isphist.c
+ create mode 100644 drivers/media/video/isp/isphist.h
+ create mode 100644 drivers/media/video/isp/isppreview.c
+ create mode 100644 drivers/media/video/isp/isppreview.h
+ create mode 100644 drivers/media/video/isp/ispqueue.c
+ create mode 100644 drivers/media/video/isp/ispqueue.h
+ create mode 100644 drivers/media/video/isp/ispreg.h
+ create mode 100644 drivers/media/video/isp/ispresizer.c
+ create mode 100644 drivers/media/video/isp/ispresizer.h
+ create mode 100644 drivers/media/video/isp/ispstat.c
+ create mode 100644 drivers/media/video/isp/ispstat.h
+ create mode 100644 drivers/media/video/isp/ispvideo.c
+ create mode 100644 drivers/media/video/isp/ispvideo.h
+ create mode 100644 drivers/media/video/isp/luma_enhance_table.h
+ create mode 100644 drivers/media/video/isp/noise_filter_table.h
+ create mode 100644 include/linux/omap3isp.h
+
+diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
+index 6830d28..60c2bf0 100644
+--- a/drivers/media/video/Kconfig
++++ b/drivers/media/video/Kconfig
+@@ -722,6 +722,19 @@ config VIDEO_VIA_CAMERA
+ Chrome9 chipsets. Currently only tested on OLPC xo-1.5 systems
+ with ov7670 sensors.
+
++config VIDEO_OMAP3
++ tristate "OMAP 3 Camera support (EXPERIMENTAL)"
++ select OMAP_IOMMU
++ depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 && EXPERIMENTAL
++ ---help---
++ Driver for an OMAP 3 camera controller.
++
++config VIDEO_OMAP3_DEBUG
++ bool "OMAP 3 Camera debug messages"
++ depends on VIDEO_OMAP3
++ ---help---
++ Enable debug messages on OMAP 3 camera controller driver.
++
+ config SOC_CAMERA
+ tristate "SoC camera support"
+ depends on VIDEO_V4L2 && HAS_DMA && I2C
+diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
+index adc1bd5..bd2f556 100644
+--- a/drivers/media/video/Makefile
++++ b/drivers/media/video/Makefile
+@@ -124,6 +124,8 @@ obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
+
+ obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o
+
++obj-$(CONFIG_VIDEO_OMAP3) += isp/
++
+ obj-$(CONFIG_USB_DABUSB) += dabusb.o
+ obj-$(CONFIG_USB_SE401) += se401.o
+ obj-$(CONFIG_USB_ZR364XX) += zr364xx.o
+diff --git a/drivers/media/video/isp/Makefile b/drivers/media/video/isp/Makefile
+new file mode 100644
+index 0000000..b1b3447
+--- /dev/null
++++ b/drivers/media/video/isp/Makefile
+@@ -0,0 +1,13 @@
++# Makefile for OMAP3 ISP driver
++
++ifdef CONFIG_VIDEO_OMAP3_DEBUG
++EXTRA_CFLAGS += -DDEBUG
++endif
++
++omap3-isp-objs += \
++ isp.o ispqueue.o ispvideo.o \
++ ispcsiphy.o ispccp2.o ispcsi2.o \
++ ispccdc.o isppreview.o ispresizer.o \
++ ispstat.o isph3a_aewb.o isph3a_af.o isphist.o
++
++obj-$(CONFIG_VIDEO_OMAP3) += omap3-isp.o
+diff --git a/drivers/media/video/isp/cfa_coef_table.h b/drivers/media/video/isp/cfa_coef_table.h
+new file mode 100644
+index 0000000..4ec3fff
+--- /dev/null
++++ b/drivers/media/video/isp/cfa_coef_table.h
+@@ -0,0 +1,601 @@
++/*
++ * cfa_coef_table.h
++ *
++ * TI OMAP3 ISP - CFA coefficients table
++ *
++ * Copyright (C) 2009-2010 Nokia Corporation
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++244,
++0,
++247,
++0,
++12,
++27,
++36,
++247,
++250,
++0,
++27,
++0,
++4,
++250,
++12,
++244,
++248,
++0,
++0,
++0,
++0,
++40,
++0,
++0,
++244,
++12,
++250,
++4,
++0,
++27,
++0,
++250,
++247,
++36,
++27,
++12,
++0,
++247,
++0,
++244,
++0,
++0,
++40,
++0,
++0,
++0,
++0,
++248,
++244,
++0,
++247,
++0,
++12,
++27,
++36,
++247,
++250,
++0,
++27,
++0,
++4,
++250,
++12,
++244,
++248,
++0,
++0,
++0,
++0,
++40,
++0,
++0,
++244,
++12,
++250,
++4,
++0,
++27,
++0,
++250,
++247,
++36,
++27,
++12,
++0,
++247,
++0,
++244,
++0,
++0,
++40,
++0,
++0,
++0,
++0,
++248,
++244,
++0,
++247,
++0,
++12,
++27,
++36,
++247,
++250,
++0,
++27,
++0,
++4,
++250,
++12,
++244,
++248,
++0,
++0,
++0,
++0,
++40,
++0,
++0,
++244,
++12,
++250,
++4,
++0,
++27,
++0,
++250,
++247,
++36,
++27,
++12,
++0,
++247,
++0,
++244,
++0,
++0,
++40,
++0,
++0,
++0,
++0,
++248,
++0,
++247,
++0,
++244,
++247,
++36,
++27,
++12,
++0,
++27,
++0,
++250,
++244,
++12,
++250,
++4,
++0,
++0,
++0,
++248,
++0,
++0,
++40,
++0,
++4,
++250,
++12,
++244,
++250,
++0,
++27,
++0,
++12,
++27,
++36,
++247,
++244,
++0,
++247,
++0,
++0,
++40,
++0,
++0,
++248,
++0,
++0,
++0,
++0,
++247,
++0,
++244,
++247,
++36,
++27,
++12,
++0,
++27,
++0,
++250,
++244,
++12,
++250,
++4,
++0,
++0,
++0,
++248,
++0,
++0,
++40,
++0,
++4,
++250,
++12,
++244,
++250,
++0,
++27,
++0,
++12,
++27,
++36,
++247,
++244,
++0,
++247,
++0,
++0,
++40,
++0,
++0,
++248,
++0,
++0,
++0,
++0,
++247,
++0,
++244,
++247,
++36,
++27,
++12,
++0,
++27,
++0,
++250,
++244,
++12,
++250,
++4,
++0,
++0,
++0,
++248,
++0,
++0,
++40,
++0,
++4,
++250,
++12,
++244,
++250,
++0,
++27,
++0,
++12,
++27,
++36,
++247,
++244,
++0,
++247,
++0,
++0,
++40,
++0,
++0,
++248,
++0,
++0,
++0,
++4,
++250,
++12,
++244,
++250,
++0,
++27,
++0,
++12,
++27,
++36,
++247,
++244,
++0,
++247,
++0,
++0,
++0,
++0,
++248,
++0,
++0,
++40,
++0,
++0,
++247,
++0,
++244,
++247,
++36,
++27,
++12,
++0,
++27,
++0,
++250,
++244,
++12,
++250,
++4,
++0,
++40,
++0,
++0,
++248,
++0,
++0,
++0,
++4,
++250,
++12,
++244,
++250,
++0,
++27,
++0,
++12,
++27,
++36,
++247,
++244,
++0,
++247,
++0,
++0,
++0,
++0,
++248,
++0,
++0,
++40,
++0,
++0,
++247,
++0,
++244,
++247,
++36,
++27,
++12,
++0,
++27,
++0,
++250,
++244,
++12,
++250,
++4,
++0,
++40,
++0,
++0,
++248,
++0,
++0,
++0,
++4,
++250,
++12,
++244,
++250,
++0,
++27,
++0,
++12,
++27,
++36,
++247,
++244,
++0,
++247,
++0,
++0,
++0,
++0,
++248,
++0,
++0,
++40,
++0,
++0,
++247,
++0,
++244,
++247,
++36,
++27,
++12,
++0,
++27,
++0,
++250,
++244,
++12,
++250,
++4,
++0,
++40,
++0,
++0,
++248,
++0,
++0,
++0,
++244,
++12,
++250,
++4,
++0,
++27,
++0,
++250,
++247,
++36,
++27,
++12,
++0,
++247,
++0,
++244,
++248,
++0,
++0,
++0,
++0,
++40,
++0,
++0,
++244,
++0,
++247,
++0,
++12,
++27,
++36,
++247,
++250,
++0,
++27,
++0,
++4,
++250,
++12,
++244,
++0,
++0,
++40,
++0,
++0,
++0,
++0,
++248,
++244,
++12,
++250,
++4,
++0,
++27,
++0,
++250,
++247,
++36,
++27,
++12,
++0,
++247,
++0,
++244,
++248,
++0,
++0,
++0,
++0,
++40,
++0,
++0,
++244,
++0,
++247,
++0,
++12,
++27,
++36,
++247,
++250,
++0,
++27,
++0,
++4,
++250,
++12,
++244,
++0,
++0,
++40,
++0,
++0,
++0,
++0,
++248,
++244,
++12,
++250,
++4,
++0,
++27,
++0,
++250,
++247,
++36,
++27,
++12,
++0,
++247,
++0,
++244,
++248,
++0,
++0,
++0,
++0,
++40,
++0,
++0,
++244,
++0,
++247,
++0,
++12,
++27,
++36,
++247,
++250,
++0,
++27,
++0,
++4,
++250,
++12,
++244,
++0,
++0,
++40,
++0,
++0,
++0,
++0,
++248
+diff --git a/drivers/media/video/isp/gamma_table.h b/drivers/media/video/isp/gamma_table.h
+new file mode 100644
+index 0000000..c2f7ec1
+--- /dev/null
++++ b/drivers/media/video/isp/gamma_table.h
+@@ -0,0 +1,90 @@
++/*
++ * gamma_table.h
++ *
++ * TI OMAP3 ISP - Default gamma table for all components
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc.
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++ 0, 0, 1, 2, 3, 3, 4, 5, 6, 8, 10, 12, 14, 16, 18, 20,
++ 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 36, 37, 39, 40, 41, 42,
++ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 52, 53, 54, 55, 56, 57,
++ 58, 59, 60, 61, 62, 63, 63, 64, 65, 66, 66, 67, 68, 69, 69, 70,
++ 71, 72, 72, 73, 74, 75, 75, 76, 77, 78, 78, 79, 80, 81, 81, 82,
++ 83, 84, 84, 85, 86, 87, 88, 88, 89, 90, 91, 91, 92, 93, 94, 94,
++ 95, 96, 97, 97, 98, 98, 99, 99, 100, 100, 101, 101, 102, 103, 104, 104,
++105, 106, 107, 108, 108, 109, 110, 111, 111, 112, 113, 114, 114, 115, 116, 117,
++117, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 123, 124, 124, 125, 125,
++126, 126, 127, 127, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132, 133, 133,
++134, 134, 135, 135, 136, 136, 137, 137, 138, 138, 139, 139, 140, 140, 141, 141,
++142, 142, 143, 143, 144, 144, 145, 145, 146, 146, 147, 147, 148, 148, 149, 149,
++150, 150, 151, 151, 152, 152, 153, 153, 153, 153, 154, 154, 154, 154, 155, 155,
++156, 156, 157, 157, 158, 158, 158, 159, 159, 159, 160, 160, 160, 161, 161, 162,
++162, 163, 163, 164, 164, 164, 164, 165, 165, 165, 165, 166, 166, 167, 167, 168,
++168, 169, 169, 170, 170, 170, 170, 171, 171, 171, 171, 172, 172, 173, 173, 174,
++174, 175, 175, 176, 176, 176, 176, 177, 177, 177, 177, 178, 178, 178, 178, 179,
++179, 179, 179, 180, 180, 180, 180, 181, 181, 181, 181, 182, 182, 182, 182, 183,
++183, 183, 183, 184, 184, 184, 184, 185, 185, 185, 185, 186, 186, 186, 186, 187,
++187, 187, 187, 188, 188, 188, 188, 189, 189, 189, 189, 190, 190, 190, 190, 191,
++191, 191, 191, 192, 192, 192, 192, 193, 193, 193, 193, 194, 194, 194, 194, 195,
++195, 195, 195, 196, 196, 196, 196, 197, 197, 197, 197, 198, 198, 198, 198, 199,
++199, 199, 199, 200, 200, 200, 200, 201, 201, 201, 201, 202, 202, 202, 203, 203,
++203, 203, 204, 204, 204, 204, 205, 205, 205, 205, 206, 206, 206, 206, 207, 207,
++207, 207, 208, 208, 208, 208, 209, 209, 209, 209, 210, 210, 210, 210, 210, 210,
++210, 210, 210, 210, 210, 210, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211,
++211, 212, 212, 212, 212, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213,
++213, 214, 214, 214, 214, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215,
++216, 216, 216, 216, 217, 217, 217, 217, 218, 218, 218, 218, 219, 219, 219, 219,
++219, 219, 219, 219, 219, 219, 219, 219, 220, 220, 220, 220, 221, 221, 221, 221,
++221, 221, 221, 221, 221, 221, 221, 222, 222, 222, 222, 223, 223, 223, 223, 223,
++223, 223, 223, 223, 223, 223, 223, 224, 224, 224, 224, 225, 225, 225, 225, 225,
++225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 226, 226,
++226, 226, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 228, 228,
++228, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 230, 230, 230,
++230, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 232, 232, 232,
++232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232,
++233, 233, 233, 233, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 235,
++235, 235, 235, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236,
++236, 236, 236, 236, 236, 236, 237, 237, 237, 237, 238, 238, 238, 238, 238, 238,
++238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238,
++238, 238, 238, 238, 238, 239, 239, 239, 239, 240, 240, 240, 240, 240, 240, 240,
++240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
++240, 240, 240, 240, 241, 241, 241, 241, 242, 242, 242, 242, 242, 242, 242, 242,
++242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242,
++242, 242, 243, 243, 243, 243, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244,
++244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244,
++244, 245, 245, 245, 245, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246,
++246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246,
++246, 246, 246, 246, 246, 246, 246, 247, 247, 247, 247, 248, 248, 248, 248, 248,
++248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
++248, 248, 248, 248, 248, 248, 249, 249, 249, 249, 250, 250, 250, 250, 250, 250,
++250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
++250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
++250, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 252, 252, 252, 252,
++252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252,
++252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252,
++252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252,
++252, 252, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 253,
++253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253,
++253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253,
++253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253,
++253, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
++255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+diff --git a/drivers/media/video/isp/isp.c b/drivers/media/video/isp/isp.c
+new file mode 100644
+index 0000000..6f8527c
+--- /dev/null
++++ b/drivers/media/video/isp/isp.c
+@@ -0,0 +1,2221 @@
++/*
++ * isp.c
++ *
++ * TI OMAP3 ISP - Core
++ *
++ * Copyright (C) 2006-2010 Nokia Corporation
++ * Copyright (C) 2007-2009 Texas Instruments, Inc.
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * Contributors:
++ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@nokia.com>
++ * David Cohen <david.cohen@nokia.com>
++ * Stanimir Varbanov <svarbanov@mm-sol.com>
++ * Vimarsh Zutshi <vimarsh.zutshi@nokia.com>
++ * Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
++ * Sergio Aguirre <saaguirre@ti.com>
++ * Antti Koskipaa <antti.koskipaa@nokia.com>
++ * Ivan T. Ivanov <iivanov@mm-sol.com>
++ * RaniSuneela <r-m@ti.com>
++ * Atanas Filipov <afilipov@mm-sol.com>
++ * Gjorgji Rosikopulos <grosikopulos@mm-sol.com>
++ * Hiroshi DOYU <hiroshi.doyu@nokia.com>
++ * Nayden Kanchev <nkanchev@mm-sol.com>
++ * Phil Carmody <ext-phil.2.carmody@nokia.com>
++ * Artem Bityutskiy <artem.bityutskiy@nokia.com>
++ * Dominic Curran <dcurran@ti.com>
++ * Ilkka Myllyperkio <ilkka.myllyperkio@sofica.fi>
++ * Pallavi Kulkarni <p-kulkarni@ti.com>
++ * Vaibhav Hiremath <hvaibhav@ti.com>
++ * Mohit Jalori <mjalori@ti.com>
++ * Sameer Venkatraman <sameerv@ti.com>
++ * Senthilvadivu Guruswamy <svadivu@ti.com>
++ * Thara Gopinath <thara@ti.com>
++ * Toni Leinonen <toni.leinonen@nokia.com>
++ * Troy Laramy <t-laramy@ti.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#include <asm/cacheflush.h>
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
++#include <linux/i2c.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/regulator/consumer.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/vmalloc.h>
++
++#include <media/v4l2-common.h>
++#include <media/v4l2-device.h>
++
++#include "isp.h"
++#include "ispreg.h"
++#include "ispccdc.h"
++#include "isppreview.h"
++#include "ispresizer.h"
++#include "ispcsi2.h"
++#include "ispccp2.h"
++#include "isph3a.h"
++#include "isphist.h"
++
++static unsigned int autoidle;
++module_param(autoidle, int, 0444);
++MODULE_PARM_DESC(autoidle, "Enable OMAP3ISP AUTOIDLE support");
++
++static void isp_save_ctx(struct isp_device *isp);
++
++static void isp_restore_ctx(struct isp_device *isp);
++
++static const struct isp_res_mapping isp_res_maps[] = {
++ {
++ .isp_rev = ISP_REVISION_2_0,
++ .map = 1 << OMAP3_ISP_IOMEM_MAIN |
++ 1 << OMAP3_ISP_IOMEM_CCP2 |
++ 1 << OMAP3_ISP_IOMEM_CCDC |
++ 1 << OMAP3_ISP_IOMEM_HIST |
++ 1 << OMAP3_ISP_IOMEM_H3A |
++ 1 << OMAP3_ISP_IOMEM_PREV |
++ 1 << OMAP3_ISP_IOMEM_RESZ |
++ 1 << OMAP3_ISP_IOMEM_SBL |
++ 1 << OMAP3_ISP_IOMEM_CSI2A_REGS1 |
++ 1 << OMAP3_ISP_IOMEM_CSIPHY2,
++ },
++ {
++ .isp_rev = ISP_REVISION_15_0,
++ .map = 1 << OMAP3_ISP_IOMEM_MAIN |
++ 1 << OMAP3_ISP_IOMEM_CCP2 |
++ 1 << OMAP3_ISP_IOMEM_CCDC |
++ 1 << OMAP3_ISP_IOMEM_HIST |
++ 1 << OMAP3_ISP_IOMEM_H3A |
++ 1 << OMAP3_ISP_IOMEM_PREV |
++ 1 << OMAP3_ISP_IOMEM_RESZ |
++ 1 << OMAP3_ISP_IOMEM_SBL |
++ 1 << OMAP3_ISP_IOMEM_CSI2A_REGS1 |
++ 1 << OMAP3_ISP_IOMEM_CSIPHY2 |
++ 1 << OMAP3_ISP_IOMEM_CSI2A_REGS2 |
++ 1 << OMAP3_ISP_IOMEM_CSI2C_REGS1 |
++ 1 << OMAP3_ISP_IOMEM_CSIPHY1 |
++ 1 << OMAP3_ISP_IOMEM_CSI2C_REGS2,
++ },
++};
++
++/* Structure for saving/restoring ISP module registers */
++static struct isp_reg isp_reg_list[] = {
++ {OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG, 0},
++ {OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, 0},
++ {OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, 0},
++ {0, ISP_TOK_TERM, 0}
++};
++
++/*
++ * omap3isp_flush - Post pending L3 bus writes by doing a register readback
++ * @isp: OMAP3 ISP device
++ *
++ * In order to force posting of pending writes, we need to write and
++ * readback the same register, in this case the revision register.
++ *
++ * See this link for reference:
++ * http://www.mail-archive.com/linux-omap@vger.kernel.org/msg08149.html
++ */
++void omap3isp_flush(struct isp_device *isp)
++{
++ isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
++ isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
++}
++
++/*
++ * isp_enable_interrupts - Enable ISP interrupts.
++ * @isp: OMAP3 ISP device
++ */
++static void isp_enable_interrupts(struct isp_device *isp)
++{
++ static const u32 irq = IRQ0ENABLE_CSIA_IRQ
++ | IRQ0ENABLE_CSIB_IRQ
++ | IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ
++ | IRQ0ENABLE_CCDC_LSC_DONE_IRQ
++ | IRQ0ENABLE_CCDC_VD0_IRQ
++ | IRQ0ENABLE_CCDC_VD1_IRQ
++ | IRQ0ENABLE_HS_VS_IRQ
++ | IRQ0ENABLE_HIST_DONE_IRQ
++ | IRQ0ENABLE_H3A_AWB_DONE_IRQ
++ | IRQ0ENABLE_H3A_AF_DONE_IRQ
++ | IRQ0ENABLE_PRV_DONE_IRQ
++ | IRQ0ENABLE_RSZ_DONE_IRQ;
++
++ isp_reg_writel(isp, irq, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
++ isp_reg_writel(isp, irq, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE);
++}
++
++/*
++ * isp_disable_interrupts - Disable ISP interrupts.
++ * @isp: OMAP3 ISP device
++ */
++static void isp_disable_interrupts(struct isp_device *isp)
++{
++ isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE);
++}
++
++/**
++ * isp_set_xclk - Configures the specified cam_xclk to the desired frequency.
++ * @isp: OMAP3 ISP device
++ * @xclk: Desired frequency of the clock in Hz. 0 = stable low, 1 is stable high
++ * @xclksel: XCLK to configure (0 = A, 1 = B).
++ *
++ * Configures the specified MCLK divisor in the ISP timing control register
++ * (TCTRL_CTRL) to generate the desired xclk clock value.
++ *
++ * Divisor = cam_mclk_hz / xclk
++ *
++ * Returns the final frequency that is actually being generated
++ **/
++static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel)
++{
++ u32 divisor;
++ u32 currentxclk;
++ unsigned long mclk_hz;
++
++ if (!omap3isp_get(isp))
++ return 0;
++
++ mclk_hz = clk_get_rate(isp->clock[ISP_CLK_CAM_MCLK]);
++
++ if (xclk >= mclk_hz) {
++ divisor = ISPTCTRL_CTRL_DIV_BYPASS;
++ currentxclk = mclk_hz;
++ } else if (xclk >= 2) {
++ divisor = mclk_hz / xclk;
++ if (divisor >= ISPTCTRL_CTRL_DIV_BYPASS)
++ divisor = ISPTCTRL_CTRL_DIV_BYPASS - 1;
++ currentxclk = mclk_hz / divisor;
++ } else {
++ divisor = xclk;
++ currentxclk = 0;
++ }
++
++ switch (xclksel) {
++ case 0:
++ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
++ ISPTCTRL_CTRL_DIVA_MASK,
++ divisor << ISPTCTRL_CTRL_DIVA_SHIFT);
++ dev_dbg(isp->dev, "isp_set_xclk(): cam_xclka set to %d Hz\n",
++ currentxclk);
++ break;
++ case 1:
++ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
++ ISPTCTRL_CTRL_DIVB_MASK,
++ divisor << ISPTCTRL_CTRL_DIVB_SHIFT);
++ dev_dbg(isp->dev, "isp_set_xclk(): cam_xclkb set to %d Hz\n",
++ currentxclk);
++ break;
++ default:
++ omap3isp_put(isp);
++ dev_dbg(isp->dev, "ISP_ERR: isp_set_xclk(): Invalid requested "
++ "xclk. Must be 0 (A) or 1 (B).\n");
++ return -EINVAL;
++ }
++
++ /* Do we go from stable whatever to clock? */
++ if (divisor >= 2 && isp->xclk_divisor[xclksel] < 2)
++ omap3isp_get(isp);
++ /* Stopping the clock. */
++ else if (divisor < 2 && isp->xclk_divisor[xclksel] >= 2)
++ omap3isp_put(isp);
++
++ isp->xclk_divisor[xclksel] = divisor;
++
++ omap3isp_put(isp);
++
++ return currentxclk;
++}
++
++/*
++ * isp_power_settings - Sysconfig settings, for Power Management.
++ * @isp: OMAP3 ISP device
++ * @idle: Consider idle state.
++ *
++ * Sets the power settings for the ISP, and SBL bus.
++ */
++static void isp_power_settings(struct isp_device *isp, int idle)
++{
++ isp_reg_writel(isp,
++ ((idle ? ISP_SYSCONFIG_MIDLEMODE_SMARTSTANDBY :
++ ISP_SYSCONFIG_MIDLEMODE_FORCESTANDBY) <<
++ ISP_SYSCONFIG_MIDLEMODE_SHIFT) |
++ ((isp->revision == ISP_REVISION_15_0) ?
++ ISP_SYSCONFIG_AUTOIDLE : 0),
++ OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG);
++
++ if (isp->autoidle)
++ isp_reg_writel(isp, ISPCTRL_SBL_AUTOIDLE, OMAP3_ISP_IOMEM_MAIN,
++ ISP_CTRL);
++}
++
++/*
++ * Configure the bridge and lane shifter. Valid inputs are
++ *
++ * CCDC_INPUT_PARALLEL: Parallel interface
++ * CCDC_INPUT_CSI2A: CSI2a receiver
++ * CCDC_INPUT_CCP2B: CCP2b receiver
++ * CCDC_INPUT_CSI2C: CSI2c receiver
++ *
++ * The bridge and lane shifter are configured according to the selected input
++ * and the ISP platform data.
++ */
++void omap3isp_configure_bridge(struct isp_device *isp,
++ enum ccdc_input_entity input,
++ const struct isp_parallel_platform_data *pdata)
++{
++ u32 ispctrl_val;
++
++ ispctrl_val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
++ ispctrl_val &= ~ISPCTRL_SHIFT_MASK;
++ ispctrl_val &= ~ISPCTRL_PAR_CLK_POL_INV;
++ ispctrl_val &= ~ISPCTRL_PAR_SER_CLK_SEL_MASK;
++ ispctrl_val &= ~ISPCTRL_PAR_BRIDGE_MASK;
++
++ switch (input) {
++ case CCDC_INPUT_PARALLEL:
++ ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL;
++ ispctrl_val |= pdata->data_lane_shift << ISPCTRL_SHIFT_SHIFT;
++ ispctrl_val |= pdata->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT;
++ ispctrl_val |= pdata->bridge << ISPCTRL_PAR_BRIDGE_SHIFT;
++ break;
++
++ case CCDC_INPUT_CSI2A:
++ ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIA;
++ break;
++
++ case CCDC_INPUT_CCP2B:
++ ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIB;
++ break;
++
++ case CCDC_INPUT_CSI2C:
++ ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIC;
++ break;
++
++ default:
++ return;
++ }
++
++ ispctrl_val &= ~ISPCTRL_SYNC_DETECT_MASK;
++ ispctrl_val |= ISPCTRL_SYNC_DETECT_VSRISE;
++
++ isp_reg_writel(isp, ispctrl_val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
++}
++
++/**
++ * isp_set_pixel_clock - Configures the ISP pixel clock
++ * @isp: OMAP3 ISP device
++ * @pixelclk: Average pixel clock in Hz
++ *
++ * Set the average pixel clock required by the sensor. The ISP will use the
++ * lowest possible memory bandwidth settings compatible with the clock.
++ **/
++static void isp_set_pixel_clock(struct isp_device *isp, unsigned int pixelclk)
++{
++ isp->isp_ccdc.vpcfg.pixelclk = pixelclk;
++}
++
++void omap3isp_hist_dma_done(struct isp_device *isp)
++{
++ if (omap3isp_ccdc_busy(&isp->isp_ccdc) ||
++ omap3isp_stat_pcr_busy(&isp->isp_hist)) {
++ /* Histogram cannot be enabled in this frame anymore */
++ atomic_set(&isp->isp_hist.buf_err, 1);
++ dev_dbg(isp->dev, "hist: Out of synchronization with "
++ "CCDC. Ignoring next buffer.\n");
++ }
++}
++
++static inline void isp_isr_dbg(struct isp_device *isp, u32 irqstatus)
++{
++ static const char *name[] = {
++ "CSIA_IRQ",
++ "res1",
++ "res2",
++ "CSIB_LCM_IRQ",
++ "CSIB_IRQ",
++ "res5",
++ "res6",
++ "res7",
++ "CCDC_VD0_IRQ",
++ "CCDC_VD1_IRQ",
++ "CCDC_VD2_IRQ",
++ "CCDC_ERR_IRQ",
++ "H3A_AF_DONE_IRQ",
++ "H3A_AWB_DONE_IRQ",
++ "res14",
++ "res15",
++ "HIST_DONE_IRQ",
++ "CCDC_LSC_DONE",
++ "CCDC_LSC_PREFETCH_COMPLETED",
++ "CCDC_LSC_PREFETCH_ERROR",
++ "PRV_DONE_IRQ",
++ "CBUFF_IRQ",
++ "res22",
++ "res23",
++ "RSZ_DONE_IRQ",
++ "OVF_IRQ",
++ "res26",
++ "res27",
++ "MMU_ERR_IRQ",
++ "OCP_ERR_IRQ",
++ "SEC_ERR_IRQ",
++ "HS_VS_IRQ",
++ };
++ int i;
++
++ dev_dbg(isp->dev, "");
++
++ for (i = 0; i < ARRAY_SIZE(name); i++) {
++ if ((1 << i) & irqstatus)
++ printk(KERN_CONT "%s ", name[i]);
++ }
++ printk(KERN_CONT "\n");
++}
++
++static void isp_isr_sbl(struct isp_device *isp)
++{
++ struct device *dev = isp->dev;
++ u32 sbl_pcr;
++
++ /*
++ * Handle shared buffer logic overflows for video buffers.
++ * ISPSBL_PCR_CCDCPRV_2_RSZ_OVF can be safely ignored.
++ */
++ sbl_pcr = isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_PCR);
++ isp_reg_writel(isp, sbl_pcr, OMAP3_ISP_IOMEM_SBL, ISPSBL_PCR);
++ sbl_pcr &= ~ISPSBL_PCR_CCDCPRV_2_RSZ_OVF;
++
++ if (sbl_pcr)
++ dev_dbg(dev, "SBL overflow (PCR = 0x%08x)\n", sbl_pcr);
++
++ if (sbl_pcr & (ISPSBL_PCR_CCDC_WBL_OVF | ISPSBL_PCR_CSIA_WBL_OVF
++ | ISPSBL_PCR_CSIB_WBL_OVF)) {
++ isp->isp_ccdc.error = 1;
++ if (isp->isp_ccdc.output & CCDC_OUTPUT_PREVIEW)
++ isp->isp_prev.error = 1;
++ if (isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER)
++ isp->isp_res.error = 1;
++ }
++
++ if (sbl_pcr & ISPSBL_PCR_PRV_WBL_OVF) {
++ isp->isp_prev.error = 1;
++ if (isp->isp_res.input == RESIZER_INPUT_VP &&
++ !(isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER))
++ isp->isp_res.error = 1;
++ }
++
++ if (sbl_pcr & (ISPSBL_PCR_RSZ1_WBL_OVF
++ | ISPSBL_PCR_RSZ2_WBL_OVF
++ | ISPSBL_PCR_RSZ3_WBL_OVF
++ | ISPSBL_PCR_RSZ4_WBL_OVF))
++ isp->isp_res.error = 1;
++
++ if (sbl_pcr & ISPSBL_PCR_H3A_AF_WBL_OVF)
++ omap3isp_stat_sbl_overflow(&isp->isp_af);
++
++ if (sbl_pcr & ISPSBL_PCR_H3A_AEAWB_WBL_OVF)
++ omap3isp_stat_sbl_overflow(&isp->isp_aewb);
++}
++
++/*
++ * isp_isr - Interrupt Service Routine for Camera ISP module.
++ * @irq: Not used currently.
++ * @_isp: Pointer to the OMAP3 ISP device
++ *
++ * Handles the corresponding callback if plugged in.
++ *
++ * Returns IRQ_HANDLED when IRQ was correctly handled, or IRQ_NONE when the
++ * IRQ wasn't handled.
++ */
++static irqreturn_t isp_isr(int irq, void *_isp)
++{
++ static const u32 ccdc_events = IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ |
++ IRQ0STATUS_CCDC_LSC_DONE_IRQ |
++ IRQ0STATUS_CCDC_VD0_IRQ |
++ IRQ0STATUS_CCDC_VD1_IRQ |
++ IRQ0STATUS_HS_VS_IRQ;
++ struct isp_device *isp = _isp;
++ u32 irqstatus;
++ int ret;
++
++ irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
++ isp_reg_writel(isp, irqstatus, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
++
++ isp_isr_sbl(isp);
++
++ if (irqstatus & IRQ0STATUS_CSIA_IRQ) {
++ ret = omap3isp_csi2_isr(&isp->isp_csi2a);
++ if (ret)
++ isp->isp_ccdc.error = 1;
++ }
++
++ if (irqstatus & IRQ0STATUS_CSIB_IRQ) {
++ ret = omap3isp_ccp2_isr(&isp->isp_ccp2);
++ if (ret)
++ isp->isp_ccdc.error = 1;
++ }
++
++ if (irqstatus & IRQ0STATUS_CCDC_VD0_IRQ) {
++ if (isp->isp_ccdc.output & CCDC_OUTPUT_PREVIEW)
++ omap3isp_preview_isr_frame_sync(&isp->isp_prev);
++ if (isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER)
++ omap3isp_resizer_isr_frame_sync(&isp->isp_res);
++ omap3isp_stat_isr_frame_sync(&isp->isp_aewb);
++ omap3isp_stat_isr_frame_sync(&isp->isp_af);
++ omap3isp_stat_isr_frame_sync(&isp->isp_hist);
++ }
++
++ if (irqstatus & ccdc_events)
++ omap3isp_ccdc_isr(&isp->isp_ccdc, irqstatus & ccdc_events);
++
++ if (irqstatus & IRQ0STATUS_PRV_DONE_IRQ) {
++ if (isp->isp_prev.output & PREVIEW_OUTPUT_RESIZER)
++ omap3isp_resizer_isr_frame_sync(&isp->isp_res);
++ omap3isp_preview_isr(&isp->isp_prev);
++ }
++
++ if (irqstatus & IRQ0STATUS_RSZ_DONE_IRQ)
++ omap3isp_resizer_isr(&isp->isp_res);
++
++ if (irqstatus & IRQ0STATUS_H3A_AWB_DONE_IRQ)
++ omap3isp_stat_isr(&isp->isp_aewb);
++
++ if (irqstatus & IRQ0STATUS_H3A_AF_DONE_IRQ)
++ omap3isp_stat_isr(&isp->isp_af);
++
++ if (irqstatus & IRQ0STATUS_HIST_DONE_IRQ)
++ omap3isp_stat_isr(&isp->isp_hist);
++
++ omap3isp_flush(isp);
++
++#if defined(DEBUG) && defined(ISP_ISR_DEBUG)
++ isp_isr_dbg(isp, irqstatus);
++#endif
++
++ return IRQ_HANDLED;
++}
++
++/* -----------------------------------------------------------------------------
++ * Pipeline power management
++ *
++ * Entities must be powered up when part of a pipeline that contains at least
++ * one open video device node.
++ *
++ * To achieve this use the entity use_count field to track the number of users.
++ * For entities corresponding to video device nodes the use_count field stores
++ * the users count of the node. For entities corresponding to subdevs the
++ * use_count field stores the total number of users of all video device nodes
++ * in the pipeline.
++ *
++ * The omap3isp_pipeline_pm_use() function must be called in the open() and
++ * close() handlers of video device nodes. It increments or decrements the use
++ * count of all subdev entities in the pipeline.
++ *
++ * To react to link management on powered pipelines, the link setup notification
++ * callback updates the use count of all entities in the source and sink sides
++ * of the link.
++ */
++
++/*
++ * isp_pipeline_pm_use_count - Count the number of users of a pipeline
++ * @entity: The entity
++ *
++ * Return the total number of users of all video device nodes in the pipeline.
++ */
++static int isp_pipeline_pm_use_count(struct media_entity *entity)
++{
++ struct media_entity_graph graph;
++ int use = 0;
++
++ media_entity_graph_walk_start(&graph, entity);
++
++ while ((entity = media_entity_graph_walk_next(&graph))) {
++ if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
++ use += entity->use_count;
++ }
++
++ return use;
++}
++
++/*
++ * isp_pipeline_pm_power_one - Apply power change to an entity
++ * @entity: The entity
++ * @change: Use count change
++ *
++ * Change the entity use count by @change. If the entity is a subdev update its
++ * power state by calling the core::s_power operation when the use count goes
++ * from 0 to != 0 or from != 0 to 0.
++ *
++ * Return 0 on success or a negative error code on failure.
++ */
++static int isp_pipeline_pm_power_one(struct media_entity *entity, int change)
++{
++ struct v4l2_subdev *subdev;
++ int ret;
++
++ subdev = media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV
++ ? media_entity_to_v4l2_subdev(entity) : NULL;
++
++ if (entity->use_count == 0 && change > 0 && subdev != NULL) {
++ ret = v4l2_subdev_call(subdev, core, s_power, 1);
++ if (ret < 0 && ret != -ENOIOCTLCMD)
++ return ret;
++ }
++
++ entity->use_count += change;
++ WARN_ON(entity->use_count < 0);
++
++ if (entity->use_count == 0 && change < 0 && subdev != NULL)
++ v4l2_subdev_call(subdev, core, s_power, 0);
++
++ return 0;
++}
++
++/*
++ * isp_pipeline_pm_power - Apply power change to all entities in a pipeline
++ * @entity: The entity
++ * @change: Use count change
++ *
++ * Walk the pipeline to update the use count and the power state of all non-node
++ * entities.
++ *
++ * Return 0 on success or a negative error code on failure.
++ */
++static int isp_pipeline_pm_power(struct media_entity *entity, int change)
++{
++ struct media_entity_graph graph;
++ struct media_entity *first = entity;
++ int ret = 0;
++
++ if (!change)
++ return 0;
++
++ media_entity_graph_walk_start(&graph, entity);
++
++ while (!ret && (entity = media_entity_graph_walk_next(&graph)))
++ if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
++ ret = isp_pipeline_pm_power_one(entity, change);
++
++ if (!ret)
++ return 0;
++
++ media_entity_graph_walk_start(&graph, first);
++
++ while ((first = media_entity_graph_walk_next(&graph))
++ && first != entity)
++ if (media_entity_type(first) != MEDIA_ENT_T_DEVNODE)
++ isp_pipeline_pm_power_one(first, -change);
++
++ return ret;
++}
++
++/*
++ * omap3isp_pipeline_pm_use - Update the use count of an entity
++ * @entity: The entity
++ * @use: Use (1) or stop using (0) the entity
++ *
++ * Update the use count of all entities in the pipeline and power entities on or
++ * off accordingly.
++ *
++ * Return 0 on success or a negative error code on failure. Powering entities
++ * off is assumed to never fail. No failure can occur when the use parameter is
++ * set to 0.
++ */
++int omap3isp_pipeline_pm_use(struct media_entity *entity, int use)
++{
++ int change = use ? 1 : -1;
++ int ret;
++
++ mutex_lock(&entity->parent->graph_mutex);
++
++ /* Apply use count to node. */
++ entity->use_count += change;
++ WARN_ON(entity->use_count < 0);
++
++ /* Apply power change to connected non-nodes. */
++ ret = isp_pipeline_pm_power(entity, change);
++
++ mutex_unlock(&entity->parent->graph_mutex);
++
++ return ret;
++}
++
++/*
++ * isp_pipeline_link_notify - Link management notification callback
++ * @source: Pad at the start of the link
++ * @sink: Pad at the end of the link
++ * @flags: New link flags that will be applied
++ *
++ * React to link management on powered pipelines by updating the use count of
++ * all entities in the source and sink sides of the link. Entities are powered
++ * on or off accordingly.
++ *
++ * Return 0 on success or a negative error code on failure. Powering entities
++ * off is assumed to never fail. This function will not fail for disconnection
++ * events.
++ */
++static int isp_pipeline_link_notify(struct media_pad *source,
++ struct media_pad *sink, u32 flags)
++{
++ int source_use = isp_pipeline_pm_use_count(source->entity);
++ int sink_use = isp_pipeline_pm_use_count(sink->entity);
++ int ret;
++
++ if (!(flags & MEDIA_LNK_FL_ENABLED)) {
++ /* Powering off entities is assumed to never fail. */
++ isp_pipeline_pm_power(source->entity, -sink_use);
++ isp_pipeline_pm_power(sink->entity, -source_use);
++ return 0;
++ }
++
++ ret = isp_pipeline_pm_power(source->entity, sink_use);
++ if (ret < 0)
++ return ret;
++
++ ret = isp_pipeline_pm_power(sink->entity, source_use);
++ if (ret < 0)
++ isp_pipeline_pm_power(source->entity, -sink_use);
++
++ return ret;
++}
++
++/* -----------------------------------------------------------------------------
++ * Pipeline stream management
++ */
++
++/*
++ * isp_pipeline_enable - Enable streaming on a pipeline
++ * @pipe: ISP pipeline
++ * @mode: Stream mode (single shot or continuous)
++ *
++ * Walk the entities chain starting at the pipeline output video node and start
++ * all modules in the chain in the given mode.
++ *
++ * Return 0 if successfull, or the return value of the failed video::s_stream
++ * operation otherwise.
++ */
++static int isp_pipeline_enable(struct isp_pipeline *pipe,
++ enum isp_pipeline_stream_state mode)
++{
++ struct isp_device *isp = pipe->output->isp;
++ struct media_entity *entity;
++ struct media_pad *pad;
++ struct v4l2_subdev *subdev;
++ unsigned long flags;
++ int ret = 0;
++
++ spin_lock_irqsave(&pipe->lock, flags);
++ pipe->state &= ~(ISP_PIPELINE_IDLE_INPUT | ISP_PIPELINE_IDLE_OUTPUT);
++ spin_unlock_irqrestore(&pipe->lock, flags);
++
++ pipe->do_propagation = false;
++
++ entity = &pipe->output->video.entity;
++ while (1) {
++ pad = &entity->pads[0];
++ if (!(pad->flags & MEDIA_PAD_FL_INPUT))
++ break;
++
++ pad = media_entity_remote_source(pad);
++ if (pad == NULL ||
++ media_entity_type(pad->entity) !=
++ MEDIA_ENT_T_V4L2_SUBDEV)
++ break;
++
++ entity = pad->entity;
++ subdev = media_entity_to_v4l2_subdev(entity);
++
++ ret = v4l2_subdev_call(subdev, video, s_stream, mode);
++ if (ret < 0 && ret != -ENOIOCTLCMD)
++ break;
++
++ if (subdev == &isp->isp_ccdc.subdev) {
++ v4l2_subdev_call(&isp->isp_aewb.subdev, video,
++ s_stream, mode);
++ v4l2_subdev_call(&isp->isp_af.subdev, video,
++ s_stream, mode);
++ v4l2_subdev_call(&isp->isp_hist.subdev, video,
++ s_stream, mode);
++ pipe->do_propagation = true;
++ }
++ }
++
++ /* Frame number propagation. In continuous streaming mode the number
++ * is incremented in the frame start ISR. In mem-to-mem mode
++ * singleshot is used and frame start IRQs are not available.
++ * Thus we have to increment the number here.
++ */
++ if (pipe->do_propagation && mode == ISP_PIPELINE_STREAM_SINGLESHOT)
++ atomic_inc(&pipe->frame_number);
++
++ return ret;
++}
++
++static int isp_pipeline_wait_resizer(struct isp_device *isp)
++{
++ return omap3isp_resizer_busy(&isp->isp_res);
++}
++
++static int isp_pipeline_wait_preview(struct isp_device *isp)
++{
++ return omap3isp_preview_busy(&isp->isp_prev);
++}
++
++static int isp_pipeline_wait_ccdc(struct isp_device *isp)
++{
++ return omap3isp_stat_busy(&isp->isp_af)
++ || omap3isp_stat_busy(&isp->isp_aewb)
++ || omap3isp_stat_busy(&isp->isp_hist)
++ || omap3isp_ccdc_busy(&isp->isp_ccdc);
++}
++
++#define ISP_STOP_TIMEOUT msecs_to_jiffies(1000)
++
++static int isp_pipeline_wait(struct isp_device *isp,
++ int(*busy)(struct isp_device *isp))
++{
++ unsigned long timeout = jiffies + ISP_STOP_TIMEOUT;
++
++ while (!time_after(jiffies, timeout)) {
++ if (!busy(isp))
++ return 0;
++ }
++
++ return 1;
++}
++
++/*
++ * isp_pipeline_disable - Disable streaming on a pipeline
++ * @pipe: ISP pipeline
++ *
++ * Walk the entities chain starting at the pipeline output video node and stop
++ * all modules in the chain. Wait synchronously for the modules to be stopped if
++ * necessary.
++ *
++ * Return 0 if all modules have been properly stopped, or -ETIMEDOUT if a module
++ * can't be stopped (in which case a software reset of the ISP is probably
++ * necessary).
++ */
++static int isp_pipeline_disable(struct isp_pipeline *pipe)
++{
++ struct isp_device *isp = pipe->output->isp;
++ struct media_entity *entity;
++ struct media_pad *pad;
++ struct v4l2_subdev *subdev;
++ int failure = 0;
++ int ret;
++
++ /*
++ * We need to stop all the modules after CCDC first or they'll
++ * never stop since they may not get a full frame from CCDC.
++ */
++ entity = &pipe->output->video.entity;
++ while (1) {
++ pad = &entity->pads[0];
++ if (!(pad->flags & MEDIA_PAD_FL_INPUT))
++ break;
++
++ pad = media_entity_remote_source(pad);
++ if (pad == NULL ||
++ media_entity_type(pad->entity) !=
++ MEDIA_ENT_T_V4L2_SUBDEV)
++ break;
++
++ entity = pad->entity;
++ subdev = media_entity_to_v4l2_subdev(entity);
++
++ if (subdev == &isp->isp_ccdc.subdev) {
++ v4l2_subdev_call(&isp->isp_aewb.subdev,
++ video, s_stream, 0);
++ v4l2_subdev_call(&isp->isp_af.subdev,
++ video, s_stream, 0);
++ v4l2_subdev_call(&isp->isp_hist.subdev,
++ video, s_stream, 0);
++ }
++
++ v4l2_subdev_call(subdev, video, s_stream, 0);
++
++ if (subdev == &isp->isp_res.subdev) {
++ ret = isp_pipeline_wait(isp, isp_pipeline_wait_resizer);
++ } else if (subdev == &isp->isp_prev.subdev) {
++ ret = isp_pipeline_wait(isp, isp_pipeline_wait_preview);
++ } else if (subdev == &isp->isp_ccdc.subdev) {
++ ret = isp_pipeline_wait(isp, isp_pipeline_wait_ccdc);
++ } else {
++ ret = 0;
++ }
++
++ if (ret) {
++ dev_info(isp->dev, "Unable to stop %s\n", subdev->name);
++ failure = -ETIMEDOUT;
++ }
++ }
++
++ return failure;
++}
++
++/*
++ * omap3isp_pipeline_set_stream - Enable/disable streaming on a pipeline
++ * @pipe: ISP pipeline
++ * @state: Stream state (stopped, single shot or continuous)
++ *
++ * Set the pipeline to the given stream state. Pipelines can be started in
++ * single-shot or continuous mode.
++ *
++ * Return 0 if successfull, or the return value of the failed video::s_stream
++ * operation otherwise.
++ */
++int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
++ enum isp_pipeline_stream_state state)
++{
++ int ret;
++
++ if (state == ISP_PIPELINE_STREAM_STOPPED)
++ ret = isp_pipeline_disable(pipe);
++ else
++ ret = isp_pipeline_enable(pipe, state);
++ pipe->stream_state = state;
++
++ return ret;
++}
++
++/*
++ * isp_pipeline_resume - Resume streaming on a pipeline
++ * @pipe: ISP pipeline
++ *
++ * Resume video output and input and re-enable pipeline.
++ */
++static void isp_pipeline_resume(struct isp_pipeline *pipe)
++{
++ int singleshot = pipe->stream_state == ISP_PIPELINE_STREAM_SINGLESHOT;
++
++ omap3isp_video_resume(pipe->output, !singleshot);
++ if (singleshot)
++ omap3isp_video_resume(pipe->input, 0);
++ isp_pipeline_enable(pipe, pipe->stream_state);
++}
++
++/*
++ * isp_pipeline_suspend - Suspend streaming on a pipeline
++ * @pipe: ISP pipeline
++ *
++ * Suspend pipeline.
++ */
++static void isp_pipeline_suspend(struct isp_pipeline *pipe)
++{
++ isp_pipeline_disable(pipe);
++}
++
++/*
++ * isp_pipeline_is_last - Verify if entity has an enbled link to the output
++ * video node
++ * @me: ISP module's media entity
++ *
++ * Returns 1 if the entity has an enabled link to the output video node or 0
++ * otherwise. It's true only while pipeline can have no more than one output
++ * node.
++ */
++static int isp_pipeline_is_last(struct media_entity *me)
++{
++ struct isp_pipeline *pipe;
++ struct media_pad *pad;
++
++ if (!me->pipe)
++ return 0;
++ pipe = to_isp_pipeline(me);
++ if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED)
++ return 0;
++ pad = media_entity_remote_source(&pipe->output->pad);
++ return pad->entity == me;
++}
++
++/*
++ * isp_suspend_module_pipeline - Suspend pipeline to which belongs the module
++ * @me: ISP module's media entity
++ *
++ * Suspend the whole pipeline if module's entity has an enabled link to the
++ * output video node. It works only while pipeline can have no more than one
++ * output node.
++ */
++static void isp_suspend_module_pipeline(struct media_entity *me)
++{
++ if (isp_pipeline_is_last(me))
++ isp_pipeline_suspend(to_isp_pipeline(me));
++}
++
++/*
++ * isp_resume_module_pipeline - Resume pipeline to which belongs the module
++ * @me: ISP module's media entity
++ *
++ * Resume the whole pipeline if module's entity has an enabled link to the
++ * output video node. It works only while pipeline can have no more than one
++ * output node.
++ */
++static void isp_resume_module_pipeline(struct media_entity *me)
++{
++ if (isp_pipeline_is_last(me))
++ isp_pipeline_resume(to_isp_pipeline(me));
++}
++
++/*
++ * isp_suspend_modules - Suspend ISP submodules.
++ * @isp: OMAP3 ISP device
++ *
++ * Returns 0 if suspend left in idle state all the submodules properly,
++ * or returns 1 if a general Reset is required to suspend the submodules.
++ */
++static int isp_suspend_modules(struct isp_device *isp)
++{
++ unsigned long timeout;
++
++ omap3isp_stat_suspend(&isp->isp_aewb);
++ omap3isp_stat_suspend(&isp->isp_af);
++ omap3isp_stat_suspend(&isp->isp_hist);
++ isp_suspend_module_pipeline(&isp->isp_res.subdev.entity);
++ isp_suspend_module_pipeline(&isp->isp_prev.subdev.entity);
++ isp_suspend_module_pipeline(&isp->isp_ccdc.subdev.entity);
++ isp_suspend_module_pipeline(&isp->isp_csi2a.subdev.entity);
++ isp_suspend_module_pipeline(&isp->isp_ccp2.subdev.entity);
++
++ timeout = jiffies + ISP_STOP_TIMEOUT;
++ while (omap3isp_stat_busy(&isp->isp_af)
++ || omap3isp_stat_busy(&isp->isp_aewb)
++ || omap3isp_stat_busy(&isp->isp_hist)
++ || omap3isp_preview_busy(&isp->isp_prev)
++ || omap3isp_resizer_busy(&isp->isp_res)
++ || omap3isp_ccdc_busy(&isp->isp_ccdc)) {
++ if (time_after(jiffies, timeout)) {
++ dev_info(isp->dev, "can't stop modules.\n");
++ return 1;
++ }
++ msleep(1);
++ }
++
++ return 0;
++}
++
++/*
++ * isp_resume_modules - Resume ISP submodules.
++ * @isp: OMAP3 ISP device
++ */
++static void isp_resume_modules(struct isp_device *isp)
++{
++ omap3isp_stat_resume(&isp->isp_aewb);
++ omap3isp_stat_resume(&isp->isp_af);
++ omap3isp_stat_resume(&isp->isp_hist);
++ isp_resume_module_pipeline(&isp->isp_res.subdev.entity);
++ isp_resume_module_pipeline(&isp->isp_prev.subdev.entity);
++ isp_resume_module_pipeline(&isp->isp_ccdc.subdev.entity);
++ isp_resume_module_pipeline(&isp->isp_csi2a.subdev.entity);
++ isp_resume_module_pipeline(&isp->isp_ccp2.subdev.entity);
++}
++
++/*
++ * isp_reset - Reset ISP with a timeout wait for idle.
++ * @isp: OMAP3 ISP device
++ */
++static int isp_reset(struct isp_device *isp)
++{
++ unsigned long timeout = 0;
++
++ isp_reg_writel(isp,
++ isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG)
++ | ISP_SYSCONFIG_SOFTRESET,
++ OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG);
++ while (!(isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN,
++ ISP_SYSSTATUS) & 0x1)) {
++ if (timeout++ > 10000) {
++ dev_alert(isp->dev, "cannot reset ISP\n");
++ return -ETIMEDOUT;
++ }
++ udelay(1);
++ }
++
++ return 0;
++}
++
++/*
++ * isp_save_context - Saves the values of the ISP module registers.
++ * @isp: OMAP3 ISP device
++ * @reg_list: Structure containing pairs of register address and value to
++ * modify on OMAP.
++ */
++static void
++isp_save_context(struct isp_device *isp, struct isp_reg *reg_list)
++{
++ struct isp_reg *next = reg_list;
++
++ for (; next->reg != ISP_TOK_TERM; next++)
++ next->val = isp_reg_readl(isp, next->mmio_range, next->reg);
++}
++
++/*
++ * isp_restore_context - Restores the values of the ISP module registers.
++ * @isp: OMAP3 ISP device
++ * @reg_list: Structure containing pairs of register address and value to
++ * modify on OMAP.
++ */
++static void
++isp_restore_context(struct isp_device *isp, struct isp_reg *reg_list)
++{
++ struct isp_reg *next = reg_list;
++
++ for (; next->reg != ISP_TOK_TERM; next++)
++ isp_reg_writel(isp, next->val, next->mmio_range, next->reg);
++}
++
++/*
++ * isp_save_ctx - Saves ISP, CCDC, HIST, H3A, PREV, RESZ & MMU context.
++ * @isp: OMAP3 ISP device
++ *
++ * Routine for saving the context of each module in the ISP.
++ * CCDC, HIST, H3A, PREV, RESZ and MMU.
++ */
++static void isp_save_ctx(struct isp_device *isp)
++{
++ isp_save_context(isp, isp_reg_list);
++ if (isp->iommu)
++ iommu_save_ctx(isp->iommu);
++}
++
++/*
++ * isp_restore_ctx - Restores ISP, CCDC, HIST, H3A, PREV, RESZ & MMU context.
++ * @isp: OMAP3 ISP device
++ *
++ * Routine for restoring the context of each module in the ISP.
++ * CCDC, HIST, H3A, PREV, RESZ and MMU.
++ */
++static void isp_restore_ctx(struct isp_device *isp)
++{
++ isp_restore_context(isp, isp_reg_list);
++ if (isp->iommu)
++ iommu_restore_ctx(isp->iommu);
++ omap3isp_ccdc_restore_context(isp);
++ omap3isp_preview_restore_context(isp);
++}
++
++/* -----------------------------------------------------------------------------
++ * SBL resources management
++ */
++#define OMAP3_ISP_SBL_READ (OMAP3_ISP_SBL_CSI1_READ | \
++ OMAP3_ISP_SBL_CCDC_LSC_READ | \
++ OMAP3_ISP_SBL_PREVIEW_READ | \
++ OMAP3_ISP_SBL_RESIZER_READ)
++#define OMAP3_ISP_SBL_WRITE (OMAP3_ISP_SBL_CSI1_WRITE | \
++ OMAP3_ISP_SBL_CSI2A_WRITE | \
++ OMAP3_ISP_SBL_CSI2C_WRITE | \
++ OMAP3_ISP_SBL_CCDC_WRITE | \
++ OMAP3_ISP_SBL_PREVIEW_WRITE)
++
++void omap3isp_sbl_enable(struct isp_device *isp, enum isp_sbl_resource res)
++{
++ u32 sbl = 0;
++
++ isp->sbl_resources |= res;
++
++ if (isp->sbl_resources & OMAP3_ISP_SBL_CSI1_READ)
++ sbl |= ISPCTRL_SBL_SHARED_RPORTA;
++
++ if (isp->sbl_resources & OMAP3_ISP_SBL_CCDC_LSC_READ)
++ sbl |= ISPCTRL_SBL_SHARED_RPORTB;
++
++ if (isp->sbl_resources & OMAP3_ISP_SBL_CSI2C_WRITE)
++ sbl |= ISPCTRL_SBL_SHARED_WPORTC;
++
++ if (isp->sbl_resources & OMAP3_ISP_SBL_RESIZER_WRITE)
++ sbl |= ISPCTRL_SBL_WR0_RAM_EN;
++
++ if (isp->sbl_resources & OMAP3_ISP_SBL_WRITE)
++ sbl |= ISPCTRL_SBL_WR1_RAM_EN;
++
++ if (isp->sbl_resources & OMAP3_ISP_SBL_READ)
++ sbl |= ISPCTRL_SBL_RD_RAM_EN;
++
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, sbl);
++}
++
++void omap3isp_sbl_disable(struct isp_device *isp, enum isp_sbl_resource res)
++{
++ u32 sbl = 0;
++
++ isp->sbl_resources &= ~res;
++
++ if (!(isp->sbl_resources & OMAP3_ISP_SBL_CSI1_READ))
++ sbl |= ISPCTRL_SBL_SHARED_RPORTA;
++
++ if (!(isp->sbl_resources & OMAP3_ISP_SBL_CCDC_LSC_READ))
++ sbl |= ISPCTRL_SBL_SHARED_RPORTB;
++
++ if (!(isp->sbl_resources & OMAP3_ISP_SBL_CSI2C_WRITE))
++ sbl |= ISPCTRL_SBL_SHARED_WPORTC;
++
++ if (!(isp->sbl_resources & OMAP3_ISP_SBL_RESIZER_WRITE))
++ sbl |= ISPCTRL_SBL_WR0_RAM_EN;
++
++ if (!(isp->sbl_resources & OMAP3_ISP_SBL_WRITE))
++ sbl |= ISPCTRL_SBL_WR1_RAM_EN;
++
++ if (!(isp->sbl_resources & OMAP3_ISP_SBL_READ))
++ sbl |= ISPCTRL_SBL_RD_RAM_EN;
++
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, sbl);
++}
++
++/*
++ * isp_module_sync_idle - Helper to sync module with its idle state
++ * @me: ISP submodule's media entity
++ * @wait: ISP submodule's wait queue for streamoff/interrupt synchronization
++ * @stopping: flag which tells module wants to stop
++ *
++ * This function checks if ISP submodule needs to wait for next interrupt. If
++ * yes, makes the caller to sleep while waiting for such event.
++ */
++int omap3isp_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait,
++ atomic_t *stopping)
++{
++ struct isp_pipeline *pipe = to_isp_pipeline(me);
++
++ if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED ||
++ (pipe->stream_state == ISP_PIPELINE_STREAM_SINGLESHOT &&
++ !isp_pipeline_ready(pipe)))
++ return 0;
++
++ /*
++ * atomic_set() doesn't include memory barrier on ARM platform for SMP
++ * scenario. We'll call it here to avoid race conditions.
++ */
++ atomic_set(stopping, 1);
++ smp_mb();
++
++ /*
++ * If module is the last one, it's writing to memory. In this case,
++ * it's necessary to check if the module is already paused due to
++ * DMA queue underrun or if it has to wait for next interrupt to be
++ * idle.
++ * If it isn't the last one, the function won't sleep but *stopping
++ * will still be set to warn next submodule caller's interrupt the
++ * module wants to be idle.
++ */
++ if (isp_pipeline_is_last(me)) {
++ struct isp_video *video = pipe->output;
++ unsigned long flags;
++ spin_lock_irqsave(&video->queue->irqlock, flags);
++ if (video->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_UNDERRUN) {
++ spin_unlock_irqrestore(&video->queue->irqlock, flags);
++ atomic_set(stopping, 0);
++ smp_mb();
++ return 0;
++ }
++ spin_unlock_irqrestore(&video->queue->irqlock, flags);
++ if (!wait_event_timeout(*wait, !atomic_read(stopping),
++ msecs_to_jiffies(1000))) {
++ atomic_set(stopping, 0);
++ smp_mb();
++ return -ETIMEDOUT;
++ }
++ }
++
++ return 0;
++}
++
++/*
++ * omap3isp_module_sync_is_stopped - Helper to verify if module was stopping
++ * @wait: ISP submodule's wait queue for streamoff/interrupt synchronization
++ * @stopping: flag which tells module wants to stop
++ *
++ * This function checks if ISP submodule was stopping. In case of yes, it
++ * notices the caller by setting stopping to 0 and waking up the wait queue.
++ * Returns 1 if it was stopping or 0 otherwise.
++ */
++int omap3isp_module_sync_is_stopping(wait_queue_head_t *wait,
++ atomic_t *stopping)
++{
++ if (atomic_cmpxchg(stopping, 1, 0)) {
++ wake_up(wait);
++ return 1;
++ }
++
++ return 0;
++}
++
++/* --------------------------------------------------------------------------
++ * Clock management
++ */
++
++#define ISPCTRL_CLKS_MASK (ISPCTRL_H3A_CLK_EN | \
++ ISPCTRL_HIST_CLK_EN | \
++ ISPCTRL_RSZ_CLK_EN | \
++ (ISPCTRL_CCDC_CLK_EN | ISPCTRL_CCDC_RAM_EN) | \
++ (ISPCTRL_PREV_CLK_EN | ISPCTRL_PREV_RAM_EN))
++
++static void __isp_subclk_update(struct isp_device *isp)
++{
++ u32 clk = 0;
++
++ if (isp->subclk_resources & OMAP3_ISP_SUBCLK_H3A)
++ clk |= ISPCTRL_H3A_CLK_EN;
++
++ if (isp->subclk_resources & OMAP3_ISP_SUBCLK_HIST)
++ clk |= ISPCTRL_HIST_CLK_EN;
++
++ if (isp->subclk_resources & OMAP3_ISP_SUBCLK_RESIZER)
++ clk |= ISPCTRL_RSZ_CLK_EN;
++
++ /* NOTE: For CCDC & Preview submodules, we need to affect internal
++ * RAM aswell.
++ */
++ if (isp->subclk_resources & OMAP3_ISP_SUBCLK_CCDC)
++ clk |= ISPCTRL_CCDC_CLK_EN | ISPCTRL_CCDC_RAM_EN;
++
++ if (isp->subclk_resources & OMAP3_ISP_SUBCLK_PREVIEW)
++ clk |= ISPCTRL_PREV_CLK_EN | ISPCTRL_PREV_RAM_EN;
++
++ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
++ ISPCTRL_CLKS_MASK, clk);
++}
++
++void omap3isp_subclk_enable(struct isp_device *isp,
++ enum isp_subclk_resource res)
++{
++ isp->subclk_resources |= res;
++
++ __isp_subclk_update(isp);
++}
++
++void omap3isp_subclk_disable(struct isp_device *isp,
++ enum isp_subclk_resource res)
++{
++ isp->subclk_resources &= ~res;
++
++ __isp_subclk_update(isp);
++}
++
++/*
++ * isp_enable_clocks - Enable ISP clocks
++ * @isp: OMAP3 ISP device
++ *
++ * Return 0 if successful, or clk_enable return value if any of tthem fails.
++ */
++static int isp_enable_clocks(struct isp_device *isp)
++{
++ int r;
++ unsigned long rate;
++ int divisor;
++
++ /*
++ * cam_mclk clock chain:
++ * dpll4 -> dpll4_m5 -> dpll4_m5x2 -> cam_mclk
++ *
++ * In OMAP3630 dpll4_m5x2 != 2 x dpll4_m5 but both are
++ * set to the same value. Hence the rate set for dpll4_m5
++ * has to be twice of what is set on OMAP3430 to get
++ * the required value for cam_mclk
++ */
++ if (cpu_is_omap3630())
++ divisor = 1;
++ else
++ divisor = 2;
++
++ r = clk_enable(isp->clock[ISP_CLK_CAM_ICK]);
++ if (r) {
++ dev_err(isp->dev, "clk_enable cam_ick failed\n");
++ goto out_clk_enable_ick;
++ }
++ r = clk_set_rate(isp->clock[ISP_CLK_DPLL4_M5_CK],
++ CM_CAM_MCLK_HZ/divisor);
++ if (r) {
++ dev_err(isp->dev, "clk_set_rate for dpll4_m5_ck failed\n");
++ goto out_clk_enable_mclk;
++ }
++ r = clk_enable(isp->clock[ISP_CLK_CAM_MCLK]);
++ if (r) {
++ dev_err(isp->dev, "clk_enable cam_mclk failed\n");
++ goto out_clk_enable_mclk;
++ }
++ rate = clk_get_rate(isp->clock[ISP_CLK_CAM_MCLK]);
++ if (rate != CM_CAM_MCLK_HZ)
++ dev_warn(isp->dev, "unexpected cam_mclk rate:\n"
++ " expected : %d\n"
++ " actual : %ld\n", CM_CAM_MCLK_HZ, rate);
++ r = clk_enable(isp->clock[ISP_CLK_CSI2_FCK]);
++ if (r) {
++ dev_err(isp->dev, "clk_enable csi2_fck failed\n");
++ goto out_clk_enable_csi2_fclk;
++ }
++ return 0;
++
++out_clk_enable_csi2_fclk:
++ clk_disable(isp->clock[ISP_CLK_CAM_MCLK]);
++out_clk_enable_mclk:
++ clk_disable(isp->clock[ISP_CLK_CAM_ICK]);
++out_clk_enable_ick:
++ return r;
++}
++
++/*
++ * isp_disable_clocks - Disable ISP clocks
++ * @isp: OMAP3 ISP device
++ */
++static void isp_disable_clocks(struct isp_device *isp)
++{
++ clk_disable(isp->clock[ISP_CLK_CAM_ICK]);
++ clk_disable(isp->clock[ISP_CLK_CAM_MCLK]);
++ clk_disable(isp->clock[ISP_CLK_CSI2_FCK]);
++}
++
++static const char *isp_clocks[] = {
++ "cam_ick",
++ "cam_mclk",
++ "dpll4_m5_ck",
++ "csi2_96m_fck",
++ "l3_ick",
++};
++
++static void isp_put_clocks(struct isp_device *isp)
++{
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_SIZE(isp_clocks); ++i) {
++ if (isp->clock[i]) {
++ clk_put(isp->clock[i]);
++ isp->clock[i] = NULL;
++ }
++ }
++}
++
++static int isp_get_clocks(struct isp_device *isp)
++{
++ struct clk *clk;
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_SIZE(isp_clocks); ++i) {
++ clk = clk_get(isp->dev, isp_clocks[i]);
++ if (IS_ERR(clk)) {
++ dev_err(isp->dev, "clk_get %s failed\n", isp_clocks[i]);
++ isp_put_clocks(isp);
++ return PTR_ERR(clk);
++ }
++
++ isp->clock[i] = clk;
++ }
++
++ return 0;
++}
++
++/*
++ * omap3isp_get - Acquire the ISP resource.
++ *
++ * Initializes the clocks for the first acquire.
++ *
++ * Increment the reference count on the ISP. If the first reference is taken,
++ * enable clocks and power-up all submodules.
++ *
++ * Return a pointer to the ISP device structure, or NULL if an error occured.
++ */
++struct isp_device *omap3isp_get(struct isp_device *isp)
++{
++ struct isp_device *__isp = isp;
++
++ if (isp == NULL)
++ return NULL;
++
++ mutex_lock(&isp->isp_mutex);
++ if (isp->ref_count > 0)
++ goto out;
++
++ if (isp_enable_clocks(isp) < 0) {
++ __isp = NULL;
++ goto out;
++ }
++
++ /* We don't want to restore context before saving it! */
++ if (isp->has_context)
++ isp_restore_ctx(isp);
++ else
++ isp->has_context = 1;
++
++ isp_enable_interrupts(isp);
++
++out:
++ if (__isp != NULL)
++ isp->ref_count++;
++ mutex_unlock(&isp->isp_mutex);
++
++ return __isp;
++}
++
++/*
++ * omap3isp_put - Release the ISP
++ *
++ * Decrement the reference count on the ISP. If the last reference is released,
++ * power-down all submodules, disable clocks and free temporary buffers.
++ */
++void omap3isp_put(struct isp_device *isp)
++{
++ if (isp == NULL)
++ return;
++
++ mutex_lock(&isp->isp_mutex);
++ BUG_ON(isp->ref_count == 0);
++ if (--isp->ref_count == 0) {
++ isp_disable_interrupts(isp);
++ isp_save_ctx(isp);
++ isp_disable_clocks(isp);
++ }
++ mutex_unlock(&isp->isp_mutex);
++}
++
++/* --------------------------------------------------------------------------
++ * Platform device driver
++ */
++
++/*
++ * omap3isp_print_status - Prints the values of the ISP Control Module registers
++ * @isp: OMAP3 ISP device
++ */
++#define ISP_PRINT_REGISTER(isp, name)\
++ dev_dbg(isp->dev, "###ISP " #name "=0x%08x\n", \
++ isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_##name))
++#define SBL_PRINT_REGISTER(isp, name)\
++ dev_dbg(isp->dev, "###SBL " #name "=0x%08x\n", \
++ isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_##name))
++
++void omap3isp_print_status(struct isp_device *isp)
++{
++ dev_dbg(isp->dev, "-------------ISP Register dump--------------\n");
++
++ ISP_PRINT_REGISTER(isp, SYSCONFIG);
++ ISP_PRINT_REGISTER(isp, SYSSTATUS);
++ ISP_PRINT_REGISTER(isp, IRQ0ENABLE);
++ ISP_PRINT_REGISTER(isp, IRQ0STATUS);
++ ISP_PRINT_REGISTER(isp, TCTRL_GRESET_LENGTH);
++ ISP_PRINT_REGISTER(isp, TCTRL_PSTRB_REPLAY);
++ ISP_PRINT_REGISTER(isp, CTRL);
++ ISP_PRINT_REGISTER(isp, TCTRL_CTRL);
++ ISP_PRINT_REGISTER(isp, TCTRL_FRAME);
++ ISP_PRINT_REGISTER(isp, TCTRL_PSTRB_DELAY);
++ ISP_PRINT_REGISTER(isp, TCTRL_STRB_DELAY);
++ ISP_PRINT_REGISTER(isp, TCTRL_SHUT_DELAY);
++ ISP_PRINT_REGISTER(isp, TCTRL_PSTRB_LENGTH);
++ ISP_PRINT_REGISTER(isp, TCTRL_STRB_LENGTH);
++ ISP_PRINT_REGISTER(isp, TCTRL_SHUT_LENGTH);
++
++ SBL_PRINT_REGISTER(isp, PCR);
++ SBL_PRINT_REGISTER(isp, SDR_REQ_EXP);
++
++ dev_dbg(isp->dev, "--------------------------------------------\n");
++}
++
++#ifdef CONFIG_PM
++
++/*
++ * Power management support.
++ *
++ * As the ISP can't properly handle an input video stream interruption on a non
++ * frame boundary, the ISP pipelines need to be stopped before sensors get
++ * suspended. However, as suspending the sensors can require a running clock,
++ * which can be provided by the ISP, the ISP can't be completely suspended
++ * before the sensor.
++ *
++ * To solve this problem power management support is split into prepare/complete
++ * and suspend/resume operations. The pipelines are stopped in prepare() and the
++ * ISP clocks get disabled in suspend(). Similarly, the clocks are reenabled in
++ * resume(), and the the pipelines are restarted in complete().
++ *
++ * TODO: PM dependencies between the ISP and sensors are not modeled explicitly
++ * yet.
++ */
++static int isp_pm_prepare(struct device *dev)
++{
++ struct isp_device *isp = dev_get_drvdata(dev);
++ int reset;
++
++ WARN_ON(mutex_is_locked(&isp->isp_mutex));
++
++ if (isp->ref_count == 0)
++ return 0;
++
++ reset = isp_suspend_modules(isp);
++ isp_disable_interrupts(isp);
++ isp_save_ctx(isp);
++ if (reset)
++ isp_reset(isp);
++
++ return 0;
++}
++
++static int isp_pm_suspend(struct device *dev)
++{
++ struct isp_device *isp = dev_get_drvdata(dev);
++
++ WARN_ON(mutex_is_locked(&isp->isp_mutex));
++
++ if (isp->ref_count)
++ isp_disable_clocks(isp);
++
++ return 0;
++}
++
++static int isp_pm_resume(struct device *dev)
++{
++ struct isp_device *isp = dev_get_drvdata(dev);
++
++ if (isp->ref_count == 0)
++ return 0;
++
++ return isp_enable_clocks(isp);
++}
++
++static void isp_pm_complete(struct device *dev)
++{
++ struct isp_device *isp = dev_get_drvdata(dev);
++
++ if (isp->ref_count == 0)
++ return;
++
++ isp_restore_ctx(isp);
++ isp_enable_interrupts(isp);
++ isp_resume_modules(isp);
++}
++
++#else
++
++#define isp_pm_prepare NULL
++#define isp_pm_suspend NULL
++#define isp_pm_resume NULL
++#define isp_pm_complete NULL
++
++#endif /* CONFIG_PM */
++
++static void isp_unregister_entities(struct isp_device *isp)
++{
++ omap3isp_csi2_unregister_entities(&isp->isp_csi2a);
++ omap3isp_ccp2_unregister_entities(&isp->isp_ccp2);
++ omap3isp_ccdc_unregister_entities(&isp->isp_ccdc);
++ omap3isp_preview_unregister_entities(&isp->isp_prev);
++ omap3isp_resizer_unregister_entities(&isp->isp_res);
++ omap3isp_stat_unregister_entities(&isp->isp_aewb);
++ omap3isp_stat_unregister_entities(&isp->isp_af);
++ omap3isp_stat_unregister_entities(&isp->isp_hist);
++
++ v4l2_device_unregister(&isp->v4l2_dev);
++ media_device_unregister(&isp->media_dev);
++}
++
++/*
++ * isp_register_subdev_group - Register a group of subdevices
++ * @isp: OMAP3 ISP device
++ * @board_info: I2C subdevs board information array
++ *
++ * Register all I2C subdevices in the board_info array. The array must be
++ * terminated by a NULL entry, and the first entry must be the sensor.
++ *
++ * Return a pointer to the sensor media entity if it has been successfully
++ * registered, or NULL otherwise.
++ */
++static struct v4l2_subdev *
++isp_register_subdev_group(struct isp_device *isp,
++ struct isp_subdev_i2c_board_info *board_info)
++{
++ struct v4l2_subdev *sensor = NULL;
++ unsigned int first;
++
++ if (board_info->board_info == NULL)
++ return NULL;
++
++ for (first = 1; board_info->board_info; ++board_info, first = 0) {
++ struct v4l2_subdev *subdev;
++ struct i2c_adapter *adapter;
++
++ adapter = i2c_get_adapter(board_info->i2c_adapter_id);
++ if (adapter == NULL) {
++ printk(KERN_ERR "%s: Unable to get I2C adapter %d for "
++ "device %s\n", __func__,
++ board_info->i2c_adapter_id,
++ board_info->board_info->type);
++ continue;
++ }
++
++ subdev = v4l2_i2c_new_subdev_board(&isp->v4l2_dev, adapter,
++ board_info->board_info, NULL, 1);
++ if (subdev == NULL) {
++ printk(KERN_ERR "%s: Unable to register subdev %s\n",
++ __func__, board_info->board_info->type);
++ continue;
++ }
++
++ if (first)
++ sensor = subdev;
++ }
++
++ return sensor;
++}
++
++static int isp_register_entities(struct isp_device *isp)
++{
++ struct isp_platform_data *pdata = isp->pdata;
++ struct isp_v4l2_subdevs_group *subdevs;
++ int ret;
++
++ isp->media_dev.dev = isp->dev;
++ strlcpy(isp->media_dev.model, "TI OMAP3 ISP",
++ sizeof(isp->media_dev.model));
++ isp->media_dev.link_notify = isp_pipeline_link_notify;
++ ret = media_device_register(&isp->media_dev);
++ if (ret < 0) {
++ printk(KERN_ERR "%s: Media device registration failed (%d)\n",
++ __func__, ret);
++ return ret;
++ }
++
++ isp->v4l2_dev.mdev = &isp->media_dev;
++ ret = v4l2_device_register(isp->dev, &isp->v4l2_dev);
++ if (ret < 0) {
++ printk(KERN_ERR "%s: V4L2 device registration failed (%d)\n",
++ __func__, ret);
++ goto done;
++ }
++
++ /* Register internal entities */
++ ret = omap3isp_ccp2_register_entities(&isp->isp_ccp2, &isp->v4l2_dev);
++ if (ret < 0)
++ goto done;
++
++ ret = omap3isp_csi2_register_entities(&isp->isp_csi2a, &isp->v4l2_dev);
++ if (ret < 0)
++ goto done;
++
++ ret = omap3isp_ccdc_register_entities(&isp->isp_ccdc, &isp->v4l2_dev);
++ if (ret < 0)
++ goto done;
++
++ ret = omap3isp_preview_register_entities(&isp->isp_prev,
++ &isp->v4l2_dev);
++ if (ret < 0)
++ goto done;
++
++ ret = omap3isp_resizer_register_entities(&isp->isp_res, &isp->v4l2_dev);
++ if (ret < 0)
++ goto done;
++
++ ret = omap3isp_stat_register_entities(&isp->isp_aewb, &isp->v4l2_dev);
++ if (ret < 0)
++ goto done;
++
++ ret = omap3isp_stat_register_entities(&isp->isp_af, &isp->v4l2_dev);
++ if (ret < 0)
++ goto done;
++
++ ret = omap3isp_stat_register_entities(&isp->isp_hist, &isp->v4l2_dev);
++ if (ret < 0)
++ goto done;
++
++ /* Register external entities */
++ for (subdevs = pdata->subdevs; subdevs->subdevs; ++subdevs) {
++ struct v4l2_subdev *sensor;
++ struct media_entity *input;
++ unsigned int flags;
++ unsigned int pad;
++
++ sensor = isp_register_subdev_group(isp, subdevs->subdevs);
++ if (sensor == NULL)
++ continue;
++
++ sensor->host_priv = subdevs;
++
++ /* Connect the sensor to the correct interface module. Parallel
++ * sensors are connected directly to the CCDC, while serial
++ * sensors are connected to the CSI2a, CCP2b or CSI2c receiver
++ * through CSIPHY1 or CSIPHY2.
++ */
++ switch (subdevs->interface) {
++ case ISP_INTERFACE_PARALLEL:
++ input = &isp->isp_ccdc.subdev.entity;
++ pad = CCDC_PAD_SINK;
++ flags = 0;
++ break;
++
++ case ISP_INTERFACE_CSI2A_PHY2:
++ input = &isp->isp_csi2a.subdev.entity;
++ pad = CSI2_PAD_SINK;
++ flags = MEDIA_LNK_FL_IMMUTABLE
++ | MEDIA_LNK_FL_ENABLED;
++ break;
++
++ case ISP_INTERFACE_CCP2B_PHY1:
++ case ISP_INTERFACE_CCP2B_PHY2:
++ input = &isp->isp_ccp2.subdev.entity;
++ pad = CCP2_PAD_SINK;
++ flags = 0;
++ break;
++
++ case ISP_INTERFACE_CSI2C_PHY1:
++ input = &isp->isp_csi2c.subdev.entity;
++ pad = CSI2_PAD_SINK;
++ flags = MEDIA_LNK_FL_IMMUTABLE
++ | MEDIA_LNK_FL_ENABLED;
++ break;
++
++ default:
++ printk(KERN_ERR "%s: invalid interface type %u\n",
++ __func__, subdevs->interface);
++ ret = -EINVAL;
++ goto done;
++ }
++
++ ret = media_entity_create_link(&sensor->entity, 0, input, pad,
++ flags);
++ if (ret < 0)
++ goto done;
++ }
++
++done:
++ if (ret < 0)
++ isp_unregister_entities(isp);
++
++ return ret;
++}
++
++static void isp_cleanup_modules(struct isp_device *isp)
++{
++ omap3isp_h3a_aewb_cleanup(isp);
++ omap3isp_h3a_af_cleanup(isp);
++ omap3isp_hist_cleanup(isp);
++ omap3isp_resizer_cleanup(isp);
++ omap3isp_preview_cleanup(isp);
++ omap3isp_ccdc_cleanup(isp);
++ omap3isp_ccp2_cleanup(isp);
++ omap3isp_csi2_cleanup(isp);
++}
++
++static int isp_initialize_modules(struct isp_device *isp)
++{
++ int ret;
++
++ ret = omap3isp_csiphy_init(isp);
++ if (ret < 0) {
++ dev_err(isp->dev, "CSI PHY initialization failed\n");
++ goto error_csiphy;
++ }
++
++ ret = omap3isp_csi2_init(isp);
++ if (ret < 0) {
++ dev_err(isp->dev, "CSI2 initialization failed\n");
++ goto error_csi2;
++ }
++
++ ret = omap3isp_ccp2_init(isp);
++ if (ret < 0) {
++ dev_err(isp->dev, "CCP2 initialization failed\n");
++ goto error_ccp2;
++ }
++
++ ret = omap3isp_ccdc_init(isp);
++ if (ret < 0) {
++ dev_err(isp->dev, "CCDC initialization failed\n");
++ goto error_ccdc;
++ }
++
++ ret = omap3isp_preview_init(isp);
++ if (ret < 0) {
++ dev_err(isp->dev, "Preview initialization failed\n");
++ goto error_preview;
++ }
++
++ ret = omap3isp_resizer_init(isp);
++ if (ret < 0) {
++ dev_err(isp->dev, "Resizer initialization failed\n");
++ goto error_resizer;
++ }
++
++ ret = omap3isp_hist_init(isp);
++ if (ret < 0) {
++ dev_err(isp->dev, "Histogram initialization failed\n");
++ goto error_hist;
++ }
++
++ ret = omap3isp_h3a_aewb_init(isp);
++ if (ret < 0) {
++ dev_err(isp->dev, "H3A AEWB initialization failed\n");
++ goto error_h3a_aewb;
++ }
++
++ ret = omap3isp_h3a_af_init(isp);
++ if (ret < 0) {
++ dev_err(isp->dev, "H3A AF initialization failed\n");
++ goto error_h3a_af;
++ }
++
++ /* Connect the submodules. */
++ ret = media_entity_create_link(
++ &isp->isp_csi2a.subdev.entity, CSI2_PAD_SOURCE,
++ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0);
++ if (ret < 0)
++ goto error_link;
++
++ ret = media_entity_create_link(
++ &isp->isp_ccp2.subdev.entity, CCP2_PAD_SOURCE,
++ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0);
++ if (ret < 0)
++ goto error_link;
++
++ ret = media_entity_create_link(
++ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
++ &isp->isp_prev.subdev.entity, PREV_PAD_SINK, 0);
++ if (ret < 0)
++ goto error_link;
++
++ ret = media_entity_create_link(
++ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_OF,
++ &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0);
++ if (ret < 0)
++ goto error_link;
++
++ ret = media_entity_create_link(
++ &isp->isp_prev.subdev.entity, PREV_PAD_SOURCE,
++ &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0);
++ if (ret < 0)
++ goto error_link;
++
++ ret = media_entity_create_link(
++ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
++ &isp->isp_aewb.subdev.entity, 0,
++ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
++ if (ret < 0)
++ goto error_link;
++
++ ret = media_entity_create_link(
++ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
++ &isp->isp_af.subdev.entity, 0,
++ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
++ if (ret < 0)
++ goto error_link;
++
++ ret = media_entity_create_link(
++ &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP,
++ &isp->isp_hist.subdev.entity, 0,
++ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
++ if (ret < 0)
++ goto error_link;
++
++ return 0;
++
++error_link:
++ omap3isp_h3a_af_cleanup(isp);
++error_h3a_af:
++ omap3isp_h3a_aewb_cleanup(isp);
++error_h3a_aewb:
++ omap3isp_hist_cleanup(isp);
++error_hist:
++ omap3isp_resizer_cleanup(isp);
++error_resizer:
++ omap3isp_preview_cleanup(isp);
++error_preview:
++ omap3isp_ccdc_cleanup(isp);
++error_ccdc:
++ omap3isp_ccp2_cleanup(isp);
++error_ccp2:
++ omap3isp_csi2_cleanup(isp);
++error_csi2:
++error_csiphy:
++ return ret;
++}
++
++/*
++ * isp_remove - Remove ISP platform device
++ * @pdev: Pointer to ISP platform device
++ *
++ * Always returns 0.
++ */
++static int isp_remove(struct platform_device *pdev)
++{
++ struct isp_device *isp = platform_get_drvdata(pdev);
++ int i;
++
++ isp_unregister_entities(isp);
++ isp_cleanup_modules(isp);
++
++ omap3isp_get(isp);
++ iommu_put(isp->iommu);
++ omap3isp_put(isp);
++
++ free_irq(isp->irq_num, isp);
++ isp_put_clocks(isp);
++
++ for (i = 0; i < OMAP3_ISP_IOMEM_LAST; i++) {
++ if (isp->mmio_base[i]) {
++ iounmap(isp->mmio_base[i]);
++ isp->mmio_base[i] = NULL;
++ }
++
++ if (isp->mmio_base_phys[i]) {
++ release_mem_region(isp->mmio_base_phys[i],
++ isp->mmio_size[i]);
++ isp->mmio_base_phys[i] = 0;
++ }
++ }
++
++ regulator_put(isp->isp_csiphy1.vdd);
++ regulator_put(isp->isp_csiphy2.vdd);
++ kfree(isp);
++
++ return 0;
++}
++
++static int isp_map_mem_resource(struct platform_device *pdev,
++ struct isp_device *isp,
++ enum isp_mem_resources res)
++{
++ struct resource *mem;
++
++ /* request the mem region for the camera registers */
++
++ mem = platform_get_resource(pdev, IORESOURCE_MEM, res);
++ if (!mem) {
++ dev_err(isp->dev, "no mem resource?\n");
++ return -ENODEV;
++ }
++
++ if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
++ dev_err(isp->dev,
++ "cannot reserve camera register I/O region\n");
++ return -ENODEV;
++ }
++ isp->mmio_base_phys[res] = mem->start;
++ isp->mmio_size[res] = resource_size(mem);
++
++ /* map the region */
++ isp->mmio_base[res] = ioremap_nocache(isp->mmio_base_phys[res],
++ isp->mmio_size[res]);
++ if (!isp->mmio_base[res]) {
++ dev_err(isp->dev, "cannot map camera register I/O region\n");
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
++/*
++ * isp_probe - Probe ISP platform device
++ * @pdev: Pointer to ISP platform device
++ *
++ * Returns 0 if successful,
++ * -ENOMEM if no memory available,
++ * -ENODEV if no platform device resources found
++ * or no space for remapping registers,
++ * -EINVAL if couldn't install ISR,
++ * or clk_get return error value.
++ */
++static int isp_probe(struct platform_device *pdev)
++{
++ struct isp_platform_data *pdata = pdev->dev.platform_data;
++ struct isp_device *isp;
++ int ret;
++ int i, m;
++
++ if (pdata == NULL)
++ return -EINVAL;
++
++ isp = kzalloc(sizeof(*isp), GFP_KERNEL);
++ if (!isp) {
++ dev_err(&pdev->dev, "could not allocate memory\n");
++ return -ENOMEM;
++ }
++
++ isp->autoidle = autoidle;
++ isp->platform_cb.set_xclk = isp_set_xclk;
++ isp->platform_cb.set_pixel_clock = isp_set_pixel_clock;
++
++ mutex_init(&isp->isp_mutex);
++ spin_lock_init(&isp->stat_lock);
++
++ isp->dev = &pdev->dev;
++ isp->pdata = pdata;
++ isp->ref_count = 0;
++
++ isp->raw_dmamask = DMA_BIT_MASK(32);
++ isp->dev->dma_mask = &isp->raw_dmamask;
++ isp->dev->coherent_dma_mask = DMA_BIT_MASK(32);
++
++ platform_set_drvdata(pdev, isp);
++
++ /* Regulators */
++ isp->isp_csiphy1.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY1");
++ isp->isp_csiphy2.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY2");
++
++ /* Clocks */
++ ret = isp_map_mem_resource(pdev, isp, OMAP3_ISP_IOMEM_MAIN);
++ if (ret < 0)
++ goto error;
++
++ ret = isp_get_clocks(isp);
++ if (ret < 0)
++ goto error;
++
++ if (omap3isp_get(isp) == NULL)
++ goto error;
++
++ ret = isp_reset(isp);
++ if (ret < 0)
++ goto error_isp;
++
++ /* Memory resources */
++ isp->revision = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
++ dev_info(isp->dev, "Revision %d.%d found\n",
++ (isp->revision & 0xf0) >> 4, isp->revision & 0x0f);
++
++ for (m = 0; m < ARRAY_SIZE(isp_res_maps); m++)
++ if (isp->revision == isp_res_maps[m].isp_rev)
++ break;
++
++ if (m == ARRAY_SIZE(isp_res_maps)) {
++ dev_err(isp->dev, "No resource map found for ISP rev %d.%d\n",
++ (isp->revision & 0xf0) >> 4, isp->revision & 0xf);
++ ret = -ENODEV;
++ goto error_isp;
++ }
++
++ for (i = 1; i < OMAP3_ISP_IOMEM_LAST; i++) {
++ if (isp_res_maps[m].map & 1 << i) {
++ ret = isp_map_mem_resource(pdev, isp, i);
++ if (ret)
++ goto error_isp;
++ }
++ }
++
++ /* IOMMU */
++ isp->iommu = iommu_get("isp");
++ if (IS_ERR_OR_NULL(isp->iommu)) {
++ isp->iommu = NULL;
++ ret = -ENODEV;
++ goto error_isp;
++ }
++
++ /* Interrupt */
++ isp->irq_num = platform_get_irq(pdev, 0);
++ if (isp->irq_num <= 0) {
++ dev_err(isp->dev, "No IRQ resource\n");
++ ret = -ENODEV;
++ goto error_isp;
++ }
++
++ if (request_irq(isp->irq_num, isp_isr, IRQF_SHARED, "OMAP3 ISP", isp)) {
++ dev_err(isp->dev, "Unable to request IRQ\n");
++ ret = -EINVAL;
++ goto error_isp;
++ }
++
++ /* Entities */
++ ret = isp_initialize_modules(isp);
++ if (ret < 0)
++ goto error_irq;
++
++ ret = isp_register_entities(isp);
++ if (ret < 0)
++ goto error_modules;
++
++ isp_power_settings(isp, 1);
++ omap3isp_put(isp);
++
++ return 0;
++
++error_modules:
++ isp_cleanup_modules(isp);
++error_irq:
++ free_irq(isp->irq_num, isp);
++error_isp:
++ iommu_put(isp->iommu);
++ omap3isp_put(isp);
++error:
++ isp_put_clocks(isp);
++
++ for (i = 0; i < OMAP3_ISP_IOMEM_LAST; i++) {
++ if (isp->mmio_base[i]) {
++ iounmap(isp->mmio_base[i]);
++ isp->mmio_base[i] = NULL;
++ }
++
++ if (isp->mmio_base_phys[i]) {
++ release_mem_region(isp->mmio_base_phys[i],
++ isp->mmio_size[i]);
++ isp->mmio_base_phys[i] = 0;
++ }
++ }
++ regulator_put(isp->isp_csiphy2.vdd);
++ regulator_put(isp->isp_csiphy1.vdd);
++ platform_set_drvdata(pdev, NULL);
++ kfree(isp);
++
++ return ret;
++}
++
++static const struct dev_pm_ops omap3isp_pm_ops = {
++ .prepare = isp_pm_prepare,
++ .suspend = isp_pm_suspend,
++ .resume = isp_pm_resume,
++ .complete = isp_pm_complete,
++};
++
++static struct platform_device_id omap3isp_id_table[] = {
++ { "omap3isp", 0 },
++ { },
++};
++MODULE_DEVICE_TABLE(platform, omap3isp_id_table);
++
++static struct platform_driver omap3isp_driver = {
++ .probe = isp_probe,
++ .remove = isp_remove,
++ .id_table = omap3isp_id_table,
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "omap3isp",
++ .pm = &omap3isp_pm_ops,
++ },
++};
++
++/*
++ * isp_init - ISP module initialization.
++ */
++static int __init isp_init(void)
++{
++ return platform_driver_register(&omap3isp_driver);
++}
++
++/*
++ * isp_cleanup - ISP module cleanup.
++ */
++static void __exit isp_cleanup(void)
++{
++ platform_driver_unregister(&omap3isp_driver);
++}
++
++module_init(isp_init);
++module_exit(isp_cleanup);
++
++MODULE_AUTHOR("Nokia Corporation");
++MODULE_DESCRIPTION("TI OMAP3 ISP driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/video/isp/isp.h b/drivers/media/video/isp/isp.h
+new file mode 100644
+index 0000000..44590a5
+--- /dev/null
++++ b/drivers/media/video/isp/isp.h
+@@ -0,0 +1,427 @@
++/*
++ * isp.h
++ *
++ * TI OMAP3 ISP - Core
++ *
++ * Copyright (C) 2009-2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc.
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#ifndef OMAP3_ISP_CORE_H
++#define OMAP3_ISP_CORE_H
++
++#include <media/v4l2-device.h>
++#include <linux/device.h>
++#include <linux/io.h>
++#include <linux/platform_device.h>
++#include <linux/wait.h>
++#include <plat/iommu.h>
++#include <plat/iovmm.h>
++
++#include "ispstat.h"
++#include "ispccdc.h"
++#include "ispreg.h"
++#include "ispresizer.h"
++#include "isppreview.h"
++#include "ispcsiphy.h"
++#include "ispcsi2.h"
++#include "ispccp2.h"
++
++#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8)
++
++#define ISP_TOK_TERM 0xFFFFFFFF /*
++ * terminating token for ISP
++ * modules reg list
++ */
++#define to_isp_device(ptr_module) \
++ container_of(ptr_module, struct isp_device, isp_##ptr_module)
++#define to_device(ptr_module) \
++ (to_isp_device(ptr_module)->dev)
++
++enum isp_mem_resources {
++ OMAP3_ISP_IOMEM_MAIN,
++ OMAP3_ISP_IOMEM_CCP2,
++ OMAP3_ISP_IOMEM_CCDC,
++ OMAP3_ISP_IOMEM_HIST,
++ OMAP3_ISP_IOMEM_H3A,
++ OMAP3_ISP_IOMEM_PREV,
++ OMAP3_ISP_IOMEM_RESZ,
++ OMAP3_ISP_IOMEM_SBL,
++ OMAP3_ISP_IOMEM_CSI2A_REGS1,
++ OMAP3_ISP_IOMEM_CSIPHY2,
++ OMAP3_ISP_IOMEM_CSI2A_REGS2,
++ OMAP3_ISP_IOMEM_CSI2C_REGS1,
++ OMAP3_ISP_IOMEM_CSIPHY1,
++ OMAP3_ISP_IOMEM_CSI2C_REGS2,
++ OMAP3_ISP_IOMEM_LAST
++};
++
++enum isp_sbl_resource {
++ OMAP3_ISP_SBL_CSI1_READ = 0x1,
++ OMAP3_ISP_SBL_CSI1_WRITE = 0x2,
++ OMAP3_ISP_SBL_CSI2A_WRITE = 0x4,
++ OMAP3_ISP_SBL_CSI2C_WRITE = 0x8,
++ OMAP3_ISP_SBL_CCDC_LSC_READ = 0x10,
++ OMAP3_ISP_SBL_CCDC_WRITE = 0x20,
++ OMAP3_ISP_SBL_PREVIEW_READ = 0x40,
++ OMAP3_ISP_SBL_PREVIEW_WRITE = 0x80,
++ OMAP3_ISP_SBL_RESIZER_READ = 0x100,
++ OMAP3_ISP_SBL_RESIZER_WRITE = 0x200,
++};
++
++enum isp_subclk_resource {
++ OMAP3_ISP_SUBCLK_CCDC = (1 << 0),
++ OMAP3_ISP_SUBCLK_H3A = (1 << 1),
++ OMAP3_ISP_SUBCLK_HIST = (1 << 2),
++ OMAP3_ISP_SUBCLK_PREVIEW = (1 << 3),
++ OMAP3_ISP_SUBCLK_RESIZER = (1 << 4),
++};
++
++enum isp_interface_type {
++ ISP_INTERFACE_PARALLEL,
++ ISP_INTERFACE_CSI2A_PHY2,
++ ISP_INTERFACE_CCP2B_PHY1,
++ ISP_INTERFACE_CCP2B_PHY2,
++ ISP_INTERFACE_CSI2C_PHY1,
++};
++
++#define ISP_REVISION_1_0 0x10
++#define ISP_REVISION_2_0 0x20
++#define ISP_REVISION_15_0 0xF0
++
++/*
++ * struct isp_res_mapping - Map ISP io resources to ISP revision.
++ * @isp_rev: ISP_REVISION_x_x
++ * @map: bitmap for enum isp_mem_resources
++ */
++struct isp_res_mapping {
++ u32 isp_rev;
++ u32 map;
++};
++
++/*
++ * struct isp_reg - Structure for ISP register values.
++ * @reg: 32-bit Register address.
++ * @val: 32-bit Register value.
++ */
++struct isp_reg {
++ enum isp_mem_resources mmio_range;
++ u32 reg;
++ u32 val;
++};
++
++/**
++ * struct isp_parallel_platform_data - Parallel interface platform data
++ * @width: Parallel bus width in bits (8, 10, 11 or 12)
++ * @data_lane_shift: Data lane shifter
++ * 0 - CAMEXT[13:0] -> CAM[13:0]
++ * 1 - CAMEXT[13:2] -> CAM[11:0]
++ * 2 - CAMEXT[13:4] -> CAM[9:0]
++ * 3 - CAMEXT[13:6] -> CAM[7:0]
++ * @clk_pol: Pixel clock polarity
++ * 0 - Non Inverted, 1 - Inverted
++ * @bridge: CCDC Bridge input control
++ * ISPCTRL_PAR_BRIDGE_DISABLE - Disable
++ * ISPCTRL_PAR_BRIDGE_LENDIAN - Little endian
++ * ISPCTRL_PAR_BRIDGE_BENDIAN - Big endian
++ */
++struct isp_parallel_platform_data {
++ unsigned int width;
++ unsigned int data_lane_shift:2;
++ unsigned int clk_pol:1;
++ unsigned int bridge:4;
++};
++
++/**
++ * struct isp_ccp2_platform_data - CCP2 interface platform data
++ * @strobe_clk_pol: Strobe/clock polarity
++ * 0 - Non Inverted, 1 - Inverted
++ * @crc: Enable the cyclic redundancy check
++ * @ccp2_mode: Enable CCP2 compatibility mode
++ * 0 - MIPI-CSI1 mode, 1 - CCP2 mode
++ * @phy_layer: Physical layer selection
++ * ISPCCP2_CTRL_PHY_SEL_CLOCK - Data/clock physical layer
++ * ISPCCP2_CTRL_PHY_SEL_STROBE - Data/strobe physical layer
++ * @vpclk_div: Video port output clock control
++ */
++struct isp_ccp2_platform_data {
++ unsigned int strobe_clk_pol:1;
++ unsigned int crc:1;
++ unsigned int ccp2_mode:1;
++ unsigned int phy_layer:1;
++ unsigned int vpclk_div:2;
++};
++
++/**
++ * struct isp_csi2_platform_data - CSI2 interface platform data
++ * @crc: Enable the cyclic redundancy check
++ * @vpclk_div: Video port output clock control
++ */
++struct isp_csi2_platform_data {
++ unsigned crc:1;
++ unsigned vpclk_div:2;
++};
++
++struct isp_subdev_i2c_board_info {
++ struct i2c_board_info *board_info;
++ int i2c_adapter_id;
++};
++
++struct isp_v4l2_subdevs_group {
++ struct isp_subdev_i2c_board_info *subdevs;
++ enum isp_interface_type interface;
++ union {
++ struct isp_parallel_platform_data parallel;
++ struct isp_ccp2_platform_data ccp2;
++ struct isp_csi2_platform_data csi2;
++ } bus; /* gcc < 4.6.0 chokes on anonymous union initializers */
++};
++
++struct isp_platform_data {
++ struct isp_v4l2_subdevs_group *subdevs;
++};
++
++struct isp_platform_callback {
++ u32 (*set_xclk)(struct isp_device *isp, u32 xclk, u8 xclksel);
++ int (*csiphy_config)(struct isp_csiphy *phy,
++ struct isp_csiphy_dphy_cfg *dphy,
++ struct isp_csiphy_lanes_cfg *lanes);
++ void (*set_pixel_clock)(struct isp_device *isp, unsigned int pixelclk);
++};
++
++/*
++ * struct isp_device - ISP device structure.
++ * @dev: Device pointer specific to the OMAP3 ISP.
++ * @revision: Stores current ISP module revision.
++ * @irq_num: Currently used IRQ number.
++ * @mmio_base: Array with kernel base addresses for ioremapped ISP register
++ * regions.
++ * @mmio_base_phys: Array with physical L4 bus addresses for ISP register
++ * regions.
++ * @mmio_size: Array with ISP register regions size in bytes.
++ * @raw_dmamask: Raw DMA mask
++ * @stat_lock: Spinlock for handling statistics
++ * @isp_mutex: Mutex for serializing requests to ISP.
++ * @has_context: Context has been saved at least once and can be restored.
++ * @ref_count: Reference count for handling multiple ISP requests.
++ * @cam_ick: Pointer to camera interface clock structure.
++ * @cam_mclk: Pointer to camera functional clock structure.
++ * @dpll4_m5_ck: Pointer to DPLL4 M5 clock structure.
++ * @csi2_fck: Pointer to camera CSI2 complexIO clock structure.
++ * @l3_ick: Pointer to OMAP3 L3 bus interface clock.
++ * @irq: Currently attached ISP ISR callbacks information structure.
++ * @isp_af: Pointer to current settings for ISP AutoFocus SCM.
++ * @isp_hist: Pointer to current settings for ISP Histogram SCM.
++ * @isp_h3a: Pointer to current settings for ISP Auto Exposure and
++ * White Balance SCM.
++ * @isp_res: Pointer to current settings for ISP Resizer.
++ * @isp_prev: Pointer to current settings for ISP Preview.
++ * @isp_ccdc: Pointer to current settings for ISP CCDC.
++ * @iommu: Pointer to requested IOMMU instance for ISP.
++ * @platform_cb: ISP driver callback function pointers for platform code
++ *
++ * This structure is used to store the OMAP ISP Information.
++ */
++struct isp_device {
++ struct v4l2_device v4l2_dev;
++ struct media_device media_dev;
++ struct device *dev;
++ u32 revision;
++
++ /* platform HW resources */
++ struct isp_platform_data *pdata;
++ unsigned int irq_num;
++
++ void __iomem *mmio_base[OMAP3_ISP_IOMEM_LAST];
++ unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_LAST];
++ resource_size_t mmio_size[OMAP3_ISP_IOMEM_LAST];
++
++ u64 raw_dmamask;
++
++ /* ISP Obj */
++ spinlock_t stat_lock; /* common lock for statistic drivers */
++ struct mutex isp_mutex; /* For handling ref_count field */
++ int has_context;
++ int ref_count;
++ unsigned int autoidle;
++ u32 xclk_divisor[2]; /* Two clocks, a and b. */
++#define ISP_CLK_CAM_ICK 0
++#define ISP_CLK_CAM_MCLK 1
++#define ISP_CLK_DPLL4_M5_CK 2
++#define ISP_CLK_CSI2_FCK 3
++#define ISP_CLK_L3_ICK 4
++ struct clk *clock[5];
++
++ /* ISP modules */
++ struct ispstat isp_af;
++ struct ispstat isp_aewb;
++ struct ispstat isp_hist;
++ struct isp_res_device isp_res;
++ struct isp_prev_device isp_prev;
++ struct isp_ccdc_device isp_ccdc;
++ struct isp_csi2_device isp_csi2a;
++ struct isp_csi2_device isp_csi2c;
++ struct isp_ccp2_device isp_ccp2;
++ struct isp_csiphy isp_csiphy1;
++ struct isp_csiphy isp_csiphy2;
++
++ unsigned int sbl_resources;
++ unsigned int subclk_resources;
++
++ struct iommu *iommu;
++
++ struct isp_platform_callback platform_cb;
++};
++
++#define v4l2_dev_to_isp_device(dev) \
++ container_of(dev, struct isp_device, v4l2_dev)
++
++void omap3isp_hist_dma_done(struct isp_device *isp);
++
++void omap3isp_flush(struct isp_device *isp);
++
++int omap3isp_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait,
++ atomic_t *stopping);
++
++int omap3isp_module_sync_is_stopping(wait_queue_head_t *wait,
++ atomic_t *stopping);
++
++int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
++ enum isp_pipeline_stream_state state);
++void omap3isp_configure_bridge(struct isp_device *isp,
++ enum ccdc_input_entity input,
++ const struct isp_parallel_platform_data *pdata);
++
++#define ISP_XCLK_NONE -1
++#define ISP_XCLK_A 0
++#define ISP_XCLK_B 1
++
++struct isp_device *omap3isp_get(struct isp_device *isp);
++void omap3isp_put(struct isp_device *isp);
++
++void omap3isp_print_status(struct isp_device *isp);
++
++void omap3isp_sbl_enable(struct isp_device *isp, enum isp_sbl_resource res);
++void omap3isp_sbl_disable(struct isp_device *isp, enum isp_sbl_resource res);
++
++void omap3isp_subclk_enable(struct isp_device *isp,
++ enum isp_subclk_resource res);
++void omap3isp_subclk_disable(struct isp_device *isp,
++ enum isp_subclk_resource res);
++
++int omap3isp_pipeline_pm_use(struct media_entity *entity, int use);
++
++int omap3isp_register_entities(struct platform_device *pdev,
++ struct v4l2_device *v4l2_dev);
++void omap3isp_unregister_entities(struct platform_device *pdev);
++
++/*
++ * isp_reg_readl - Read value of an OMAP3 ISP register
++ * @dev: Device pointer specific to the OMAP3 ISP.
++ * @isp_mmio_range: Range to which the register offset refers to.
++ * @reg_offset: Register offset to read from.
++ *
++ * Returns an unsigned 32 bit value with the required register contents.
++ */
++static inline
++u32 isp_reg_readl(struct isp_device *isp, enum isp_mem_resources isp_mmio_range,
++ u32 reg_offset)
++{
++ return __raw_readl(isp->mmio_base[isp_mmio_range] + reg_offset);
++}
++
++/*
++ * isp_reg_writel - Write value to an OMAP3 ISP register
++ * @dev: Device pointer specific to the OMAP3 ISP.
++ * @reg_value: 32 bit value to write to the register.
++ * @isp_mmio_range: Range to which the register offset refers to.
++ * @reg_offset: Register offset to write into.
++ */
++static inline
++void isp_reg_writel(struct isp_device *isp, u32 reg_value,
++ enum isp_mem_resources isp_mmio_range, u32 reg_offset)
++{
++ __raw_writel(reg_value, isp->mmio_base[isp_mmio_range] + reg_offset);
++}
++
++/*
++ * isp_reg_and - Clear individual bits in an OMAP3 ISP register
++ * @dev: Device pointer specific to the OMAP3 ISP.
++ * @mmio_range: Range to which the register offset refers to.
++ * @reg: Register offset to work on.
++ * @clr_bits: 32 bit value which would be cleared in the register.
++ */
++static inline
++void isp_reg_clr(struct isp_device *isp, enum isp_mem_resources mmio_range,
++ u32 reg, u32 clr_bits)
++{
++ u32 v = isp_reg_readl(isp, mmio_range, reg);
++
++ isp_reg_writel(isp, v & ~clr_bits, mmio_range, reg);
++}
++
++/*
++ * isp_reg_set - Set individual bits in an OMAP3 ISP register
++ * @dev: Device pointer specific to the OMAP3 ISP.
++ * @mmio_range: Range to which the register offset refers to.
++ * @reg: Register offset to work on.
++ * @set_bits: 32 bit value which would be set in the register.
++ */
++static inline
++void isp_reg_set(struct isp_device *isp, enum isp_mem_resources mmio_range,
++ u32 reg, u32 set_bits)
++{
++ u32 v = isp_reg_readl(isp, mmio_range, reg);
++
++ isp_reg_writel(isp, v | set_bits, mmio_range, reg);
++}
++
++/*
++ * isp_reg_clr_set - Clear and set invidial bits in an OMAP3 ISP register
++ * @dev: Device pointer specific to the OMAP3 ISP.
++ * @mmio_range: Range to which the register offset refers to.
++ * @reg: Register offset to work on.
++ * @clr_bits: 32 bit value which would be cleared in the register.
++ * @set_bits: 32 bit value which would be set in the register.
++ *
++ * The clear operation is done first, and then the set operation.
++ */
++static inline
++void isp_reg_clr_set(struct isp_device *isp, enum isp_mem_resources mmio_range,
++ u32 reg, u32 clr_bits, u32 set_bits)
++{
++ u32 v = isp_reg_readl(isp, mmio_range, reg);
++
++ isp_reg_writel(isp, (v & ~clr_bits) | set_bits, mmio_range, reg);
++}
++
++static inline enum v4l2_buf_type
++isp_pad_buffer_type(const struct v4l2_subdev *subdev, int pad)
++{
++ if (pad >= subdev->entity.num_pads)
++ return 0;
++
++ if (subdev->entity.pads[pad].flags & MEDIA_PAD_FL_INPUT)
++ return V4L2_BUF_TYPE_VIDEO_OUTPUT;
++ else
++ return V4L2_BUF_TYPE_VIDEO_CAPTURE;
++}
++
++#endif /* OMAP3_ISP_CORE_H */
+diff --git a/drivers/media/video/isp/ispccdc.c b/drivers/media/video/isp/ispccdc.c
+new file mode 100644
+index 0000000..cb71e4f
+--- /dev/null
++++ b/drivers/media/video/isp/ispccdc.c
+@@ -0,0 +1,2280 @@
++/*
++ * ispccdc.c
++ *
++ * TI OMAP3 ISP - CCDC module
++ *
++ * Copyright (C) 2009-2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc.
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#include <linux/module.h>
++#include <linux/uaccess.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
++#include <linux/mm.h>
++#include <linux/sched.h>
++#include <media/v4l2-ctrls.h>
++#include <media/v4l2-event.h>
++
++#include "isp.h"
++#include "ispreg.h"
++#include "ispccdc.h"
++
++static struct v4l2_mbus_framefmt *
++__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
++ unsigned int pad, enum v4l2_subdev_format_whence which);
++
++static const unsigned int ccdc_fmts[] = {
++ V4L2_MBUS_FMT_Y8_1X8,
++ V4L2_MBUS_FMT_SGRBG10_1X10,
++ V4L2_MBUS_FMT_SRGGB10_1X10,
++ V4L2_MBUS_FMT_SBGGR10_1X10,
++ V4L2_MBUS_FMT_SGBRG10_1X10,
++ V4L2_MBUS_FMT_SGRBG12_1X12,
++ V4L2_MBUS_FMT_SRGGB12_1X12,
++ V4L2_MBUS_FMT_SBGGR12_1X12,
++ V4L2_MBUS_FMT_SGBRG12_1X12,
++};
++
++/*
++ * ccdc_print_status - Print current CCDC Module register values.
++ * @ccdc: Pointer to ISP CCDC device.
++ *
++ * Also prints other debug information stored in the CCDC module.
++ */
++#define CCDC_PRINT_REGISTER(isp, name)\
++ dev_dbg(isp->dev, "###CCDC " #name "=0x%08x\n", \
++ isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_##name))
++
++static void ccdc_print_status(struct isp_ccdc_device *ccdc)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++
++ dev_dbg(isp->dev, "-------------CCDC Register dump-------------\n");
++
++ CCDC_PRINT_REGISTER(isp, PCR);
++ CCDC_PRINT_REGISTER(isp, SYN_MODE);
++ CCDC_PRINT_REGISTER(isp, HD_VD_WID);
++ CCDC_PRINT_REGISTER(isp, PIX_LINES);
++ CCDC_PRINT_REGISTER(isp, HORZ_INFO);
++ CCDC_PRINT_REGISTER(isp, VERT_START);
++ CCDC_PRINT_REGISTER(isp, VERT_LINES);
++ CCDC_PRINT_REGISTER(isp, CULLING);
++ CCDC_PRINT_REGISTER(isp, HSIZE_OFF);
++ CCDC_PRINT_REGISTER(isp, SDOFST);
++ CCDC_PRINT_REGISTER(isp, SDR_ADDR);
++ CCDC_PRINT_REGISTER(isp, CLAMP);
++ CCDC_PRINT_REGISTER(isp, DCSUB);
++ CCDC_PRINT_REGISTER(isp, COLPTN);
++ CCDC_PRINT_REGISTER(isp, BLKCMP);
++ CCDC_PRINT_REGISTER(isp, FPC);
++ CCDC_PRINT_REGISTER(isp, FPC_ADDR);
++ CCDC_PRINT_REGISTER(isp, VDINT);
++ CCDC_PRINT_REGISTER(isp, ALAW);
++ CCDC_PRINT_REGISTER(isp, REC656IF);
++ CCDC_PRINT_REGISTER(isp, CFG);
++ CCDC_PRINT_REGISTER(isp, FMTCFG);
++ CCDC_PRINT_REGISTER(isp, FMT_HORZ);
++ CCDC_PRINT_REGISTER(isp, FMT_VERT);
++ CCDC_PRINT_REGISTER(isp, PRGEVEN0);
++ CCDC_PRINT_REGISTER(isp, PRGEVEN1);
++ CCDC_PRINT_REGISTER(isp, PRGODD0);
++ CCDC_PRINT_REGISTER(isp, PRGODD1);
++ CCDC_PRINT_REGISTER(isp, VP_OUT);
++ CCDC_PRINT_REGISTER(isp, LSC_CONFIG);
++ CCDC_PRINT_REGISTER(isp, LSC_INITIAL);
++ CCDC_PRINT_REGISTER(isp, LSC_TABLE_BASE);
++ CCDC_PRINT_REGISTER(isp, LSC_TABLE_OFFSET);
++
++ dev_dbg(isp->dev, "--------------------------------------------\n");
++}
++
++/*
++ * omap3isp_ccdc_busy - Get busy state of the CCDC.
++ * @ccdc: Pointer to ISP CCDC device.
++ */
++int omap3isp_ccdc_busy(struct isp_ccdc_device *ccdc)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++
++ return isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR) &
++ ISPCCDC_PCR_BUSY;
++}
++
++/* -----------------------------------------------------------------------------
++ * Lens Shading Compensation
++ */
++
++/*
++ * ccdc_lsc_validate_config - Check that LSC configuration is valid.
++ * @ccdc: Pointer to ISP CCDC device.
++ * @lsc_cfg: the LSC configuration to check.
++ *
++ * Returns 0 if the LSC configuration is valid, or -EINVAL if invalid.
++ */
++static int ccdc_lsc_validate_config(struct isp_ccdc_device *ccdc,
++ struct omap3isp_ccdc_lsc_config *lsc_cfg)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++ struct v4l2_mbus_framefmt *format;
++ unsigned int paxel_width, paxel_height;
++ unsigned int paxel_shift_x, paxel_shift_y;
++ unsigned int min_width, min_height, min_size;
++ unsigned int input_width, input_height;
++
++ paxel_shift_x = lsc_cfg->gain_mode_m;
++ paxel_shift_y = lsc_cfg->gain_mode_n;
++
++ if ((paxel_shift_x < 2) || (paxel_shift_x > 6) ||
++ (paxel_shift_y < 2) || (paxel_shift_y > 6)) {
++ dev_dbg(isp->dev, "CCDC: LSC: Invalid paxel size\n");
++ return -EINVAL;
++ }
++
++ if (lsc_cfg->offset & 3) {
++ dev_dbg(isp->dev, "CCDC: LSC: Offset must be a multiple of "
++ "4\n");
++ return -EINVAL;
++ }
++
++ if ((lsc_cfg->initial_x & 1) || (lsc_cfg->initial_y & 1)) {
++ dev_dbg(isp->dev, "CCDC: LSC: initial_x and y must be even\n");
++ return -EINVAL;
++ }
++
++ format = __ccdc_get_format(ccdc, NULL, CCDC_PAD_SINK,
++ V4L2_SUBDEV_FORMAT_ACTIVE);
++ input_width = format->width;
++ input_height = format->height;
++
++ /* Calculate minimum bytesize for validation */
++ paxel_width = 1 << paxel_shift_x;
++ min_width = ((input_width + lsc_cfg->initial_x + paxel_width - 1)
++ >> paxel_shift_x) + 1;
++
++ paxel_height = 1 << paxel_shift_y;
++ min_height = ((input_height + lsc_cfg->initial_y + paxel_height - 1)
++ >> paxel_shift_y) + 1;
++
++ min_size = 4 * min_width * min_height;
++ if (min_size > lsc_cfg->size) {
++ dev_dbg(isp->dev, "CCDC: LSC: too small table\n");
++ return -EINVAL;
++ }
++ if (lsc_cfg->offset < (min_width * 4)) {
++ dev_dbg(isp->dev, "CCDC: LSC: Offset is too small\n");
++ return -EINVAL;
++ }
++ if ((lsc_cfg->size / lsc_cfg->offset) < min_height) {
++ dev_dbg(isp->dev, "CCDC: LSC: Wrong size/offset combination\n");
++ return -EINVAL;
++ }
++ return 0;
++}
++
++/*
++ * ccdc_lsc_program_table - Program Lens Shading Compensation table address.
++ * @ccdc: Pointer to ISP CCDC device.
++ */
++static void ccdc_lsc_program_table(struct isp_ccdc_device *ccdc, u32 addr)
++{
++ isp_reg_writel(to_isp_device(ccdc), addr,
++ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_TABLE_BASE);
++}
++
++/*
++ * ccdc_lsc_setup_regs - Configures the lens shading compensation module
++ * @ccdc: Pointer to ISP CCDC device.
++ */
++static void ccdc_lsc_setup_regs(struct isp_ccdc_device *ccdc,
++ struct omap3isp_ccdc_lsc_config *cfg)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++ int reg;
++
++ isp_reg_writel(isp, cfg->offset, OMAP3_ISP_IOMEM_CCDC,
++ ISPCCDC_LSC_TABLE_OFFSET);
++
++ reg = 0;
++ reg |= cfg->gain_mode_n << ISPCCDC_LSC_GAIN_MODE_N_SHIFT;
++ reg |= cfg->gain_mode_m << ISPCCDC_LSC_GAIN_MODE_M_SHIFT;
++ reg |= cfg->gain_format << ISPCCDC_LSC_GAIN_FORMAT_SHIFT;
++ isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG);
++
++ reg = 0;
++ reg &= ~ISPCCDC_LSC_INITIAL_X_MASK;
++ reg |= cfg->initial_x << ISPCCDC_LSC_INITIAL_X_SHIFT;
++ reg &= ~ISPCCDC_LSC_INITIAL_Y_MASK;
++ reg |= cfg->initial_y << ISPCCDC_LSC_INITIAL_Y_SHIFT;
++ isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_CCDC,
++ ISPCCDC_LSC_INITIAL);
++}
++
++static int ccdc_lsc_wait_prefetch(struct isp_ccdc_device *ccdc)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++ unsigned int wait;
++
++ isp_reg_writel(isp, IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ,
++ OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
++
++ /* timeout 1 ms */
++ for (wait = 0; wait < 1000; wait++) {
++ if (isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS) &
++ IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ) {
++ isp_reg_writel(isp, IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ,
++ OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
++ return 0;
++ }
++
++ rmb();
++ udelay(1);
++ }
++
++ return -ETIMEDOUT;
++}
++
++/*
++ * __ccdc_lsc_enable - Enables/Disables the Lens Shading Compensation module.
++ * @ccdc: Pointer to ISP CCDC device.
++ * @enable: 0 Disables LSC, 1 Enables LSC.
++ */
++static int __ccdc_lsc_enable(struct isp_ccdc_device *ccdc, int enable)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++ const struct v4l2_mbus_framefmt *format =
++ __ccdc_get_format(ccdc, NULL, CCDC_PAD_SINK,
++ V4L2_SUBDEV_FORMAT_ACTIVE);
++
++ if ((format->code != V4L2_MBUS_FMT_SGRBG10_1X10) &&
++ (format->code != V4L2_MBUS_FMT_SRGGB10_1X10) &&
++ (format->code != V4L2_MBUS_FMT_SBGGR10_1X10) &&
++ (format->code != V4L2_MBUS_FMT_SGBRG10_1X10))
++ return -EINVAL;
++
++ if (enable)
++ omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_LSC_READ);
++
++ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG,
++ ISPCCDC_LSC_ENABLE, enable ? ISPCCDC_LSC_ENABLE : 0);
++
++ if (enable) {
++ if (ccdc_lsc_wait_prefetch(ccdc) < 0) {
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC,
++ ISPCCDC_LSC_CONFIG, ISPCCDC_LSC_ENABLE);
++ ccdc->lsc.state = LSC_STATE_STOPPED;
++ dev_warn(to_device(ccdc), "LSC prefecth timeout\n");
++ return -ETIMEDOUT;
++ }
++ ccdc->lsc.state = LSC_STATE_RUNNING;
++ } else {
++ ccdc->lsc.state = LSC_STATE_STOPPING;
++ }
++
++ return 0;
++}
++
++static int ccdc_lsc_busy(struct isp_ccdc_device *ccdc)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++
++ return isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG) &
++ ISPCCDC_LSC_BUSY;
++}
++
++/* __ccdc_lsc_configure - Apply a new configuration to the LSC engine
++ * @ccdc: Pointer to ISP CCDC device
++ * @req: New configuration request
++ *
++ * context: in_interrupt()
++ */
++static int __ccdc_lsc_configure(struct isp_ccdc_device *ccdc,
++ struct ispccdc_lsc_config_req *req)
++{
++ if (!req->enable)
++ return -EINVAL;
++
++ if (ccdc_lsc_validate_config(ccdc, &req->config) < 0) {
++ dev_dbg(to_device(ccdc), "Discard LSC configuration\n");
++ return -EINVAL;
++ }
++
++ if (ccdc_lsc_busy(ccdc))
++ return -EBUSY;
++
++ ccdc_lsc_setup_regs(ccdc, &req->config);
++ ccdc_lsc_program_table(ccdc, req->table);
++ return 0;
++}
++
++/*
++ * ccdc_lsc_error_handler - Handle LSC prefetch error scenario.
++ * @ccdc: Pointer to ISP CCDC device.
++ *
++ * Disables LSC, and defers enablement to shadow registers update time.
++ */
++static void ccdc_lsc_error_handler(struct isp_ccdc_device *ccdc)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++ /*
++ * From OMAP3 TRM: When this event is pending, the module
++ * goes into transparent mode (output =input). Normal
++ * operation can be resumed at the start of the next frame
++ * after:
++ * 1) Clearing this event
++ * 2) Disabling the LSC module
++ * 3) Enabling it
++ */
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG,
++ ISPCCDC_LSC_ENABLE);
++ ccdc->lsc.state = LSC_STATE_STOPPED;
++}
++
++static void ccdc_lsc_free_request(struct isp_ccdc_device *ccdc,
++ struct ispccdc_lsc_config_req *req)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++
++ if (req == NULL)
++ return;
++
++ if (req->iovm)
++ dma_unmap_sg(isp->dev, req->iovm->sgt->sgl,
++ req->iovm->sgt->nents, DMA_TO_DEVICE);
++ if (req->table)
++ iommu_vfree(isp->iommu, req->table);
++ kfree(req);
++}
++
++static void ccdc_lsc_free_queue(struct isp_ccdc_device *ccdc,
++ struct list_head *queue)
++{
++ struct ispccdc_lsc_config_req *req, *n;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
++ list_for_each_entry_safe(req, n, queue, list) {
++ list_del(&req->list);
++ spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
++ ccdc_lsc_free_request(ccdc, req);
++ spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
++ }
++ spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
++}
++
++static void ccdc_lsc_free_table_work(struct work_struct *work)
++{
++ struct isp_ccdc_device *ccdc;
++ struct ispccdc_lsc *lsc;
++
++ lsc = container_of(work, struct ispccdc_lsc, table_work);
++ ccdc = container_of(lsc, struct isp_ccdc_device, lsc);
++
++ ccdc_lsc_free_queue(ccdc, &lsc->free_queue);
++}
++
++/*
++ * ccdc_lsc_config - Configure the LSC module from a userspace request
++ *
++ * Store the request LSC configuration in the LSC engine request pointer. The
++ * configuration will be applied to the hardware when the CCDC will be enabled,
++ * or at the next LSC interrupt if the CCDC is already running.
++ */
++static int ccdc_lsc_config(struct isp_ccdc_device *ccdc,
++ struct omap3isp_ccdc_update_config *config)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++ struct ispccdc_lsc_config_req *req;
++ unsigned long flags;
++ void *table;
++ u16 update;
++ int ret;
++
++ update = config->update &
++ (OMAP3ISP_CCDC_CONFIG_LSC | OMAP3ISP_CCDC_TBL_LSC);
++ if (!update)
++ return 0;
++
++ if (update != (OMAP3ISP_CCDC_CONFIG_LSC | OMAP3ISP_CCDC_TBL_LSC)) {
++ dev_dbg(to_device(ccdc), "%s: Both LSC configuration and table "
++ "need to be supplied\n", __func__);
++ return -EINVAL;
++ }
++
++ req = kzalloc(sizeof(*req), GFP_KERNEL);
++ if (req == NULL)
++ return -ENOMEM;
++
++ if (config->flag & OMAP3ISP_CCDC_CONFIG_LSC) {
++ if (copy_from_user(&req->config, config->lsc_cfg,
++ sizeof(req->config))) {
++ ret = -EFAULT;
++ goto done;
++ }
++
++ req->enable = 1;
++
++ req->table = iommu_vmalloc(isp->iommu, 0, req->config.size,
++ IOMMU_FLAG);
++ if (IS_ERR_VALUE(req->table)) {
++ req->table = 0;
++ ret = -ENOMEM;
++ goto done;
++ }
++
++ req->iovm = find_iovm_area(isp->iommu, req->table);
++ if (req->iovm == NULL) {
++ ret = -ENOMEM;
++ goto done;
++ }
++
++ if (!dma_map_sg(isp->dev, req->iovm->sgt->sgl,
++ req->iovm->sgt->nents, DMA_TO_DEVICE)) {
++ ret = -ENOMEM;
++ req->iovm = NULL;
++ goto done;
++ }
++
++ dma_sync_sg_for_cpu(isp->dev, req->iovm->sgt->sgl,
++ req->iovm->sgt->nents, DMA_TO_DEVICE);
++
++ table = da_to_va(isp->iommu, req->table);
++ if (copy_from_user(table, config->lsc, req->config.size)) {
++ ret = -EFAULT;
++ goto done;
++ }
++
++ dma_sync_sg_for_device(isp->dev, req->iovm->sgt->sgl,
++ req->iovm->sgt->nents, DMA_TO_DEVICE);
++ }
++
++ spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
++ if (ccdc->lsc.request) {
++ list_add_tail(&ccdc->lsc.request->list, &ccdc->lsc.free_queue);
++ schedule_work(&ccdc->lsc.table_work);
++ }
++ ccdc->lsc.request = req;
++ spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
++
++ ret = 0;
++
++done:
++ if (ret < 0)
++ ccdc_lsc_free_request(ccdc, req);
++
++ return ret;
++}
++
++static inline int ccdc_lsc_is_configured(struct isp_ccdc_device *ccdc)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
++ if (ccdc->lsc.active) {
++ spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
++ return 1;
++ }
++ spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
++ return 0;
++}
++
++static int ccdc_lsc_enable(struct isp_ccdc_device *ccdc)
++{
++ struct ispccdc_lsc *lsc = &ccdc->lsc;
++
++ if (lsc->state != LSC_STATE_STOPPED)
++ return -EINVAL;
++
++ if (lsc->active) {
++ list_add_tail(&lsc->active->list, &lsc->free_queue);
++ lsc->active = NULL;
++ }
++
++ if (__ccdc_lsc_configure(ccdc, lsc->request) < 0) {
++ omap3isp_sbl_disable(to_isp_device(ccdc),
++ OMAP3_ISP_SBL_CCDC_LSC_READ);
++ list_add_tail(&lsc->request->list, &lsc->free_queue);
++ lsc->request = NULL;
++ goto done;
++ }
++
++ lsc->active = lsc->request;
++ lsc->request = NULL;
++ __ccdc_lsc_enable(ccdc, 1);
++
++done:
++ if (!list_empty(&lsc->free_queue))
++ schedule_work(&lsc->table_work);
++
++ return 0;
++}
++
++/* -----------------------------------------------------------------------------
++ * Parameters configuration
++ */
++
++/*
++ * ccdc_configure_clamp - Configure optical-black or digital clamping
++ * @ccdc: Pointer to ISP CCDC device.
++ *
++ * The CCDC performs either optical-black or digital clamp. Configure and enable
++ * the selected clamp method.
++ */
++static void ccdc_configure_clamp(struct isp_ccdc_device *ccdc)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++ u32 clamp;
++
++ if (ccdc->obclamp) {
++ clamp = ccdc->clamp.obgain << ISPCCDC_CLAMP_OBGAIN_SHIFT;
++ clamp |= ccdc->clamp.oblen << ISPCCDC_CLAMP_OBSLEN_SHIFT;
++ clamp |= ccdc->clamp.oblines << ISPCCDC_CLAMP_OBSLN_SHIFT;
++ clamp |= ccdc->clamp.obstpixel << ISPCCDC_CLAMP_OBST_SHIFT;
++ isp_reg_writel(isp, clamp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP);
++ } else {
++ isp_reg_writel(isp, ccdc->clamp.dcsubval,
++ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_DCSUB);
++ }
++
++ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP,
++ ISPCCDC_CLAMP_CLAMPEN,
++ ccdc->obclamp ? ISPCCDC_CLAMP_CLAMPEN : 0);
++}
++
++/*
++ * ccdc_configure_fpc - Configure Faulty Pixel Correction
++ * @ccdc: Pointer to ISP CCDC device.
++ */
++static void ccdc_configure_fpc(struct isp_ccdc_device *ccdc)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC, ISPCCDC_FPC_FPCEN);
++
++ if (!ccdc->fpc_en)
++ return;
++
++ isp_reg_writel(isp, ccdc->fpc.fpcaddr, OMAP3_ISP_IOMEM_CCDC,
++ ISPCCDC_FPC_ADDR);
++ /* The FPNUM field must be set before enabling FPC. */
++ isp_reg_writel(isp, (ccdc->fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT),
++ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
++ isp_reg_writel(isp, (ccdc->fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT) |
++ ISPCCDC_FPC_FPCEN, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
++}
++
++/*
++ * ccdc_configure_black_comp - Configure Black Level Compensation.
++ * @ccdc: Pointer to ISP CCDC device.
++ */
++static void ccdc_configure_black_comp(struct isp_ccdc_device *ccdc)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++ u32 blcomp;
++
++ blcomp = ccdc->blcomp.b_mg << ISPCCDC_BLKCMP_B_MG_SHIFT;
++ blcomp |= ccdc->blcomp.gb_g << ISPCCDC_BLKCMP_GB_G_SHIFT;
++ blcomp |= ccdc->blcomp.gr_cy << ISPCCDC_BLKCMP_GR_CY_SHIFT;
++ blcomp |= ccdc->blcomp.r_ye << ISPCCDC_BLKCMP_R_YE_SHIFT;
++
++ isp_reg_writel(isp, blcomp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_BLKCMP);
++}
++
++/*
++ * ccdc_configure_lpf - Configure Low-Pass Filter (LPF).
++ * @ccdc: Pointer to ISP CCDC device.
++ */
++static void ccdc_configure_lpf(struct isp_ccdc_device *ccdc)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++
++ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE,
++ ISPCCDC_SYN_MODE_LPF,
++ ccdc->lpf ? ISPCCDC_SYN_MODE_LPF : 0);
++}
++
++/*
++ * ccdc_configure_alaw - Configure A-law compression.
++ * @ccdc: Pointer to ISP CCDC device.
++ */
++static void ccdc_configure_alaw(struct isp_ccdc_device *ccdc)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++ u32 alaw = 0;
++
++ switch (ccdc->syncif.datsz) {
++ case 8:
++ return;
++
++ case 10:
++ alaw = ISPCCDC_ALAW_GWDI_9_0;
++ break;
++ case 11:
++ alaw = ISPCCDC_ALAW_GWDI_10_1;
++ break;
++ case 12:
++ alaw = ISPCCDC_ALAW_GWDI_11_2;
++ break;
++ case 13:
++ alaw = ISPCCDC_ALAW_GWDI_12_3;
++ break;
++ }
++
++ if (ccdc->alaw)
++ alaw |= ISPCCDC_ALAW_CCDTBL;
++
++ isp_reg_writel(isp, alaw, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW);
++}
++
++/*
++ * ccdc_config_imgattr - Configure sensor image specific attributes.
++ * @ccdc: Pointer to ISP CCDC device.
++ * @colptn: Color pattern of the sensor.
++ */
++static void ccdc_config_imgattr(struct isp_ccdc_device *ccdc, u32 colptn)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++
++ isp_reg_writel(isp, colptn, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_COLPTN);
++}
++
++/*
++ * ccdc_config - Set CCDC configuration from userspace
++ * @ccdc: Pointer to ISP CCDC device.
++ * @userspace_add: Structure containing CCDC configuration sent from userspace.
++ *
++ * Returns 0 if successful, -EINVAL if the pointer to the configuration
++ * structure is null, or the copy_from_user function fails to copy user space
++ * memory to kernel space memory.
++ */
++static int ccdc_config(struct isp_ccdc_device *ccdc,
++ struct omap3isp_ccdc_update_config *ccdc_struct)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++ unsigned long flags;
++
++ spin_lock_irqsave(&ccdc->lock, flags);
++ ccdc->shadow_update = 1;
++ spin_unlock_irqrestore(&ccdc->lock, flags);
++
++ if (OMAP3ISP_CCDC_ALAW & ccdc_struct->update) {
++ ccdc->alaw = !!(OMAP3ISP_CCDC_ALAW & ccdc_struct->flag);
++ ccdc->update |= OMAP3ISP_CCDC_ALAW;
++ }
++
++ if (OMAP3ISP_CCDC_LPF & ccdc_struct->update) {
++ ccdc->lpf = !!(OMAP3ISP_CCDC_LPF & ccdc_struct->flag);
++ ccdc->update |= OMAP3ISP_CCDC_LPF;
++ }
++
++ if (OMAP3ISP_CCDC_BLCLAMP & ccdc_struct->update) {
++ if (copy_from_user(&ccdc->clamp, ccdc_struct->bclamp,
++ sizeof(ccdc->clamp))) {
++ ccdc->shadow_update = 0;
++ return -EFAULT;
++ }
++
++ ccdc->obclamp = !!(OMAP3ISP_CCDC_BLCLAMP & ccdc_struct->flag);
++ ccdc->update |= OMAP3ISP_CCDC_BLCLAMP;
++ }
++
++ if (OMAP3ISP_CCDC_BCOMP & ccdc_struct->update) {
++ if (copy_from_user(&ccdc->blcomp, ccdc_struct->blcomp,
++ sizeof(ccdc->blcomp))) {
++ ccdc->shadow_update = 0;
++ return -EFAULT;
++ }
++
++ ccdc->update |= OMAP3ISP_CCDC_BCOMP;
++ }
++
++ ccdc->shadow_update = 0;
++
++ if (OMAP3ISP_CCDC_FPC & ccdc_struct->update) {
++ u32 table_old = 0;
++ u32 table_new;
++ u32 size;
++
++ if (ccdc->state != ISP_PIPELINE_STREAM_STOPPED)
++ return -EBUSY;
++
++ ccdc->fpc_en = !!(OMAP3ISP_CCDC_FPC & ccdc_struct->flag);
++
++ if (ccdc->fpc_en) {
++ if (copy_from_user(&ccdc->fpc, ccdc_struct->fpc,
++ sizeof(ccdc->fpc)))
++ return -EFAULT;
++
++ /*
++ * table_new must be 64-bytes aligned, but it's
++ * already done by iommu_vmalloc().
++ */
++ size = ccdc->fpc.fpnum * 4;
++ table_new = iommu_vmalloc(isp->iommu, 0, size,
++ IOMMU_FLAG);
++ if (IS_ERR_VALUE(table_new))
++ return -ENOMEM;
++
++ if (copy_from_user(da_to_va(isp->iommu, table_new),
++ (__force void __user *)
++ ccdc->fpc.fpcaddr, size)) {
++ iommu_vfree(isp->iommu, table_new);
++ return -EFAULT;
++ }
++
++ table_old = ccdc->fpc.fpcaddr;
++ ccdc->fpc.fpcaddr = table_new;
++ }
++
++ ccdc_configure_fpc(ccdc);
++ if (table_old != 0)
++ iommu_vfree(isp->iommu, table_old);
++ }
++
++ return ccdc_lsc_config(ccdc, ccdc_struct);
++}
++
++static void ccdc_apply_controls(struct isp_ccdc_device *ccdc)
++{
++ if (ccdc->update & OMAP3ISP_CCDC_ALAW) {
++ ccdc_configure_alaw(ccdc);
++ ccdc->update &= ~OMAP3ISP_CCDC_ALAW;
++ }
++
++ if (ccdc->update & OMAP3ISP_CCDC_LPF) {
++ ccdc_configure_lpf(ccdc);
++ ccdc->update &= ~OMAP3ISP_CCDC_LPF;
++ }
++
++ if (ccdc->update & OMAP3ISP_CCDC_BLCLAMP) {
++ ccdc_configure_clamp(ccdc);
++ ccdc->update &= ~OMAP3ISP_CCDC_BLCLAMP;
++ }
++
++ if (ccdc->update & OMAP3ISP_CCDC_BCOMP) {
++ ccdc_configure_black_comp(ccdc);
++ ccdc->update &= ~OMAP3ISP_CCDC_BCOMP;
++ }
++}
++
++/*
++ * omap3isp_ccdc_restore_context - Restore values of the CCDC module registers
++ * @dev: Pointer to ISP device
++ */
++void omap3isp_ccdc_restore_context(struct isp_device *isp)
++{
++ struct isp_ccdc_device *ccdc = &isp->isp_ccdc;
++
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, ISPCCDC_CFG_VDLC);
++
++ ccdc->update = OMAP3ISP_CCDC_ALAW | OMAP3ISP_CCDC_LPF
++ | OMAP3ISP_CCDC_BLCLAMP | OMAP3ISP_CCDC_BCOMP;
++ ccdc_apply_controls(ccdc);
++ ccdc_configure_fpc(ccdc);
++}
++
++/* -----------------------------------------------------------------------------
++ * Format- and pipeline-related configuration helpers
++ */
++
++/*
++ * ccdc_config_vp - Configure the Video Port.
++ * @ccdc: Pointer to ISP CCDC device.
++ */
++static void ccdc_config_vp(struct isp_ccdc_device *ccdc)
++{
++ struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
++ struct isp_device *isp = to_isp_device(ccdc);
++ unsigned long l3_ick = pipe->l3_ick;
++ unsigned int max_div = isp->revision == ISP_REVISION_15_0 ? 64 : 8;
++ unsigned int div = 0;
++ u32 fmtcfg_vp;
++
++ fmtcfg_vp = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG)
++ & ~(ISPCCDC_FMTCFG_VPIN_MASK | ISPCCDC_FMTCFG_VPIF_FRQ_MASK);
++
++ switch (ccdc->syncif.datsz) {
++ case 8:
++ case 10:
++ fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_9_0;
++ break;
++ case 11:
++ fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_10_1;
++ break;
++ case 12:
++ fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_11_2;
++ break;
++ case 13:
++ fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_12_3;
++ break;
++ };
++
++ if (pipe->input)
++ div = DIV_ROUND_UP(l3_ick, pipe->max_rate);
++ else if (ccdc->vpcfg.pixelclk)
++ div = l3_ick / ccdc->vpcfg.pixelclk;
++
++ div = clamp(div, 2U, max_div);
++ fmtcfg_vp |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT;
++
++ isp_reg_writel(isp, fmtcfg_vp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
++}
++
++/*
++ * ccdc_enable_vp - Enable Video Port.
++ * @ccdc: Pointer to ISP CCDC device.
++ * @enable: 0 Disables VP, 1 Enables VP
++ *
++ * This is needed for outputting image to Preview, H3A and HIST ISP submodules.
++ */
++static void ccdc_enable_vp(struct isp_ccdc_device *ccdc, u8 enable)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++
++ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG,
++ ISPCCDC_FMTCFG_VPEN, enable ? ISPCCDC_FMTCFG_VPEN : 0);
++}
++
++/*
++ * ccdc_config_outlineoffset - Configure memory saving output line offset
++ * @ccdc: Pointer to ISP CCDC device.
++ * @offset: Address offset to start a new line. Must be twice the
++ * Output width and aligned on 32 byte boundary
++ * @oddeven: Specifies the odd/even line pattern to be chosen to store the
++ * output.
++ * @numlines: Set the value 0-3 for +1-4lines, 4-7 for -1-4lines.
++ *
++ * - Configures the output line offset when stored in memory
++ * - Sets the odd/even line pattern to store the output
++ * (EVENEVEN (1), ODDEVEN (2), EVENODD (3), ODDODD (4))
++ * - Configures the number of even and odd line fields in case of rearranging
++ * the lines.
++ */
++static void ccdc_config_outlineoffset(struct isp_ccdc_device *ccdc,
++ u32 offset, u8 oddeven, u8 numlines)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++
++ isp_reg_writel(isp, offset & 0xffff,
++ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF);
++
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
++ ISPCCDC_SDOFST_FINV);
++
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
++ ISPCCDC_SDOFST_FOFST_4L);
++
++ switch (oddeven) {
++ case EVENEVEN:
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
++ (numlines & 0x7) << ISPCCDC_SDOFST_LOFST0_SHIFT);
++ break;
++ case ODDEVEN:
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
++ (numlines & 0x7) << ISPCCDC_SDOFST_LOFST1_SHIFT);
++ break;
++ case EVENODD:
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
++ (numlines & 0x7) << ISPCCDC_SDOFST_LOFST2_SHIFT);
++ break;
++ case ODDODD:
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
++ (numlines & 0x7) << ISPCCDC_SDOFST_LOFST3_SHIFT);
++ break;
++ default:
++ break;
++ }
++}
++
++/*
++ * ccdc_set_outaddr - Set memory address to save output image
++ * @ccdc: Pointer to ISP CCDC device.
++ * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary.
++ *
++ * Sets the memory address where the output will be saved.
++ */
++static void ccdc_set_outaddr(struct isp_ccdc_device *ccdc, u32 addr)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++
++ isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDR_ADDR);
++}
++
++/*
++ * omap3isp_ccdc_max_rate - Calculate maximum input data rate based on the input
++ * @ccdc: Pointer to ISP CCDC device.
++ * @max_rate: Maximum calculated data rate.
++ *
++ * Returns in *max_rate less value between calculated and passed
++ */
++void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc,
++ unsigned int *max_rate)
++{
++ struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
++ unsigned int rate;
++
++ if (pipe == NULL)
++ return;
++
++ /*
++ * TRM says that for parallel sensors the maximum data rate
++ * should be 90% form L3/2 clock, otherwise just L3/2.
++ */
++ if (ccdc->input == CCDC_INPUT_PARALLEL)
++ rate = pipe->l3_ick / 2 * 9 / 10;
++ else
++ rate = pipe->l3_ick / 2;
++
++ *max_rate = min(*max_rate, rate);
++}
++
++/*
++ * ccdc_config_sync_if - Set CCDC sync interface configuration
++ * @ccdc: Pointer to ISP CCDC device.
++ * @syncif: Structure containing the sync parameters like field state, CCDC in
++ * master/slave mode, raw/yuv data, polarity of data, field, hs, vs
++ * signals.
++ */
++static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
++ struct ispccdc_syncif *syncif)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++ u32 syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC,
++ ISPCCDC_SYN_MODE);
++
++ syn_mode |= ISPCCDC_SYN_MODE_VDHDEN;
++
++ if (syncif->fldstat)
++ syn_mode |= ISPCCDC_SYN_MODE_FLDSTAT;
++ else
++ syn_mode &= ~ISPCCDC_SYN_MODE_FLDSTAT;
++
++ syn_mode &= ~ISPCCDC_SYN_MODE_DATSIZ_MASK;
++ switch (syncif->datsz) {
++ case 8:
++ syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_8;
++ break;
++ case 10:
++ syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_10;
++ break;
++ case 11:
++ syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_11;
++ break;
++ case 12:
++ syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_12;
++ break;
++ };
++
++ if (syncif->fldmode)
++ syn_mode |= ISPCCDC_SYN_MODE_FLDMODE;
++ else
++ syn_mode &= ~ISPCCDC_SYN_MODE_FLDMODE;
++
++ if (syncif->datapol)
++ syn_mode |= ISPCCDC_SYN_MODE_DATAPOL;
++ else
++ syn_mode &= ~ISPCCDC_SYN_MODE_DATAPOL;
++
++ if (syncif->fldpol)
++ syn_mode |= ISPCCDC_SYN_MODE_FLDPOL;
++ else
++ syn_mode &= ~ISPCCDC_SYN_MODE_FLDPOL;
++
++ if (syncif->hdpol)
++ syn_mode |= ISPCCDC_SYN_MODE_HDPOL;
++ else
++ syn_mode &= ~ISPCCDC_SYN_MODE_HDPOL;
++
++ if (syncif->vdpol)
++ syn_mode |= ISPCCDC_SYN_MODE_VDPOL;
++ else
++ syn_mode &= ~ISPCCDC_SYN_MODE_VDPOL;
++
++ if (syncif->ccdc_mastermode) {
++ syn_mode |= ISPCCDC_SYN_MODE_FLDOUT | ISPCCDC_SYN_MODE_VDHDOUT;
++ isp_reg_writel(isp,
++ syncif->hs_width << ISPCCDC_HD_VD_WID_HDW_SHIFT
++ | syncif->vs_width << ISPCCDC_HD_VD_WID_VDW_SHIFT,
++ OMAP3_ISP_IOMEM_CCDC,
++ ISPCCDC_HD_VD_WID);
++
++ isp_reg_writel(isp,
++ syncif->ppln << ISPCCDC_PIX_LINES_PPLN_SHIFT
++ | syncif->hlprf << ISPCCDC_PIX_LINES_HLPRF_SHIFT,
++ OMAP3_ISP_IOMEM_CCDC,
++ ISPCCDC_PIX_LINES);
++ } else
++ syn_mode &= ~(ISPCCDC_SYN_MODE_FLDOUT |
++ ISPCCDC_SYN_MODE_VDHDOUT);
++
++ isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
++
++ if (!syncif->bt_r656_en)
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,
++ ISPCCDC_REC656IF_R656ON);
++}
++
++/* CCDC formats descriptions */
++static const u32 ccdc_sgrbg_pattern =
++ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
++ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
++ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
++ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
++ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
++ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
++ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
++ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
++ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
++ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
++ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
++ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
++ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
++ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
++ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
++ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
++
++static const u32 ccdc_srggb_pattern =
++ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
++ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
++ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
++ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
++ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
++ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
++ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
++ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
++ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
++ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
++ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
++ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
++ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
++ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
++ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
++ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
++
++static const u32 ccdc_sbggr_pattern =
++ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
++ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
++ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
++ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
++ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
++ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
++ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
++ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
++ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
++ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
++ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
++ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
++ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
++ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
++ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
++ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
++
++static const u32 ccdc_sgbrg_pattern =
++ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
++ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
++ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
++ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
++ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
++ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
++ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
++ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
++ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
++ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
++ ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
++ ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
++ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
++ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
++ ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
++ ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
++
++static void ccdc_configure(struct isp_ccdc_device *ccdc)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++ struct isp_parallel_platform_data *pdata = NULL;
++ struct v4l2_subdev *sensor;
++ struct v4l2_mbus_framefmt *format;
++ struct media_pad *pad;
++ unsigned long flags;
++ u32 syn_mode;
++ u32 ccdc_pattern;
++
++ if (ccdc->input == CCDC_INPUT_PARALLEL) {
++ pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]);
++ sensor = media_entity_to_v4l2_subdev(pad->entity);
++ pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv)
++ ->bus.parallel;
++ }
++
++ omap3isp_configure_bridge(isp, ccdc->input, pdata);
++
++ ccdc->syncif.datsz = pdata ? pdata->width : 10;
++ ccdc_config_sync_if(ccdc, &ccdc->syncif);
++
++ /* CCDC_PAD_SINK */
++ format = &ccdc->formats[CCDC_PAD_SINK];
++
++ syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
++
++ /* Use the raw, unprocessed data when writing to memory. The H3A and
++ * histogram modules are still fed with lens shading corrected data.
++ */
++ syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
++
++ if (ccdc->output & CCDC_OUTPUT_MEMORY)
++ syn_mode |= ISPCCDC_SYN_MODE_WEN;
++ else
++ syn_mode &= ~ISPCCDC_SYN_MODE_WEN;
++
++ if (ccdc->output & CCDC_OUTPUT_RESIZER)
++ syn_mode |= ISPCCDC_SYN_MODE_SDR2RSZ;
++ else
++ syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
++
++ /* Use PACK8 mode for 1byte per pixel formats. */
++ if (omap3isp_video_format_info(format->code)->bpp <= 8)
++ syn_mode |= ISPCCDC_SYN_MODE_PACK8;
++ else
++ syn_mode &= ~ISPCCDC_SYN_MODE_PACK8;
++
++ isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
++
++ /* Mosaic filter */
++ switch (format->code) {
++ case V4L2_MBUS_FMT_SRGGB10_1X10:
++ case V4L2_MBUS_FMT_SRGGB12_1X12:
++ ccdc_pattern = ccdc_srggb_pattern;
++ break;
++ case V4L2_MBUS_FMT_SBGGR10_1X10:
++ case V4L2_MBUS_FMT_SBGGR12_1X12:
++ ccdc_pattern = ccdc_sbggr_pattern;
++ break;
++ case V4L2_MBUS_FMT_SGBRG10_1X10:
++ case V4L2_MBUS_FMT_SGBRG12_1X12:
++ ccdc_pattern = ccdc_sgbrg_pattern;
++ break;
++ default:
++ /* Use GRBG */
++ ccdc_pattern = ccdc_sgrbg_pattern;
++ break;
++ }
++ ccdc_config_imgattr(ccdc, ccdc_pattern);
++
++ /* Generate VD0 on the last line of the image and VD1 on the
++ * 2/3 height line.
++ */
++ isp_reg_writel(isp, ((format->height - 2) << ISPCCDC_VDINT_0_SHIFT) |
++ ((format->height * 2 / 3) << ISPCCDC_VDINT_1_SHIFT),
++ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT);
++
++ /* CCDC_PAD_SOURCE_OF */
++ format = &ccdc->formats[CCDC_PAD_SOURCE_OF];
++
++ isp_reg_writel(isp, (0 << ISPCCDC_HORZ_INFO_SPH_SHIFT) |
++ ((format->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT),
++ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO);
++ isp_reg_writel(isp, 0 << ISPCCDC_VERT_START_SLV0_SHIFT,
++ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START);
++ isp_reg_writel(isp, (format->height - 1)
++ << ISPCCDC_VERT_LINES_NLV_SHIFT,
++ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_LINES);
++
++ ccdc_config_outlineoffset(ccdc, ccdc->video_out.bpl_value, 0, 0);
++
++ /* CCDC_PAD_SOURCE_VP */
++ format = &ccdc->formats[CCDC_PAD_SOURCE_VP];
++
++ isp_reg_writel(isp, (0 << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |
++ (format->width << ISPCCDC_FMT_HORZ_FMTLNH_SHIFT),
++ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ);
++ isp_reg_writel(isp, (0 << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) |
++ ((format->height + 1) << ISPCCDC_FMT_VERT_FMTLNV_SHIFT),
++ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT);
++
++ isp_reg_writel(isp, (format->width << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) |
++ (format->height << ISPCCDC_VP_OUT_VERT_NUM_SHIFT),
++ OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT);
++
++ spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
++ if (ccdc->lsc.request == NULL)
++ goto unlock;
++
++ WARN_ON(ccdc->lsc.active);
++
++ /* Get last good LSC configuration. If it is not supported for
++ * the current active resolution discard it.
++ */
++ if (ccdc->lsc.active == NULL &&
++ __ccdc_lsc_configure(ccdc, ccdc->lsc.request) == 0) {
++ ccdc->lsc.active = ccdc->lsc.request;
++ } else {
++ list_add_tail(&ccdc->lsc.request->list, &ccdc->lsc.free_queue);
++ schedule_work(&ccdc->lsc.table_work);
++ }
++
++ ccdc->lsc.request = NULL;
++
++unlock:
++ spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
++
++ ccdc_apply_controls(ccdc);
++}
++
++static void __ccdc_enable(struct isp_ccdc_device *ccdc, int enable)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++
++ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR,
++ ISPCCDC_PCR_EN, enable ? ISPCCDC_PCR_EN : 0);
++}
++
++static int ccdc_disable(struct isp_ccdc_device *ccdc)
++{
++ unsigned long flags;
++ int ret = 0;
++
++ spin_lock_irqsave(&ccdc->lock, flags);
++ if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS)
++ ccdc->stopping = CCDC_STOP_REQUEST;
++ spin_unlock_irqrestore(&ccdc->lock, flags);
++
++ ret = wait_event_timeout(ccdc->wait,
++ ccdc->stopping == CCDC_STOP_FINISHED,
++ msecs_to_jiffies(2000));
++ if (ret == 0) {
++ ret = -ETIMEDOUT;
++ dev_warn(to_device(ccdc), "CCDC stop timeout!\n");
++ }
++
++ omap3isp_sbl_disable(to_isp_device(ccdc), OMAP3_ISP_SBL_CCDC_LSC_READ);
++
++ mutex_lock(&ccdc->ioctl_lock);
++ ccdc_lsc_free_request(ccdc, ccdc->lsc.request);
++ ccdc->lsc.request = ccdc->lsc.active;
++ ccdc->lsc.active = NULL;
++ cancel_work_sync(&ccdc->lsc.table_work);
++ ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue);
++ mutex_unlock(&ccdc->ioctl_lock);
++
++ ccdc->stopping = CCDC_STOP_NOT_REQUESTED;
++
++ return ret > 0 ? 0 : ret;
++}
++
++static void ccdc_enable(struct isp_ccdc_device *ccdc)
++{
++ if (ccdc_lsc_is_configured(ccdc))
++ __ccdc_lsc_enable(ccdc, 1);
++ __ccdc_enable(ccdc, 1);
++}
++
++/* -----------------------------------------------------------------------------
++ * Interrupt handling
++ */
++
++/*
++ * ccdc_sbl_busy - Poll idle state of CCDC and related SBL memory write bits
++ * @ccdc: Pointer to ISP CCDC device.
++ *
++ * Returns zero if the CCDC is idle and the image has been written to
++ * memory, too.
++ */
++static int ccdc_sbl_busy(struct isp_ccdc_device *ccdc)
++{
++ struct isp_device *isp = to_isp_device(ccdc);
++
++ return omap3isp_ccdc_busy(ccdc)
++ | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_0) &
++ ISPSBL_CCDC_WR_0_DATA_READY)
++ | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_1) &
++ ISPSBL_CCDC_WR_0_DATA_READY)
++ | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_2) &
++ ISPSBL_CCDC_WR_0_DATA_READY)
++ | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_3) &
++ ISPSBL_CCDC_WR_0_DATA_READY);
++}
++
++/*
++ * ccdc_sbl_wait_idle - Wait until the CCDC and related SBL are idle
++ * @ccdc: Pointer to ISP CCDC device.
++ * @max_wait: Max retry count in us for wait for idle/busy transition.
++ */
++static int ccdc_sbl_wait_idle(struct isp_ccdc_device *ccdc,
++ unsigned int max_wait)
++{
++ unsigned int wait = 0;
++
++ if (max_wait == 0)
++ max_wait = 10000; /* 10 ms */
++
++ for (wait = 0; wait <= max_wait; wait++) {
++ if (!ccdc_sbl_busy(ccdc))
++ return 0;
++
++ rmb();
++ udelay(1);
++ }
++
++ return -EBUSY;
++}
++
++/* __ccdc_handle_stopping - Handle CCDC and/or LSC stopping sequence
++ * @ccdc: Pointer to ISP CCDC device.
++ * @event: Pointing which event trigger handler
++ *
++ * Return 1 when the event and stopping request combination is satisfyied,
++ * zero otherwise.
++ */
++static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event)
++{
++ int rval = 0;
++
++ switch ((ccdc->stopping & 3) | event) {
++ case CCDC_STOP_REQUEST | CCDC_EVENT_VD1:
++ if (ccdc->lsc.state != LSC_STATE_STOPPED)
++ __ccdc_lsc_enable(ccdc, 0);
++ __ccdc_enable(ccdc, 0);
++ ccdc->stopping = CCDC_STOP_EXECUTED;
++ return 1;
++
++ case CCDC_STOP_EXECUTED | CCDC_EVENT_VD0:
++ ccdc->stopping |= CCDC_STOP_CCDC_FINISHED;
++ if (ccdc->lsc.state == LSC_STATE_STOPPED)
++ ccdc->stopping |= CCDC_STOP_LSC_FINISHED;
++ rval = 1;
++ break;
++
++ case CCDC_STOP_EXECUTED | CCDC_EVENT_LSC_DONE:
++ ccdc->stopping |= CCDC_STOP_LSC_FINISHED;
++ rval = 1;
++ break;
++
++ case CCDC_STOP_EXECUTED | CCDC_EVENT_VD1:
++ return 1;
++ }
++
++ if (ccdc->stopping == CCDC_STOP_FINISHED) {
++ wake_up(&ccdc->wait);
++ rval = 1;
++ }
++
++ return rval;
++}
++
++static void ccdc_hs_vs_isr(struct isp_ccdc_device *ccdc)
++{
++ struct video_device *vdev = &ccdc->subdev.devnode;
++ struct v4l2_event event;
++
++ memset(&event, 0, sizeof(event));
++ event.type = V4L2_EVENT_OMAP3ISP_HS_VS;
++
++ v4l2_event_queue(vdev, &event);
++}
++
++/*
++ * ccdc_lsc_isr - Handle LSC events
++ * @ccdc: Pointer to ISP CCDC device.
++ * @events: LSC events
++ */
++static void ccdc_lsc_isr(struct isp_ccdc_device *ccdc, u32 events)
++{
++ unsigned long flags;
++
++ if (events & IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ) {
++ ccdc_lsc_error_handler(ccdc);
++ ccdc->error = 1;
++ dev_dbg(to_device(ccdc), "lsc prefetch error\n");
++ }
++
++ if (!(events & IRQ0STATUS_CCDC_LSC_DONE_IRQ))
++ return;
++
++ /* LSC_DONE interrupt occur, there are two cases
++ * 1. stopping for reconfiguration
++ * 2. stopping because of STREAM OFF command
++ */
++ spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
++
++ if (ccdc->lsc.state == LSC_STATE_STOPPING)
++ ccdc->lsc.state = LSC_STATE_STOPPED;
++
++ if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_LSC_DONE))
++ goto done;
++
++ if (ccdc->lsc.state != LSC_STATE_RECONFIG)
++ goto done;
++
++ /* LSC is in STOPPING state, change to the new state */
++ ccdc->lsc.state = LSC_STATE_STOPPED;
++
++ /* This is an exception. Start of frame and LSC_DONE interrupt
++ * have been received on the same time. Skip this event and wait
++ * for better times.
++ */
++ if (events & IRQ0STATUS_HS_VS_IRQ)
++ goto done;
++
++ /* The LSC engine is stopped at this point. Enable it if there's a
++ * pending request.
++ */
++ if (ccdc->lsc.request == NULL)
++ goto done;
++
++ ccdc_lsc_enable(ccdc);
++
++done:
++ spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
++}
++
++static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
++{
++ struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
++ struct isp_device *isp = to_isp_device(ccdc);
++ struct isp_buffer *buffer;
++ int restart = 0;
++
++ /* The CCDC generates VD0 interrupts even when disabled (the datasheet
++ * doesn't explicitly state if that's supposed to happen or not, so it
++ * can be considered as a hardware bug or as a feature, but we have to
++ * deal with it anyway). Disabling the CCDC when no buffer is available
++ * would thus not be enough, we need to handle the situation explicitly.
++ */
++ if (list_empty(&ccdc->video_out.dmaqueue))
++ goto done;
++
++ /* We're in continuous mode, and memory writes were disabled due to a
++ * buffer underrun. Reenable them now that we have a buffer. The buffer
++ * address has been set in ccdc_video_queue.
++ */
++ if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && ccdc->underrun) {
++ restart = 1;
++ ccdc->underrun = 0;
++ goto done;
++ }
++
++ if (ccdc_sbl_wait_idle(ccdc, 1000)) {
++ dev_info(isp->dev, "CCDC won't become idle!\n");
++ goto done;
++ }
++
++ buffer = omap3isp_video_buffer_next(&ccdc->video_out, ccdc->error);
++ if (buffer != NULL) {
++ ccdc_set_outaddr(ccdc, buffer->isp_addr);
++ restart = 1;
++ }
++
++ pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
++
++ if (ccdc->state == ISP_PIPELINE_STREAM_SINGLESHOT &&
++ isp_pipeline_ready(pipe))
++ omap3isp_pipeline_set_stream(pipe,
++ ISP_PIPELINE_STREAM_SINGLESHOT);
++
++done:
++ ccdc->error = 0;
++ return restart;
++}
++
++/*
++ * ccdc_vd0_isr - Handle VD0 event
++ * @ccdc: Pointer to ISP CCDC device.
++ *
++ * Executes LSC deferred enablement before next frame starts.
++ */
++static void ccdc_vd0_isr(struct isp_ccdc_device *ccdc)
++{
++ unsigned long flags;
++ int restart = 0;
++
++ if (ccdc->output & CCDC_OUTPUT_MEMORY)
++ restart = ccdc_isr_buffer(ccdc);
++
++ spin_lock_irqsave(&ccdc->lock, flags);
++ if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) {
++ spin_unlock_irqrestore(&ccdc->lock, flags);
++ return;
++ }
++
++ if (!ccdc->shadow_update)
++ ccdc_apply_controls(ccdc);
++ spin_unlock_irqrestore(&ccdc->lock, flags);
++
++ if (restart)
++ ccdc_enable(ccdc);
++}
++
++/*
++ * ccdc_vd1_isr - Handle VD1 event
++ * @ccdc: Pointer to ISP CCDC device.
++ */
++static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
++
++ /*
++ * Depending on the CCDC pipeline state, CCDC stopping should be
++ * handled differently. In SINGLESHOT we emulate an internal CCDC
++ * stopping because the CCDC hw works only in continuous mode.
++ * When CONTINUOUS pipeline state is used and the CCDC writes it's
++ * data to memory the CCDC and LSC are stopped immediately but
++ * without change the CCDC stopping state machine. The CCDC
++ * stopping state machine should be used only when user request
++ * for stopping is received (SINGLESHOT is an exeption).
++ */
++ switch (ccdc->state) {
++ case ISP_PIPELINE_STREAM_SINGLESHOT:
++ ccdc->stopping = CCDC_STOP_REQUEST;
++ break;
++
++ case ISP_PIPELINE_STREAM_CONTINUOUS:
++ if (ccdc->output & CCDC_OUTPUT_MEMORY) {
++ if (ccdc->lsc.state != LSC_STATE_STOPPED)
++ __ccdc_lsc_enable(ccdc, 0);
++ __ccdc_enable(ccdc, 0);
++ }
++ break;
++
++ case ISP_PIPELINE_STREAM_STOPPED:
++ break;
++ }
++
++ if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1))
++ goto done;
++
++ if (ccdc->lsc.request == NULL)
++ goto done;
++
++ /*
++ * LSC need to be reconfigured. Stop it here and on next LSC_DONE IRQ
++ * do the appropriate changes in registers
++ */
++ if (ccdc->lsc.state == LSC_STATE_RUNNING) {
++ __ccdc_lsc_enable(ccdc, 0);
++ ccdc->lsc.state = LSC_STATE_RECONFIG;
++ goto done;
++ }
++
++ /* LSC has been in STOPPED state, enable it */
++ if (ccdc->lsc.state == LSC_STATE_STOPPED)
++ ccdc_lsc_enable(ccdc);
++
++done:
++ spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);
++}
++
++/*
++ * omap3isp_ccdc_isr - Configure CCDC during interframe time.
++ * @ccdc: Pointer to ISP CCDC device.
++ * @events: CCDC events
++ */
++int omap3isp_ccdc_isr(struct isp_ccdc_device *ccdc, u32 events)
++{
++ if (ccdc->state == ISP_PIPELINE_STREAM_STOPPED)
++ return 0;
++
++ if (events & IRQ0STATUS_CCDC_VD1_IRQ)
++ ccdc_vd1_isr(ccdc);
++
++ ccdc_lsc_isr(ccdc, events);
++
++ if (events & IRQ0STATUS_CCDC_VD0_IRQ)
++ ccdc_vd0_isr(ccdc);
++
++ if (events & IRQ0STATUS_HS_VS_IRQ)
++ ccdc_hs_vs_isr(ccdc);
++
++ return 0;
++}
++
++/* -----------------------------------------------------------------------------
++ * ISP video operations
++ */
++
++static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer)
++{
++ struct isp_ccdc_device *ccdc = &video->isp->isp_ccdc;
++
++ if (!(ccdc->output & CCDC_OUTPUT_MEMORY))
++ return -ENODEV;
++
++ ccdc_set_outaddr(ccdc, buffer->isp_addr);
++
++ /* We now have a buffer queued on the output, restart the pipeline in
++ * on the next CCDC interrupt if running in continuous mode (or when
++ * starting the stream).
++ */
++ ccdc->underrun = 1;
++
++ return 0;
++}
++
++static const struct isp_video_operations ccdc_video_ops = {
++ .queue = ccdc_video_queue,
++};
++
++/* -----------------------------------------------------------------------------
++ * V4L2 subdev operations
++ */
++
++/*
++ * ccdc_ioctl - CCDC module private ioctl's
++ * @sd: ISP CCDC V4L2 subdevice
++ * @cmd: ioctl command
++ * @arg: ioctl argument
++ *
++ * Return 0 on success or a negative error code otherwise.
++ */
++static long ccdc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
++{
++ struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
++ int ret;
++
++ switch (cmd) {
++ case VIDIOC_OMAP3ISP_CCDC_CFG:
++ mutex_lock(&ccdc->ioctl_lock);
++ ret = ccdc_config(ccdc, arg);
++ mutex_unlock(&ccdc->ioctl_lock);
++ break;
++
++ default:
++ return -ENOIOCTLCMD;
++ }
++
++ return ret;
++}
++
++static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
++ struct v4l2_event_subscription *sub)
++{
++ if (sub->type != V4L2_EVENT_OMAP3ISP_HS_VS)
++ return -EINVAL;
++
++ return v4l2_event_subscribe(fh, sub);
++}
++
++static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
++ struct v4l2_event_subscription *sub)
++{
++ return v4l2_event_unsubscribe(fh, sub);
++}
++
++/*
++ * ccdc_set_stream - Enable/Disable streaming on the CCDC module
++ * @sd: ISP CCDC V4L2 subdevice
++ * @enable: Enable/disable stream
++ *
++ * When writing to memory, the CCDC hardware can't be enabled without a memory
++ * buffer to write to. As the s_stream operation is called in response to a
++ * STREAMON call without any buffer queued yet, just update the enabled field
++ * and return immediately. The CCDC will be enabled in ccdc_isr_buffer().
++ *
++ * When not writing to memory enable the CCDC immediately.
++ */
++static int ccdc_set_stream(struct v4l2_subdev *sd, int enable)
++{
++ struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
++ struct isp_device *isp = to_isp_device(ccdc);
++ int ret = 0;
++
++ if (ccdc->state == ISP_PIPELINE_STREAM_STOPPED) {
++ if (enable == ISP_PIPELINE_STREAM_STOPPED)
++ return 0;
++
++ omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_CCDC);
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
++ ISPCCDC_CFG_VDLC);
++
++ ccdc_configure(ccdc);
++
++ /* TODO: Don't configure the video port if all of its output
++ * links are inactive.
++ */
++ ccdc_config_vp(ccdc);
++ ccdc_enable_vp(ccdc, 1);
++ ccdc->error = 0;
++ ccdc_print_status(ccdc);
++ }
++
++ switch (enable) {
++ case ISP_PIPELINE_STREAM_CONTINUOUS:
++ if (ccdc->output & CCDC_OUTPUT_MEMORY)
++ omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_WRITE);
++
++ if (ccdc->underrun || !(ccdc->output & CCDC_OUTPUT_MEMORY))
++ ccdc_enable(ccdc);
++
++ ccdc->underrun = 0;
++ break;
++
++ case ISP_PIPELINE_STREAM_SINGLESHOT:
++ if (ccdc->output & CCDC_OUTPUT_MEMORY &&
++ ccdc->state != ISP_PIPELINE_STREAM_SINGLESHOT)
++ omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_WRITE);
++
++ ccdc_enable(ccdc);
++ break;
++
++ case ISP_PIPELINE_STREAM_STOPPED:
++ ret = ccdc_disable(ccdc);
++ if (ccdc->output & CCDC_OUTPUT_MEMORY)
++ omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CCDC_WRITE);
++ omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_CCDC);
++ ccdc->underrun = 0;
++ break;
++ }
++
++ ccdc->state = enable;
++ return ret;
++}
++
++static struct v4l2_mbus_framefmt *
++__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
++ unsigned int pad, enum v4l2_subdev_format_whence which)
++{
++ if (which == V4L2_SUBDEV_FORMAT_TRY)
++ return v4l2_subdev_get_try_format(fh, pad);
++ else
++ return &ccdc->formats[pad];
++}
++
++/*
++ * ccdc_try_format - Try video format on a pad
++ * @ccdc: ISP CCDC device
++ * @fh : V4L2 subdev file handle
++ * @pad: Pad number
++ * @fmt: Format
++ */
++static void
++ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
++ unsigned int pad, struct v4l2_mbus_framefmt *fmt,
++ enum v4l2_subdev_format_whence which)
++{
++ struct v4l2_mbus_framefmt *format;
++ const struct isp_format_info *info;
++ unsigned int width = fmt->width;
++ unsigned int height = fmt->height;
++ unsigned int i;
++
++ switch (pad) {
++ case CCDC_PAD_SINK:
++ /* TODO: If the CCDC output formatter pad is connected directly
++ * to the resizer, only YUV formats can be used.
++ */
++ for (i = 0; i < ARRAY_SIZE(ccdc_fmts); i++) {
++ if (fmt->code == ccdc_fmts[i])
++ break;
++ }
++
++ /* If not found, use SGRBG10 as default */
++ if (i >= ARRAY_SIZE(ccdc_fmts))
++ fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
++
++ /* Clamp the input size. */
++ fmt->width = clamp_t(u32, width, 32, 4096);
++ fmt->height = clamp_t(u32, height, 32, 4096);
++ break;
++
++ case CCDC_PAD_SOURCE_OF:
++ format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
++ memcpy(fmt, format, sizeof(*fmt));
++
++ /* The data formatter truncates the number of horizontal output
++ * pixels to a multiple of 16. To avoid clipping data, allow
++ * callers to request an output size bigger than the input size
++ * up to the nearest multiple of 16.
++ */
++ fmt->width = clamp_t(u32, width, 32, (fmt->width + 15) & ~15);
++ fmt->width &= ~15;
++ fmt->height = clamp_t(u32, height, 32, fmt->height);
++ break;
++
++ case CCDC_PAD_SOURCE_VP:
++ format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
++ memcpy(fmt, format, sizeof(*fmt));
++
++ /* The video port interface truncates the data to 10 bits. */
++ info = omap3isp_video_format_info(fmt->code);
++ fmt->code = info->truncated;
++
++ /* The number of lines that can be clocked out from the video
++ * port output must be at least one line less than the number
++ * of input lines.
++ */
++ fmt->width = clamp_t(u32, width, 32, fmt->width);
++ fmt->height = clamp_t(u32, height, 32, fmt->height - 1);
++ break;
++ }
++
++ /* Data is written to memory unpacked, each 10-bit or 12-bit pixel is
++ * stored on 2 bytes.
++ */
++ fmt->colorspace = V4L2_COLORSPACE_SRGB;
++ fmt->field = V4L2_FIELD_NONE;
++}
++
++/*
++ * ccdc_enum_mbus_code - Handle pixel format enumeration
++ * @sd : pointer to v4l2 subdev structure
++ * @fh : V4L2 subdev file handle
++ * @code : pointer to v4l2_subdev_mbus_code_enum structure
++ * return -EINVAL or zero on success
++ */
++static int ccdc_enum_mbus_code(struct v4l2_subdev *sd,
++ struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_mbus_code_enum *code)
++{
++ struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
++ struct v4l2_mbus_framefmt *format;
++
++ switch (code->pad) {
++ case CCDC_PAD_SINK:
++ if (code->index >= ARRAY_SIZE(ccdc_fmts))
++ return -EINVAL;
++
++ code->code = ccdc_fmts[code->index];
++ break;
++
++ case CCDC_PAD_SOURCE_OF:
++ case CCDC_PAD_SOURCE_VP:
++ /* No format conversion inside CCDC */
++ if (code->index != 0)
++ return -EINVAL;
++
++ format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK,
++ V4L2_SUBDEV_FORMAT_TRY);
++
++ code->code = format->code;
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
++ struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_frame_size_enum *fse)
++{
++ struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
++ struct v4l2_mbus_framefmt format;
++
++ if (fse->index != 0)
++ return -EINVAL;
++
++ format.code = fse->code;
++ format.width = 1;
++ format.height = 1;
++ ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
++ fse->min_width = format.width;
++ fse->min_height = format.height;
++
++ if (format.code != fse->code)
++ return -EINVAL;
++
++ format.code = fse->code;
++ format.width = -1;
++ format.height = -1;
++ ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
++ fse->max_width = format.width;
++ fse->max_height = format.height;
++
++ return 0;
++}
++
++/*
++ * ccdc_get_format - Retrieve the video format on a pad
++ * @sd : ISP CCDC V4L2 subdevice
++ * @fh : V4L2 subdev file handle
++ * @fmt: Format
++ *
++ * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
++ * to the format type.
++ */
++static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_format *fmt)
++{
++ struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
++ struct v4l2_mbus_framefmt *format;
++
++ format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which);
++ if (format == NULL)
++ return -EINVAL;
++
++ fmt->format = *format;
++ return 0;
++}
++
++/*
++ * ccdc_set_format - Set the video format on a pad
++ * @sd : ISP CCDC V4L2 subdevice
++ * @fh : V4L2 subdev file handle
++ * @fmt: Format
++ *
++ * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
++ * to the format type.
++ */
++static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_format *fmt)
++{
++ struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
++ struct v4l2_mbus_framefmt *format;
++
++ format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which);
++ if (format == NULL)
++ return -EINVAL;
++
++ ccdc_try_format(ccdc, fh, fmt->pad, &fmt->format, fmt->which);
++ *format = fmt->format;
++
++ /* Propagate the format from sink to source */
++ if (fmt->pad == CCDC_PAD_SINK) {
++ format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF,
++ fmt->which);
++ *format = fmt->format;
++ ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format,
++ fmt->which);
++
++ format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_VP,
++ fmt->which);
++ *format = fmt->format;
++ ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_VP, format,
++ fmt->which);
++ }
++
++ return 0;
++}
++
++/*
++ * ccdc_init_formats - Initialize formats on all pads
++ * @sd: ISP CCDC V4L2 subdevice
++ * @fh: V4L2 subdev file handle
++ *
++ * Initialize all pad formats with default values. If fh is not NULL, try
++ * formats are initialized on the file handle. Otherwise active formats are
++ * initialized on the device.
++ */
++static int ccdc_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
++{
++ struct v4l2_subdev_format format;
++
++ memset(&format, 0, sizeof(format));
++ format.pad = CCDC_PAD_SINK;
++ format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
++ format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
++ format.format.width = 4096;
++ format.format.height = 4096;
++ ccdc_set_format(sd, fh, &format);
++
++ return 0;
++}
++
++/* V4L2 subdev core operations */
++static const struct v4l2_subdev_core_ops ccdc_v4l2_core_ops = {
++ .queryctrl = v4l2_subdev_queryctrl,
++ .querymenu = v4l2_subdev_querymenu,
++ .g_ctrl = v4l2_subdev_g_ctrl,
++ .s_ctrl = v4l2_subdev_s_ctrl,
++ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
++ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
++ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
++ .ioctl = ccdc_ioctl,
++ .subscribe_event = ccdc_subscribe_event,
++ .unsubscribe_event = ccdc_unsubscribe_event,
++};
++
++/* V4L2 subdev file operations */
++static const struct v4l2_subdev_file_ops ccdc_v4l2_file_ops = {
++ .open = ccdc_init_formats,
++};
++
++/* V4L2 subdev video operations */
++static const struct v4l2_subdev_video_ops ccdc_v4l2_video_ops = {
++ .s_stream = ccdc_set_stream,
++};
++
++/* V4L2 subdev pad operations */
++static const struct v4l2_subdev_pad_ops ccdc_v4l2_pad_ops = {
++ .enum_mbus_code = ccdc_enum_mbus_code,
++ .enum_frame_size = ccdc_enum_frame_size,
++ .get_fmt = ccdc_get_format,
++ .set_fmt = ccdc_set_format,
++};
++
++/* V4L2 subdev operations */
++static const struct v4l2_subdev_ops ccdc_v4l2_ops = {
++ .core = &ccdc_v4l2_core_ops,
++ .file = &ccdc_v4l2_file_ops,
++ .video = &ccdc_v4l2_video_ops,
++ .pad = &ccdc_v4l2_pad_ops,
++};
++
++/* -----------------------------------------------------------------------------
++ * Media entity operations
++ */
++
++/*
++ * ccdc_link_setup - Setup CCDC connections
++ * @entity: CCDC media entity
++ * @local: Pad at the local end of the link
++ * @remote: Pad at the remote end of the link
++ * @flags: Link flags
++ *
++ * return -EINVAL or zero on success
++ */
++static int ccdc_link_setup(struct media_entity *entity,
++ const struct media_pad *local,
++ const struct media_pad *remote, u32 flags)
++{
++ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
++ struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
++ struct isp_device *isp = to_isp_device(ccdc);
++
++ switch (local->index | media_entity_type(remote->entity)) {
++ case CCDC_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
++ /* Read from the sensor (parallel interface), CCP2, CSI2a or
++ * CSI2c.
++ */
++ if (!(flags & MEDIA_LNK_FL_ENABLED)) {
++ ccdc->input = CCDC_INPUT_NONE;
++ break;
++ }
++
++ if (ccdc->input != CCDC_INPUT_NONE)
++ return -EBUSY;
++
++ if (remote->entity == &isp->isp_ccp2.subdev.entity)
++ ccdc->input = CCDC_INPUT_CCP2B;
++ else if (remote->entity == &isp->isp_csi2a.subdev.entity)
++ ccdc->input = CCDC_INPUT_CSI2A;
++ else if (remote->entity == &isp->isp_csi2c.subdev.entity)
++ ccdc->input = CCDC_INPUT_CSI2C;
++ else
++ ccdc->input = CCDC_INPUT_PARALLEL;
++
++ break;
++
++ /*
++ * The ISP core doesn't support pipelines with multiple video outputs.
++ * Revisit this when it will be implemented, and return -EBUSY for now.
++ */
++
++ case CCDC_PAD_SOURCE_VP | MEDIA_ENT_T_V4L2_SUBDEV:
++ /* Write to preview engine, histogram and H3A. When none of
++ * those links are active, the video port can be disabled.
++ */
++ if (flags & MEDIA_LNK_FL_ENABLED) {
++ if (ccdc->output & ~CCDC_OUTPUT_PREVIEW)
++ return -EBUSY;
++ ccdc->output |= CCDC_OUTPUT_PREVIEW;
++ } else {
++ ccdc->output &= ~CCDC_OUTPUT_PREVIEW;
++ }
++ break;
++
++ case CCDC_PAD_SOURCE_OF | MEDIA_ENT_T_DEVNODE:
++ /* Write to memory */
++ if (flags & MEDIA_LNK_FL_ENABLED) {
++ if (ccdc->output & ~CCDC_OUTPUT_MEMORY)
++ return -EBUSY;
++ ccdc->output |= CCDC_OUTPUT_MEMORY;
++ } else {
++ ccdc->output &= ~CCDC_OUTPUT_MEMORY;
++ }
++ break;
++
++ case CCDC_PAD_SOURCE_OF | MEDIA_ENT_T_V4L2_SUBDEV:
++ /* Write to resizer */
++ if (flags & MEDIA_LNK_FL_ENABLED) {
++ if (ccdc->output & ~CCDC_OUTPUT_RESIZER)
++ return -EBUSY;
++ ccdc->output |= CCDC_OUTPUT_RESIZER;
++ } else {
++ ccdc->output &= ~CCDC_OUTPUT_RESIZER;
++ }
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++/* media operations */
++static const struct media_entity_operations ccdc_media_ops = {
++ .link_setup = ccdc_link_setup,
++};
++
++/*
++ * ccdc_init_entities - Initialize V4L2 subdev and media entity
++ * @ccdc: ISP CCDC module
++ *
++ * Return 0 on success and a negative error code on failure.
++ */
++static int ccdc_init_entities(struct isp_ccdc_device *ccdc)
++{
++ struct v4l2_subdev *sd = &ccdc->subdev;
++ struct media_pad *pads = ccdc->pads;
++ struct media_entity *me = &sd->entity;
++ int ret;
++
++ ccdc->input = CCDC_INPUT_NONE;
++
++ v4l2_subdev_init(sd, &ccdc_v4l2_ops);
++ strlcpy(sd->name, "OMAP3 ISP CCDC", sizeof(sd->name));
++ sd->grp_id = 1 << 16; /* group ID for isp subdevs */
++ v4l2_set_subdevdata(sd, ccdc);
++ sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
++ sd->nevents = OMAP3ISP_CCDC_NEVENTS;
++
++ v4l2_ctrl_handler_init(&ccdc->ctrls, 1);
++ sd->ctrl_handler = &ccdc->ctrls;
++
++ pads[CCDC_PAD_SINK].flags = MEDIA_PAD_FL_INPUT;
++ pads[CCDC_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_OUTPUT;
++ pads[CCDC_PAD_SOURCE_OF].flags = MEDIA_PAD_FL_OUTPUT;
++
++ me->ops = &ccdc_media_ops;
++ ret = media_entity_init(me, CCDC_PADS_NUM, pads, 0);
++ if (ret < 0)
++ return ret;
++
++ ccdc_init_formats(sd, NULL);
++
++ ccdc->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ ccdc->video_out.ops = &ccdc_video_ops;
++ ccdc->video_out.isp = to_isp_device(ccdc);
++ ccdc->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3;
++ ccdc->video_out.bpl_alignment = 32;
++
++ ret = omap3isp_video_init(&ccdc->video_out, "CCDC");
++ if (ret < 0)
++ return ret;
++
++ /* Connect the CCDC subdev to the video node. */
++ ret = media_entity_create_link(&ccdc->subdev.entity, CCDC_PAD_SOURCE_OF,
++ &ccdc->video_out.video.entity, 0, 0);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc)
++{
++ media_entity_cleanup(&ccdc->subdev.entity);
++
++ v4l2_device_unregister_subdev(&ccdc->subdev);
++ v4l2_ctrl_handler_free(&ccdc->ctrls);
++ omap3isp_video_unregister(&ccdc->video_out);
++}
++
++int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc,
++ struct v4l2_device *vdev)
++{
++ int ret;
++
++ /* Register the subdev and video node. */
++ ret = v4l2_device_register_subdev(vdev, &ccdc->subdev);
++ if (ret < 0)
++ goto error;
++
++ ret = omap3isp_video_register(&ccdc->video_out, vdev);
++ if (ret < 0)
++ goto error;
++
++ return 0;
++
++error:
++ omap3isp_ccdc_unregister_entities(ccdc);
++ return ret;
++}
++
++/* -----------------------------------------------------------------------------
++ * ISP CCDC initialisation and cleanup
++ */
++
++/*
++ * omap3isp_ccdc_init - CCDC module initialization.
++ * @dev: Device pointer specific to the OMAP3 ISP.
++ *
++ * TODO: Get the initialisation values from platform data.
++ *
++ * Return 0 on success or a negative error code otherwise.
++ */
++int omap3isp_ccdc_init(struct isp_device *isp)
++{
++ struct isp_ccdc_device *ccdc = &isp->isp_ccdc;
++
++ spin_lock_init(&ccdc->lock);
++ init_waitqueue_head(&ccdc->wait);
++ mutex_init(&ccdc->ioctl_lock);
++
++ ccdc->stopping = CCDC_STOP_NOT_REQUESTED;
++
++ INIT_WORK(&ccdc->lsc.table_work, ccdc_lsc_free_table_work);
++ ccdc->lsc.state = LSC_STATE_STOPPED;
++ INIT_LIST_HEAD(&ccdc->lsc.free_queue);
++ spin_lock_init(&ccdc->lsc.req_lock);
++
++ ccdc->syncif.ccdc_mastermode = 0;
++ ccdc->syncif.datapol = 0;
++ ccdc->syncif.datsz = 0;
++ ccdc->syncif.fldmode = 0;
++ ccdc->syncif.fldout = 0;
++ ccdc->syncif.fldpol = 0;
++ ccdc->syncif.fldstat = 0;
++ ccdc->syncif.hdpol = 0;
++ ccdc->syncif.vdpol = 0;
++
++ ccdc->clamp.oblen = 0;
++ ccdc->clamp.dcsubval = 0;
++
++ ccdc->vpcfg.pixelclk = 0;
++
++ ccdc->update = OMAP3ISP_CCDC_BLCLAMP;
++ ccdc_apply_controls(ccdc);
++
++ return ccdc_init_entities(ccdc);
++}
++
++/*
++ * omap3isp_ccdc_cleanup - CCDC module cleanup.
++ * @dev: Device pointer specific to the OMAP3 ISP.
++ */
++void omap3isp_ccdc_cleanup(struct isp_device *isp)
++{
++ struct isp_ccdc_device *ccdc = &isp->isp_ccdc;
++
++ /* Free LSC requests. As the CCDC is stopped there's no active request,
++ * so only the pending request and the free queue need to be handled.
++ */
++ ccdc_lsc_free_request(ccdc, ccdc->lsc.request);
++ cancel_work_sync(&ccdc->lsc.table_work);
++ ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue);
++
++ if (ccdc->fpc.fpcaddr != 0)
++ iommu_vfree(isp->iommu, ccdc->fpc.fpcaddr);
++}
+diff --git a/drivers/media/video/isp/ispccdc.h b/drivers/media/video/isp/ispccdc.h
+new file mode 100644
+index 0000000..5c00e2c
+--- /dev/null
++++ b/drivers/media/video/isp/ispccdc.h
+@@ -0,0 +1,223 @@
++/*
++ * ispccdc.h
++ *
++ * TI OMAP3 ISP - CCDC module
++ *
++ * Copyright (C) 2009-2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc.
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#ifndef OMAP3_ISP_CCDC_H
++#define OMAP3_ISP_CCDC_H
++
++#include <linux/omap3isp.h>
++#include <linux/workqueue.h>
++#include <media/v4l2-ctrls.h>
++
++#include "ispvideo.h"
++
++enum ccdc_input_entity {
++ CCDC_INPUT_NONE,
++ CCDC_INPUT_PARALLEL,
++ CCDC_INPUT_CSI2A,
++ CCDC_INPUT_CCP2B,
++ CCDC_INPUT_CSI2C
++};
++
++#define CCDC_OUTPUT_MEMORY (1 << 0)
++#define CCDC_OUTPUT_PREVIEW (1 << 1)
++#define CCDC_OUTPUT_RESIZER (1 << 2)
++
++#define OMAP3ISP_CCDC_NEVENTS 16
++
++/*
++ * struct ispccdc_syncif - Structure for Sync Interface between sensor and CCDC
++ * @ccdc_mastermode: Master mode. 1 - Master, 0 - Slave.
++ * @fldstat: Field state. 0 - Odd Field, 1 - Even Field.
++ * @datsz: Data size.
++ * @fldmode: 0 - Progressive, 1 - Interlaced.
++ * @datapol: 0 - Positive, 1 - Negative.
++ * @fldpol: 0 - Positive, 1 - Negative.
++ * @hdpol: 0 - Positive, 1 - Negative.
++ * @vdpol: 0 - Positive, 1 - Negative.
++ * @fldout: 0 - Input, 1 - Output.
++ * @hs_width: Width of the Horizontal Sync pulse, used for HS/VS Output.
++ * @vs_width: Width of the Vertical Sync pulse, used for HS/VS Output.
++ * @ppln: Number of pixels per line, used for HS/VS Output.
++ * @hlprf: Number of half lines per frame, used for HS/VS Output.
++ * @bt_r656_en: 1 - Enable ITU-R BT656 mode, 0 - Sync mode.
++ */
++struct ispccdc_syncif {
++ u8 ccdc_mastermode;
++ u8 fldstat;
++ u8 datsz;
++ u8 fldmode;
++ u8 datapol;
++ u8 fldpol;
++ u8 hdpol;
++ u8 vdpol;
++ u8 fldout;
++ u8 hs_width;
++ u8 vs_width;
++ u8 ppln;
++ u8 hlprf;
++ u8 bt_r656_en;
++};
++
++/*
++ * struct ispccdc_vp - Structure for Video Port parameters
++ * @pixelclk: Input pixel clock in Hz
++ */
++struct ispccdc_vp {
++ unsigned int pixelclk;
++};
++
++enum ispccdc_lsc_state {
++ LSC_STATE_STOPPED = 0,
++ LSC_STATE_STOPPING = 1,
++ LSC_STATE_RUNNING = 2,
++ LSC_STATE_RECONFIG = 3,
++};
++
++struct ispccdc_lsc_config_req {
++ struct list_head list;
++ struct omap3isp_ccdc_lsc_config config;
++ unsigned char enable;
++ u32 table;
++ struct iovm_struct *iovm;
++};
++
++/*
++ * ispccdc_lsc - CCDC LSC parameters
++ * @update_config: Set when user changes config
++ * @request_enable: Whether LSC is requested to be enabled
++ * @config: LSC config set by user
++ * @update_table: Set when user provides a new LSC table to table_new
++ * @table_new: LSC table set by user, ISP address
++ * @table_inuse: LSC table currently in use, ISP address
++ */
++struct ispccdc_lsc {
++ enum ispccdc_lsc_state state;
++ struct work_struct table_work;
++
++ /* LSC queue of configurations */
++ spinlock_t req_lock;
++ struct ispccdc_lsc_config_req *request; /* requested configuration */
++ struct ispccdc_lsc_config_req *active; /* active configuration */
++ struct list_head free_queue; /* configurations for freeing */
++};
++
++#define CCDC_STOP_NOT_REQUESTED 0x00
++#define CCDC_STOP_REQUEST 0x01
++#define CCDC_STOP_EXECUTED (0x02 | CCDC_STOP_REQUEST)
++#define CCDC_STOP_CCDC_FINISHED 0x04
++#define CCDC_STOP_LSC_FINISHED 0x08
++#define CCDC_STOP_FINISHED \
++ (CCDC_STOP_EXECUTED | CCDC_STOP_CCDC_FINISHED | CCDC_STOP_LSC_FINISHED)
++
++#define CCDC_EVENT_VD1 0x10
++#define CCDC_EVENT_VD0 0x20
++#define CCDC_EVENT_LSC_DONE 0x40
++
++/* Sink and source CCDC pads */
++#define CCDC_PAD_SINK 0
++#define CCDC_PAD_SOURCE_OF 1
++#define CCDC_PAD_SOURCE_VP 2
++#define CCDC_PADS_NUM 3
++
++/*
++ * struct isp_ccdc_device - Structure for the CCDC module to store its own
++ * information
++ * @subdev: V4L2 subdevice
++ * @pads: Sink and source media entity pads
++ * @formats: Active video formats
++ * @ctrls: V4L2 controls handler
++ * @input: Active input
++ * @output: Active outputs
++ * @video_out: Output video node
++ * @error: A hardware error occured during capture
++ * @alaw: A-law compression enabled (1) or disabled (0)
++ * @lpf: Low pass filter enabled (1) or disabled (0)
++ * @obclamp: Optical-black clamp enabled (1) or disabled (0)
++ * @fpc_en: Faulty pixels correction enabled (1) or disabled (0)
++ * @blcomp: Black level compensation configuration
++ * @clamp: Optical-black or digital clamp configuration
++ * @fpc: Faulty pixels correction configuration
++ * @lsc: Lens shading compensation configuration
++ * @update: Bitmask of controls to update during the next interrupt
++ * @shadow_update: Controls update in progress by userspace
++ * @syncif: Interface synchronization configuration
++ * @vpcfg: Video port configuration
++ * @underrun: A buffer underrun occured and a new buffer has been queued
++ * @state: Streaming state
++ * @lock: Serializes shadow_update with interrupt handler
++ * @wait: Wait queue used to stop the module
++ * @stopping: Stopping state
++ * @ioctl_lock: Serializes ioctl calls and LSC requests freeing
++ */
++struct isp_ccdc_device {
++ struct v4l2_subdev subdev;
++ struct media_pad pads[CCDC_PADS_NUM];
++ struct v4l2_mbus_framefmt formats[CCDC_PADS_NUM];
++
++ struct v4l2_ctrl_handler ctrls;
++
++ enum ccdc_input_entity input;
++ unsigned int output;
++ struct isp_video video_out;
++ unsigned int error;
++
++ unsigned int alaw:1,
++ lpf:1,
++ obclamp:1,
++ fpc_en:1;
++ struct omap3isp_ccdc_blcomp blcomp;
++ struct omap3isp_ccdc_bclamp clamp;
++ struct omap3isp_ccdc_fpc fpc;
++ struct ispccdc_lsc lsc;
++ unsigned int update;
++ unsigned int shadow_update;
++
++ struct ispccdc_syncif syncif;
++ struct ispccdc_vp vpcfg;
++
++ unsigned int underrun:1;
++ enum isp_pipeline_stream_state state;
++ spinlock_t lock;
++ wait_queue_head_t wait;
++ unsigned int stopping;
++ struct mutex ioctl_lock;
++};
++
++struct isp_device;
++
++int omap3isp_ccdc_init(struct isp_device *isp);
++void omap3isp_ccdc_cleanup(struct isp_device *isp);
++int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc,
++ struct v4l2_device *vdev);
++void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc);
++
++int omap3isp_ccdc_busy(struct isp_ccdc_device *isp_ccdc);
++int omap3isp_ccdc_isr(struct isp_ccdc_device *isp_ccdc, u32 events);
++void omap3isp_ccdc_restore_context(struct isp_device *isp);
++void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc,
++ unsigned int *max_rate);
++
++#endif /* OMAP3_ISP_CCDC_H */
+diff --git a/drivers/media/video/isp/ispccp2.c b/drivers/media/video/isp/ispccp2.c
+new file mode 100644
+index 0000000..efcf827
+--- /dev/null
++++ b/drivers/media/video/isp/ispccp2.c
+@@ -0,0 +1,1189 @@
++/*
++ * ispccp2.c
++ *
++ * TI OMAP3 ISP - CCP2 module
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2010 Texas Instruments, Inc.
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/uaccess.h>
++
++#include "isp.h"
++#include "ispreg.h"
++#include "ispccp2.h"
++
++/* Number of LCX channels */
++#define CCP2_LCx_CHANS_NUM 3
++/* Max/Min size for CCP2 video port */
++#define ISPCCP2_DAT_START_MIN 0
++#define ISPCCP2_DAT_START_MAX 4095
++#define ISPCCP2_DAT_SIZE_MIN 0
++#define ISPCCP2_DAT_SIZE_MAX 4095
++#define ISPCCP2_VPCLK_FRACDIV 65536
++#define ISPCCP2_LCx_CTRL_FORMAT_RAW8_DPCM10_VP 0x12
++#define ISPCCP2_LCx_CTRL_FORMAT_RAW10_VP 0x16
++/* Max/Min size for CCP2 memory channel */
++#define ISPCCP2_LCM_HSIZE_COUNT_MIN 16
++#define ISPCCP2_LCM_HSIZE_COUNT_MAX 8191
++#define ISPCCP2_LCM_HSIZE_SKIP_MIN 0
++#define ISPCCP2_LCM_HSIZE_SKIP_MAX 8191
++#define ISPCCP2_LCM_VSIZE_MIN 1
++#define ISPCCP2_LCM_VSIZE_MAX 8191
++#define ISPCCP2_LCM_HWORDS_MIN 1
++#define ISPCCP2_LCM_HWORDS_MAX 4095
++#define ISPCCP2_LCM_CTRL_BURST_SIZE_32X 5
++#define ISPCCP2_LCM_CTRL_READ_THROTTLE_FULL 0
++#define ISPCCP2_LCM_CTRL_SRC_DECOMPR_DPCM10 2
++#define ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW8 2
++#define ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW10 3
++#define ISPCCP2_LCM_CTRL_DST_FORMAT_RAW10 3
++#define ISPCCP2_LCM_CTRL_DST_PORT_VP 0
++#define ISPCCP2_LCM_CTRL_DST_PORT_MEM 1
++
++/* Set only the required bits */
++#define BIT_SET(var, shift, mask, val) \
++ do { \
++ var = ((var) & ~((mask) << (shift))) \
++ | ((val) << (shift)); \
++ } while (0)
++
++/*
++ * ccp2_print_status - Print current CCP2 module register values.
++ */
++#define CCP2_PRINT_REGISTER(isp, name)\
++ dev_dbg(isp->dev, "###CCP2 " #name "=0x%08x\n", \
++ isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_##name))
++
++static void ccp2_print_status(struct isp_ccp2_device *ccp2)
++{
++ struct isp_device *isp = to_isp_device(ccp2);
++
++ dev_dbg(isp->dev, "-------------CCP2 Register dump-------------\n");
++
++ CCP2_PRINT_REGISTER(isp, SYSCONFIG);
++ CCP2_PRINT_REGISTER(isp, SYSSTATUS);
++ CCP2_PRINT_REGISTER(isp, LC01_IRQENABLE);
++ CCP2_PRINT_REGISTER(isp, LC01_IRQSTATUS);
++ CCP2_PRINT_REGISTER(isp, LC23_IRQENABLE);
++ CCP2_PRINT_REGISTER(isp, LC23_IRQSTATUS);
++ CCP2_PRINT_REGISTER(isp, LCM_IRQENABLE);
++ CCP2_PRINT_REGISTER(isp, LCM_IRQSTATUS);
++ CCP2_PRINT_REGISTER(isp, CTRL);
++ CCP2_PRINT_REGISTER(isp, LCx_CTRL(0));
++ CCP2_PRINT_REGISTER(isp, LCx_CODE(0));
++ CCP2_PRINT_REGISTER(isp, LCx_STAT_START(0));
++ CCP2_PRINT_REGISTER(isp, LCx_STAT_SIZE(0));
++ CCP2_PRINT_REGISTER(isp, LCx_SOF_ADDR(0));
++ CCP2_PRINT_REGISTER(isp, LCx_EOF_ADDR(0));
++ CCP2_PRINT_REGISTER(isp, LCx_DAT_START(0));
++ CCP2_PRINT_REGISTER(isp, LCx_DAT_SIZE(0));
++ CCP2_PRINT_REGISTER(isp, LCx_DAT_PING_ADDR(0));
++ CCP2_PRINT_REGISTER(isp, LCx_DAT_PONG_ADDR(0));
++ CCP2_PRINT_REGISTER(isp, LCx_DAT_OFST(0));
++ CCP2_PRINT_REGISTER(isp, LCM_CTRL);
++ CCP2_PRINT_REGISTER(isp, LCM_VSIZE);
++ CCP2_PRINT_REGISTER(isp, LCM_HSIZE);
++ CCP2_PRINT_REGISTER(isp, LCM_PREFETCH);
++ CCP2_PRINT_REGISTER(isp, LCM_SRC_ADDR);
++ CCP2_PRINT_REGISTER(isp, LCM_SRC_OFST);
++ CCP2_PRINT_REGISTER(isp, LCM_DST_ADDR);
++ CCP2_PRINT_REGISTER(isp, LCM_DST_OFST);
++
++ dev_dbg(isp->dev, "--------------------------------------------\n");
++}
++
++/*
++ * ccp2_reset - Reset the CCP2
++ * @ccp2: pointer to ISP CCP2 device
++ */
++static void ccp2_reset(struct isp_ccp2_device *ccp2)
++{
++ struct isp_device *isp = to_isp_device(ccp2);
++ int i = 0;
++
++ /* Reset the CSI1/CCP2B and wait for reset to complete */
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSCONFIG,
++ ISPCCP2_SYSCONFIG_SOFT_RESET);
++ while (!(isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSSTATUS) &
++ ISPCCP2_SYSSTATUS_RESET_DONE)) {
++ udelay(10);
++ if (i++ > 10) { /* try read 10 times */
++ dev_warn(isp->dev,
++ "omap3_isp: timeout waiting for ccp2 reset\n");
++ break;
++ }
++ }
++}
++
++/*
++ * ccp2_pwr_cfg - Configure the power mode settings
++ * @ccp2: pointer to ISP CCP2 device
++ */
++static void ccp2_pwr_cfg(struct isp_ccp2_device *ccp2)
++{
++ struct isp_device *isp = to_isp_device(ccp2);
++
++ isp_reg_writel(isp, ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SMART |
++ ((isp->revision == ISP_REVISION_15_0 && isp->autoidle) ?
++ ISPCCP2_SYSCONFIG_AUTO_IDLE : 0),
++ OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSCONFIG);
++}
++
++/*
++ * ccp2_if_enable - Enable CCP2 interface.
++ * @ccp2: pointer to ISP CCP2 device
++ * @enable: enable/disable flag
++ */
++static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable)
++{
++ struct isp_device *isp = to_isp_device(ccp2);
++ struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
++ int i;
++
++ /* Enable/Disable all the LCx channels */
++ for (i = 0; i < CCP2_LCx_CHANS_NUM; i++)
++ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(i),
++ ISPCCP2_LCx_CTRL_CHAN_EN,
++ enable ? ISPCCP2_LCx_CTRL_CHAN_EN : 0);
++
++ /* Enable/Disable ccp2 interface in ccp2 mode */
++ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL,
++ ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN,
++ enable ? (ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN) : 0);
++
++ /* For frame count propagation */
++ if (pipe->do_propagation) {
++ /* We may want the Frame Start IRQ from LC0 */
++ if (enable)
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2,
++ ISPCCP2_LC01_IRQENABLE,
++ ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ);
++ else
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCP2,
++ ISPCCP2_LC01_IRQENABLE,
++ ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ);
++ }
++}
++
++/*
++ * ccp2_mem_enable - Enable CCP2 memory interface.
++ * @ccp2: pointer to ISP CCP2 device
++ * @enable: enable/disable flag
++ */
++static void ccp2_mem_enable(struct isp_ccp2_device *ccp2, u8 enable)
++{
++ struct isp_device *isp = to_isp_device(ccp2);
++
++ if (enable)
++ ccp2_if_enable(ccp2, 0);
++
++ /* Enable/Disable ccp2 interface in ccp2 mode */
++ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL,
++ ISPCCP2_CTRL_MODE, enable ? ISPCCP2_CTRL_MODE : 0);
++
++ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_CTRL,
++ ISPCCP2_LCM_CTRL_CHAN_EN,
++ enable ? ISPCCP2_LCM_CTRL_CHAN_EN : 0);
++}
++
++/*
++ * ccp2_phyif_config - Initialize CCP2 phy interface config
++ * @ccp2: Pointer to ISP CCP2 device
++ * @config: CCP2 platform data
++ *
++ * Configure the CCP2 physical interface module from platform data.
++ *
++ * Returns -EIO if strobe is chosen in CSI1 mode, or 0 on success.
++ */
++static int ccp2_phyif_config(struct isp_ccp2_device *ccp2,
++ const struct isp_ccp2_platform_data *pdata)
++{
++ struct isp_device *isp = to_isp_device(ccp2);
++ u32 val;
++
++ /* CCP2B mode */
++ val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL) |
++ ISPCCP2_CTRL_IO_OUT_SEL | ISPCCP2_CTRL_MODE;
++ /* Data/strobe physical layer */
++ BIT_SET(val, ISPCCP2_CTRL_PHY_SEL_SHIFT, ISPCCP2_CTRL_PHY_SEL_MASK,
++ pdata->phy_layer);
++ BIT_SET(val, ISPCCP2_CTRL_INV_SHIFT, ISPCCP2_CTRL_INV_MASK,
++ pdata->strobe_clk_pol);
++ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL);
++
++ val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL);
++ if (!(val & ISPCCP2_CTRL_MODE)) {
++ if (pdata->ccp2_mode)
++ dev_warn(isp->dev, "OMAP3 CCP2 bus not available\n");
++ if (pdata->phy_layer == ISPCCP2_CTRL_PHY_SEL_STROBE)
++ /* Strobe mode requires CCP2 */
++ return -EIO;
++ }
++
++ return 0;
++}
++
++/*
++ * ccp2_vp_config - Initialize CCP2 video port interface.
++ * @ccp2: Pointer to ISP CCP2 device
++ * @vpclk_div: Video port divisor
++ *
++ * Configure the CCP2 video port with the given clock divisor. The valid divisor
++ * values depend on the ISP revision:
++ *
++ * - revision 1.0 and 2.0 1 to 4
++ * - revision 15.0 1 to 65536
++ *
++ * The exact divisor value used might differ from the requested value, as ISP
++ * revision 15.0 represent the divisor by 65536 divided by an integer.
++ */
++static void ccp2_vp_config(struct isp_ccp2_device *ccp2,
++ unsigned int vpclk_div)
++{
++ struct isp_device *isp = to_isp_device(ccp2);
++ u32 val;
++
++ /* ISPCCP2_CTRL Video port */
++ val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL);
++ val |= ISPCCP2_CTRL_VP_ONLY_EN; /* Disable the memory write port */
++
++ if (isp->revision == ISP_REVISION_15_0) {
++ vpclk_div = clamp_t(unsigned int, vpclk_div, 1, 65536);
++ vpclk_div = min(ISPCCP2_VPCLK_FRACDIV / vpclk_div, 65535U);
++ BIT_SET(val, ISPCCP2_CTRL_VPCLK_DIV_SHIFT,
++ ISPCCP2_CTRL_VPCLK_DIV_MASK, vpclk_div);
++ } else {
++ vpclk_div = clamp_t(unsigned int, vpclk_div, 1, 4);
++ BIT_SET(val, ISPCCP2_CTRL_VP_OUT_CTRL_SHIFT,
++ ISPCCP2_CTRL_VP_OUT_CTRL_MASK, vpclk_div - 1);
++ }
++
++ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL);
++}
++
++/*
++ * ccp2_lcx_config - Initialize CCP2 logical channel interface.
++ * @ccp2: Pointer to ISP CCP2 device
++ * @config: Pointer to ISP LCx config structure.
++ *
++ * This will analyze the parameters passed by the interface config
++ * and configure CSI1/CCP2 logical channel
++ *
++ */
++static void ccp2_lcx_config(struct isp_ccp2_device *ccp2,
++ struct isp_interface_lcx_config *config)
++{
++ struct isp_device *isp = to_isp_device(ccp2);
++ u32 val, format;
++
++ switch (config->format) {
++ case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
++ format = ISPCCP2_LCx_CTRL_FORMAT_RAW8_DPCM10_VP;
++ break;
++ case V4L2_MBUS_FMT_SGRBG10_1X10:
++ default:
++ format = ISPCCP2_LCx_CTRL_FORMAT_RAW10_VP; /* RAW10+VP */
++ break;
++ }
++ /* ISPCCP2_LCx_CTRL logical channel #0 */
++ val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(0))
++ | (ISPCCP2_LCx_CTRL_REGION_EN); /* Region */
++
++ if (isp->revision == ISP_REVISION_15_0) {
++ /* CRC */
++ BIT_SET(val, ISPCCP2_LCx_CTRL_CRC_SHIFT_15_0,
++ ISPCCP2_LCx_CTRL_CRC_MASK,
++ config->crc);
++ /* Format = RAW10+VP or RAW8+DPCM10+VP*/
++ BIT_SET(val, ISPCCP2_LCx_CTRL_FORMAT_SHIFT_15_0,
++ ISPCCP2_LCx_CTRL_FORMAT_MASK_15_0, format);
++ } else {
++ BIT_SET(val, ISPCCP2_LCx_CTRL_CRC_SHIFT,
++ ISPCCP2_LCx_CTRL_CRC_MASK,
++ config->crc);
++
++ BIT_SET(val, ISPCCP2_LCx_CTRL_FORMAT_SHIFT,
++ ISPCCP2_LCx_CTRL_FORMAT_MASK, format);
++ }
++ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(0));
++
++ /* ISPCCP2_DAT_START for logical channel #0 */
++ isp_reg_writel(isp, config->data_start << ISPCCP2_LCx_DAT_SHIFT,
++ OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_DAT_START(0));
++
++ /* ISPCCP2_DAT_SIZE for logical channel #0 */
++ isp_reg_writel(isp, config->data_size << ISPCCP2_LCx_DAT_SHIFT,
++ OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_DAT_SIZE(0));
++
++ /* Enable error IRQs for logical channel #0 */
++ val = ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ |
++ ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ |
++ ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ |
++ ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ |
++ ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ |
++ ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ |
++ ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ;
++
++ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQSTATUS);
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQENABLE, val);
++}
++
++/*
++ * ccp2_if_configure - Configure ccp2 with data from sensor
++ * @ccp2: Pointer to ISP CCP2 device
++ *
++ * Return 0 on success or a negative error code
++ */
++static int ccp2_if_configure(struct isp_ccp2_device *ccp2)
++{
++ const struct isp_v4l2_subdevs_group *pdata;
++ struct v4l2_mbus_framefmt *format;
++ struct media_pad *pad;
++ struct v4l2_subdev *sensor;
++ u32 lines = 0;
++ int ret;
++
++ ccp2_pwr_cfg(ccp2);
++
++ pad = media_entity_remote_source(&ccp2->pads[CCP2_PAD_SINK]);
++ sensor = media_entity_to_v4l2_subdev(pad->entity);
++ pdata = sensor->host_priv;
++
++ ret = ccp2_phyif_config(ccp2, &pdata->bus.ccp2);
++ if (ret < 0)
++ return ret;
++
++ ccp2_vp_config(ccp2, pdata->bus.ccp2.vpclk_div + 1);
++
++ v4l2_subdev_call(sensor, sensor, g_skip_top_lines, &lines);
++
++ format = &ccp2->formats[CCP2_PAD_SINK];
++
++ ccp2->if_cfg.data_start = lines;
++ ccp2->if_cfg.crc = pdata->bus.ccp2.crc;
++ ccp2->if_cfg.format = format->code;
++ ccp2->if_cfg.data_size = format->height;
++
++ ccp2_lcx_config(ccp2, &ccp2->if_cfg);
++
++ return 0;
++}
++
++static int ccp2_adjust_bandwidth(struct isp_ccp2_device *ccp2)
++{
++ struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
++ struct isp_device *isp = to_isp_device(ccp2);
++ const struct v4l2_mbus_framefmt *ofmt = &ccp2->formats[CCP2_PAD_SOURCE];
++ unsigned long l3_ick = pipe->l3_ick;
++ struct v4l2_fract *timeperframe;
++ unsigned int vpclk_div = 2;
++ unsigned int value;
++ u64 bound;
++ u64 area;
++
++ /* Compute the minimum clock divisor, based on the pipeline maximum
++ * data rate. This is an absolute lower bound if we don't want SBL
++ * overflows, so round the value up.
++ */
++ vpclk_div = max_t(unsigned int, DIV_ROUND_UP(l3_ick, pipe->max_rate),
++ vpclk_div);
++
++ /* Compute the maximum clock divisor, based on the requested frame rate.
++ * This is a soft lower bound to achieve a frame rate equal or higher
++ * than the requested value, so round the value down.
++ */
++ timeperframe = &pipe->max_timeperframe;
++
++ if (timeperframe->numerator) {
++ area = ofmt->width * ofmt->height;
++ bound = div_u64(area * timeperframe->denominator,
++ timeperframe->numerator);
++ value = min_t(u64, bound, l3_ick);
++ vpclk_div = max_t(unsigned int, l3_ick / value, vpclk_div);
++ }
++
++ dev_dbg(isp->dev, "%s: minimum clock divisor = %u\n", __func__,
++ vpclk_div);
++
++ return vpclk_div;
++}
++
++/*
++ * ccp2_mem_configure - Initialize CCP2 memory input/output interface
++ * @ccp2: Pointer to ISP CCP2 device
++ * @config: Pointer to ISP mem interface config structure
++ *
++ * This will analyze the parameters passed by the interface config
++ * structure, and configure the respective registers for proper
++ * CSI1/CCP2 memory input.
++ */
++static void ccp2_mem_configure(struct isp_ccp2_device *ccp2,
++ struct isp_interface_mem_config *config)
++{
++ struct isp_device *isp = to_isp_device(ccp2);
++ u32 sink_pixcode = ccp2->formats[CCP2_PAD_SINK].code;
++ u32 source_pixcode = ccp2->formats[CCP2_PAD_SOURCE].code;
++ unsigned int dpcm_decompress = 0;
++ u32 val, hwords;
++
++ if (sink_pixcode != source_pixcode &&
++ sink_pixcode == V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8)
++ dpcm_decompress = 1;
++
++ ccp2_pwr_cfg(ccp2);
++
++ /* Hsize, Skip */
++ isp_reg_writel(isp, ISPCCP2_LCM_HSIZE_SKIP_MIN |
++ (config->hsize_count << ISPCCP2_LCM_HSIZE_SHIFT),
++ OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_HSIZE);
++
++ /* Vsize, no. of lines */
++ isp_reg_writel(isp, config->vsize_count << ISPCCP2_LCM_VSIZE_SHIFT,
++ OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_VSIZE);
++
++ if (ccp2->video_in.bpl_padding == 0)
++ config->src_ofst = 0;
++ else
++ config->src_ofst = ccp2->video_in.bpl_value;
++
++ isp_reg_writel(isp, config->src_ofst, OMAP3_ISP_IOMEM_CCP2,
++ ISPCCP2_LCM_SRC_OFST);
++
++ /* Source and Destination formats */
++ val = ISPCCP2_LCM_CTRL_DST_FORMAT_RAW10 <<
++ ISPCCP2_LCM_CTRL_DST_FORMAT_SHIFT;
++
++ if (dpcm_decompress) {
++ /* source format is RAW8 */
++ val |= ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW8 <<
++ ISPCCP2_LCM_CTRL_SRC_FORMAT_SHIFT;
++
++ /* RAW8 + DPCM10 - simple predictor */
++ val |= ISPCCP2_LCM_CTRL_SRC_DPCM_PRED;
++
++ /* enable source DPCM decompression */
++ val |= ISPCCP2_LCM_CTRL_SRC_DECOMPR_DPCM10 <<
++ ISPCCP2_LCM_CTRL_SRC_DECOMPR_SHIFT;
++ } else {
++ /* source format is RAW10 */
++ val |= ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW10 <<
++ ISPCCP2_LCM_CTRL_SRC_FORMAT_SHIFT;
++ }
++
++ /* Burst size to 32x64 */
++ val |= ISPCCP2_LCM_CTRL_BURST_SIZE_32X <<
++ ISPCCP2_LCM_CTRL_BURST_SIZE_SHIFT;
++
++ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_CTRL);
++
++ /* Prefetch setup */
++ if (dpcm_decompress)
++ hwords = (ISPCCP2_LCM_HSIZE_SKIP_MIN +
++ config->hsize_count) >> 3;
++ else
++ hwords = (ISPCCP2_LCM_HSIZE_SKIP_MIN +
++ config->hsize_count) >> 2;
++
++ isp_reg_writel(isp, hwords << ISPCCP2_LCM_PREFETCH_SHIFT,
++ OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_PREFETCH);
++
++ /* Video port */
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL,
++ ISPCCP2_CTRL_IO_OUT_SEL | ISPCCP2_CTRL_MODE);
++ ccp2_vp_config(ccp2, ccp2_adjust_bandwidth(ccp2));
++
++ /* Clear LCM interrupts */
++ isp_reg_writel(isp, ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ |
++ ISPCCP2_LCM_IRQSTATUS_EOF_IRQ,
++ OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_IRQSTATUS);
++
++ /* Enable LCM interupts */
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_IRQENABLE,
++ ISPCCP2_LCM_IRQSTATUS_EOF_IRQ |
++ ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ);
++}
++
++/*
++ * ccp2_set_inaddr - Sets memory address of input frame.
++ * @ccp2: Pointer to ISP CCP2 device
++ * @addr: 32bit memory address aligned on 32byte boundary.
++ *
++ * Configures the memory address from which the input frame is to be read.
++ */
++static void ccp2_set_inaddr(struct isp_ccp2_device *ccp2, u32 addr)
++{
++ struct isp_device *isp = to_isp_device(ccp2);
++
++ isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_SRC_ADDR);
++}
++
++/* -----------------------------------------------------------------------------
++ * Interrupt handling
++ */
++
++static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2)
++{
++ struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
++ struct isp_buffer *buffer;
++
++ buffer = omap3isp_video_buffer_next(&ccp2->video_in, ccp2->error);
++ if (buffer != NULL)
++ ccp2_set_inaddr(ccp2, buffer->isp_addr);
++
++ pipe->state |= ISP_PIPELINE_IDLE_INPUT;
++
++ if (ccp2->state == ISP_PIPELINE_STREAM_SINGLESHOT) {
++ if (isp_pipeline_ready(pipe))
++ omap3isp_pipeline_set_stream(pipe,
++ ISP_PIPELINE_STREAM_SINGLESHOT);
++ }
++
++ ccp2->error = 0;
++}
++
++/*
++ * omap3isp_ccp2_isr - Handle ISP CCP2 interrupts
++ * @ccp2: Pointer to ISP CCP2 device
++ *
++ * This will handle the CCP2 interrupts
++ *
++ * Returns -EIO in case of error, or 0 on success.
++ */
++int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2)
++{
++ struct isp_device *isp = to_isp_device(ccp2);
++ int ret = 0;
++ static const u32 ISPCCP2_LC01_ERROR =
++ ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ |
++ ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ |
++ ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ |
++ ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ |
++ ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ |
++ ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ;
++ u32 lcx_irqstatus, lcm_irqstatus;
++
++ /* First clear the interrupts */
++ lcx_irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2,
++ ISPCCP2_LC01_IRQSTATUS);
++ isp_reg_writel(isp, lcx_irqstatus, OMAP3_ISP_IOMEM_CCP2,
++ ISPCCP2_LC01_IRQSTATUS);
++
++ lcm_irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2,
++ ISPCCP2_LCM_IRQSTATUS);
++ isp_reg_writel(isp, lcm_irqstatus, OMAP3_ISP_IOMEM_CCP2,
++ ISPCCP2_LCM_IRQSTATUS);
++ /* Errors */
++ if (lcx_irqstatus & ISPCCP2_LC01_ERROR) {
++ ccp2->error = 1;
++ dev_dbg(isp->dev, "CCP2 err:%x\n", lcx_irqstatus);
++ return -EIO;
++ }
++
++ if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ) {
++ ccp2->error = 1;
++ dev_dbg(isp->dev, "CCP2 OCP err:%x\n", lcm_irqstatus);
++ ret = -EIO;
++ }
++
++ if (omap3isp_module_sync_is_stopping(&ccp2->wait, &ccp2->stopping))
++ return 0;
++
++ /* Frame number propagation */
++ if (lcx_irqstatus & ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ) {
++ struct isp_pipeline *pipe =
++ to_isp_pipeline(&ccp2->subdev.entity);
++ if (pipe->do_propagation)
++ atomic_inc(&pipe->frame_number);
++ }
++
++ /* Handle queued buffers on frame end interrupts */
++ if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_EOF_IRQ)
++ ccp2_isr_buffer(ccp2);
++
++ return ret;
++}
++
++/* -----------------------------------------------------------------------------
++ * V4L2 subdev operations
++ */
++
++static const unsigned int ccp2_fmts[] = {
++ V4L2_MBUS_FMT_SGRBG10_1X10,
++ V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
++};
++
++/*
++ * __ccp2_get_format - helper function for getting ccp2 format
++ * @ccp2 : Pointer to ISP CCP2 device
++ * @fh : V4L2 subdev file handle
++ * @pad : pad number
++ * @which : wanted subdev format
++ * return format structure or NULL on error
++ */
++static struct v4l2_mbus_framefmt *
++__ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_fh *fh,
++ unsigned int pad, enum v4l2_subdev_format_whence which)
++{
++ if (which == V4L2_SUBDEV_FORMAT_TRY)
++ return v4l2_subdev_get_try_format(fh, pad);
++ else
++ return &ccp2->formats[pad];
++}
++
++/*
++ * ccp2_try_format - Handle try format by pad subdev method
++ * @ccp2 : Pointer to ISP CCP2 device
++ * @fh : V4L2 subdev file handle
++ * @pad : pad num
++ * @fmt : pointer to v4l2 mbus format structure
++ * @which : wanted subdev format
++ */
++static void ccp2_try_format(struct isp_ccp2_device *ccp2,
++ struct v4l2_subdev_fh *fh, unsigned int pad,
++ struct v4l2_mbus_framefmt *fmt,
++ enum v4l2_subdev_format_whence which)
++{
++ struct v4l2_mbus_framefmt *format;
++
++ switch (pad) {
++ case CCP2_PAD_SINK:
++ if (fmt->code != V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8)
++ fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
++
++ if (ccp2->input == CCP2_INPUT_SENSOR) {
++ fmt->width = clamp_t(u32, fmt->width,
++ ISPCCP2_DAT_START_MIN,
++ ISPCCP2_DAT_START_MAX);
++ fmt->height = clamp_t(u32, fmt->height,
++ ISPCCP2_DAT_SIZE_MIN,
++ ISPCCP2_DAT_SIZE_MAX);
++ } else if (ccp2->input == CCP2_INPUT_MEMORY) {
++ fmt->width = clamp_t(u32, fmt->width,
++ ISPCCP2_LCM_HSIZE_COUNT_MIN,
++ ISPCCP2_LCM_HSIZE_COUNT_MAX);
++ fmt->height = clamp_t(u32, fmt->height,
++ ISPCCP2_LCM_VSIZE_MIN,
++ ISPCCP2_LCM_VSIZE_MAX);
++ }
++ break;
++
++ case CCP2_PAD_SOURCE:
++ /* Source format - copy sink format and change pixel code
++ * to SGRBG10_1X10 as we don't support CCP2 write to memory.
++ * When CCP2 write to memory feature will be added this
++ * should be changed properly.
++ */
++ format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK, which);
++ memcpy(fmt, format, sizeof(*fmt));
++ fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
++ break;
++ }
++
++ fmt->field = V4L2_FIELD_NONE;
++ fmt->colorspace = V4L2_COLORSPACE_SRGB;
++}
++
++/*
++ * ccp2_enum_mbus_code - Handle pixel format enumeration
++ * @sd : pointer to v4l2 subdev structure
++ * @fh : V4L2 subdev file handle
++ * @code : pointer to v4l2_subdev_mbus_code_enum structure
++ * return -EINVAL or zero on success
++ */
++static int ccp2_enum_mbus_code(struct v4l2_subdev *sd,
++ struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_mbus_code_enum *code)
++{
++ struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
++ struct v4l2_mbus_framefmt *format;
++
++ if (code->pad == CCP2_PAD_SINK) {
++ if (code->index >= ARRAY_SIZE(ccp2_fmts))
++ return -EINVAL;
++
++ code->code = ccp2_fmts[code->index];
++ } else {
++ if (code->index != 0)
++ return -EINVAL;
++
++ format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK,
++ V4L2_SUBDEV_FORMAT_TRY);
++ code->code = format->code;
++ }
++
++ return 0;
++}
++
++static int ccp2_enum_frame_size(struct v4l2_subdev *sd,
++ struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_frame_size_enum *fse)
++{
++ struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
++ struct v4l2_mbus_framefmt format;
++
++ if (fse->index != 0)
++ return -EINVAL;
++
++ format.code = fse->code;
++ format.width = 1;
++ format.height = 1;
++ ccp2_try_format(ccp2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
++ fse->min_width = format.width;
++ fse->min_height = format.height;
++
++ if (format.code != fse->code)
++ return -EINVAL;
++
++ format.code = fse->code;
++ format.width = -1;
++ format.height = -1;
++ ccp2_try_format(ccp2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
++ fse->max_width = format.width;
++ fse->max_height = format.height;
++
++ return 0;
++}
++
++/*
++ * ccp2_get_format - Handle get format by pads subdev method
++ * @sd : pointer to v4l2 subdev structure
++ * @fh : V4L2 subdev file handle
++ * @fmt : pointer to v4l2 subdev format structure
++ * return -EINVAL or zero on sucess
++ */
++static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_format *fmt)
++{
++ struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
++ struct v4l2_mbus_framefmt *format;
++
++ format = __ccp2_get_format(ccp2, fh, fmt->pad, fmt->which);
++ if (format == NULL)
++ return -EINVAL;
++
++ fmt->format = *format;
++ return 0;
++}
++
++/*
++ * ccp2_set_format - Handle set format by pads subdev method
++ * @sd : pointer to v4l2 subdev structure
++ * @fh : V4L2 subdev file handle
++ * @fmt : pointer to v4l2 subdev format structure
++ * returns zero
++ */
++static int ccp2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_format *fmt)
++{
++ struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
++ struct v4l2_mbus_framefmt *format;
++
++ format = __ccp2_get_format(ccp2, fh, fmt->pad, fmt->which);
++ if (format == NULL)
++ return -EINVAL;
++
++ ccp2_try_format(ccp2, fh, fmt->pad, &fmt->format, fmt->which);
++ *format = fmt->format;
++
++ /* Propagate the format from sink to source */
++ if (fmt->pad == CCP2_PAD_SINK) {
++ format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SOURCE,
++ fmt->which);
++ *format = fmt->format;
++ ccp2_try_format(ccp2, fh, CCP2_PAD_SOURCE, format, fmt->which);
++ }
++
++ return 0;
++}
++
++/*
++ * ccp2_init_formats - Initialize formats on all pads
++ * @sd: ISP CCP2 V4L2 subdevice
++ * @fh: V4L2 subdev file handle
++ *
++ * Initialize all pad formats with default values. If fh is not NULL, try
++ * formats are initialized on the file handle. Otherwise active formats are
++ * initialized on the device.
++ */
++static int ccp2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
++{
++ struct v4l2_subdev_format format;
++
++ memset(&format, 0, sizeof(format));
++ format.pad = CCP2_PAD_SINK;
++ format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
++ format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
++ format.format.width = 4096;
++ format.format.height = 4096;
++ ccp2_set_format(sd, fh, &format);
++
++ return 0;
++}
++
++/*
++ * ccp2_s_stream - Enable/Disable streaming on ccp2 subdev
++ * @sd : pointer to v4l2 subdev structure
++ * @enable: 1 == Enable, 0 == Disable
++ * return zero
++ */
++static int ccp2_s_stream(struct v4l2_subdev *sd, int enable)
++{
++ struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
++ struct isp_device *isp = to_isp_device(ccp2);
++ struct device *dev = to_device(ccp2);
++ int ret;
++
++ if (ccp2->state == ISP_PIPELINE_STREAM_STOPPED) {
++ if (enable == ISP_PIPELINE_STREAM_STOPPED)
++ return 0;
++ atomic_set(&ccp2->stopping, 0);
++ ccp2->error = 0;
++ }
++
++ switch (enable) {
++ case ISP_PIPELINE_STREAM_CONTINUOUS:
++ if (ccp2->phy) {
++ ret = omap3isp_csiphy_acquire(ccp2->phy);
++ if (ret < 0)
++ return ret;
++ }
++
++ ccp2_if_configure(ccp2);
++ ccp2_print_status(ccp2);
++
++ /* Enable CSI1/CCP2 interface */
++ ccp2_if_enable(ccp2, 1);
++ break;
++
++ case ISP_PIPELINE_STREAM_SINGLESHOT:
++ if (ccp2->state != ISP_PIPELINE_STREAM_SINGLESHOT) {
++ struct v4l2_mbus_framefmt *format;
++
++ format = &ccp2->formats[CCP2_PAD_SINK];
++
++ ccp2->mem_cfg.hsize_count = format->width;
++ ccp2->mem_cfg.vsize_count = format->height;
++ ccp2->mem_cfg.src_ofst = 0;
++
++ ccp2_mem_configure(ccp2, &ccp2->mem_cfg);
++ omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI1_READ);
++ ccp2_print_status(ccp2);
++ }
++ ccp2_mem_enable(ccp2, 1);
++ break;
++
++ case ISP_PIPELINE_STREAM_STOPPED:
++ if (omap3isp_module_sync_idle(&sd->entity, &ccp2->wait,
++ &ccp2->stopping))
++ dev_dbg(dev, "%s: module stop timeout.\n", sd->name);
++ if (ccp2->input == CCP2_INPUT_MEMORY) {
++ ccp2_mem_enable(ccp2, 0);
++ omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CSI1_READ);
++ } else if (ccp2->input == CCP2_INPUT_SENSOR) {
++ /* Disable CSI1/CCP2 interface */
++ ccp2_if_enable(ccp2, 0);
++ if (ccp2->phy)
++ omap3isp_csiphy_release(ccp2->phy);
++ }
++ break;
++ }
++
++ ccp2->state = enable;
++ return 0;
++}
++
++/* subdev core operations */
++static const struct v4l2_subdev_core_ops ccp2_sd_core_ops = {
++ .queryctrl = v4l2_subdev_queryctrl,
++ .querymenu = v4l2_subdev_querymenu,
++ .g_ctrl = v4l2_subdev_g_ctrl,
++ .s_ctrl = v4l2_subdev_s_ctrl,
++ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
++ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
++ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
++};
++
++/* subdev file operations */
++static const struct v4l2_subdev_file_ops ccp2_sd_file_ops = {
++ .open = ccp2_init_formats,
++};
++
++/* subdev video operations */
++static const struct v4l2_subdev_video_ops ccp2_sd_video_ops = {
++ .s_stream = ccp2_s_stream,
++};
++
++/* subdev pad operations */
++static const struct v4l2_subdev_pad_ops ccp2_sd_pad_ops = {
++ .enum_mbus_code = ccp2_enum_mbus_code,
++ .enum_frame_size = ccp2_enum_frame_size,
++ .get_fmt = ccp2_get_format,
++ .set_fmt = ccp2_set_format,
++};
++
++/* subdev operations */
++static const struct v4l2_subdev_ops ccp2_sd_ops = {
++ .core = &ccp2_sd_core_ops,
++ .file = &ccp2_sd_file_ops,
++ .video = &ccp2_sd_video_ops,
++ .pad = &ccp2_sd_pad_ops,
++};
++
++/* --------------------------------------------------------------------------
++ * ISP ccp2 video device node
++ */
++
++/*
++ * ccp2_video_queue - Queue video buffer.
++ * @video : Pointer to isp video structure
++ * @buffer: Pointer to isp_buffer structure
++ * return -EIO or zero on success
++ */
++static int ccp2_video_queue(struct isp_video *video, struct isp_buffer *buffer)
++{
++ struct isp_ccp2_device *ccp2 = &video->isp->isp_ccp2;
++
++ ccp2_set_inaddr(ccp2, buffer->isp_addr);
++ return 0;
++}
++
++static const struct isp_video_operations ccp2_video_ops = {
++ .queue = ccp2_video_queue,
++};
++
++/* -----------------------------------------------------------------------------
++ * Media entity operations
++ */
++
++/*
++ * ccp2_link_setup - Setup ccp2 connections.
++ * @entity : Pointer to media entity structure
++ * @local : Pointer to local pad array
++ * @remote : Pointer to remote pad array
++ * @flags : Link flags
++ * return -EINVAL on error or zero on success
++ */
++static int ccp2_link_setup(struct media_entity *entity,
++ const struct media_pad *local,
++ const struct media_pad *remote, u32 flags)
++{
++ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
++ struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd);
++
++ switch (local->index | media_entity_type(remote->entity)) {
++ case CCP2_PAD_SINK | MEDIA_ENT_T_DEVNODE:
++ /* read from memory */
++ if (flags & MEDIA_LNK_FL_ENABLED) {
++ if (ccp2->input == CCP2_INPUT_SENSOR)
++ return -EBUSY;
++ ccp2->input = CCP2_INPUT_MEMORY;
++ } else {
++ if (ccp2->input == CCP2_INPUT_MEMORY)
++ ccp2->input = CCP2_INPUT_NONE;
++ }
++ break;
++
++ case CCP2_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
++ /* read from sensor/phy */
++ if (flags & MEDIA_LNK_FL_ENABLED) {
++ if (ccp2->input == CCP2_INPUT_MEMORY)
++ return -EBUSY;
++ ccp2->input = CCP2_INPUT_SENSOR;
++ } else {
++ if (ccp2->input == CCP2_INPUT_SENSOR)
++ ccp2->input = CCP2_INPUT_NONE;
++ } break;
++
++ case CCP2_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
++ /* write to video port/ccdc */
++ if (flags & MEDIA_LNK_FL_ENABLED)
++ ccp2->output = CCP2_OUTPUT_CCDC;
++ else
++ ccp2->output = CCP2_OUTPUT_NONE;
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++/* media operations */
++static const struct media_entity_operations ccp2_media_ops = {
++ .link_setup = ccp2_link_setup,
++};
++
++/*
++ * ccp2_init_entities - Initialize ccp2 subdev and media entity.
++ * @ccp2: Pointer to ISP CCP2 device
++ * return negative error code or zero on success
++ */
++static int ccp2_init_entities(struct isp_ccp2_device *ccp2)
++{
++ struct v4l2_subdev *sd = &ccp2->subdev;
++ struct media_pad *pads = ccp2->pads;
++ struct media_entity *me = &sd->entity;
++ int ret;
++
++ ccp2->input = CCP2_INPUT_NONE;
++ ccp2->output = CCP2_OUTPUT_NONE;
++
++ v4l2_subdev_init(sd, &ccp2_sd_ops);
++ strlcpy(sd->name, "OMAP3 ISP CCP2", sizeof(sd->name));
++ sd->grp_id = 1 << 16; /* group ID for isp subdevs */
++ v4l2_set_subdevdata(sd, ccp2);
++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
++
++ v4l2_ctrl_handler_init(&ccp2->ctrls, 1);
++ sd->ctrl_handler = &ccp2->ctrls;
++
++ pads[CCP2_PAD_SINK].flags = MEDIA_PAD_FL_INPUT;
++ pads[CCP2_PAD_SOURCE].flags = MEDIA_PAD_FL_OUTPUT;
++
++ me->ops = &ccp2_media_ops;
++ ret = media_entity_init(me, CCP2_PADS_NUM, pads, 0);
++ if (ret < 0)
++ return ret;
++
++ ccp2_init_formats(sd, NULL);
++
++ /*
++ * The CCP2 has weird line alignment requirements, possibly caused by
++ * DPCM8 decompression. Line length for data read from memory must be a
++ * multiple of 128 bits (16 bytes) in continuous mode (when no padding
++ * is present at end of lines). Additionally, if padding is used, the
++ * padded line length must be a multiple of 32 bytes. To simplify the
++ * implementation we use a fixed 32 bytes alignment regardless of the
++ * input format and width. If strict 128 bits alignment support is
++ * required ispvideo will need to be made aware of this special dual
++ * alignement requirements.
++ */
++ ccp2->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
++ ccp2->video_in.bpl_alignment = 32;
++ ccp2->video_in.bpl_max = 0xffffffe0;
++ ccp2->video_in.isp = to_isp_device(ccp2);
++ ccp2->video_in.ops = &ccp2_video_ops;
++ ccp2->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 3;
++
++ ret = omap3isp_video_init(&ccp2->video_in, "CCP2");
++ if (ret < 0)
++ return ret;
++
++ /* Connect the video node to the ccp2 subdev. */
++ ret = media_entity_create_link(&ccp2->video_in.video.entity, 0,
++ &ccp2->subdev.entity, CCP2_PAD_SINK, 0);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++/*
++ * omap3isp_ccp2_unregister_entities - Unregister media entities: subdev
++ * @ccp2: Pointer to ISP CCP2 device
++ */
++void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2)
++{
++ media_entity_cleanup(&ccp2->subdev.entity);
++
++ v4l2_device_unregister_subdev(&ccp2->subdev);
++ v4l2_ctrl_handler_free(&ccp2->ctrls);
++ omap3isp_video_unregister(&ccp2->video_in);
++}
++
++/*
++ * omap3isp_ccp2_register_entities - Register the subdev media entity
++ * @ccp2: Pointer to ISP CCP2 device
++ * @vdev: Pointer to v4l device
++ * return negative error code or zero on success
++ */
++
++int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2,
++ struct v4l2_device *vdev)
++{
++ int ret;
++
++ /* Register the subdev and video nodes. */
++ ret = v4l2_device_register_subdev(vdev, &ccp2->subdev);
++ if (ret < 0)
++ goto error;
++
++ ret = omap3isp_video_register(&ccp2->video_in, vdev);
++ if (ret < 0)
++ goto error;
++
++ return 0;
++
++error:
++ omap3isp_ccp2_unregister_entities(ccp2);
++ return ret;
++}
++
++/* -----------------------------------------------------------------------------
++ * ISP ccp2 initialisation and cleanup
++ */
++
++/*
++ * omap3isp_ccp2_cleanup - CCP2 un-initialization
++ * @isp : Pointer to ISP device
++ */
++void omap3isp_ccp2_cleanup(struct isp_device *isp)
++{
++}
++
++/*
++ * omap3isp_ccp2_init - CCP2 initialization.
++ * @isp : Pointer to ISP device
++ * return negative error code or zero on success
++ */
++int omap3isp_ccp2_init(struct isp_device *isp)
++{
++ struct isp_ccp2_device *ccp2 = &isp->isp_ccp2;
++ int ret;
++
++ init_waitqueue_head(&ccp2->wait);
++
++ /* On the OMAP36xx, the CCP2 uses the CSI PHY1 or PHY2, shared with
++ * the CSI2c or CSI2a receivers. The PHY then needs to be explicitly
++ * configured.
++ *
++ * TODO: Don't hardcode the usage of PHY1 (shared with CSI2c).
++ */
++ if (isp->revision == ISP_REVISION_15_0)
++ ccp2->phy = &isp->isp_csiphy1;
++
++ ret = ccp2_init_entities(ccp2);
++ if (ret < 0)
++ goto out;
++
++ ccp2_reset(ccp2);
++out:
++ if (ret)
++ omap3isp_ccp2_cleanup(isp);
++
++ return ret;
++}
+diff --git a/drivers/media/video/isp/ispccp2.h b/drivers/media/video/isp/ispccp2.h
+new file mode 100644
+index 0000000..1c1504e
+--- /dev/null
++++ b/drivers/media/video/isp/ispccp2.h
+@@ -0,0 +1,101 @@
++/*
++ * ispccp2.h
++ *
++ * TI OMAP3 ISP - CCP2 module
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2010 Texas Instruments, Inc.
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#ifndef OMAP3_ISP_CCP2_H
++#define OMAP3_ISP_CCP2_H
++
++#include <linux/videodev2.h>
++#include <media/v4l2-ctrls.h>
++
++struct isp_device;
++struct isp_csiphy;
++
++/* Sink and source ccp2 pads */
++#define CCP2_PAD_SINK 0
++#define CCP2_PAD_SOURCE 1
++#define CCP2_PADS_NUM 2
++
++/* CCP2 input media entity */
++enum ccp2_input_entity {
++ CCP2_INPUT_NONE,
++ CCP2_INPUT_SENSOR,
++ CCP2_INPUT_MEMORY,
++};
++
++/* CCP2 output media entity */
++enum ccp2_output_entity {
++ CCP2_OUTPUT_NONE,
++ CCP2_OUTPUT_CCDC,
++ CCP2_OUTPUT_MEMORY,
++};
++
++
++/* Logical channel configuration */
++struct isp_interface_lcx_config {
++ int crc;
++ u32 data_start;
++ u32 data_size;
++ u32 format;
++};
++
++/* Memory channel configuration */
++struct isp_interface_mem_config {
++ u32 dst_port;
++ u32 vsize_count;
++ u32 hsize_count;
++ u32 src_ofst;
++ u32 dst_ofst;
++};
++
++/* CCP2 device */
++struct isp_ccp2_device {
++ struct v4l2_subdev subdev;
++ struct v4l2_mbus_framefmt formats[CCP2_PADS_NUM];
++ struct media_pad pads[CCP2_PADS_NUM];
++
++ struct v4l2_ctrl_handler ctrls;
++
++ enum ccp2_input_entity input;
++ enum ccp2_output_entity output;
++ struct isp_interface_lcx_config if_cfg;
++ struct isp_interface_mem_config mem_cfg;
++ struct isp_video video_in;
++ struct isp_csiphy *phy;
++ unsigned int error;
++ enum isp_pipeline_stream_state state;
++ wait_queue_head_t wait;
++ atomic_t stopping;
++};
++
++/* Function declarations */
++int omap3isp_ccp2_init(struct isp_device *isp);
++void omap3isp_ccp2_cleanup(struct isp_device *isp);
++int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2,
++ struct v4l2_device *vdev);
++void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2);
++int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2);
++
++#endif /* OMAP3_ISP_CCP2_H */
+diff --git a/drivers/media/video/isp/ispcsi2.c b/drivers/media/video/isp/ispcsi2.c
+new file mode 100644
+index 0000000..30ced95
+--- /dev/null
++++ b/drivers/media/video/isp/ispcsi2.c
+@@ -0,0 +1,1332 @@
++/*
++ * ispcsi2.c
++ *
++ * TI OMAP3 ISP - CSI2 module
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc.
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++#include <linux/delay.h>
++#include <media/v4l2-common.h>
++#include <linux/v4l2-mediabus.h>
++#include <linux/mm.h>
++
++#include "isp.h"
++#include "ispreg.h"
++#include "ispcsi2.h"
++
++/*
++ * csi2_if_enable - Enable CSI2 Receiver interface.
++ * @enable: enable flag
++ *
++ */
++static void csi2_if_enable(struct isp_device *isp,
++ struct isp_csi2_device *csi2, u8 enable)
++{
++ struct isp_csi2_ctrl_cfg *currctrl = &csi2->ctrl;
++
++ isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_CTRL, ISPCSI2_CTRL_IF_EN,
++ enable ? ISPCSI2_CTRL_IF_EN : 0);
++
++ currctrl->if_enable = enable;
++}
++
++/*
++ * csi2_recv_config - CSI2 receiver module configuration.
++ * @currctrl: isp_csi2_ctrl_cfg structure
++ *
++ */
++static void csi2_recv_config(struct isp_device *isp,
++ struct isp_csi2_device *csi2,
++ struct isp_csi2_ctrl_cfg *currctrl)
++{
++ u32 reg;
++
++ reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTRL);
++
++ if (currctrl->frame_mode)
++ reg |= ISPCSI2_CTRL_FRAME;
++ else
++ reg &= ~ISPCSI2_CTRL_FRAME;
++
++ if (currctrl->vp_clk_enable)
++ reg |= ISPCSI2_CTRL_VP_CLK_EN;
++ else
++ reg &= ~ISPCSI2_CTRL_VP_CLK_EN;
++
++ if (currctrl->vp_only_enable)
++ reg |= ISPCSI2_CTRL_VP_ONLY_EN;
++ else
++ reg &= ~ISPCSI2_CTRL_VP_ONLY_EN;
++
++ reg &= ~ISPCSI2_CTRL_VP_OUT_CTRL_MASK;
++ reg |= currctrl->vp_out_ctrl << ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT;
++
++ if (currctrl->ecc_enable)
++ reg |= ISPCSI2_CTRL_ECC_EN;
++ else
++ reg &= ~ISPCSI2_CTRL_ECC_EN;
++
++ isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTRL);
++}
++
++static const unsigned int csi2_input_fmts[] = {
++ V4L2_MBUS_FMT_SGRBG10_1X10,
++ V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
++ V4L2_MBUS_FMT_SRGGB10_1X10,
++ V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8,
++ V4L2_MBUS_FMT_SBGGR10_1X10,
++ V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8,
++ V4L2_MBUS_FMT_SGBRG10_1X10,
++ V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8,
++};
++
++/* To set the format on the CSI2 requires a mapping function that takes
++ * the following inputs:
++ * - 2 different formats (at this time)
++ * - 2 destinations (mem, vp+mem) (vp only handled separately)
++ * - 2 decompression options (on, off)
++ * - 2 isp revisions (certain format must be handled differently on OMAP3630)
++ * Output should be CSI2 frame format code
++ * Array indices as follows: [format][dest][decompr][is_3630]
++ * Not all combinations are valid. 0 means invalid.
++ */
++static const u16 __csi2_fmt_map[2][2][2][2] = {
++ /* RAW10 formats */
++ {
++ /* Output to memory */
++ {
++ /* No DPCM decompression */
++ { CSI2_PIX_FMT_RAW10_EXP16, CSI2_PIX_FMT_RAW10_EXP16 },
++ /* DPCM decompression */
++ { 0, 0 },
++ },
++ /* Output to both */
++ {
++ /* No DPCM decompression */
++ { CSI2_PIX_FMT_RAW10_EXP16_VP,
++ CSI2_PIX_FMT_RAW10_EXP16_VP },
++ /* DPCM decompression */
++ { 0, 0 },
++ },
++ },
++ /* RAW10 DPCM8 formats */
++ {
++ /* Output to memory */
++ {
++ /* No DPCM decompression */
++ { CSI2_PIX_FMT_RAW8, CSI2_USERDEF_8BIT_DATA1 },
++ /* DPCM decompression */
++ { CSI2_PIX_FMT_RAW8_DPCM10_EXP16,
++ CSI2_USERDEF_8BIT_DATA1_DPCM10 },
++ },
++ /* Output to both */
++ {
++ /* No DPCM decompression */
++ { CSI2_PIX_FMT_RAW8_VP,
++ CSI2_PIX_FMT_RAW8_VP },
++ /* DPCM decompression */
++ { CSI2_PIX_FMT_RAW8_DPCM10_VP,
++ CSI2_USERDEF_8BIT_DATA1_DPCM10_VP },
++ },
++ },
++};
++
++/*
++ * csi2_ctx_map_format - Map CSI2 sink media bus format to CSI2 format ID
++ * @csi2: ISP CSI2 device
++ *
++ * Returns CSI2 physical format id
++ */
++static u16 csi2_ctx_map_format(struct isp_csi2_device *csi2)
++{
++ const struct v4l2_mbus_framefmt *fmt = &csi2->formats[CSI2_PAD_SINK];
++ int fmtidx, destidx, is_3630;
++
++ switch (fmt->code) {
++ case V4L2_MBUS_FMT_SGRBG10_1X10:
++ case V4L2_MBUS_FMT_SRGGB10_1X10:
++ case V4L2_MBUS_FMT_SBGGR10_1X10:
++ case V4L2_MBUS_FMT_SGBRG10_1X10:
++ fmtidx = 0;
++ break;
++ case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
++ case V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8:
++ case V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8:
++ case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8:
++ fmtidx = 1;
++ break;
++ default:
++ WARN(1, KERN_ERR "CSI2: pixel format %08x unsupported!\n",
++ fmt->code);
++ return 0;
++ }
++
++ if (!(csi2->output & CSI2_OUTPUT_CCDC) &&
++ !(csi2->output & CSI2_OUTPUT_MEMORY)) {
++ /* Neither output enabled is a valid combination */
++ return CSI2_PIX_FMT_OTHERS;
++ }
++
++ /* If we need to skip frames at the beginning of the stream disable the
++ * video port to avoid sending the skipped frames to the CCDC.
++ */
++ destidx = csi2->frame_skip ? 0 : !!(csi2->output & CSI2_OUTPUT_CCDC);
++ is_3630 = csi2->isp->revision == ISP_REVISION_15_0;
++
++ return __csi2_fmt_map[fmtidx][destidx][csi2->dpcm_decompress][is_3630];
++}
++
++/*
++ * csi2_set_outaddr - Set memory address to save output image
++ * @csi2: Pointer to ISP CSI2a device.
++ * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary.
++ *
++ * Sets the memory address where the output will be saved.
++ *
++ * Returns 0 if successful, or -EINVAL if the address is not in the 32 byte
++ * boundary.
++ */
++static void csi2_set_outaddr(struct isp_csi2_device *csi2, u32 addr)
++{
++ struct isp_device *isp = csi2->isp;
++ struct isp_csi2_ctx_cfg *ctx = &csi2->contexts[0];
++
++ ctx->ping_addr = ctx->pong_addr = addr;
++ isp_reg_writel(isp, ctx->ping_addr,
++ csi2->regs1, ISPCSI2_CTX_DAT_PING_ADDR(ctx->ctxnum));
++ isp_reg_writel(isp, ctx->pong_addr,
++ csi2->regs1, ISPCSI2_CTX_DAT_PONG_ADDR(ctx->ctxnum));
++}
++
++/*
++ * is_usr_def_mapping - Checks whether USER_DEF_MAPPING should
++ * be enabled by CSI2.
++ * @format_id: mapped format id
++ *
++ */
++static inline int is_usr_def_mapping(u32 format_id)
++{
++ return (format_id & 0x40) ? 1 : 0;
++}
++
++/*
++ * csi2_ctx_enable - Enable specified CSI2 context
++ * @ctxnum: Context number, valid between 0 and 7 values.
++ * @enable: enable
++ *
++ */
++static void csi2_ctx_enable(struct isp_device *isp,
++ struct isp_csi2_device *csi2, u8 ctxnum, u8 enable)
++{
++ struct isp_csi2_ctx_cfg *ctx = &csi2->contexts[ctxnum];
++ unsigned int skip = 0;
++ u32 reg;
++
++ reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL1(ctxnum));
++
++ if (enable) {
++ if (csi2->frame_skip)
++ skip = csi2->frame_skip;
++ else if (csi2->output & CSI2_OUTPUT_MEMORY)
++ skip = 1;
++
++ reg &= ~ISPCSI2_CTX_CTRL1_COUNT_MASK;
++ reg |= ISPCSI2_CTX_CTRL1_COUNT_UNLOCK
++ | (skip << ISPCSI2_CTX_CTRL1_COUNT_SHIFT)
++ | ISPCSI2_CTX_CTRL1_CTX_EN;
++ } else {
++ reg &= ~ISPCSI2_CTX_CTRL1_CTX_EN;
++ }
++
++ isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL1(ctxnum));
++ ctx->enabled = enable;
++}
++
++/*
++ * csi2_ctx_config - CSI2 context configuration.
++ * @ctx: context configuration
++ *
++ */
++static void csi2_ctx_config(struct isp_device *isp,
++ struct isp_csi2_device *csi2,
++ struct isp_csi2_ctx_cfg *ctx)
++{
++ u32 reg;
++
++ /* Set up CSI2_CTx_CTRL1 */
++ reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL1(ctx->ctxnum));
++
++ if (ctx->eof_enabled)
++ reg |= ISPCSI2_CTX_CTRL1_EOF_EN;
++ else
++ reg &= ~ISPCSI2_CTX_CTRL1_EOF_EN;
++
++ if (ctx->eol_enabled)
++ reg |= ISPCSI2_CTX_CTRL1_EOL_EN;
++ else
++ reg &= ~ISPCSI2_CTX_CTRL1_EOL_EN;
++
++ if (ctx->checksum_enabled)
++ reg |= ISPCSI2_CTX_CTRL1_CS_EN;
++ else
++ reg &= ~ISPCSI2_CTX_CTRL1_CS_EN;
++
++ isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL1(ctx->ctxnum));
++
++ /* Set up CSI2_CTx_CTRL2 */
++ reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL2(ctx->ctxnum));
++
++ reg &= ~(ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK);
++ reg |= ctx->virtual_id << ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT;
++
++ reg &= ~(ISPCSI2_CTX_CTRL2_FORMAT_MASK);
++ reg |= ctx->format_id << ISPCSI2_CTX_CTRL2_FORMAT_SHIFT;
++
++ if (ctx->dpcm_decompress) {
++ if (ctx->dpcm_predictor)
++ reg |= ISPCSI2_CTX_CTRL2_DPCM_PRED;
++ else
++ reg &= ~ISPCSI2_CTX_CTRL2_DPCM_PRED;
++ }
++
++ if (is_usr_def_mapping(ctx->format_id)) {
++ reg &= ~ISPCSI2_CTX_CTRL2_USER_DEF_MAP_MASK;
++ reg |= 2 << ISPCSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT;
++ }
++
++ isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL2(ctx->ctxnum));
++
++ /* Set up CSI2_CTx_CTRL3 */
++ reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL3(ctx->ctxnum));
++ reg &= ~(ISPCSI2_CTX_CTRL3_ALPHA_MASK);
++ reg |= (ctx->alpha << ISPCSI2_CTX_CTRL3_ALPHA_SHIFT);
++
++ isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL3(ctx->ctxnum));
++
++ /* Set up CSI2_CTx_DAT_OFST */
++ reg = isp_reg_readl(isp, csi2->regs1,
++ ISPCSI2_CTX_DAT_OFST(ctx->ctxnum));
++ reg &= ~ISPCSI2_CTX_DAT_OFST_OFST_MASK;
++ reg |= ctx->data_offset << ISPCSI2_CTX_DAT_OFST_OFST_SHIFT;
++ isp_reg_writel(isp, reg, csi2->regs1,
++ ISPCSI2_CTX_DAT_OFST(ctx->ctxnum));
++
++ isp_reg_writel(isp, ctx->ping_addr,
++ csi2->regs1, ISPCSI2_CTX_DAT_PING_ADDR(ctx->ctxnum));
++
++ isp_reg_writel(isp, ctx->pong_addr,
++ csi2->regs1, ISPCSI2_CTX_DAT_PONG_ADDR(ctx->ctxnum));
++}
++
++/*
++ * csi2_timing_config - CSI2 timing configuration.
++ * @timing: csi2_timing_cfg structure
++ */
++static void csi2_timing_config(struct isp_device *isp,
++ struct isp_csi2_device *csi2,
++ struct isp_csi2_timing_cfg *timing)
++{
++ u32 reg;
++
++ reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_TIMING);
++
++ if (timing->force_rx_mode)
++ reg |= ISPCSI2_TIMING_FORCE_RX_MODE_IO(timing->ionum);
++ else
++ reg &= ~ISPCSI2_TIMING_FORCE_RX_MODE_IO(timing->ionum);
++
++ if (timing->stop_state_16x)
++ reg |= ISPCSI2_TIMING_STOP_STATE_X16_IO(timing->ionum);
++ else
++ reg &= ~ISPCSI2_TIMING_STOP_STATE_X16_IO(timing->ionum);
++
++ if (timing->stop_state_4x)
++ reg |= ISPCSI2_TIMING_STOP_STATE_X4_IO(timing->ionum);
++ else
++ reg &= ~ISPCSI2_TIMING_STOP_STATE_X4_IO(timing->ionum);
++
++ reg &= ~ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(timing->ionum);
++ reg |= timing->stop_state_counter <<
++ ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(timing->ionum);
++
++ isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_TIMING);
++}
++
++/*
++ * csi2_irq_ctx_set - Enables CSI2 Context IRQs.
++ * @enable: Enable/disable CSI2 Context interrupts
++ */
++static void csi2_irq_ctx_set(struct isp_device *isp,
++ struct isp_csi2_device *csi2, int enable)
++{
++ u32 reg = ISPCSI2_CTX_IRQSTATUS_FE_IRQ;
++ int i;
++
++ if (csi2->use_fs_irq)
++ reg |= ISPCSI2_CTX_IRQSTATUS_FS_IRQ;
++
++ for (i = 0; i < 8; i++) {
++ isp_reg_writel(isp, reg, csi2->regs1,
++ ISPCSI2_CTX_IRQSTATUS(i));
++ if (enable)
++ isp_reg_set(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i),
++ reg);
++ else
++ isp_reg_clr(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i),
++ reg);
++ }
++}
++
++/*
++ * csi2_irq_complexio1_set - Enables CSI2 ComplexIO IRQs.
++ * @enable: Enable/disable CSI2 ComplexIO #1 interrupts
++ */
++static void csi2_irq_complexio1_set(struct isp_device *isp,
++ struct isp_csi2_device *csi2, int enable)
++{
++ u32 reg;
++ reg = ISPCSI2_PHY_IRQENABLE_STATEALLULPMEXIT |
++ ISPCSI2_PHY_IRQENABLE_STATEALLULPMENTER |
++ ISPCSI2_PHY_IRQENABLE_STATEULPM5 |
++ ISPCSI2_PHY_IRQENABLE_ERRCONTROL5 |
++ ISPCSI2_PHY_IRQENABLE_ERRESC5 |
++ ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS5 |
++ ISPCSI2_PHY_IRQENABLE_ERRSOTHS5 |
++ ISPCSI2_PHY_IRQENABLE_STATEULPM4 |
++ ISPCSI2_PHY_IRQENABLE_ERRCONTROL4 |
++ ISPCSI2_PHY_IRQENABLE_ERRESC4 |
++ ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS4 |
++ ISPCSI2_PHY_IRQENABLE_ERRSOTHS4 |
++ ISPCSI2_PHY_IRQENABLE_STATEULPM3 |
++ ISPCSI2_PHY_IRQENABLE_ERRCONTROL3 |
++ ISPCSI2_PHY_IRQENABLE_ERRESC3 |
++ ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS3 |
++ ISPCSI2_PHY_IRQENABLE_ERRSOTHS3 |
++ ISPCSI2_PHY_IRQENABLE_STATEULPM2 |
++ ISPCSI2_PHY_IRQENABLE_ERRCONTROL2 |
++ ISPCSI2_PHY_IRQENABLE_ERRESC2 |
++ ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS2 |
++ ISPCSI2_PHY_IRQENABLE_ERRSOTHS2 |
++ ISPCSI2_PHY_IRQENABLE_STATEULPM1 |
++ ISPCSI2_PHY_IRQENABLE_ERRCONTROL1 |
++ ISPCSI2_PHY_IRQENABLE_ERRESC1 |
++ ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS1 |
++ ISPCSI2_PHY_IRQENABLE_ERRSOTHS1;
++ isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_PHY_IRQSTATUS);
++ if (enable)
++ reg |= isp_reg_readl(isp, csi2->regs1, ISPCSI2_PHY_IRQENABLE);
++ else
++ reg = 0;
++ isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_PHY_IRQENABLE);
++}
++
++/*
++ * csi2_irq_status_set - Enables CSI2 Status IRQs.
++ * @enable: Enable/disable CSI2 Status interrupts
++ */
++static void csi2_irq_status_set(struct isp_device *isp,
++ struct isp_csi2_device *csi2, int enable)
++{
++ u32 reg;
++ reg = ISPCSI2_IRQSTATUS_OCP_ERR_IRQ |
++ ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ |
++ ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ |
++ ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ |
++ ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ |
++ ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ |
++ ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ |
++ ISPCSI2_IRQSTATUS_CONTEXT(0);
++ isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_IRQSTATUS);
++ if (enable)
++ reg |= isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQENABLE);
++ else
++ reg = 0;
++
++ isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_IRQENABLE);
++}
++
++/*
++ * omap3isp_csi2_reset - Resets the CSI2 module.
++ *
++ * Must be called with the phy lock held.
++ *
++ * Returns 0 if successful, or -EBUSY if power command didn't respond.
++ */
++int omap3isp_csi2_reset(struct isp_csi2_device *csi2)
++{
++ struct isp_device *isp = csi2->isp;
++ u8 soft_reset_retries = 0;
++ u32 reg;
++ int i;
++
++ if (!csi2->available)
++ return -ENODEV;
++
++ if (csi2->phy->phy_in_use)
++ return -EBUSY;
++
++ isp_reg_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG,
++ ISPCSI2_SYSCONFIG_SOFT_RESET);
++
++ do {
++ reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_SYSSTATUS) &
++ ISPCSI2_SYSSTATUS_RESET_DONE;
++ if (reg == ISPCSI2_SYSSTATUS_RESET_DONE)
++ break;
++ soft_reset_retries++;
++ if (soft_reset_retries < 5)
++ udelay(100);
++ } while (soft_reset_retries < 5);
++
++ if (soft_reset_retries == 5) {
++ printk(KERN_ERR "CSI2: Soft reset try count exceeded!\n");
++ return -EBUSY;
++ }
++
++ if (isp->revision == ISP_REVISION_15_0)
++ isp_reg_set(isp, csi2->regs1, ISPCSI2_PHY_CFG,
++ ISPCSI2_PHY_CFG_RESET_CTRL);
++
++ i = 100;
++ do {
++ reg = isp_reg_readl(isp, csi2->phy->phy_regs, ISPCSIPHY_REG1)
++ & ISPCSIPHY_REG1_RESET_DONE_CTRLCLK;
++ if (reg == ISPCSIPHY_REG1_RESET_DONE_CTRLCLK)
++ break;
++ udelay(100);
++ } while (--i > 0);
++
++ if (i == 0) {
++ printk(KERN_ERR
++ "CSI2: Reset for CSI2_96M_FCLK domain Failed!\n");
++ return -EBUSY;
++ }
++
++ if (isp->autoidle)
++ isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG,
++ ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK |
++ ISPCSI2_SYSCONFIG_AUTO_IDLE,
++ ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SMART |
++ ((isp->revision == ISP_REVISION_15_0) ?
++ ISPCSI2_SYSCONFIG_AUTO_IDLE : 0));
++ else
++ isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG,
++ ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK |
++ ISPCSI2_SYSCONFIG_AUTO_IDLE,
++ ISPCSI2_SYSCONFIG_MSTANDBY_MODE_NO);
++
++ return 0;
++}
++
++static int csi2_configure(struct isp_csi2_device *csi2)
++{
++ const struct isp_v4l2_subdevs_group *pdata;
++ struct isp_device *isp = csi2->isp;
++ struct isp_csi2_timing_cfg *timing = &csi2->timing[0];
++ struct v4l2_subdev *sensor;
++ struct media_pad *pad;
++
++ /*
++ * CSI2 fields that can be updated while the context has
++ * been enabled or the interface has been enabled are not
++ * updated dynamically currently. So we do not allow to
++ * reconfigure if either has been enabled
++ */
++ if (csi2->contexts[0].enabled || csi2->ctrl.if_enable)
++ return -EBUSY;
++
++ pad = media_entity_remote_source(&csi2->pads[CSI2_PAD_SINK]);
++ sensor = media_entity_to_v4l2_subdev(pad->entity);
++ pdata = sensor->host_priv;
++
++ csi2->frame_skip = 0;
++ v4l2_subdev_call(sensor, sensor, g_skip_frames, &csi2->frame_skip);
++
++ csi2->ctrl.vp_out_ctrl = pdata->bus.csi2.vpclk_div;
++ csi2->ctrl.frame_mode = ISP_CSI2_FRAME_IMMEDIATE;
++ csi2->ctrl.ecc_enable = pdata->bus.csi2.crc;
++
++ timing->ionum = 1;
++ timing->force_rx_mode = 1;
++ timing->stop_state_16x = 1;
++ timing->stop_state_4x = 1;
++ timing->stop_state_counter = 0x1FF;
++
++ /*
++ * The CSI2 receiver can't do any format conversion except DPCM
++ * decompression, so every set_format call configures both pads
++ * and enables DPCM decompression as a special case:
++ */
++ if (csi2->formats[CSI2_PAD_SINK].code !=
++ csi2->formats[CSI2_PAD_SOURCE].code)
++ csi2->dpcm_decompress = true;
++ else
++ csi2->dpcm_decompress = false;
++
++ csi2->contexts[0].format_id = csi2_ctx_map_format(csi2);
++
++ if (csi2->video_out.bpl_padding == 0)
++ csi2->contexts[0].data_offset = 0;
++ else
++ csi2->contexts[0].data_offset = csi2->video_out.bpl_value;
++
++ /*
++ * Enable end of frame and end of line signals generation for
++ * context 0. These signals are generated from CSI2 receiver to
++ * qualify the last pixel of a frame and the last pixel of a line.
++ * Without enabling the signals CSI2 receiver writes data to memory
++ * beyond buffer size and/or data line offset is not handled correctly.
++ */
++ csi2->contexts[0].eof_enabled = 1;
++ csi2->contexts[0].eol_enabled = 1;
++
++ csi2_irq_complexio1_set(isp, csi2, 1);
++ csi2_irq_ctx_set(isp, csi2, 1);
++ csi2_irq_status_set(isp, csi2, 1);
++
++ /* Set configuration (timings, format and links) */
++ csi2_timing_config(isp, csi2, timing);
++ csi2_recv_config(isp, csi2, &csi2->ctrl);
++ csi2_ctx_config(isp, csi2, &csi2->contexts[0]);
++
++ return 0;
++}
++
++/*
++ * csi2_print_status - Prints CSI2 debug information.
++ */
++#define CSI2_PRINT_REGISTER(isp, regs, name)\
++ dev_dbg(isp->dev, "###CSI2 " #name "=0x%08x\n", \
++ isp_reg_readl(isp, regs, ISPCSI2_##name))
++
++static void csi2_print_status(struct isp_csi2_device *csi2)
++{
++ struct isp_device *isp = csi2->isp;
++
++ if (!csi2->available)
++ return;
++
++ dev_dbg(isp->dev, "-------------CSI2 Register dump-------------\n");
++
++ CSI2_PRINT_REGISTER(isp, csi2->regs1, SYSCONFIG);
++ CSI2_PRINT_REGISTER(isp, csi2->regs1, SYSSTATUS);
++ CSI2_PRINT_REGISTER(isp, csi2->regs1, IRQENABLE);
++ CSI2_PRINT_REGISTER(isp, csi2->regs1, IRQSTATUS);
++ CSI2_PRINT_REGISTER(isp, csi2->regs1, CTRL);
++ CSI2_PRINT_REGISTER(isp, csi2->regs1, DBG_H);
++ CSI2_PRINT_REGISTER(isp, csi2->regs1, GNQ);
++ CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_CFG);
++ CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_IRQSTATUS);
++ CSI2_PRINT_REGISTER(isp, csi2->regs1, SHORT_PACKET);
++ CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_IRQENABLE);
++ CSI2_PRINT_REGISTER(isp, csi2->regs1, DBG_P);
++ CSI2_PRINT_REGISTER(isp, csi2->regs1, TIMING);
++ CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL1(0));
++ CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL2(0));
++ CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_OFST(0));
++ CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_PING_ADDR(0));
++ CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_PONG_ADDR(0));
++ CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_IRQENABLE(0));
++ CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_IRQSTATUS(0));
++ CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL3(0));
++
++ dev_dbg(isp->dev, "--------------------------------------------\n");
++}
++
++/* -----------------------------------------------------------------------------
++ * Interrupt handling
++ */
++
++/*
++ * csi2_isr_buffer - Does buffer handling at end-of-frame
++ * when writing to memory.
++ */
++static void csi2_isr_buffer(struct isp_csi2_device *csi2)
++{
++ struct isp_device *isp = csi2->isp;
++ struct isp_buffer *buffer;
++
++ csi2_ctx_enable(isp, csi2, 0, 0);
++
++ buffer = omap3isp_video_buffer_next(&csi2->video_out, 0);
++
++ /*
++ * Let video queue operation restart engine if there is an underrun
++ * condition.
++ */
++ if (buffer == NULL)
++ return;
++
++ csi2_set_outaddr(csi2, buffer->isp_addr);
++ csi2_ctx_enable(isp, csi2, 0, 1);
++}
++
++static void csi2_isr_ctx(struct isp_csi2_device *csi2,
++ struct isp_csi2_ctx_cfg *ctx)
++{
++ struct isp_device *isp = csi2->isp;
++ unsigned int n = ctx->ctxnum;
++ u32 status;
++
++ status = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n));
++ isp_reg_writel(isp, status, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n));
++
++ /* Propagate frame number */
++ if (status & ISPCSI2_CTX_IRQSTATUS_FS_IRQ) {
++ struct isp_pipeline *pipe =
++ to_isp_pipeline(&csi2->subdev.entity);
++ if (pipe->do_propagation)
++ atomic_inc(&pipe->frame_number);
++ }
++
++ if (!(status & ISPCSI2_CTX_IRQSTATUS_FE_IRQ))
++ return;
++
++ /* Skip interrupts until we reach the frame skip count. The CSI2 will be
++ * automatically disabled, as the frame skip count has been programmed
++ * in the CSI2_CTx_CTRL1::COUNT field, so reenable it.
++ *
++ * It would have been nice to rely on the FRAME_NUMBER interrupt instead
++ * but it turned out that the interrupt is only generated when the CSI2
++ * writes to memory (the CSI2_CTx_CTRL1::COUNT field is decreased
++ * correctly and reaches 0 when data is forwarded to the video port only
++ * but no interrupt arrives). Maybe a CSI2 hardware bug.
++ */
++ if (csi2->frame_skip) {
++ csi2->frame_skip--;
++ if (csi2->frame_skip == 0) {
++ ctx->format_id = csi2_ctx_map_format(csi2);
++ csi2_ctx_config(isp, csi2, ctx);
++ csi2_ctx_enable(isp, csi2, n, 1);
++ }
++ return;
++ }
++
++ if (csi2->output & CSI2_OUTPUT_MEMORY)
++ csi2_isr_buffer(csi2);
++}
++
++/*
++ * omap3isp_csi2_isr - CSI2 interrupt handling.
++ *
++ * Return -EIO on Transmission error
++ */
++int omap3isp_csi2_isr(struct isp_csi2_device *csi2)
++{
++ u32 csi2_irqstatus, cpxio1_irqstatus;
++ struct isp_device *isp = csi2->isp;
++ int retval = 0;
++
++ if (!csi2->available)
++ return -ENODEV;
++
++ csi2_irqstatus = isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQSTATUS);
++ isp_reg_writel(isp, csi2_irqstatus, csi2->regs1, ISPCSI2_IRQSTATUS);
++
++ /* Failure Cases */
++ if (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ) {
++ cpxio1_irqstatus = isp_reg_readl(isp, csi2->regs1,
++ ISPCSI2_PHY_IRQSTATUS);
++ isp_reg_writel(isp, cpxio1_irqstatus,
++ csi2->regs1, ISPCSI2_PHY_IRQSTATUS);
++ dev_dbg(isp->dev, "CSI2: ComplexIO Error IRQ "
++ "%x\n", cpxio1_irqstatus);
++ retval = -EIO;
++ }
++
++ if (csi2_irqstatus & (ISPCSI2_IRQSTATUS_OCP_ERR_IRQ |
++ ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ |
++ ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ |
++ ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ |
++ ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ)) {
++ dev_dbg(isp->dev, "CSI2 Err:"
++ " OCP:%d,"
++ " Short_pack:%d,"
++ " ECC:%d,"
++ " CPXIO2:%d,"
++ " FIFO_OVF:%d,"
++ "\n",
++ (csi2_irqstatus &
++ ISPCSI2_IRQSTATUS_OCP_ERR_IRQ) ? 1 : 0,
++ (csi2_irqstatus &
++ ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ) ? 1 : 0,
++ (csi2_irqstatus &
++ ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ) ? 1 : 0,
++ (csi2_irqstatus &
++ ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ) ? 1 : 0,
++ (csi2_irqstatus &
++ ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ) ? 1 : 0);
++ retval = -EIO;
++ }
++
++ if (omap3isp_module_sync_is_stopping(&csi2->wait, &csi2->stopping))
++ return 0;
++
++ /* Successful cases */
++ if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0))
++ csi2_isr_ctx(csi2, &csi2->contexts[0]);
++
++ if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ)
++ dev_dbg(isp->dev, "CSI2: ECC correction done\n");
++
++ return retval;
++}
++
++/* -----------------------------------------------------------------------------
++ * ISP video operations
++ */
++
++/*
++ * csi2_queue - Queues the first buffer when using memory output
++ * @video: The video node
++ * @buffer: buffer to queue
++ */
++static int csi2_queue(struct isp_video *video, struct isp_buffer *buffer)
++{
++ struct isp_device *isp = video->isp;
++ struct isp_csi2_device *csi2 = &isp->isp_csi2a;
++
++ csi2_set_outaddr(csi2, buffer->isp_addr);
++
++ /*
++ * If streaming was enabled before there was a buffer queued
++ * or underrun happened in the ISR, the hardware was not enabled
++ * and DMA queue flag ISP_VIDEO_DMAQUEUE_UNDERRUN is still set.
++ * Enable it now.
++ */
++ if (csi2->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_UNDERRUN) {
++ /* Enable / disable context 0 and IRQs */
++ csi2_if_enable(isp, csi2, 1);
++ csi2_ctx_enable(isp, csi2, 0, 1);
++ isp_video_dmaqueue_flags_clr(&csi2->video_out);
++ }
++
++ return 0;
++}
++
++static const struct isp_video_operations csi2_ispvideo_ops = {
++ .queue = csi2_queue,
++};
++
++/* -----------------------------------------------------------------------------
++ * V4L2 subdev operations
++ */
++
++static struct v4l2_mbus_framefmt *
++__csi2_get_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh,
++ unsigned int pad, enum v4l2_subdev_format_whence which)
++{
++ if (which == V4L2_SUBDEV_FORMAT_TRY)
++ return v4l2_subdev_get_try_format(fh, pad);
++ else
++ return &csi2->formats[pad];
++}
++
++static void
++csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh,
++ unsigned int pad, struct v4l2_mbus_framefmt *fmt,
++ enum v4l2_subdev_format_whence which)
++{
++ enum v4l2_mbus_pixelcode pixelcode;
++ struct v4l2_mbus_framefmt *format;
++ const struct isp_format_info *info;
++ unsigned int i;
++
++ switch (pad) {
++ case CSI2_PAD_SINK:
++ /* Clamp the width and height to valid range (1-8191). */
++ for (i = 0; i < ARRAY_SIZE(csi2_input_fmts); i++) {
++ if (fmt->code == csi2_input_fmts[i])
++ break;
++ }
++
++ /* If not found, use SGRBG10 as default */
++ if (i >= ARRAY_SIZE(csi2_input_fmts))
++ fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
++
++ fmt->width = clamp_t(u32, fmt->width, 1, 8191);
++ fmt->height = clamp_t(u32, fmt->height, 1, 8191);
++ break;
++
++ case CSI2_PAD_SOURCE:
++ /* Source format same as sink format, except for DPCM
++ * compression.
++ */
++ pixelcode = fmt->code;
++ format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, which);
++ memcpy(fmt, format, sizeof(*fmt));
++
++ /*
++ * Only Allow DPCM decompression, and check that the
++ * pattern is preserved
++ */
++ info = omap3isp_video_format_info(fmt->code);
++ if (info->uncompressed == pixelcode)
++ fmt->code = pixelcode;
++ break;
++ }
++
++ /* RGB, non-interlaced */
++ fmt->colorspace = V4L2_COLORSPACE_SRGB;
++ fmt->field = V4L2_FIELD_NONE;
++}
++
++/*
++ * csi2_enum_mbus_code - Handle pixel format enumeration
++ * @sd : pointer to v4l2 subdev structure
++ * @fh : V4L2 subdev file handle
++ * @code : pointer to v4l2_subdev_mbus_code_enum structure
++ * return -EINVAL or zero on success
++ */
++static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
++ struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_mbus_code_enum *code)
++{
++ struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
++ struct v4l2_mbus_framefmt *format;
++ const struct isp_format_info *info;
++
++ if (code->pad == CSI2_PAD_SINK) {
++ if (code->index >= ARRAY_SIZE(csi2_input_fmts))
++ return -EINVAL;
++
++ code->code = csi2_input_fmts[code->index];
++ } else {
++ format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK,
++ V4L2_SUBDEV_FORMAT_TRY);
++ switch (code->index) {
++ case 0:
++ /* Passthrough sink pad code */
++ code->code = format->code;
++ break;
++ case 1:
++ /* Uncompressed code */
++ info = omap3isp_video_format_info(format->code);
++ if (info->uncompressed == format->code)
++ return -EINVAL;
++
++ code->code = info->uncompressed;
++ break;
++ default:
++ return -EINVAL;
++ }
++ }
++
++ return 0;
++}
++
++static int csi2_enum_frame_size(struct v4l2_subdev *sd,
++ struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_frame_size_enum *fse)
++{
++ struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
++ struct v4l2_mbus_framefmt format;
++
++ if (fse->index != 0)
++ return -EINVAL;
++
++ format.code = fse->code;
++ format.width = 1;
++ format.height = 1;
++ csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
++ fse->min_width = format.width;
++ fse->min_height = format.height;
++
++ if (format.code != fse->code)
++ return -EINVAL;
++
++ format.code = fse->code;
++ format.width = -1;
++ format.height = -1;
++ csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
++ fse->max_width = format.width;
++ fse->max_height = format.height;
++
++ return 0;
++}
++
++/*
++ * csi2_get_format - Handle get format by pads subdev method
++ * @sd : pointer to v4l2 subdev structure
++ * @fh : V4L2 subdev file handle
++ * @fmt: pointer to v4l2 subdev format structure
++ * return -EINVAL or zero on sucess
++ */
++static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_format *fmt)
++{
++ struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
++ struct v4l2_mbus_framefmt *format;
++
++ format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which);
++ if (format == NULL)
++ return -EINVAL;
++
++ fmt->format = *format;
++ return 0;
++}
++
++/*
++ * csi2_set_format - Handle set format by pads subdev method
++ * @sd : pointer to v4l2 subdev structure
++ * @fh : V4L2 subdev file handle
++ * @fmt: pointer to v4l2 subdev format structure
++ * return -EINVAL or zero on success
++ */
++static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_format *fmt)
++{
++ struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
++ struct v4l2_mbus_framefmt *format;
++
++ format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which);
++ if (format == NULL)
++ return -EINVAL;
++
++ csi2_try_format(csi2, fh, fmt->pad, &fmt->format, fmt->which);
++ *format = fmt->format;
++
++ /* Propagate the format from sink to source */
++ if (fmt->pad == CSI2_PAD_SINK) {
++ format = __csi2_get_format(csi2, fh, CSI2_PAD_SOURCE,
++ fmt->which);
++ *format = fmt->format;
++ csi2_try_format(csi2, fh, CSI2_PAD_SOURCE, format, fmt->which);
++ }
++
++ return 0;
++}
++
++/*
++ * csi2_init_formats - Initialize formats on all pads
++ * @sd: ISP CSI2 V4L2 subdevice
++ * @fh: V4L2 subdev file handle
++ *
++ * Initialize all pad formats with default values. If fh is not NULL, try
++ * formats are initialized on the file handle. Otherwise active formats are
++ * initialized on the device.
++ */
++static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
++{
++ struct v4l2_subdev_format format;
++
++ memset(&format, 0, sizeof(format));
++ format.pad = CSI2_PAD_SINK;
++ format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
++ format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
++ format.format.width = 4096;
++ format.format.height = 4096;
++ csi2_set_format(sd, fh, &format);
++
++ return 0;
++}
++
++/*
++ * csi2_set_stream - Enable/Disable streaming on the CSI2 module
++ * @sd: ISP CSI2 V4L2 subdevice
++ * @enable: ISP pipeline stream state
++ *
++ * Return 0 on success or a negative error code otherwise.
++ */
++static int csi2_set_stream(struct v4l2_subdev *sd, int enable)
++{
++ struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
++ struct isp_device *isp = csi2->isp;
++ struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity);
++ struct isp_video *video_out = &csi2->video_out;
++
++ switch (enable) {
++ case ISP_PIPELINE_STREAM_CONTINUOUS:
++ if (omap3isp_csiphy_acquire(csi2->phy) < 0)
++ return -ENODEV;
++ csi2->use_fs_irq = pipe->do_propagation;
++ if (csi2->output & CSI2_OUTPUT_MEMORY)
++ omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI2A_WRITE);
++ csi2_configure(csi2);
++ csi2_print_status(csi2);
++
++ /*
++ * When outputting to memory with no buffer available, let the
++ * buffer queue handler start the hardware. A DMA queue flag
++ * ISP_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is
++ * a buffer available.
++ */
++ if (csi2->output & CSI2_OUTPUT_MEMORY &&
++ !(video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED))
++ break;
++ /* Enable context 0 and IRQs */
++ atomic_set(&csi2->stopping, 0);
++ csi2_ctx_enable(isp, csi2, 0, 1);
++ csi2_if_enable(isp, csi2, 1);
++ isp_video_dmaqueue_flags_clr(video_out);
++ break;
++
++ case ISP_PIPELINE_STREAM_STOPPED:
++ if (csi2->state == ISP_PIPELINE_STREAM_STOPPED)
++ return 0;
++ if (omap3isp_module_sync_idle(&sd->entity, &csi2->wait,
++ &csi2->stopping))
++ dev_dbg(isp->dev, "%s: module stop timeout.\n",
++ sd->name);
++ csi2_ctx_enable(isp, csi2, 0, 0);
++ csi2_if_enable(isp, csi2, 0);
++ csi2_irq_ctx_set(isp, csi2, 0);
++ omap3isp_csiphy_release(csi2->phy);
++ isp_video_dmaqueue_flags_clr(video_out);
++ omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CSI2A_WRITE);
++ break;
++ }
++
++ csi2->state = enable;
++ return 0;
++}
++
++/* subdev core operations */
++static const struct v4l2_subdev_core_ops csi2_core_ops = {
++ .queryctrl = v4l2_subdev_queryctrl,
++ .querymenu = v4l2_subdev_querymenu,
++ .g_ctrl = v4l2_subdev_g_ctrl,
++ .s_ctrl = v4l2_subdev_s_ctrl,
++ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
++ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
++ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
++};
++
++/* subdev file operations */
++static const struct v4l2_subdev_file_ops csi2_file_ops = {
++ .open = csi2_init_formats,
++};
++
++/* subdev video operations */
++static const struct v4l2_subdev_video_ops csi2_video_ops = {
++ .s_stream = csi2_set_stream,
++};
++
++/* subdev pad operations */
++static const struct v4l2_subdev_pad_ops csi2_pad_ops = {
++ .enum_mbus_code = csi2_enum_mbus_code,
++ .enum_frame_size = csi2_enum_frame_size,
++ .get_fmt = csi2_get_format,
++ .set_fmt = csi2_set_format,
++};
++
++/* subdev operations */
++static const struct v4l2_subdev_ops csi2_ops = {
++ .core = &csi2_core_ops,
++ .file = &csi2_file_ops,
++ .video = &csi2_video_ops,
++ .pad = &csi2_pad_ops,
++};
++
++/* -----------------------------------------------------------------------------
++ * Media entity operations
++ */
++
++/*
++ * csi2_link_setup - Setup CSI2 connections.
++ * @entity : Pointer to media entity structure
++ * @local : Pointer to local pad array
++ * @remote : Pointer to remote pad array
++ * @flags : Link flags
++ * return -EINVAL or zero on success
++ */
++static int csi2_link_setup(struct media_entity *entity,
++ const struct media_pad *local,
++ const struct media_pad *remote, u32 flags)
++{
++ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
++ struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
++ struct isp_csi2_ctrl_cfg *ctrl = &csi2->ctrl;
++
++ /*
++ * The ISP core doesn't support pipelines with multiple video outputs.
++ * Revisit this when it will be implemented, and return -EBUSY for now.
++ */
++
++ switch (local->index | media_entity_type(remote->entity)) {
++ case CSI2_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
++ if (flags & MEDIA_LNK_FL_ENABLED) {
++ if (csi2->output & ~CSI2_OUTPUT_MEMORY)
++ return -EBUSY;
++ csi2->output |= CSI2_OUTPUT_MEMORY;
++ } else {
++ csi2->output &= ~CSI2_OUTPUT_MEMORY;
++ }
++ break;
++
++ case CSI2_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
++ if (flags & MEDIA_LNK_FL_ENABLED) {
++ if (csi2->output & ~CSI2_OUTPUT_CCDC)
++ return -EBUSY;
++ csi2->output |= CSI2_OUTPUT_CCDC;
++ } else {
++ csi2->output &= ~CSI2_OUTPUT_CCDC;
++ }
++ break;
++
++ default:
++ /* Link from camera to CSI2 is fixed... */
++ return -EINVAL;
++ }
++
++ ctrl->vp_only_enable =
++ (csi2->output & CSI2_OUTPUT_MEMORY) ? false : true;
++ ctrl->vp_clk_enable = !!(csi2->output & CSI2_OUTPUT_CCDC);
++
++ return 0;
++}
++
++/* media operations */
++static const struct media_entity_operations csi2_media_ops = {
++ .link_setup = csi2_link_setup,
++};
++
++/*
++ * csi2_init_entities - Initialize subdev and media entity.
++ * @csi2: Pointer to csi2 structure.
++ * return -ENOMEM or zero on success
++ */
++static int csi2_init_entities(struct isp_csi2_device *csi2)
++{
++ struct v4l2_subdev *sd = &csi2->subdev;
++ struct media_pad *pads = csi2->pads;
++ struct media_entity *me = &sd->entity;
++ int ret;
++
++ v4l2_subdev_init(sd, &csi2_ops);
++ strlcpy(sd->name, "OMAP3 ISP CSI2a", sizeof(sd->name));
++
++ sd->grp_id = 1 << 16; /* group ID for isp subdevs */
++ v4l2_set_subdevdata(sd, csi2);
++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
++
++ v4l2_ctrl_handler_init(&csi2->ctrls, 1);
++ sd->ctrl_handler = &csi2->ctrls;
++
++ pads[CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_OUTPUT;
++ pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_INPUT;
++
++ me->ops = &csi2_media_ops;
++ ret = media_entity_init(me, CSI2_PADS_NUM, pads, 0);
++ if (ret < 0)
++ return ret;
++
++ csi2_init_formats(sd, NULL);
++
++ /* Video device node */
++ csi2->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ csi2->video_out.ops = &csi2_ispvideo_ops;
++ csi2->video_out.bpl_alignment = 32;
++ csi2->video_out.bpl_zero_padding = 1;
++ csi2->video_out.bpl_max = 0x1ffe0;
++ csi2->video_out.isp = csi2->isp;
++ csi2->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3;
++
++ ret = omap3isp_video_init(&csi2->video_out, "CSI2a");
++ if (ret < 0)
++ return ret;
++
++ /* Connect the CSI2 subdev to the video node. */
++ ret = media_entity_create_link(&csi2->subdev.entity, CSI2_PAD_SOURCE,
++ &csi2->video_out.video.entity, 0, 0);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2)
++{
++ media_entity_cleanup(&csi2->subdev.entity);
++
++ v4l2_device_unregister_subdev(&csi2->subdev);
++ v4l2_ctrl_handler_free(&csi2->ctrls);
++ omap3isp_video_unregister(&csi2->video_out);
++}
++
++int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2,
++ struct v4l2_device *vdev)
++{
++ int ret;
++
++ /* Register the subdev and video nodes. */
++ ret = v4l2_device_register_subdev(vdev, &csi2->subdev);
++ if (ret < 0)
++ goto error;
++
++ ret = omap3isp_video_register(&csi2->video_out, vdev);
++ if (ret < 0)
++ goto error;
++
++ return 0;
++
++error:
++ omap3isp_csi2_unregister_entities(csi2);
++ return ret;
++}
++
++/* -----------------------------------------------------------------------------
++ * ISP CSI2 initialisation and cleanup
++ */
++
++/*
++ * omap3isp_csi2_cleanup - Routine for module driver cleanup
++ */
++void omap3isp_csi2_cleanup(struct isp_device *isp)
++{
++}
++
++/*
++ * omap3isp_csi2_init - Routine for module driver init
++ */
++int omap3isp_csi2_init(struct isp_device *isp)
++{
++ struct isp_csi2_device *csi2a = &isp->isp_csi2a;
++ struct isp_csi2_device *csi2c = &isp->isp_csi2c;
++ int ret;
++
++ csi2a->isp = isp;
++ csi2a->available = 1;
++ csi2a->regs1 = OMAP3_ISP_IOMEM_CSI2A_REGS1;
++ csi2a->regs2 = OMAP3_ISP_IOMEM_CSI2A_REGS2;
++ csi2a->phy = &isp->isp_csiphy2;
++ csi2a->state = ISP_PIPELINE_STREAM_STOPPED;
++ init_waitqueue_head(&csi2a->wait);
++
++ ret = csi2_init_entities(csi2a);
++ if (ret < 0)
++ goto fail;
++
++ if (isp->revision == ISP_REVISION_15_0) {
++ csi2c->isp = isp;
++ csi2c->available = 1;
++ csi2c->regs1 = OMAP3_ISP_IOMEM_CSI2C_REGS1;
++ csi2c->regs2 = OMAP3_ISP_IOMEM_CSI2C_REGS2;
++ csi2c->phy = &isp->isp_csiphy1;
++ csi2c->state = ISP_PIPELINE_STREAM_STOPPED;
++ init_waitqueue_head(&csi2c->wait);
++ }
++
++ return 0;
++fail:
++ omap3isp_csi2_cleanup(isp);
++ return ret;
++}
+diff --git a/drivers/media/video/isp/ispcsi2.h b/drivers/media/video/isp/ispcsi2.h
+new file mode 100644
+index 0000000..b367326
+--- /dev/null
++++ b/drivers/media/video/isp/ispcsi2.h
+@@ -0,0 +1,169 @@
++/*
++ * ispcsi2.h
++ *
++ * TI OMAP3 ISP - CSI2 module
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc.
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#ifndef OMAP3_ISP_CSI2_H
++#define OMAP3_ISP_CSI2_H
++
++#include <linux/types.h>
++#include <linux/videodev2.h>
++#include <media/v4l2-ctrls.h>
++
++struct isp_csiphy;
++
++/* This is not an exhaustive list */
++enum isp_csi2_pix_formats {
++ CSI2_PIX_FMT_OTHERS = 0,
++ CSI2_PIX_FMT_YUV422_8BIT = 0x1e,
++ CSI2_PIX_FMT_YUV422_8BIT_VP = 0x9e,
++ CSI2_PIX_FMT_RAW10_EXP16 = 0xab,
++ CSI2_PIX_FMT_RAW10_EXP16_VP = 0x12f,
++ CSI2_PIX_FMT_RAW8 = 0x2a,
++ CSI2_PIX_FMT_RAW8_DPCM10_EXP16 = 0x2aa,
++ CSI2_PIX_FMT_RAW8_DPCM10_VP = 0x32a,
++ CSI2_PIX_FMT_RAW8_VP = 0x12a,
++ CSI2_USERDEF_8BIT_DATA1_DPCM10_VP = 0x340,
++ CSI2_USERDEF_8BIT_DATA1_DPCM10 = 0x2c0,
++ CSI2_USERDEF_8BIT_DATA1 = 0x40,
++};
++
++enum isp_csi2_irqevents {
++ OCP_ERR_IRQ = 0x4000,
++ SHORT_PACKET_IRQ = 0x2000,
++ ECC_CORRECTION_IRQ = 0x1000,
++ ECC_NO_CORRECTION_IRQ = 0x800,
++ COMPLEXIO2_ERR_IRQ = 0x400,
++ COMPLEXIO1_ERR_IRQ = 0x200,
++ FIFO_OVF_IRQ = 0x100,
++ CONTEXT7 = 0x80,
++ CONTEXT6 = 0x40,
++ CONTEXT5 = 0x20,
++ CONTEXT4 = 0x10,
++ CONTEXT3 = 0x8,
++ CONTEXT2 = 0x4,
++ CONTEXT1 = 0x2,
++ CONTEXT0 = 0x1,
++};
++
++enum isp_csi2_ctx_irqevents {
++ CTX_ECC_CORRECTION = 0x100,
++ CTX_LINE_NUMBER = 0x80,
++ CTX_FRAME_NUMBER = 0x40,
++ CTX_CS = 0x20,
++ CTX_LE = 0x8,
++ CTX_LS = 0x4,
++ CTX_FE = 0x2,
++ CTX_FS = 0x1,
++};
++
++enum isp_csi2_frame_mode {
++ ISP_CSI2_FRAME_IMMEDIATE,
++ ISP_CSI2_FRAME_AFTERFEC,
++};
++
++#define ISP_CSI2_MAX_CTX_NUM 7
++
++struct isp_csi2_ctx_cfg {
++ u8 ctxnum; /* context number 0 - 7 */
++ u8 dpcm_decompress;
++
++ /* Fields in CSI2_CTx_CTRL2 - locked by CSI2_CTx_CTRL1.CTX_EN */
++ u8 virtual_id;
++ u16 format_id; /* as in CSI2_CTx_CTRL2[9:0] */
++ u8 dpcm_predictor; /* 1: simple, 0: advanced */
++
++ /* Fields in CSI2_CTx_CTRL1/3 - Shadowed */
++ u16 alpha;
++ u16 data_offset;
++ u32 ping_addr;
++ u32 pong_addr;
++ u8 eof_enabled;
++ u8 eol_enabled;
++ u8 checksum_enabled;
++ u8 enabled;
++};
++
++struct isp_csi2_timing_cfg {
++ u8 ionum; /* IO1 or IO2 as in CSI2_TIMING */
++ unsigned force_rx_mode:1;
++ unsigned stop_state_16x:1;
++ unsigned stop_state_4x:1;
++ u16 stop_state_counter;
++};
++
++struct isp_csi2_ctrl_cfg {
++ bool vp_clk_enable;
++ bool vp_only_enable;
++ u8 vp_out_ctrl;
++ enum isp_csi2_frame_mode frame_mode;
++ bool ecc_enable;
++ bool if_enable;
++};
++
++#define CSI2_PAD_SINK 0
++#define CSI2_PAD_SOURCE 1
++#define CSI2_PADS_NUM 2
++
++#define CSI2_OUTPUT_CCDC (1 << 0)
++#define CSI2_OUTPUT_MEMORY (1 << 1)
++
++struct isp_csi2_device {
++ struct v4l2_subdev subdev;
++ struct media_pad pads[CSI2_PADS_NUM];
++ struct v4l2_mbus_framefmt formats[CSI2_PADS_NUM];
++
++ struct v4l2_ctrl_handler ctrls;
++
++ struct isp_video video_out;
++ struct isp_device *isp;
++
++ u8 available; /* Is the IP present on the silicon? */
++
++ /* mem resources - enums as defined in enum isp_mem_resources */
++ u8 regs1;
++ u8 regs2;
++
++ u32 output; /* output to CCDC, memory or both? */
++ bool dpcm_decompress;
++ unsigned int frame_skip;
++ bool use_fs_irq;
++
++ struct isp_csiphy *phy;
++ struct isp_csi2_ctx_cfg contexts[ISP_CSI2_MAX_CTX_NUM + 1];
++ struct isp_csi2_timing_cfg timing[2];
++ struct isp_csi2_ctrl_cfg ctrl;
++ enum isp_pipeline_stream_state state;
++ wait_queue_head_t wait;
++ atomic_t stopping;
++};
++
++int omap3isp_csi2_isr(struct isp_csi2_device *csi2);
++int omap3isp_csi2_reset(struct isp_csi2_device *csi2);
++int omap3isp_csi2_init(struct isp_device *isp);
++void omap3isp_csi2_cleanup(struct isp_device *isp);
++void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2);
++int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2,
++ struct v4l2_device *vdev);
++#endif /* OMAP3_ISP_CSI2_H */
+diff --git a/drivers/media/video/isp/ispcsiphy.c b/drivers/media/video/isp/ispcsiphy.c
+new file mode 100644
+index 0000000..59cd477
+--- /dev/null
++++ b/drivers/media/video/isp/ispcsiphy.c
+@@ -0,0 +1,247 @@
++/*
++ * ispcsiphy.c
++ *
++ * TI OMAP3 ISP - CSI PHY module
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc.
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/regulator/consumer.h>
++
++#include "isp.h"
++#include "ispreg.h"
++#include "ispcsiphy.h"
++
++/*
++ * csiphy_lanes_config - Configuration of CSIPHY lanes.
++ *
++ * Updates HW configuration.
++ * Called with phy->mutex taken.
++ */
++static void csiphy_lanes_config(struct isp_csiphy *phy)
++{
++ unsigned int i;
++ u32 reg;
++
++ reg = isp_reg_readl(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG);
++
++ for (i = 0; i < phy->num_data_lanes; i++) {
++ reg &= ~(ISPCSI2_PHY_CFG_DATA_POL_MASK(i + 1) |
++ ISPCSI2_PHY_CFG_DATA_POSITION_MASK(i + 1));
++ reg |= (phy->lanes.data[i].pol <<
++ ISPCSI2_PHY_CFG_DATA_POL_SHIFT(i + 1));
++ reg |= (phy->lanes.data[i].pos <<
++ ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(i + 1));
++ }
++
++ reg &= ~(ISPCSI2_PHY_CFG_CLOCK_POL_MASK |
++ ISPCSI2_PHY_CFG_CLOCK_POSITION_MASK);
++ reg |= phy->lanes.clk.pol << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT;
++ reg |= phy->lanes.clk.pos << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT;
++
++ isp_reg_writel(phy->isp, reg, phy->cfg_regs, ISPCSI2_PHY_CFG);
++}
++
++/*
++ * csiphy_power_autoswitch_enable
++ * @enable: Sets or clears the autoswitch function enable flag.
++ */
++static void csiphy_power_autoswitch_enable(struct isp_csiphy *phy, bool enable)
++{
++ isp_reg_clr_set(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG,
++ ISPCSI2_PHY_CFG_PWR_AUTO,
++ enable ? ISPCSI2_PHY_CFG_PWR_AUTO : 0);
++}
++
++/*
++ * csiphy_set_power
++ * @power: Power state to be set.
++ *
++ * Returns 0 if successful, or -EBUSY if the retry count is exceeded.
++ */
++static int csiphy_set_power(struct isp_csiphy *phy, u32 power)
++{
++ u32 reg;
++ u8 retry_count;
++
++ isp_reg_clr_set(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG,
++ ISPCSI2_PHY_CFG_PWR_CMD_MASK, power);
++
++ retry_count = 0;
++ do {
++ udelay(50);
++ reg = isp_reg_readl(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG) &
++ ISPCSI2_PHY_CFG_PWR_STATUS_MASK;
++
++ if (reg != power >> 2)
++ retry_count++;
++
++ } while ((reg != power >> 2) && (retry_count < 100));
++
++ if (retry_count == 100) {
++ printk(KERN_ERR "CSI2 CIO set power failed!\n");
++ return -EBUSY;
++ }
++
++ return 0;
++}
++
++/*
++ * csiphy_dphy_config - Configure CSI2 D-PHY parameters.
++ *
++ * Called with phy->mutex taken.
++ */
++static void csiphy_dphy_config(struct isp_csiphy *phy)
++{
++ u32 reg;
++
++ /* Set up ISPCSIPHY_REG0 */
++ reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG0);
++
++ reg &= ~(ISPCSIPHY_REG0_THS_TERM_MASK |
++ ISPCSIPHY_REG0_THS_SETTLE_MASK);
++ reg |= phy->dphy.ths_term << ISPCSIPHY_REG0_THS_TERM_SHIFT;
++ reg |= phy->dphy.ths_settle << ISPCSIPHY_REG0_THS_SETTLE_SHIFT;
++
++ isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG0);
++
++ /* Set up ISPCSIPHY_REG1 */
++ reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG1);
++
++ reg &= ~(ISPCSIPHY_REG1_TCLK_TERM_MASK |
++ ISPCSIPHY_REG1_TCLK_MISS_MASK |
++ ISPCSIPHY_REG1_TCLK_SETTLE_MASK);
++ reg |= phy->dphy.tclk_term << ISPCSIPHY_REG1_TCLK_TERM_SHIFT;
++ reg |= phy->dphy.tclk_miss << ISPCSIPHY_REG1_TCLK_MISS_SHIFT;
++ reg |= phy->dphy.tclk_settle << ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT;
++
++ isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG1);
++}
++
++static int csiphy_config(struct isp_csiphy *phy,
++ struct isp_csiphy_dphy_cfg *dphy,
++ struct isp_csiphy_lanes_cfg *lanes)
++{
++ unsigned int used_lanes = 0;
++ unsigned int i;
++
++ /* Clock and data lanes verification */
++ for (i = 0; i < phy->num_data_lanes; i++) {
++ if (lanes->data[i].pol > 1 || lanes->data[i].pos > 3)
++ return -EINVAL;
++
++ if (used_lanes & (1 << lanes->data[i].pos))
++ return -EINVAL;
++
++ used_lanes |= 1 << lanes->data[i].pos;
++ }
++
++ if (lanes->clk.pol > 1 || lanes->clk.pos > 3)
++ return -EINVAL;
++
++ if (lanes->clk.pos == 0 || used_lanes & (1 << lanes->clk.pos))
++ return -EINVAL;
++
++ mutex_lock(&phy->mutex);
++ phy->dphy = *dphy;
++ phy->lanes = *lanes;
++ mutex_unlock(&phy->mutex);
++
++ return 0;
++}
++
++int omap3isp_csiphy_acquire(struct isp_csiphy *phy)
++{
++ int rval;
++
++ if (phy->vdd == NULL) {
++ dev_err(phy->isp->dev, "Power regulator for CSI PHY not "
++ "available\n");
++ return -ENODEV;
++ }
++
++ mutex_lock(&phy->mutex);
++
++ rval = regulator_enable(phy->vdd);
++ if (rval < 0)
++ goto done;
++
++ omap3isp_csi2_reset(phy->csi2);
++
++ csiphy_dphy_config(phy);
++ csiphy_lanes_config(phy);
++
++ rval = csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_ON);
++ if (rval) {
++ regulator_disable(phy->vdd);
++ goto done;
++ }
++
++ csiphy_power_autoswitch_enable(phy, true);
++ phy->phy_in_use = 1;
++
++done:
++ mutex_unlock(&phy->mutex);
++ return rval;
++}
++
++void omap3isp_csiphy_release(struct isp_csiphy *phy)
++{
++ mutex_lock(&phy->mutex);
++ if (phy->phy_in_use) {
++ csiphy_power_autoswitch_enable(phy, false);
++ csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_OFF);
++ regulator_disable(phy->vdd);
++ phy->phy_in_use = 0;
++ }
++ mutex_unlock(&phy->mutex);
++}
++
++/*
++ * omap3isp_csiphy_init - Initialize the CSI PHY frontends
++ */
++int omap3isp_csiphy_init(struct isp_device *isp)
++{
++ struct isp_csiphy *phy1 = &isp->isp_csiphy1;
++ struct isp_csiphy *phy2 = &isp->isp_csiphy2;
++
++ isp->platform_cb.csiphy_config = csiphy_config;
++
++ phy2->isp = isp;
++ phy2->csi2 = &isp->isp_csi2a;
++ phy2->num_data_lanes = ISP_CSIPHY2_NUM_DATA_LANES;
++ phy2->cfg_regs = OMAP3_ISP_IOMEM_CSI2A_REGS1;
++ phy2->phy_regs = OMAP3_ISP_IOMEM_CSIPHY2;
++ mutex_init(&phy2->mutex);
++
++ if (isp->revision == ISP_REVISION_15_0) {
++ phy1->isp = isp;
++ phy1->csi2 = &isp->isp_csi2c;
++ phy1->num_data_lanes = ISP_CSIPHY1_NUM_DATA_LANES;
++ phy1->cfg_regs = OMAP3_ISP_IOMEM_CSI2C_REGS1;
++ phy1->phy_regs = OMAP3_ISP_IOMEM_CSIPHY1;
++ mutex_init(&phy1->mutex);
++ }
++
++ return 0;
++}
+diff --git a/drivers/media/video/isp/ispcsiphy.h b/drivers/media/video/isp/ispcsiphy.h
+new file mode 100644
+index 0000000..39a7e6b
+--- /dev/null
++++ b/drivers/media/video/isp/ispcsiphy.h
+@@ -0,0 +1,74 @@
++/*
++ * ispcsiphy.h
++ *
++ * TI OMAP3 ISP - CSI PHY module
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc.
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#ifndef OMAP3_ISP_CSI_PHY_H
++#define OMAP3_ISP_CSI_PHY_H
++
++struct isp_csi2_device;
++struct regulator;
++
++struct csiphy_lane {
++ u8 pos;
++ u8 pol;
++};
++
++#define ISP_CSIPHY2_NUM_DATA_LANES 2
++#define ISP_CSIPHY1_NUM_DATA_LANES 1
++
++struct isp_csiphy_lanes_cfg {
++ struct csiphy_lane data[ISP_CSIPHY2_NUM_DATA_LANES];
++ struct csiphy_lane clk;
++};
++
++struct isp_csiphy_dphy_cfg {
++ u8 ths_term;
++ u8 ths_settle;
++ u8 tclk_term;
++ unsigned tclk_miss:1;
++ u8 tclk_settle;
++};
++
++struct isp_csiphy {
++ struct isp_device *isp;
++ struct mutex mutex; /* serialize csiphy configuration */
++ u8 phy_in_use;
++ struct isp_csi2_device *csi2;
++ struct regulator *vdd;
++
++ /* mem resources - enums as defined in enum isp_mem_resources */
++ unsigned int cfg_regs;
++ unsigned int phy_regs;
++
++ u8 num_data_lanes; /* number of CSI2 Data Lanes supported */
++ struct isp_csiphy_lanes_cfg lanes;
++ struct isp_csiphy_dphy_cfg dphy;
++};
++
++int omap3isp_csiphy_acquire(struct isp_csiphy *phy);
++void omap3isp_csiphy_release(struct isp_csiphy *phy);
++int omap3isp_csiphy_init(struct isp_device *isp);
++
++#endif /* OMAP3_ISP_CSI_PHY_H */
+diff --git a/drivers/media/video/isp/isph3a.h b/drivers/media/video/isp/isph3a.h
+new file mode 100644
+index 0000000..6d43529
+--- /dev/null
++++ b/drivers/media/video/isp/isph3a.h
+@@ -0,0 +1,117 @@
++/*
++ * isph3a.h
++ *
++ * TI OMAP3 ISP - H3A AF module
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc.
++ *
++ * Contacts: David Cohen <david.cohen@nokia.com>
++ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#ifndef OMAP3_ISP_H3A_H
++#define OMAP3_ISP_H3A_H
++
++#include <linux/omap3isp.h>
++
++/*
++ * ----------
++ * -H3A AEWB-
++ * ----------
++ */
++
++#define AEWB_PACKET_SIZE 16
++#define AEWB_SATURATION_LIMIT 0x3ff
++
++/* Flags for changed registers */
++#define PCR_CHNG (1 << 0)
++#define AEWWIN1_CHNG (1 << 1)
++#define AEWINSTART_CHNG (1 << 2)
++#define AEWINBLK_CHNG (1 << 3)
++#define AEWSUBWIN_CHNG (1 << 4)
++#define PRV_WBDGAIN_CHNG (1 << 5)
++#define PRV_WBGAIN_CHNG (1 << 6)
++
++/* ISPH3A REGISTERS bits */
++#define ISPH3A_PCR_AF_EN (1 << 0)
++#define ISPH3A_PCR_AF_ALAW_EN (1 << 1)
++#define ISPH3A_PCR_AF_MED_EN (1 << 2)
++#define ISPH3A_PCR_AF_BUSY (1 << 15)
++#define ISPH3A_PCR_AEW_EN (1 << 16)
++#define ISPH3A_PCR_AEW_ALAW_EN (1 << 17)
++#define ISPH3A_PCR_AEW_BUSY (1 << 18)
++#define ISPH3A_PCR_AEW_MASK (ISPH3A_PCR_AEW_ALAW_EN | \
++ ISPH3A_PCR_AEW_AVE2LMT_MASK)
++
++/*
++ * --------
++ * -H3A AF-
++ * --------
++ */
++
++/* Peripheral Revision */
++#define AFPID 0x0
++
++#define AFCOEF_OFFSET 0x00000004 /* COEF base address */
++
++/* PCR fields */
++#define AF_BUSYAF (1 << 15)
++#define AF_FVMODE (1 << 14)
++#define AF_RGBPOS (0x7 << 11)
++#define AF_MED_TH (0xFF << 3)
++#define AF_MED_EN (1 << 2)
++#define AF_ALAW_EN (1 << 1)
++#define AF_EN (1 << 0)
++#define AF_PCR_MASK (AF_FVMODE | AF_RGBPOS | AF_MED_TH | \
++ AF_MED_EN | AF_ALAW_EN)
++
++/* AFPAX1 fields */
++#define AF_PAXW (0x7F << 16)
++#define AF_PAXH 0x7F
++
++/* AFPAX2 fields */
++#define AF_AFINCV (0xF << 13)
++#define AF_PAXVC (0x7F << 6)
++#define AF_PAXHC 0x3F
++
++/* AFPAXSTART fields */
++#define AF_PAXSH (0xFFF<<16)
++#define AF_PAXSV 0xFFF
++
++/* COEFFICIENT MASK */
++#define AF_COEF_MASK0 0xFFF
++#define AF_COEF_MASK1 (0xFFF<<16)
++
++/* BIT SHIFTS */
++#define AF_RGBPOS_SHIFT 11
++#define AF_MED_TH_SHIFT 3
++#define AF_PAXW_SHIFT 16
++#define AF_LINE_INCR_SHIFT 13
++#define AF_VT_COUNT_SHIFT 6
++#define AF_HZ_START_SHIFT 16
++#define AF_COEF_SHIFT 16
++
++/* Init and cleanup functions */
++int omap3isp_h3a_aewb_init(struct isp_device *isp);
++int omap3isp_h3a_af_init(struct isp_device *isp);
++
++void omap3isp_h3a_aewb_cleanup(struct isp_device *isp);
++void omap3isp_h3a_af_cleanup(struct isp_device *isp);
++
++#endif /* OMAP3_ISP_H3A_H */
+diff --git a/drivers/media/video/isp/isph3a_aewb.c b/drivers/media/video/isp/isph3a_aewb.c
+new file mode 100644
+index 0000000..b4e97f2
+--- /dev/null
++++ b/drivers/media/video/isp/isph3a_aewb.c
+@@ -0,0 +1,374 @@
++/*
++ * isph3a.c
++ *
++ * TI OMAP3 ISP - H3A module
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc.
++ *
++ * Contacts: David Cohen <david.cohen@nokia.com>
++ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++
++#include "isp.h"
++#include "isph3a.h"
++#include "ispstat.h"
++
++/*
++ * h3a_aewb_update_regs - Helper function to update h3a registers.
++ */
++static void h3a_aewb_setup_regs(struct ispstat *aewb, void *priv)
++{
++ struct omap3isp_h3a_aewb_config *conf = priv;
++ u32 pcr;
++ u32 win1;
++ u32 start;
++ u32 blk;
++ u32 subwin;
++
++ if (aewb->state == ISPSTAT_DISABLED)
++ return;
++
++ isp_reg_writel(aewb->isp, aewb->active_buf->iommu_addr,
++ OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST);
++
++ if (!aewb->update)
++ return;
++
++ /* Converting config metadata into reg values */
++ pcr = conf->saturation_limit << ISPH3A_PCR_AEW_AVE2LMT_SHIFT;
++ pcr |= !!conf->alaw_enable << ISPH3A_PCR_AEW_ALAW_EN_SHIFT;
++
++ win1 = ((conf->win_height >> 1) - 1) << ISPH3A_AEWWIN1_WINH_SHIFT;
++ win1 |= ((conf->win_width >> 1) - 1) << ISPH3A_AEWWIN1_WINW_SHIFT;
++ win1 |= (conf->ver_win_count - 1) << ISPH3A_AEWWIN1_WINVC_SHIFT;
++ win1 |= (conf->hor_win_count - 1) << ISPH3A_AEWWIN1_WINHC_SHIFT;
++
++ start = conf->hor_win_start << ISPH3A_AEWINSTART_WINSH_SHIFT;
++ start |= conf->ver_win_start << ISPH3A_AEWINSTART_WINSV_SHIFT;
++
++ blk = conf->blk_ver_win_start << ISPH3A_AEWINBLK_WINSV_SHIFT;
++ blk |= ((conf->blk_win_height >> 1) - 1) << ISPH3A_AEWINBLK_WINH_SHIFT;
++
++ subwin = ((conf->subsample_ver_inc >> 1) - 1) <<
++ ISPH3A_AEWSUBWIN_AEWINCV_SHIFT;
++ subwin |= ((conf->subsample_hor_inc >> 1) - 1) <<
++ ISPH3A_AEWSUBWIN_AEWINCH_SHIFT;
++
++ isp_reg_writel(aewb->isp, win1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1);
++ isp_reg_writel(aewb->isp, start, OMAP3_ISP_IOMEM_H3A,
++ ISPH3A_AEWINSTART);
++ isp_reg_writel(aewb->isp, blk, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK);
++ isp_reg_writel(aewb->isp, subwin, OMAP3_ISP_IOMEM_H3A,
++ ISPH3A_AEWSUBWIN);
++ isp_reg_clr_set(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
++ ISPH3A_PCR_AEW_MASK, pcr);
++
++ aewb->update = 0;
++ aewb->config_counter += aewb->inc_config;
++ aewb->inc_config = 0;
++ aewb->buf_size = conf->buf_size;
++}
++
++static void h3a_aewb_enable(struct ispstat *aewb, int enable)
++{
++ if (enable) {
++ isp_reg_set(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
++ ISPH3A_PCR_AEW_EN);
++ /* This bit is already set if AF is enabled */
++ if (aewb->isp->isp_af.state != ISPSTAT_ENABLED)
++ isp_reg_set(aewb->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
++ ISPCTRL_H3A_CLK_EN);
++ } else {
++ isp_reg_clr(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
++ ISPH3A_PCR_AEW_EN);
++ /* This bit can't be cleared if AF is enabled */
++ if (aewb->isp->isp_af.state != ISPSTAT_ENABLED)
++ isp_reg_clr(aewb->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
++ ISPCTRL_H3A_CLK_EN);
++ }
++}
++
++static int h3a_aewb_busy(struct ispstat *aewb)
++{
++ return isp_reg_readl(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
++ & ISPH3A_PCR_BUSYAEAWB;
++}
++
++static u32 h3a_aewb_get_buf_size(struct omap3isp_h3a_aewb_config *conf)
++{
++ /* Number of configured windows + extra row for black data */
++ u32 win_count = (conf->ver_win_count + 1) * conf->hor_win_count;
++
++ /*
++ * Unsaturated block counts for each 8 windows.
++ * 1 extra for the last (win_count % 8) windows if win_count is not
++ * divisible by 8.
++ */
++ win_count += (win_count + 7) / 8;
++
++ return win_count * AEWB_PACKET_SIZE;
++}
++
++static int h3a_aewb_validate_params(struct ispstat *aewb, void *new_conf)
++{
++ struct omap3isp_h3a_aewb_config *user_cfg = new_conf;
++ u32 buf_size;
++
++ if (unlikely(user_cfg->saturation_limit >
++ OMAP3ISP_AEWB_MAX_SATURATION_LIM))
++ return -EINVAL;
++
++ if (unlikely(user_cfg->win_height < OMAP3ISP_AEWB_MIN_WIN_H ||
++ user_cfg->win_height > OMAP3ISP_AEWB_MAX_WIN_H ||
++ user_cfg->win_height & 0x01))
++ return -EINVAL;
++
++ if (unlikely(user_cfg->win_width < OMAP3ISP_AEWB_MIN_WIN_W ||
++ user_cfg->win_width > OMAP3ISP_AEWB_MAX_WIN_W ||
++ user_cfg->win_width & 0x01))
++ return -EINVAL;
++
++ if (unlikely(user_cfg->ver_win_count < OMAP3ISP_AEWB_MIN_WINVC ||
++ user_cfg->ver_win_count > OMAP3ISP_AEWB_MAX_WINVC))
++ return -EINVAL;
++
++ if (unlikely(user_cfg->hor_win_count < OMAP3ISP_AEWB_MIN_WINHC ||
++ user_cfg->hor_win_count > OMAP3ISP_AEWB_MAX_WINHC))
++ return -EINVAL;
++
++ if (unlikely(user_cfg->ver_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
++ return -EINVAL;
++
++ if (unlikely(user_cfg->hor_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
++ return -EINVAL;
++
++ if (unlikely(user_cfg->blk_ver_win_start > OMAP3ISP_AEWB_MAX_WINSTART))
++ return -EINVAL;
++
++ if (unlikely(user_cfg->blk_win_height < OMAP3ISP_AEWB_MIN_WIN_H ||
++ user_cfg->blk_win_height > OMAP3ISP_AEWB_MAX_WIN_H ||
++ user_cfg->blk_win_height & 0x01))
++ return -EINVAL;
++
++ if (unlikely(user_cfg->subsample_ver_inc < OMAP3ISP_AEWB_MIN_SUB_INC ||
++ user_cfg->subsample_ver_inc > OMAP3ISP_AEWB_MAX_SUB_INC ||
++ user_cfg->subsample_ver_inc & 0x01))
++ return -EINVAL;
++
++ if (unlikely(user_cfg->subsample_hor_inc < OMAP3ISP_AEWB_MIN_SUB_INC ||
++ user_cfg->subsample_hor_inc > OMAP3ISP_AEWB_MAX_SUB_INC ||
++ user_cfg->subsample_hor_inc & 0x01))
++ return -EINVAL;
++
++ buf_size = h3a_aewb_get_buf_size(user_cfg);
++ if (buf_size > user_cfg->buf_size)
++ user_cfg->buf_size = buf_size;
++ else if (user_cfg->buf_size > OMAP3ISP_AEWB_MAX_BUF_SIZE)
++ user_cfg->buf_size = OMAP3ISP_AEWB_MAX_BUF_SIZE;
++
++ return 0;
++}
++
++/*
++ * h3a_aewb_set_params - Helper function to check & store user given params.
++ * @new_conf: Pointer to AE and AWB parameters struct.
++ *
++ * As most of them are busy-lock registers, need to wait until AEW_BUSY = 0 to
++ * program them during ISR.
++ */
++static void h3a_aewb_set_params(struct ispstat *aewb, void *new_conf)
++{
++ struct omap3isp_h3a_aewb_config *user_cfg = new_conf;
++ struct omap3isp_h3a_aewb_config *cur_cfg = aewb->priv;
++ int update = 0;
++
++ if (cur_cfg->saturation_limit != user_cfg->saturation_limit) {
++ cur_cfg->saturation_limit = user_cfg->saturation_limit;
++ update = 1;
++ }
++ if (cur_cfg->alaw_enable != user_cfg->alaw_enable) {
++ cur_cfg->alaw_enable = user_cfg->alaw_enable;
++ update = 1;
++ }
++ if (cur_cfg->win_height != user_cfg->win_height) {
++ cur_cfg->win_height = user_cfg->win_height;
++ update = 1;
++ }
++ if (cur_cfg->win_width != user_cfg->win_width) {
++ cur_cfg->win_width = user_cfg->win_width;
++ update = 1;
++ }
++ if (cur_cfg->ver_win_count != user_cfg->ver_win_count) {
++ cur_cfg->ver_win_count = user_cfg->ver_win_count;
++ update = 1;
++ }
++ if (cur_cfg->hor_win_count != user_cfg->hor_win_count) {
++ cur_cfg->hor_win_count = user_cfg->hor_win_count;
++ update = 1;
++ }
++ if (cur_cfg->ver_win_start != user_cfg->ver_win_start) {
++ cur_cfg->ver_win_start = user_cfg->ver_win_start;
++ update = 1;
++ }
++ if (cur_cfg->hor_win_start != user_cfg->hor_win_start) {
++ cur_cfg->hor_win_start = user_cfg->hor_win_start;
++ update = 1;
++ }
++ if (cur_cfg->blk_ver_win_start != user_cfg->blk_ver_win_start) {
++ cur_cfg->blk_ver_win_start = user_cfg->blk_ver_win_start;
++ update = 1;
++ }
++ if (cur_cfg->blk_win_height != user_cfg->blk_win_height) {
++ cur_cfg->blk_win_height = user_cfg->blk_win_height;
++ update = 1;
++ }
++ if (cur_cfg->subsample_ver_inc != user_cfg->subsample_ver_inc) {
++ cur_cfg->subsample_ver_inc = user_cfg->subsample_ver_inc;
++ update = 1;
++ }
++ if (cur_cfg->subsample_hor_inc != user_cfg->subsample_hor_inc) {
++ cur_cfg->subsample_hor_inc = user_cfg->subsample_hor_inc;
++ update = 1;
++ }
++
++ if (update || !aewb->configured) {
++ aewb->inc_config++;
++ aewb->update = 1;
++ cur_cfg->buf_size = h3a_aewb_get_buf_size(cur_cfg);
++ }
++}
++
++static long h3a_aewb_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
++{
++ struct ispstat *stat = v4l2_get_subdevdata(sd);
++
++ switch (cmd) {
++ case VIDIOC_OMAP3ISP_AEWB_CFG:
++ return omap3isp_stat_config(stat, arg);
++ case VIDIOC_OMAP3ISP_STAT_REQ:
++ return omap3isp_stat_request_statistics(stat, arg);
++ case VIDIOC_OMAP3ISP_STAT_EN: {
++ unsigned long *en = arg;
++ return omap3isp_stat_enable(stat, !!*en);
++ }
++ }
++
++ return -ENOIOCTLCMD;
++}
++
++static const struct ispstat_ops h3a_aewb_ops = {
++ .validate_params = h3a_aewb_validate_params,
++ .set_params = h3a_aewb_set_params,
++ .setup_regs = h3a_aewb_setup_regs,
++ .enable = h3a_aewb_enable,
++ .busy = h3a_aewb_busy,
++};
++
++static const struct v4l2_subdev_core_ops h3a_aewb_subdev_core_ops = {
++ .ioctl = h3a_aewb_ioctl,
++ .subscribe_event = omap3isp_stat_subscribe_event,
++ .unsubscribe_event = omap3isp_stat_unsubscribe_event,
++};
++
++static const struct v4l2_subdev_video_ops h3a_aewb_subdev_video_ops = {
++ .s_stream = omap3isp_stat_s_stream,
++};
++
++static const struct v4l2_subdev_ops h3a_aewb_subdev_ops = {
++ .core = &h3a_aewb_subdev_core_ops,
++ .video = &h3a_aewb_subdev_video_ops,
++};
++
++/*
++ * omap3isp_h3a_aewb_init - Module Initialisation.
++ */
++int omap3isp_h3a_aewb_init(struct isp_device *isp)
++{
++ struct ispstat *aewb = &isp->isp_aewb;
++ struct omap3isp_h3a_aewb_config *aewb_cfg;
++ struct omap3isp_h3a_aewb_config *aewb_recover_cfg;
++ int ret;
++
++ aewb_cfg = kzalloc(sizeof(*aewb_cfg), GFP_KERNEL);
++ if (!aewb_cfg)
++ return -ENOMEM;
++
++ memset(aewb, 0, sizeof(*aewb));
++ aewb->ops = &h3a_aewb_ops;
++ aewb->priv = aewb_cfg;
++ aewb->dma_ch = -1;
++ aewb->event_type = V4L2_EVENT_OMAP3ISP_AEWB;
++ aewb->isp = isp;
++
++ /* Set recover state configuration */
++ aewb_recover_cfg = kzalloc(sizeof(*aewb_recover_cfg), GFP_KERNEL);
++ if (!aewb_recover_cfg) {
++ dev_err(aewb->isp->dev, "AEWB: cannot allocate memory for "
++ "recover configuration.\n");
++ ret = -ENOMEM;
++ goto err_recover_alloc;
++ }
++
++ aewb_recover_cfg->saturation_limit = OMAP3ISP_AEWB_MAX_SATURATION_LIM;
++ aewb_recover_cfg->win_height = OMAP3ISP_AEWB_MIN_WIN_H;
++ aewb_recover_cfg->win_width = OMAP3ISP_AEWB_MIN_WIN_W;
++ aewb_recover_cfg->ver_win_count = OMAP3ISP_AEWB_MIN_WINVC;
++ aewb_recover_cfg->hor_win_count = OMAP3ISP_AEWB_MIN_WINHC;
++ aewb_recover_cfg->blk_ver_win_start = aewb_recover_cfg->ver_win_start +
++ aewb_recover_cfg->win_height * aewb_recover_cfg->ver_win_count;
++ aewb_recover_cfg->blk_win_height = OMAP3ISP_AEWB_MIN_WIN_H;
++ aewb_recover_cfg->subsample_ver_inc = OMAP3ISP_AEWB_MIN_SUB_INC;
++ aewb_recover_cfg->subsample_hor_inc = OMAP3ISP_AEWB_MIN_SUB_INC;
++
++ if (h3a_aewb_validate_params(aewb, aewb_recover_cfg)) {
++ dev_err(aewb->isp->dev, "AEWB: recover configuration is "
++ "invalid.\n");
++ ret = -EINVAL;
++ goto err_conf;
++ }
++
++ aewb_recover_cfg->buf_size = h3a_aewb_get_buf_size(aewb_recover_cfg);
++ aewb->recover_priv = aewb_recover_cfg;
++
++ ret = omap3isp_stat_init(aewb, "AEWB", &h3a_aewb_subdev_ops);
++ if (ret)
++ goto err_conf;
++
++ return 0;
++
++err_conf:
++ kfree(aewb_recover_cfg);
++err_recover_alloc:
++ kfree(aewb_cfg);
++
++ return ret;
++}
++
++/*
++ * omap3isp_h3a_aewb_cleanup - Module exit.
++ */
++void omap3isp_h3a_aewb_cleanup(struct isp_device *isp)
++{
++ kfree(isp->isp_aewb.priv);
++ kfree(isp->isp_aewb.recover_priv);
++ omap3isp_stat_free(&isp->isp_aewb);
++}
+diff --git a/drivers/media/video/isp/isph3a_af.c b/drivers/media/video/isp/isph3a_af.c
+new file mode 100644
+index 0000000..c32a18e
+--- /dev/null
++++ b/drivers/media/video/isp/isph3a_af.c
+@@ -0,0 +1,429 @@
++/*
++ * isph3a_af.c
++ *
++ * TI OMAP3 ISP - H3A AF module
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc.
++ *
++ * Contacts: David Cohen <david.cohen@nokia.com>
++ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++/* Linux specific include files */
++#include <linux/device.h>
++#include <linux/slab.h>
++
++#include "isp.h"
++#include "isph3a.h"
++#include "ispstat.h"
++
++#define IS_OUT_OF_BOUNDS(value, min, max) \
++ (((value) < (min)) || ((value) > (max)))
++
++static void h3a_af_setup_regs(struct ispstat *af, void *priv)
++{
++ struct omap3isp_h3a_af_config *conf = priv;
++ u32 pcr;
++ u32 pax1;
++ u32 pax2;
++ u32 paxstart;
++ u32 coef;
++ u32 base_coef_set0;
++ u32 base_coef_set1;
++ int index;
++
++ if (af->state == ISPSTAT_DISABLED)
++ return;
++
++ isp_reg_writel(af->isp, af->active_buf->iommu_addr, OMAP3_ISP_IOMEM_H3A,
++ ISPH3A_AFBUFST);
++
++ if (!af->update)
++ return;
++
++ /* Configure Hardware Registers */
++ pax1 = ((conf->paxel.width >> 1) - 1) << AF_PAXW_SHIFT;
++ /* Set height in AFPAX1 */
++ pax1 |= (conf->paxel.height >> 1) - 1;
++ isp_reg_writel(af->isp, pax1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX1);
++
++ /* Configure AFPAX2 Register */
++ /* Set Line Increment in AFPAX2 Register */
++ pax2 = ((conf->paxel.line_inc >> 1) - 1) << AF_LINE_INCR_SHIFT;
++ /* Set Vertical Count */
++ pax2 |= (conf->paxel.v_cnt - 1) << AF_VT_COUNT_SHIFT;
++ /* Set Horizontal Count */
++ pax2 |= (conf->paxel.h_cnt - 1);
++ isp_reg_writel(af->isp, pax2, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX2);
++
++ /* Configure PAXSTART Register */
++ /*Configure Horizontal Start */
++ paxstart = conf->paxel.h_start << AF_HZ_START_SHIFT;
++ /* Configure Vertical Start */
++ paxstart |= conf->paxel.v_start;
++ isp_reg_writel(af->isp, paxstart, OMAP3_ISP_IOMEM_H3A,
++ ISPH3A_AFPAXSTART);
++
++ /*SetIIRSH Register */
++ isp_reg_writel(af->isp, conf->iir.h_start,
++ OMAP3_ISP_IOMEM_H3A, ISPH3A_AFIIRSH);
++
++ base_coef_set0 = ISPH3A_AFCOEF010;
++ base_coef_set1 = ISPH3A_AFCOEF110;
++ for (index = 0; index <= 8; index += 2) {
++ /*Set IIR Filter0 Coefficients */
++ coef = 0;
++ coef |= conf->iir.coeff_set0[index];
++ coef |= conf->iir.coeff_set0[index + 1] <<
++ AF_COEF_SHIFT;
++ isp_reg_writel(af->isp, coef, OMAP3_ISP_IOMEM_H3A,
++ base_coef_set0);
++ base_coef_set0 += AFCOEF_OFFSET;
++
++ /*Set IIR Filter1 Coefficients */
++ coef = 0;
++ coef |= conf->iir.coeff_set1[index];
++ coef |= conf->iir.coeff_set1[index + 1] <<
++ AF_COEF_SHIFT;
++ isp_reg_writel(af->isp, coef, OMAP3_ISP_IOMEM_H3A,
++ base_coef_set1);
++ base_coef_set1 += AFCOEF_OFFSET;
++ }
++ /* set AFCOEF0010 Register */
++ isp_reg_writel(af->isp, conf->iir.coeff_set0[10],
++ OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF0010);
++ /* set AFCOEF1010 Register */
++ isp_reg_writel(af->isp, conf->iir.coeff_set1[10],
++ OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF1010);
++
++ /* PCR Register */
++ /* Set RGB Position */
++ pcr = conf->rgb_pos << AF_RGBPOS_SHIFT;
++ /* Set Accumulator Mode */
++ if (conf->fvmode == OMAP3ISP_AF_MODE_PEAK)
++ pcr |= AF_FVMODE;
++ /* Set A-law */
++ if (conf->alaw_enable)
++ pcr |= AF_ALAW_EN;
++ /* HMF Configurations */
++ if (conf->hmf.enable) {
++ /* Enable HMF */
++ pcr |= AF_MED_EN;
++ /* Set Median Threshold */
++ pcr |= conf->hmf.threshold << AF_MED_TH_SHIFT;
++ }
++ /* Set PCR Register */
++ isp_reg_clr_set(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
++ AF_PCR_MASK, pcr);
++
++ af->update = 0;
++ af->config_counter += af->inc_config;
++ af->inc_config = 0;
++ af->buf_size = conf->buf_size;
++}
++
++static void h3a_af_enable(struct ispstat *af, int enable)
++{
++ if (enable) {
++ isp_reg_set(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
++ ISPH3A_PCR_AF_EN);
++ /* This bit is already set if AEWB is enabled */
++ if (af->isp->isp_aewb.state != ISPSTAT_ENABLED)
++ isp_reg_set(af->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
++ ISPCTRL_H3A_CLK_EN);
++ } else {
++ isp_reg_clr(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
++ ISPH3A_PCR_AF_EN);
++ /* This bit can't be cleared if AEWB is enabled */
++ if (af->isp->isp_aewb.state != ISPSTAT_ENABLED)
++ isp_reg_clr(af->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
++ ISPCTRL_H3A_CLK_EN);
++ }
++}
++
++static int h3a_af_busy(struct ispstat *af)
++{
++ return isp_reg_readl(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
++ & ISPH3A_PCR_BUSYAF;
++}
++
++static u32 h3a_af_get_buf_size(struct omap3isp_h3a_af_config *conf)
++{
++ return conf->paxel.h_cnt * conf->paxel.v_cnt * OMAP3ISP_AF_PAXEL_SIZE;
++}
++
++/* Function to check paxel parameters */
++static int h3a_af_validate_params(struct ispstat *af, void *new_conf)
++{
++ struct omap3isp_h3a_af_config *user_cfg = new_conf;
++ struct omap3isp_h3a_af_paxel *paxel_cfg = &user_cfg->paxel;
++ struct omap3isp_h3a_af_iir *iir_cfg = &user_cfg->iir;
++ int index;
++ u32 buf_size;
++
++ /* Check horizontal Count */
++ if (IS_OUT_OF_BOUNDS(paxel_cfg->h_cnt,
++ OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MIN,
++ OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MAX))
++ return -EINVAL;
++
++ /* Check Vertical Count */
++ if (IS_OUT_OF_BOUNDS(paxel_cfg->v_cnt,
++ OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MIN,
++ OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MAX))
++ return -EINVAL;
++
++ if (IS_OUT_OF_BOUNDS(paxel_cfg->height, OMAP3ISP_AF_PAXEL_HEIGHT_MIN,
++ OMAP3ISP_AF_PAXEL_HEIGHT_MAX) ||
++ paxel_cfg->height % 2)
++ return -EINVAL;
++
++ /* Check width */
++ if (IS_OUT_OF_BOUNDS(paxel_cfg->width, OMAP3ISP_AF_PAXEL_WIDTH_MIN,
++ OMAP3ISP_AF_PAXEL_WIDTH_MAX) ||
++ paxel_cfg->width % 2)
++ return -EINVAL;
++
++ /* Check Line Increment */
++ if (IS_OUT_OF_BOUNDS(paxel_cfg->line_inc,
++ OMAP3ISP_AF_PAXEL_INCREMENT_MIN,
++ OMAP3ISP_AF_PAXEL_INCREMENT_MAX) ||
++ paxel_cfg->line_inc % 2)
++ return -EINVAL;
++
++ /* Check Horizontal Start */
++ if ((paxel_cfg->h_start < iir_cfg->h_start) ||
++ IS_OUT_OF_BOUNDS(paxel_cfg->h_start,
++ OMAP3ISP_AF_PAXEL_HZSTART_MIN,
++ OMAP3ISP_AF_PAXEL_HZSTART_MAX))
++ return -EINVAL;
++
++ /* Check IIR */
++ for (index = 0; index < OMAP3ISP_AF_NUM_COEF; index++) {
++ if ((iir_cfg->coeff_set0[index]) > OMAP3ISP_AF_COEF_MAX)
++ return -EINVAL;
++
++ if ((iir_cfg->coeff_set1[index]) > OMAP3ISP_AF_COEF_MAX)
++ return -EINVAL;
++ }
++
++ if (IS_OUT_OF_BOUNDS(iir_cfg->h_start, OMAP3ISP_AF_IIRSH_MIN,
++ OMAP3ISP_AF_IIRSH_MAX))
++ return -EINVAL;
++
++ /* Hack: If paxel size is 12, the 10th AF window may be corrupted */
++ if ((paxel_cfg->h_cnt * paxel_cfg->v_cnt > 9) &&
++ (paxel_cfg->width * paxel_cfg->height == 12))
++ return -EINVAL;
++
++ buf_size = h3a_af_get_buf_size(user_cfg);
++ if (buf_size > user_cfg->buf_size)
++ /* User buf_size request wasn't enough */
++ user_cfg->buf_size = buf_size;
++ else if (user_cfg->buf_size > OMAP3ISP_AF_MAX_BUF_SIZE)
++ user_cfg->buf_size = OMAP3ISP_AF_MAX_BUF_SIZE;
++
++ return 0;
++}
++
++/* Update local parameters */
++static void h3a_af_set_params(struct ispstat *af, void *new_conf)
++{
++ struct omap3isp_h3a_af_config *user_cfg = new_conf;
++ struct omap3isp_h3a_af_config *cur_cfg = af->priv;
++ int update = 0;
++ int index;
++
++ /* alaw */
++ if (cur_cfg->alaw_enable != user_cfg->alaw_enable) {
++ update = 1;
++ goto out;
++ }
++
++ /* hmf */
++ if (cur_cfg->hmf.enable != user_cfg->hmf.enable) {
++ update = 1;
++ goto out;
++ }
++ if (cur_cfg->hmf.threshold != user_cfg->hmf.threshold) {
++ update = 1;
++ goto out;
++ }
++
++ /* rgbpos */
++ if (cur_cfg->rgb_pos != user_cfg->rgb_pos) {
++ update = 1;
++ goto out;
++ }
++
++ /* iir */
++ if (cur_cfg->iir.h_start != user_cfg->iir.h_start) {
++ update = 1;
++ goto out;
++ }
++ for (index = 0; index < OMAP3ISP_AF_NUM_COEF; index++) {
++ if (cur_cfg->iir.coeff_set0[index] !=
++ user_cfg->iir.coeff_set0[index]) {
++ update = 1;
++ goto out;
++ }
++ if (cur_cfg->iir.coeff_set1[index] !=
++ user_cfg->iir.coeff_set1[index]) {
++ update = 1;
++ goto out;
++ }
++ }
++
++ /* paxel */
++ if ((cur_cfg->paxel.width != user_cfg->paxel.width) ||
++ (cur_cfg->paxel.height != user_cfg->paxel.height) ||
++ (cur_cfg->paxel.h_start != user_cfg->paxel.h_start) ||
++ (cur_cfg->paxel.v_start != user_cfg->paxel.v_start) ||
++ (cur_cfg->paxel.h_cnt != user_cfg->paxel.h_cnt) ||
++ (cur_cfg->paxel.v_cnt != user_cfg->paxel.v_cnt) ||
++ (cur_cfg->paxel.line_inc != user_cfg->paxel.line_inc)) {
++ update = 1;
++ goto out;
++ }
++
++ /* af_mode */
++ if (cur_cfg->fvmode != user_cfg->fvmode)
++ update = 1;
++
++out:
++ if (update || !af->configured) {
++ memcpy(cur_cfg, user_cfg, sizeof(*cur_cfg));
++ af->inc_config++;
++ af->update = 1;
++ /*
++ * User might be asked for a bigger buffer than necessary for
++ * this configuration. In order to return the right amount of
++ * data during buffer request, let's calculate the size here
++ * instead of stick with user_cfg->buf_size.
++ */
++ cur_cfg->buf_size = h3a_af_get_buf_size(cur_cfg);
++ }
++}
++
++static long h3a_af_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
++{
++ struct ispstat *stat = v4l2_get_subdevdata(sd);
++
++ switch (cmd) {
++ case VIDIOC_OMAP3ISP_AF_CFG:
++ return omap3isp_stat_config(stat, arg);
++ case VIDIOC_OMAP3ISP_STAT_REQ:
++ return omap3isp_stat_request_statistics(stat, arg);
++ case VIDIOC_OMAP3ISP_STAT_EN: {
++ int *en = arg;
++ return omap3isp_stat_enable(stat, !!*en);
++ }
++ }
++
++ return -ENOIOCTLCMD;
++
++}
++
++static const struct ispstat_ops h3a_af_ops = {
++ .validate_params = h3a_af_validate_params,
++ .set_params = h3a_af_set_params,
++ .setup_regs = h3a_af_setup_regs,
++ .enable = h3a_af_enable,
++ .busy = h3a_af_busy,
++};
++
++static const struct v4l2_subdev_core_ops h3a_af_subdev_core_ops = {
++ .ioctl = h3a_af_ioctl,
++ .subscribe_event = omap3isp_stat_subscribe_event,
++ .unsubscribe_event = omap3isp_stat_unsubscribe_event,
++};
++
++static const struct v4l2_subdev_video_ops h3a_af_subdev_video_ops = {
++ .s_stream = omap3isp_stat_s_stream,
++};
++
++static const struct v4l2_subdev_ops h3a_af_subdev_ops = {
++ .core = &h3a_af_subdev_core_ops,
++ .video = &h3a_af_subdev_video_ops,
++};
++
++/* Function to register the AF character device driver. */
++int omap3isp_h3a_af_init(struct isp_device *isp)
++{
++ struct ispstat *af = &isp->isp_af;
++ struct omap3isp_h3a_af_config *af_cfg;
++ struct omap3isp_h3a_af_config *af_recover_cfg;
++ int ret;
++
++ af_cfg = kzalloc(sizeof(*af_cfg), GFP_KERNEL);
++ if (af_cfg == NULL)
++ return -ENOMEM;
++
++ memset(af, 0, sizeof(*af));
++ af->ops = &h3a_af_ops;
++ af->priv = af_cfg;
++ af->dma_ch = -1;
++ af->event_type = V4L2_EVENT_OMAP3ISP_AF;
++ af->isp = isp;
++
++ /* Set recover state configuration */
++ af_recover_cfg = kzalloc(sizeof(*af_recover_cfg), GFP_KERNEL);
++ if (!af_recover_cfg) {
++ dev_err(af->isp->dev, "AF: cannot allocate memory for recover "
++ "configuration.\n");
++ ret = -ENOMEM;
++ goto err_recover_alloc;
++ }
++
++ af_recover_cfg->paxel.h_start = OMAP3ISP_AF_PAXEL_HZSTART_MIN;
++ af_recover_cfg->paxel.width = OMAP3ISP_AF_PAXEL_WIDTH_MIN;
++ af_recover_cfg->paxel.height = OMAP3ISP_AF_PAXEL_HEIGHT_MIN;
++ af_recover_cfg->paxel.h_cnt = OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MIN;
++ af_recover_cfg->paxel.v_cnt = OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MIN;
++ af_recover_cfg->paxel.line_inc = OMAP3ISP_AF_PAXEL_INCREMENT_MIN;
++ if (h3a_af_validate_params(af, af_recover_cfg)) {
++ dev_err(af->isp->dev, "AF: recover configuration is "
++ "invalid.\n");
++ ret = -EINVAL;
++ goto err_conf;
++ }
++
++ af_recover_cfg->buf_size = h3a_af_get_buf_size(af_recover_cfg);
++ af->recover_priv = af_recover_cfg;
++
++ ret = omap3isp_stat_init(af, "AF", &h3a_af_subdev_ops);
++ if (ret)
++ goto err_conf;
++
++ return 0;
++
++err_conf:
++ kfree(af_recover_cfg);
++err_recover_alloc:
++ kfree(af_cfg);
++
++ return ret;
++}
++
++void omap3isp_h3a_af_cleanup(struct isp_device *isp)
++{
++ kfree(isp->isp_af.priv);
++ kfree(isp->isp_af.recover_priv);
++ omap3isp_stat_free(&isp->isp_af);
++}
+diff --git a/drivers/media/video/isp/isphist.c b/drivers/media/video/isp/isphist.c
+new file mode 100644
+index 0000000..a43eb92
+--- /dev/null
++++ b/drivers/media/video/isp/isphist.c
+@@ -0,0 +1,520 @@
++/*
++ * isphist.c
++ *
++ * TI OMAP3 ISP - Histogram module
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc.
++ *
++ * Contacts: David Cohen <david.cohen@nokia.com>
++ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++#include <linux/device.h>
++
++#include "isp.h"
++#include "ispreg.h"
++#include "isphist.h"
++
++#define HIST_CONFIG_DMA 1
++
++#define HIST_USING_DMA(hist) ((hist)->dma_ch >= 0)
++
++/*
++ * hist_reset_mem - clear Histogram memory before start stats engine.
++ */
++static void hist_reset_mem(struct ispstat *hist)
++{
++ struct isp_device *isp = hist->isp;
++ struct omap3isp_hist_config *conf = hist->priv;
++ unsigned int i;
++
++ isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
++
++ /*
++ * By setting it, the histogram internal buffer is being cleared at the
++ * same time it's being read. This bit must be cleared afterwards.
++ */
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR);
++
++ /*
++ * We'll clear 4 words at each iteration for optimization. It avoids
++ * 3/4 of the jumps. We also know HIST_MEM_SIZE is divisible by 4.
++ */
++ for (i = OMAP3ISP_HIST_MEM_SIZE / 4; i > 0; i--) {
++ isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
++ isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
++ isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
++ isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
++ }
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR);
++
++ hist->wait_acc_frames = conf->num_acc_frames;
++}
++
++static void hist_dma_config(struct ispstat *hist)
++{
++ hist->dma_config.data_type = OMAP_DMA_DATA_TYPE_S32;
++ hist->dma_config.sync_mode = OMAP_DMA_SYNC_ELEMENT;
++ hist->dma_config.frame_count = 1;
++ hist->dma_config.src_amode = OMAP_DMA_AMODE_CONSTANT;
++ hist->dma_config.src_start = OMAP3ISP_HIST_REG_BASE + ISPHIST_DATA;
++ hist->dma_config.dst_amode = OMAP_DMA_AMODE_POST_INC;
++ hist->dma_config.src_or_dst_synch = OMAP_DMA_SRC_SYNC;
++}
++
++/*
++ * hist_setup_regs - Helper function to update Histogram registers.
++ */
++static void hist_setup_regs(struct ispstat *hist, void *priv)
++{
++ struct isp_device *isp = hist->isp;
++ struct omap3isp_hist_config *conf = priv;
++ int c;
++ u32 cnt;
++ u32 wb_gain;
++ u32 reg_hor[OMAP3ISP_HIST_MAX_REGIONS];
++ u32 reg_ver[OMAP3ISP_HIST_MAX_REGIONS];
++
++ if (!hist->update || hist->state == ISPSTAT_DISABLED ||
++ hist->state == ISPSTAT_DISABLING)
++ return;
++
++ cnt = conf->cfa << ISPHIST_CNT_CFA_SHIFT;
++
++ wb_gain = conf->wg[0] << ISPHIST_WB_GAIN_WG00_SHIFT;
++ wb_gain |= conf->wg[1] << ISPHIST_WB_GAIN_WG01_SHIFT;
++ wb_gain |= conf->wg[2] << ISPHIST_WB_GAIN_WG02_SHIFT;
++ if (conf->cfa == OMAP3ISP_HIST_CFA_BAYER)
++ wb_gain |= conf->wg[3] << ISPHIST_WB_GAIN_WG03_SHIFT;
++
++ /* Regions size and position */
++ for (c = 0; c < OMAP3ISP_HIST_MAX_REGIONS; c++) {
++ if (c < conf->num_regions) {
++ reg_hor[c] = conf->region[c].h_start <<
++ ISPHIST_REG_START_SHIFT;
++ reg_hor[c] = conf->region[c].h_end <<
++ ISPHIST_REG_END_SHIFT;
++ reg_ver[c] = conf->region[c].v_start <<
++ ISPHIST_REG_START_SHIFT;
++ reg_ver[c] = conf->region[c].v_end <<
++ ISPHIST_REG_END_SHIFT;
++ } else {
++ reg_hor[c] = 0;
++ reg_ver[c] = 0;
++ }
++ }
++
++ cnt |= conf->hist_bins << ISPHIST_CNT_BINS_SHIFT;
++ switch (conf->hist_bins) {
++ case OMAP3ISP_HIST_BINS_256:
++ cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 8) <<
++ ISPHIST_CNT_SHIFT_SHIFT;
++ break;
++ case OMAP3ISP_HIST_BINS_128:
++ cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 7) <<
++ ISPHIST_CNT_SHIFT_SHIFT;
++ break;
++ case OMAP3ISP_HIST_BINS_64:
++ cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 6) <<
++ ISPHIST_CNT_SHIFT_SHIFT;
++ break;
++ default: /* OMAP3ISP_HIST_BINS_32 */
++ cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 5) <<
++ ISPHIST_CNT_SHIFT_SHIFT;
++ break;
++ }
++
++ hist_reset_mem(hist);
++
++ isp_reg_writel(isp, cnt, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT);
++ isp_reg_writel(isp, wb_gain, OMAP3_ISP_IOMEM_HIST, ISPHIST_WB_GAIN);
++ isp_reg_writel(isp, reg_hor[0], OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_HORZ);
++ isp_reg_writel(isp, reg_ver[0], OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_VERT);
++ isp_reg_writel(isp, reg_hor[1], OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_HORZ);
++ isp_reg_writel(isp, reg_ver[1], OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_VERT);
++ isp_reg_writel(isp, reg_hor[2], OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_HORZ);
++ isp_reg_writel(isp, reg_ver[2], OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_VERT);
++ isp_reg_writel(isp, reg_hor[3], OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_HORZ);
++ isp_reg_writel(isp, reg_ver[3], OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_VERT);
++
++ hist->update = 0;
++ hist->config_counter += hist->inc_config;
++ hist->inc_config = 0;
++ hist->buf_size = conf->buf_size;
++}
++
++static void hist_enable(struct ispstat *hist, int enable)
++{
++ if (enable) {
++ isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR,
++ ISPHIST_PCR_ENABLE);
++ isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
++ ISPCTRL_HIST_CLK_EN);
++ } else {
++ isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR,
++ ISPHIST_PCR_ENABLE);
++ isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
++ ISPCTRL_HIST_CLK_EN);
++ }
++}
++
++static int hist_busy(struct ispstat *hist)
++{
++ return isp_reg_readl(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR)
++ & ISPHIST_PCR_BUSY;
++}
++
++static void hist_dma_cb(int lch, u16 ch_status, void *data)
++{
++ struct ispstat *hist = data;
++
++ if (ch_status & ~OMAP_DMA_BLOCK_IRQ) {
++ dev_dbg(hist->isp->dev, "hist: DMA error. status = 0x%04x\n",
++ ch_status);
++ omap_stop_dma(lch);
++ hist_reset_mem(hist);
++ atomic_set(&hist->buf_err, 1);
++ }
++ isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
++ ISPHIST_CNT_CLEAR);
++
++ omap3isp_stat_dma_isr(hist);
++ if (hist->state != ISPSTAT_DISABLED)
++ omap3isp_hist_dma_done(hist->isp);
++}
++
++static int hist_buf_dma(struct ispstat *hist)
++{
++ dma_addr_t dma_addr = hist->active_buf->dma_addr;
++
++ if (unlikely(!dma_addr)) {
++ dev_dbg(hist->isp->dev, "hist: invalid DMA buffer address\n");
++ hist_reset_mem(hist);
++ return STAT_NO_BUF;
++ }
++
++ isp_reg_writel(hist->isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
++ isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
++ ISPHIST_CNT_CLEAR);
++ omap3isp_flush(hist->isp);
++ hist->dma_config.dst_start = dma_addr;
++ hist->dma_config.elem_count = hist->buf_size / sizeof(u32);
++ omap_set_dma_params(hist->dma_ch, &hist->dma_config);
++
++ omap_start_dma(hist->dma_ch);
++
++ return STAT_BUF_WAITING_DMA;
++}
++
++static int hist_buf_pio(struct ispstat *hist)
++{
++ struct isp_device *isp = hist->isp;
++ u32 *buf = hist->active_buf->virt_addr;
++ unsigned int i;
++
++ if (!buf) {
++ dev_dbg(isp->dev, "hist: invalid PIO buffer address\n");
++ hist_reset_mem(hist);
++ return STAT_NO_BUF;
++ }
++
++ isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
++
++ /*
++ * By setting it, the histogram internal buffer is being cleared at the
++ * same time it's being read. This bit must be cleared just after all
++ * data is acquired.
++ */
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR);
++
++ /*
++ * We'll read 4 times a 4-bytes-word at each iteration for
++ * optimization. It avoids 3/4 of the jumps. We also know buf_size is
++ * divisible by 16.
++ */
++ for (i = hist->buf_size / 16; i > 0; i--) {
++ *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
++ *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
++ *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
++ *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
++ }
++ isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
++ ISPHIST_CNT_CLEAR);
++
++ return STAT_BUF_DONE;
++}
++
++/*
++ * hist_buf_process - Callback from ISP driver for HIST interrupt.
++ */
++static int hist_buf_process(struct ispstat *hist)
++{
++ struct omap3isp_hist_config *user_cfg = hist->priv;
++ int ret;
++
++ if (atomic_read(&hist->buf_err) || hist->state != ISPSTAT_ENABLED) {
++ hist_reset_mem(hist);
++ return STAT_NO_BUF;
++ }
++
++ if (--(hist->wait_acc_frames))
++ return STAT_NO_BUF;
++
++ if (HIST_USING_DMA(hist))
++ ret = hist_buf_dma(hist);
++ else
++ ret = hist_buf_pio(hist);
++
++ hist->wait_acc_frames = user_cfg->num_acc_frames;
++
++ return ret;
++}
++
++static u32 hist_get_buf_size(struct omap3isp_hist_config *conf)
++{
++ return OMAP3ISP_HIST_MEM_SIZE_BINS(conf->hist_bins) * conf->num_regions;
++}
++
++/*
++ * hist_validate_params - Helper function to check user given params.
++ * @user_cfg: Pointer to user configuration structure.
++ *
++ * Returns 0 on success configuration.
++ */
++static int hist_validate_params(struct ispstat *hist, void *new_conf)
++{
++ struct omap3isp_hist_config *user_cfg = new_conf;
++ int c;
++ u32 buf_size;
++
++ if (user_cfg->cfa > OMAP3ISP_HIST_CFA_FOVEONX3)
++ return -EINVAL;
++
++ /* Regions size and position */
++
++ if ((user_cfg->num_regions < OMAP3ISP_HIST_MIN_REGIONS) ||
++ (user_cfg->num_regions > OMAP3ISP_HIST_MAX_REGIONS))
++ return -EINVAL;
++
++ /* Regions */
++ for (c = 0; c < user_cfg->num_regions; c++) {
++ if (user_cfg->region[c].h_start & ~ISPHIST_REG_START_END_MASK)
++ return -EINVAL;
++ if (user_cfg->region[c].h_end & ~ISPHIST_REG_START_END_MASK)
++ return -EINVAL;
++ if (user_cfg->region[c].v_start & ~ISPHIST_REG_START_END_MASK)
++ return -EINVAL;
++ if (user_cfg->region[c].v_end & ~ISPHIST_REG_START_END_MASK)
++ return -EINVAL;
++ if (user_cfg->region[c].h_start > user_cfg->region[c].h_end)
++ return -EINVAL;
++ if (user_cfg->region[c].v_start > user_cfg->region[c].v_end)
++ return -EINVAL;
++ }
++
++ switch (user_cfg->num_regions) {
++ case 1:
++ if (user_cfg->hist_bins > OMAP3ISP_HIST_BINS_256)
++ return -EINVAL;
++ break;
++ case 2:
++ if (user_cfg->hist_bins > OMAP3ISP_HIST_BINS_128)
++ return -EINVAL;
++ break;
++ default: /* 3 or 4 */
++ if (user_cfg->hist_bins > OMAP3ISP_HIST_BINS_64)
++ return -EINVAL;
++ break;
++ }
++
++ buf_size = hist_get_buf_size(user_cfg);
++ if (buf_size > user_cfg->buf_size)
++ /* User's buf_size request wasn't enoght */
++ user_cfg->buf_size = buf_size;
++ else if (user_cfg->buf_size > OMAP3ISP_HIST_MAX_BUF_SIZE)
++ user_cfg->buf_size = OMAP3ISP_HIST_MAX_BUF_SIZE;
++
++ return 0;
++}
++
++static int hist_comp_params(struct ispstat *hist,
++ struct omap3isp_hist_config *user_cfg)
++{
++ struct omap3isp_hist_config *cur_cfg = hist->priv;
++ int c;
++
++ if (cur_cfg->cfa != user_cfg->cfa)
++ return 1;
++
++ if (cur_cfg->num_acc_frames != user_cfg->num_acc_frames)
++ return 1;
++
++ if (cur_cfg->hist_bins != user_cfg->hist_bins)
++ return 1;
++
++ for (c = 0; c < OMAP3ISP_HIST_MAX_WG; c++) {
++ if (c == 3 && user_cfg->cfa == OMAP3ISP_HIST_CFA_FOVEONX3)
++ break;
++ else if (cur_cfg->wg[c] != user_cfg->wg[c])
++ return 1;
++ }
++
++ if (cur_cfg->num_regions != user_cfg->num_regions)
++ return 1;
++
++ /* Regions */
++ for (c = 0; c < user_cfg->num_regions; c++) {
++ if (cur_cfg->region[c].h_start != user_cfg->region[c].h_start)
++ return 1;
++ if (cur_cfg->region[c].h_end != user_cfg->region[c].h_end)
++ return 1;
++ if (cur_cfg->region[c].v_start != user_cfg->region[c].v_start)
++ return 1;
++ if (cur_cfg->region[c].v_end != user_cfg->region[c].v_end)
++ return 1;
++ }
++
++ return 0;
++}
++
++/*
++ * hist_update_params - Helper function to check and store user given params.
++ * @new_conf: Pointer to user configuration structure.
++ */
++static void hist_set_params(struct ispstat *hist, void *new_conf)
++{
++ struct omap3isp_hist_config *user_cfg = new_conf;
++ struct omap3isp_hist_config *cur_cfg = hist->priv;
++
++ if (!hist->configured || hist_comp_params(hist, user_cfg)) {
++ memcpy(cur_cfg, user_cfg, sizeof(*user_cfg));
++ if (user_cfg->num_acc_frames == 0)
++ user_cfg->num_acc_frames = 1;
++ hist->inc_config++;
++ hist->update = 1;
++ /*
++ * User might be asked for a bigger buffer than necessary for
++ * this configuration. In order to return the right amount of
++ * data during buffer request, let's calculate the size here
++ * instead of stick with user_cfg->buf_size.
++ */
++ cur_cfg->buf_size = hist_get_buf_size(cur_cfg);
++
++ }
++}
++
++static long hist_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
++{
++ struct ispstat *stat = v4l2_get_subdevdata(sd);
++
++ switch (cmd) {
++ case VIDIOC_OMAP3ISP_HIST_CFG:
++ return omap3isp_stat_config(stat, arg);
++ case VIDIOC_OMAP3ISP_STAT_REQ:
++ return omap3isp_stat_request_statistics(stat, arg);
++ case VIDIOC_OMAP3ISP_STAT_EN: {
++ int *en = arg;
++ return omap3isp_stat_enable(stat, !!*en);
++ }
++ }
++
++ return -ENOIOCTLCMD;
++
++}
++
++static const struct ispstat_ops hist_ops = {
++ .validate_params = hist_validate_params,
++ .set_params = hist_set_params,
++ .setup_regs = hist_setup_regs,
++ .enable = hist_enable,
++ .busy = hist_busy,
++ .buf_process = hist_buf_process,
++};
++
++static const struct v4l2_subdev_core_ops hist_subdev_core_ops = {
++ .ioctl = hist_ioctl,
++ .subscribe_event = omap3isp_stat_subscribe_event,
++ .unsubscribe_event = omap3isp_stat_unsubscribe_event,
++};
++
++static const struct v4l2_subdev_video_ops hist_subdev_video_ops = {
++ .s_stream = omap3isp_stat_s_stream,
++};
++
++static const struct v4l2_subdev_ops hist_subdev_ops = {
++ .core = &hist_subdev_core_ops,
++ .video = &hist_subdev_video_ops,
++};
++
++/*
++ * omap3isp_hist_init - Module Initialization.
++ */
++int omap3isp_hist_init(struct isp_device *isp)
++{
++ struct ispstat *hist = &isp->isp_hist;
++ struct omap3isp_hist_config *hist_cfg;
++ int ret = -1;
++
++ hist_cfg = kzalloc(sizeof(*hist_cfg), GFP_KERNEL);
++ if (hist_cfg == NULL)
++ return -ENOMEM;
++
++ memset(hist, 0, sizeof(*hist));
++ if (HIST_CONFIG_DMA)
++ ret = omap_request_dma(OMAP24XX_DMA_NO_DEVICE, "DMA_ISP_HIST",
++ hist_dma_cb, hist, &hist->dma_ch);
++ if (ret) {
++ if (HIST_CONFIG_DMA)
++ dev_warn(isp->dev, "hist: DMA request channel failed. "
++ "Using PIO only.\n");
++ hist->dma_ch = -1;
++ } else {
++ dev_dbg(isp->dev, "hist: DMA channel = %d\n", hist->dma_ch);
++ hist_dma_config(hist);
++ omap_enable_dma_irq(hist->dma_ch, OMAP_DMA_BLOCK_IRQ);
++ }
++
++ hist->ops = &hist_ops;
++ hist->priv = hist_cfg;
++ hist->event_type = V4L2_EVENT_OMAP3ISP_HIST;
++ hist->isp = isp;
++
++ ret = omap3isp_stat_init(hist, "histogram", &hist_subdev_ops);
++ if (ret) {
++ kfree(hist_cfg);
++ if (HIST_USING_DMA(hist))
++ omap_free_dma(hist->dma_ch);
++ }
++
++ return ret;
++}
++
++/*
++ * omap3isp_hist_cleanup - Module cleanup.
++ */
++void omap3isp_hist_cleanup(struct isp_device *isp)
++{
++ if (HIST_USING_DMA(&isp->isp_hist))
++ omap_free_dma(isp->isp_hist.dma_ch);
++ kfree(isp->isp_hist.priv);
++ omap3isp_stat_free(&isp->isp_hist);
++}
+diff --git a/drivers/media/video/isp/isphist.h b/drivers/media/video/isp/isphist.h
+new file mode 100644
+index 0000000..247192b
+--- /dev/null
++++ b/drivers/media/video/isp/isphist.h
+@@ -0,0 +1,40 @@
++/*
++ * isphist.h
++ *
++ * TI OMAP3 ISP - Histogram module
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc.
++ *
++ * Contacts: David Cohen <david.cohen@nokia.com>
++ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#ifndef OMAP3_ISP_HIST_H
++#define OMAP3_ISP_HIST_H
++
++#include <linux/omap3isp.h>
++
++#define ISPHIST_IN_BIT_WIDTH_CCDC 10
++
++struct isp_device;
++
++int omap3isp_hist_init(struct isp_device *isp);
++void omap3isp_hist_cleanup(struct isp_device *isp);
++
++#endif /* OMAP3_ISP_HIST */
+diff --git a/drivers/media/video/isp/isppreview.c b/drivers/media/video/isp/isppreview.c
+new file mode 100644
+index 0000000..869583c
+--- /dev/null
++++ b/drivers/media/video/isp/isppreview.c
+@@ -0,0 +1,2120 @@
++/*
++ * isppreview.c
++ *
++ * TI OMAP3 ISP driver - Preview module
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc.
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#include <linux/device.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/uaccess.h>
++
++#include "isp.h"
++#include "ispreg.h"
++#include "isppreview.h"
++
++/* Default values in Office Flourescent Light for RGBtoRGB Blending */
++static struct omap3isp_prev_rgbtorgb flr_rgb2rgb = {
++ { /* RGB-RGB Matrix */
++ {0x01E2, 0x0F30, 0x0FEE},
++ {0x0F9B, 0x01AC, 0x0FB9},
++ {0x0FE0, 0x0EC0, 0x0260}
++ }, /* RGB Offset */
++ {0x0000, 0x0000, 0x0000}
++};
++
++/* Default values in Office Flourescent Light for RGB to YUV Conversion*/
++static struct omap3isp_prev_csc flr_prev_csc = {
++ { /* CSC Coef Matrix */
++ {66, 129, 25},
++ {-38, -75, 112},
++ {112, -94 , -18}
++ }, /* CSC Offset */
++ {0x0, 0x0, 0x0}
++};
++
++/* Default values in Office Flourescent Light for CFA Gradient*/
++#define FLR_CFA_GRADTHRS_HORZ 0x28
++#define FLR_CFA_GRADTHRS_VERT 0x28
++
++/* Default values in Office Flourescent Light for Chroma Suppression*/
++#define FLR_CSUP_GAIN 0x0D
++#define FLR_CSUP_THRES 0xEB
++
++/* Default values in Office Flourescent Light for Noise Filter*/
++#define FLR_NF_STRGTH 0x03
++
++/* Default values for White Balance */
++#define FLR_WBAL_DGAIN 0x100
++#define FLR_WBAL_COEF 0x20
++
++/* Default values in Office Flourescent Light for Black Adjustment*/
++#define FLR_BLKADJ_BLUE 0x0
++#define FLR_BLKADJ_GREEN 0x0
++#define FLR_BLKADJ_RED 0x0
++
++#define DEF_DETECT_CORRECT_VAL 0xe
++
++#define PREV_MIN_WIDTH 64
++#define PREV_MIN_HEIGHT 8
++#define PREV_MAX_HEIGHT 16384
++
++/*
++ * Coeficient Tables for the submodules in Preview.
++ * Array is initialised with the values from.the tables text file.
++ */
++
++/*
++ * CFA Filter Coefficient Table
++ *
++ */
++static u32 cfa_coef_table[] = {
++#include "cfa_coef_table.h"
++};
++
++/*
++ * Default Gamma Correction Table - All components
++ */
++static u32 gamma_table[] = {
++#include "gamma_table.h"
++};
++
++/*
++ * Noise Filter Threshold table
++ */
++static u32 noise_filter_table[] = {
++#include "noise_filter_table.h"
++};
++
++/*
++ * Luminance Enhancement Table
++ */
++static u32 luma_enhance_table[] = {
++#include "luma_enhance_table.h"
++};
++
++/*
++ * preview_enable_invalaw - Enable/Disable Inverse A-Law module in Preview.
++ * @enable: 1 - Reverse the A-Law done in CCDC.
++ */
++static void
++preview_enable_invalaw(struct isp_prev_device *prev, u8 enable)
++{
++ struct isp_device *isp = to_isp_device(prev);
++
++ if (enable)
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW);
++ else
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW);
++}
++
++/*
++ * preview_enable_drkframe_capture - Enable/Disable of the darkframe capture.
++ * @prev -
++ * @enable: 1 - Enable, 0 - Disable
++ *
++ * NOTE: PRV_WSDR_ADDR and PRV_WADD_OFFSET must be set also
++ * The proccess is applied for each captured frame.
++ */
++static void
++preview_enable_drkframe_capture(struct isp_prev_device *prev, u8 enable)
++{
++ struct isp_device *isp = to_isp_device(prev);
++
++ if (enable)
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_DRKFCAP);
++ else
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_DRKFCAP);
++}
++
++/*
++ * preview_enable_drkframe - Enable/Disable of the darkframe subtract.
++ * @enable: 1 - Acquires memory bandwidth since the pixels in each frame is
++ * subtracted with the pixels in the current frame.
++ *
++ * The proccess is applied for each captured frame.
++ */
++static void
++preview_enable_drkframe(struct isp_prev_device *prev, u8 enable)
++{
++ struct isp_device *isp = to_isp_device(prev);
++
++ if (enable)
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_DRKFEN);
++ else
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_DRKFEN);
++}
++
++/*
++ * preview_config_drkf_shadcomp - Configures shift value in shading comp.
++ * @scomp_shtval: 3bit value of shift used in shading compensation.
++ */
++static void
++preview_config_drkf_shadcomp(struct isp_prev_device *prev,
++ const void *scomp_shtval)
++{
++ struct isp_device *isp = to_isp_device(prev);
++ const u32 *shtval = scomp_shtval;
++
++ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_SCOMP_SFT_MASK,
++ *shtval << ISPPRV_PCR_SCOMP_SFT_SHIFT);
++}
++
++/*
++ * preview_enable_hmed - Enables/Disables of the Horizontal Median Filter.
++ * @enable: 1 - Enables Horizontal Median Filter.
++ */
++static void
++preview_enable_hmed(struct isp_prev_device *prev, u8 enable)
++{
++ struct isp_device *isp = to_isp_device(prev);
++
++ if (enable)
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_HMEDEN);
++ else
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_HMEDEN);
++}
++
++/*
++ * preview_config_hmed - Configures the Horizontal Median Filter.
++ * @prev_hmed: Structure containing the odd and even distance between the
++ * pixels in the image along with the filter threshold.
++ */
++static void
++preview_config_hmed(struct isp_prev_device *prev, const void *prev_hmed)
++{
++ struct isp_device *isp = to_isp_device(prev);
++ const struct omap3isp_prev_hmed *hmed = prev_hmed;
++
++ isp_reg_writel(isp, (hmed->odddist == 1 ? 0 : ISPPRV_HMED_ODDDIST) |
++ (hmed->evendist == 1 ? 0 : ISPPRV_HMED_EVENDIST) |
++ (hmed->thres << ISPPRV_HMED_THRESHOLD_SHIFT),
++ OMAP3_ISP_IOMEM_PREV, ISPPRV_HMED);
++}
++
++/*
++ * preview_config_noisefilter - Configures the Noise Filter.
++ * @prev_nf: Structure containing the noisefilter table, strength to be used
++ * for the noise filter and the defect correction enable flag.
++ */
++static void
++preview_config_noisefilter(struct isp_prev_device *prev, const void *prev_nf)
++{
++ struct isp_device *isp = to_isp_device(prev);
++ const struct omap3isp_prev_nf *nf = prev_nf;
++ unsigned int i;
++
++ isp_reg_writel(isp, nf->spread, OMAP3_ISP_IOMEM_PREV, ISPPRV_NF);
++ isp_reg_writel(isp, ISPPRV_NF_TABLE_ADDR,
++ OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
++ for (i = 0; i < OMAP3ISP_PREV_NF_TBL_SIZE; i++) {
++ isp_reg_writel(isp, nf->table[i],
++ OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
++ }
++}
++
++/*
++ * preview_config_dcor - Configures the defect correction
++ * @prev_dcor: Structure containing the defect correct thresholds
++ */
++static void
++preview_config_dcor(struct isp_prev_device *prev, const void *prev_dcor)
++{
++ struct isp_device *isp = to_isp_device(prev);
++ const struct omap3isp_prev_dcor *dcor = prev_dcor;
++
++ isp_reg_writel(isp, dcor->detect_correct[0],
++ OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR0);
++ isp_reg_writel(isp, dcor->detect_correct[1],
++ OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR1);
++ isp_reg_writel(isp, dcor->detect_correct[2],
++ OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR2);
++ isp_reg_writel(isp, dcor->detect_correct[3],
++ OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR3);
++ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_DCCOUP,
++ dcor->couplet_mode_en ? ISPPRV_PCR_DCCOUP : 0);
++}
++
++/*
++ * preview_config_cfa - Configures the CFA Interpolation parameters.
++ * @prev_cfa: Structure containing the CFA interpolation table, CFA format
++ * in the image, vertical and horizontal gradient threshold.
++ */
++static void
++preview_config_cfa(struct isp_prev_device *prev, const void *prev_cfa)
++{
++ struct isp_device *isp = to_isp_device(prev);
++ const struct omap3isp_prev_cfa *cfa = prev_cfa;
++ unsigned int i;
++
++ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_CFAFMT_MASK,
++ cfa->format << ISPPRV_PCR_CFAFMT_SHIFT);
++
++ isp_reg_writel(isp,
++ (cfa->gradthrs_vert << ISPPRV_CFA_GRADTH_VER_SHIFT) |
++ (cfa->gradthrs_horz << ISPPRV_CFA_GRADTH_HOR_SHIFT),
++ OMAP3_ISP_IOMEM_PREV, ISPPRV_CFA);
++
++ isp_reg_writel(isp, ISPPRV_CFA_TABLE_ADDR,
++ OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
++
++ for (i = 0; i < OMAP3ISP_PREV_CFA_TBL_SIZE; i++) {
++ isp_reg_writel(isp, cfa->table[i],
++ OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
++ }
++}
++
++/*
++ * preview_config_gammacorrn - Configures the Gamma Correction table values
++ * @gtable: Structure containing the table for red, blue, green gamma table.
++ */
++static void
++preview_config_gammacorrn(struct isp_prev_device *prev, const void *gtable)
++{
++ struct isp_device *isp = to_isp_device(prev);
++ const struct omap3isp_prev_gtables *gt = gtable;
++ unsigned int i;
++
++ isp_reg_writel(isp, ISPPRV_REDGAMMA_TABLE_ADDR,
++ OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
++ for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
++ isp_reg_writel(isp, gt->red[i], OMAP3_ISP_IOMEM_PREV,
++ ISPPRV_SET_TBL_DATA);
++
++ isp_reg_writel(isp, ISPPRV_GREENGAMMA_TABLE_ADDR,
++ OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
++ for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
++ isp_reg_writel(isp, gt->green[i], OMAP3_ISP_IOMEM_PREV,
++ ISPPRV_SET_TBL_DATA);
++
++ isp_reg_writel(isp, ISPPRV_BLUEGAMMA_TABLE_ADDR,
++ OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
++ for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
++ isp_reg_writel(isp, gt->blue[i], OMAP3_ISP_IOMEM_PREV,
++ ISPPRV_SET_TBL_DATA);
++}
++
++/*
++ * preview_config_luma_enhancement - Sets the Luminance Enhancement table.
++ * @ytable: Structure containing the table for Luminance Enhancement table.
++ */
++static void
++preview_config_luma_enhancement(struct isp_prev_device *prev,
++ const void *ytable)
++{
++ struct isp_device *isp = to_isp_device(prev);
++ const struct omap3isp_prev_luma *yt = ytable;
++ unsigned int i;
++
++ isp_reg_writel(isp, ISPPRV_YENH_TABLE_ADDR,
++ OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
++ for (i = 0; i < OMAP3ISP_PREV_YENH_TBL_SIZE; i++) {
++ isp_reg_writel(isp, yt->table[i],
++ OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
++ }
++}
++
++/*
++ * preview_config_chroma_suppression - Configures the Chroma Suppression.
++ * @csup: Structure containing the threshold value for suppression
++ * and the hypass filter enable flag.
++ */
++static void
++preview_config_chroma_suppression(struct isp_prev_device *prev,
++ const void *csup)
++{
++ struct isp_device *isp = to_isp_device(prev);
++ const struct omap3isp_prev_csup *cs = csup;
++
++ isp_reg_writel(isp,
++ cs->gain | (cs->thres << ISPPRV_CSUP_THRES_SHIFT) |
++ (cs->hypf_en << ISPPRV_CSUP_HPYF_SHIFT),
++ OMAP3_ISP_IOMEM_PREV, ISPPRV_CSUP);
++}
++
++/*
++ * preview_enable_noisefilter - Enables/Disables the Noise Filter.
++ * @enable: 1 - Enables the Noise Filter.
++ */
++static void
++preview_enable_noisefilter(struct isp_prev_device *prev, u8 enable)
++{
++ struct isp_device *isp = to_isp_device(prev);
++
++ if (enable)
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_NFEN);
++ else
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_NFEN);
++}
++
++/*
++ * preview_enable_dcor - Enables/Disables the defect correction.
++ * @enable: 1 - Enables the defect correction.
++ */
++static void
++preview_enable_dcor(struct isp_prev_device *prev, u8 enable)
++{
++ struct isp_device *isp = to_isp_device(prev);
++
++ if (enable)
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_DCOREN);
++ else
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_DCOREN);
++}
++
++/*
++ * preview_enable_cfa - Enable/Disable the CFA Interpolation.
++ * @enable: 1 - Enables the CFA.
++ */
++static void
++preview_enable_cfa(struct isp_prev_device *prev, u8 enable)
++{
++ struct isp_device *isp = to_isp_device(prev);
++
++ if (enable)
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_CFAEN);
++ else
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_CFAEN);
++}
++
++/*
++ * preview_enable_gammabypass - Enables/Disables the GammaByPass
++ * @enable: 1 - Bypasses Gamma - 10bit input is cropped to 8MSB.
++ * 0 - Goes through Gamma Correction. input and output is 10bit.
++ */
++static void
++preview_enable_gammabypass(struct isp_prev_device *prev, u8 enable)
++{
++ struct isp_device *isp = to_isp_device(prev);
++
++ if (enable)
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_GAMMA_BYPASS);
++ else
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_GAMMA_BYPASS);
++}
++
++/*
++ * preview_enable_luma_enhancement - Enables/Disables Luminance Enhancement
++ * @enable: 1 - Enable the Luminance Enhancement.
++ */
++static void
++preview_enable_luma_enhancement(struct isp_prev_device *prev, u8 enable)
++{
++ struct isp_device *isp = to_isp_device(prev);
++
++ if (enable)
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_YNENHEN);
++ else
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_YNENHEN);
++}
++
++/*
++ * preview_enable_chroma_suppression - Enables/Disables Chrominance Suppr.
++ * @enable: 1 - Enable the Chrominance Suppression.
++ */
++static void
++preview_enable_chroma_suppression(struct isp_prev_device *prev, u8 enable)
++{
++ struct isp_device *isp = to_isp_device(prev);
++
++ if (enable)
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_SUPEN);
++ else
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_SUPEN);
++}
++
++/*
++ * preview_config_whitebalance - Configures the White Balance parameters.
++ * @prev_wbal: Structure containing the digital gain and white balance
++ * coefficient.
++ *
++ * Coefficient matrix always with default values.
++ */
++static void
++preview_config_whitebalance(struct isp_prev_device *prev, const void *prev_wbal)
++{
++ struct isp_device *isp = to_isp_device(prev);
++ const struct omap3isp_prev_wbal *wbal = prev_wbal;
++ u32 val;
++
++ isp_reg_writel(isp, wbal->dgain, OMAP3_ISP_IOMEM_PREV, ISPPRV_WB_DGAIN);
++
++ val = wbal->coef0 << ISPPRV_WBGAIN_COEF0_SHIFT;
++ val |= wbal->coef1 << ISPPRV_WBGAIN_COEF1_SHIFT;
++ val |= wbal->coef2 << ISPPRV_WBGAIN_COEF2_SHIFT;
++ val |= wbal->coef3 << ISPPRV_WBGAIN_COEF3_SHIFT;
++ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_WBGAIN);
++
++ isp_reg_writel(isp,
++ ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_0_SHIFT |
++ ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_1_SHIFT |
++ ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_2_SHIFT |
++ ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_3_SHIFT |
++ ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_0_SHIFT |
++ ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_1_SHIFT |
++ ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_2_SHIFT |
++ ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_3_SHIFT |
++ ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_0_SHIFT |
++ ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_1_SHIFT |
++ ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_2_SHIFT |
++ ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_3_SHIFT |
++ ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_0_SHIFT |
++ ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_1_SHIFT |
++ ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_2_SHIFT |
++ ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_3_SHIFT,
++ OMAP3_ISP_IOMEM_PREV, ISPPRV_WBSEL);
++}
++
++/*
++ * preview_config_blkadj - Configures the Black Adjustment parameters.
++ * @prev_blkadj: Structure containing the black adjustment towards red, green,
++ * blue.
++ */
++static void
++preview_config_blkadj(struct isp_prev_device *prev, const void *prev_blkadj)
++{
++ struct isp_device *isp = to_isp_device(prev);
++ const struct omap3isp_prev_blkadj *blkadj = prev_blkadj;
++
++ isp_reg_writel(isp, (blkadj->blue << ISPPRV_BLKADJOFF_B_SHIFT) |
++ (blkadj->green << ISPPRV_BLKADJOFF_G_SHIFT) |
++ (blkadj->red << ISPPRV_BLKADJOFF_R_SHIFT),
++ OMAP3_ISP_IOMEM_PREV, ISPPRV_BLKADJOFF);
++}
++
++/*
++ * preview_config_rgb_blending - Configures the RGB-RGB Blending matrix.
++ * @rgb2rgb: Structure containing the rgb to rgb blending matrix and the rgb
++ * offset.
++ */
++static void
++preview_config_rgb_blending(struct isp_prev_device *prev, const void *rgb2rgb)
++{
++ struct isp_device *isp = to_isp_device(prev);
++ const struct omap3isp_prev_rgbtorgb *rgbrgb = rgb2rgb;
++ u32 val;
++
++ val = (rgbrgb->matrix[0][0] & 0xfff) << ISPPRV_RGB_MAT1_MTX_RR_SHIFT;
++ val |= (rgbrgb->matrix[0][1] & 0xfff) << ISPPRV_RGB_MAT1_MTX_GR_SHIFT;
++ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT1);
++
++ val = (rgbrgb->matrix[0][2] & 0xfff) << ISPPRV_RGB_MAT2_MTX_BR_SHIFT;
++ val |= (rgbrgb->matrix[1][0] & 0xfff) << ISPPRV_RGB_MAT2_MTX_RG_SHIFT;
++ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT2);
++
++ val = (rgbrgb->matrix[1][1] & 0xfff) << ISPPRV_RGB_MAT3_MTX_GG_SHIFT;
++ val |= (rgbrgb->matrix[1][2] & 0xfff) << ISPPRV_RGB_MAT3_MTX_BG_SHIFT;
++ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT3);
++
++ val = (rgbrgb->matrix[2][0] & 0xfff) << ISPPRV_RGB_MAT4_MTX_RB_SHIFT;
++ val |= (rgbrgb->matrix[2][1] & 0xfff) << ISPPRV_RGB_MAT4_MTX_GB_SHIFT;
++ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT4);
++
++ val = (rgbrgb->matrix[2][2] & 0xfff) << ISPPRV_RGB_MAT5_MTX_BB_SHIFT;
++ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT5);
++
++ val = (rgbrgb->offset[0] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT;
++ val |= (rgbrgb->offset[1] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT;
++ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF1);
++
++ val = (rgbrgb->offset[2] & 0x3ff) << ISPPRV_RGB_OFF2_MTX_OFFB_SHIFT;
++ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF2);
++}
++
++/*
++ * Configures the RGB-YCbYCr conversion matrix
++ * @prev_csc: Structure containing the RGB to YCbYCr matrix and the
++ * YCbCr offset.
++ */
++static void
++preview_config_rgb_to_ycbcr(struct isp_prev_device *prev, const void *prev_csc)
++{
++ struct isp_device *isp = to_isp_device(prev);
++ const struct omap3isp_prev_csc *csc = prev_csc;
++ u32 val;
++
++ val = (csc->matrix[0][0] & 0x3ff) << ISPPRV_CSC0_RY_SHIFT;
++ val |= (csc->matrix[0][1] & 0x3ff) << ISPPRV_CSC0_GY_SHIFT;
++ val |= (csc->matrix[0][2] & 0x3ff) << ISPPRV_CSC0_BY_SHIFT;
++ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC0);
++
++ val = (csc->matrix[1][0] & 0x3ff) << ISPPRV_CSC1_RCB_SHIFT;
++ val |= (csc->matrix[1][1] & 0x3ff) << ISPPRV_CSC1_GCB_SHIFT;
++ val |= (csc->matrix[1][2] & 0x3ff) << ISPPRV_CSC1_BCB_SHIFT;
++ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC1);
++
++ val = (csc->matrix[2][0] & 0x3ff) << ISPPRV_CSC2_RCR_SHIFT;
++ val |= (csc->matrix[2][1] & 0x3ff) << ISPPRV_CSC2_GCR_SHIFT;
++ val |= (csc->matrix[2][2] & 0x3ff) << ISPPRV_CSC2_BCR_SHIFT;
++ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC2);
++
++ val = (csc->offset[0] & 0xff) << ISPPRV_CSC_OFFSET_Y_SHIFT;
++ val |= (csc->offset[1] & 0xff) << ISPPRV_CSC_OFFSET_CB_SHIFT;
++ val |= (csc->offset[2] & 0xff) << ISPPRV_CSC_OFFSET_CR_SHIFT;
++ isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC_OFFSET);
++}
++
++/*
++ * preview_update_contrast - Updates the contrast.
++ * @contrast: Pointer to hold the current programmed contrast value.
++ *
++ * Value should be programmed before enabling the module.
++ */
++static void
++preview_update_contrast(struct isp_prev_device *prev, u8 contrast)
++{
++ struct prev_params *params = &prev->params;
++
++ if (params->contrast != (contrast * ISPPRV_CONTRAST_UNITS)) {
++ params->contrast = contrast * ISPPRV_CONTRAST_UNITS;
++ prev->update |= PREV_CONTRAST;
++ }
++}
++
++/*
++ * preview_config_contrast - Configures the Contrast.
++ * @params: Contrast value (u8 pointer, U8Q0 format).
++ *
++ * Value should be programmed before enabling the module.
++ */
++static void
++preview_config_contrast(struct isp_prev_device *prev, const void *params)
++{
++ struct isp_device *isp = to_isp_device(prev);
++
++ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
++ 0xff << ISPPRV_CNT_BRT_CNT_SHIFT,
++ *(u8 *)params << ISPPRV_CNT_BRT_CNT_SHIFT);
++}
++
++/*
++ * preview_update_brightness - Updates the brightness in preview module.
++ * @brightness: Pointer to hold the current programmed brightness value.
++ *
++ */
++static void
++preview_update_brightness(struct isp_prev_device *prev, u8 brightness)
++{
++ struct prev_params *params = &prev->params;
++
++ if (params->brightness != (brightness * ISPPRV_BRIGHT_UNITS)) {
++ params->brightness = brightness * ISPPRV_BRIGHT_UNITS;
++ prev->update |= PREV_BRIGHTNESS;
++ }
++}
++
++/*
++ * preview_config_brightness - Configures the brightness.
++ * @params: Brightness value (u8 pointer, U8Q0 format).
++ */
++static void
++preview_config_brightness(struct isp_prev_device *prev, const void *params)
++{
++ struct isp_device *isp = to_isp_device(prev);
++
++ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
++ 0xff << ISPPRV_CNT_BRT_BRT_SHIFT,
++ *(u8 *)params << ISPPRV_CNT_BRT_BRT_SHIFT);
++}
++
++/*
++ * preview_config_yc_range - Configures the max and min Y and C values.
++ * @yclimit: Structure containing the range of Y and C values.
++ */
++static void
++preview_config_yc_range(struct isp_prev_device *prev, const void *yclimit)
++{
++ struct isp_device *isp = to_isp_device(prev);
++ const struct omap3isp_prev_yclimit *yc = yclimit;
++
++ isp_reg_writel(isp,
++ yc->maxC << ISPPRV_SETUP_YC_MAXC_SHIFT |
++ yc->maxY << ISPPRV_SETUP_YC_MAXY_SHIFT |
++ yc->minC << ISPPRV_SETUP_YC_MINC_SHIFT |
++ yc->minY << ISPPRV_SETUP_YC_MINY_SHIFT,
++ OMAP3_ISP_IOMEM_PREV, ISPPRV_SETUP_YC);
++}
++
++/* preview parameters update structure */
++struct preview_update {
++ int cfg_bit;
++ int feature_bit;
++ void (*config)(struct isp_prev_device *, const void *);
++ void (*enable)(struct isp_prev_device *, u8);
++};
++
++static struct preview_update update_attrs[] = {
++ {OMAP3ISP_PREV_LUMAENH, PREV_LUMA_ENHANCE,
++ preview_config_luma_enhancement,
++ preview_enable_luma_enhancement},
++ {OMAP3ISP_PREV_INVALAW, PREV_INVERSE_ALAW,
++ NULL,
++ preview_enable_invalaw},
++ {OMAP3ISP_PREV_HRZ_MED, PREV_HORZ_MEDIAN_FILTER,
++ preview_config_hmed,
++ preview_enable_hmed},
++ {OMAP3ISP_PREV_CFA, PREV_CFA,
++ preview_config_cfa,
++ preview_enable_cfa},
++ {OMAP3ISP_PREV_CHROMA_SUPP, PREV_CHROMA_SUPPRESS,
++ preview_config_chroma_suppression,
++ preview_enable_chroma_suppression},
++ {OMAP3ISP_PREV_WB, PREV_WB,
++ preview_config_whitebalance,
++ NULL},
++ {OMAP3ISP_PREV_BLKADJ, PREV_BLKADJ,
++ preview_config_blkadj,
++ NULL},
++ {OMAP3ISP_PREV_RGB2RGB, PREV_RGB2RGB,
++ preview_config_rgb_blending,
++ NULL},
++ {OMAP3ISP_PREV_COLOR_CONV, PREV_COLOR_CONV,
++ preview_config_rgb_to_ycbcr,
++ NULL},
++ {OMAP3ISP_PREV_YC_LIMIT, PREV_YCLIMITS,
++ preview_config_yc_range,
++ NULL},
++ {OMAP3ISP_PREV_DEFECT_COR, PREV_DEFECT_COR,
++ preview_config_dcor,
++ preview_enable_dcor},
++ {OMAP3ISP_PREV_GAMMABYPASS, PREV_GAMMA_BYPASS,
++ NULL,
++ preview_enable_gammabypass},
++ {OMAP3ISP_PREV_DRK_FRM_CAPTURE, PREV_DARK_FRAME_CAPTURE,
++ NULL,
++ preview_enable_drkframe_capture},
++ {OMAP3ISP_PREV_DRK_FRM_SUBTRACT, PREV_DARK_FRAME_SUBTRACT,
++ NULL,
++ preview_enable_drkframe},
++ {OMAP3ISP_PREV_LENS_SHADING, PREV_LENS_SHADING,
++ preview_config_drkf_shadcomp,
++ preview_enable_drkframe},
++ {OMAP3ISP_PREV_NF, PREV_NOISE_FILTER,
++ preview_config_noisefilter,
++ preview_enable_noisefilter},
++ {OMAP3ISP_PREV_GAMMA, PREV_GAMMA,
++ preview_config_gammacorrn,
++ NULL},
++ {-1, PREV_CONTRAST,
++ preview_config_contrast,
++ NULL},
++ {-1, PREV_BRIGHTNESS,
++ preview_config_brightness,
++ NULL},
++};
++
++/*
++ * __preview_get_ptrs - helper function which return pointers to members
++ * of params and config structures.
++ * @params - pointer to preview_params structure.
++ * @param - return pointer to appropriate structure field.
++ * @configs - pointer to update config structure.
++ * @config - return pointer to appropriate structure field.
++ * @bit - for which feature to return pointers.
++ * Return size of coresponding prev_params member
++ */
++static u32
++__preview_get_ptrs(struct prev_params *params, void **param,
++ struct omap3isp_prev_update_config *configs,
++ void __user **config, u32 bit)
++{
++#define CHKARG(cfgs, cfg, field) \
++ if (cfgs && cfg) { \
++ *(cfg) = (cfgs)->field; \
++ }
++
++ switch (bit) {
++ case PREV_HORZ_MEDIAN_FILTER:
++ *param = &params->hmed;
++ CHKARG(configs, config, hmed)
++ return sizeof(params->hmed);
++ case PREV_NOISE_FILTER:
++ *param = &params->nf;
++ CHKARG(configs, config, nf)
++ return sizeof(params->nf);
++ break;
++ case PREV_CFA:
++ *param = &params->cfa;
++ CHKARG(configs, config, cfa)
++ return sizeof(params->cfa);
++ case PREV_LUMA_ENHANCE:
++ *param = &params->luma;
++ CHKARG(configs, config, luma)
++ return sizeof(params->luma);
++ case PREV_CHROMA_SUPPRESS:
++ *param = &params->csup;
++ CHKARG(configs, config, csup)
++ return sizeof(params->csup);
++ case PREV_DEFECT_COR:
++ *param = &params->dcor;
++ CHKARG(configs, config, dcor)
++ return sizeof(params->dcor);
++ case PREV_BLKADJ:
++ *param = &params->blk_adj;
++ CHKARG(configs, config, blkadj)
++ return sizeof(params->blk_adj);
++ case PREV_YCLIMITS:
++ *param = &params->yclimit;
++ CHKARG(configs, config, yclimit)
++ return sizeof(params->yclimit);
++ case PREV_RGB2RGB:
++ *param = &params->rgb2rgb;
++ CHKARG(configs, config, rgb2rgb)
++ return sizeof(params->rgb2rgb);
++ case PREV_COLOR_CONV:
++ *param = &params->rgb2ycbcr;
++ CHKARG(configs, config, csc)
++ return sizeof(params->rgb2ycbcr);
++ case PREV_WB:
++ *param = &params->wbal;
++ CHKARG(configs, config, wbal)
++ return sizeof(params->wbal);
++ case PREV_GAMMA:
++ *param = &params->gamma;
++ CHKARG(configs, config, gamma)
++ return sizeof(params->gamma);
++ case PREV_CONTRAST:
++ *param = &params->contrast;
++ return 0;
++ case PREV_BRIGHTNESS:
++ *param = &params->brightness;
++ return 0;
++ default:
++ *param = NULL;
++ *config = NULL;
++ break;
++ }
++ return 0;
++}
++
++/*
++ * preview_config - Copy and update local structure with userspace preview
++ * configuration.
++ * @prev: ISP preview engine
++ * @cfg: Configuration
++ *
++ * Return zero if success or -EFAULT if the configuration can't be copied from
++ * userspace.
++ */
++static int preview_config(struct isp_prev_device *prev,
++ struct omap3isp_prev_update_config *cfg)
++{
++ struct prev_params *params;
++ struct preview_update *attr;
++ int i, bit, rval = 0;
++
++ params = &prev->params;
++
++ if (prev->state != ISP_PIPELINE_STREAM_STOPPED) {
++ unsigned long flags;
++
++ spin_lock_irqsave(&prev->lock, flags);
++ prev->shadow_update = 1;
++ spin_unlock_irqrestore(&prev->lock, flags);
++ }
++
++ for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
++ attr = &update_attrs[i];
++ bit = 0;
++
++ if (!(cfg->update & attr->cfg_bit))
++ continue;
++
++ bit = cfg->flag & attr->cfg_bit;
++ if (bit) {
++ void *to = NULL, __user *from = NULL;
++ unsigned long sz = 0;
++
++ sz = __preview_get_ptrs(params, &to, cfg, &from,
++ bit);
++ if (to && from && sz) {
++ if (copy_from_user(to, from, sz)) {
++ rval = -EFAULT;
++ break;
++ }
++ }
++ params->features |= attr->feature_bit;
++ } else {
++ params->features &= ~attr->feature_bit;
++ }
++
++ prev->update |= attr->feature_bit;
++ }
++
++ prev->shadow_update = 0;
++ return rval;
++}
++
++/*
++ * preview_setup_hw - Setup preview registers and/or internal memory
++ * @prev: pointer to preview private structure
++ * Note: can be called from interrupt context
++ * Return none
++ */
++static void preview_setup_hw(struct isp_prev_device *prev)
++{
++ struct prev_params *params = &prev->params;
++ struct preview_update *attr;
++ int i, bit;
++ void *param_ptr;
++
++ for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
++ attr = &update_attrs[i];
++
++ if (!(prev->update & attr->feature_bit))
++ continue;
++ bit = params->features & attr->feature_bit;
++ if (bit) {
++ if (attr->config) {
++ __preview_get_ptrs(params, &param_ptr, NULL,
++ NULL, bit);
++ attr->config(prev, param_ptr);
++ }
++ if (attr->enable)
++ attr->enable(prev, 1);
++ } else
++ if (attr->enable)
++ attr->enable(prev, 0);
++
++ prev->update &= ~attr->feature_bit;
++ }
++}
++
++/*
++ * preview_config_ycpos - Configure byte layout of YUV image.
++ * @mode: Indicates the required byte layout.
++ */
++static void
++preview_config_ycpos(struct isp_prev_device *prev,
++ enum v4l2_mbus_pixelcode pixelcode)
++{
++ struct isp_device *isp = to_isp_device(prev);
++ enum preview_ycpos_mode mode;
++
++ switch (pixelcode) {
++ case V4L2_MBUS_FMT_YUYV8_1X16:
++ mode = YCPOS_CrYCbY;
++ break;
++ case V4L2_MBUS_FMT_UYVY8_1X16:
++ mode = YCPOS_YCrYCb;
++ break;
++ default:
++ return;
++ }
++
++ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_YCPOS_CrYCbY,
++ mode << ISPPRV_PCR_YCPOS_SHIFT);
++}
++
++/*
++ * preview_config_averager - Enable / disable / configure averager
++ * @average: Average value to be configured.
++ */
++static void preview_config_averager(struct isp_prev_device *prev, u8 average)
++{
++ struct isp_device *isp = to_isp_device(prev);
++ int reg = 0;
++
++ if (prev->params.cfa.format == OMAP3ISP_CFAFMT_BAYER)
++ reg = ISPPRV_AVE_EVENDIST_2 << ISPPRV_AVE_EVENDIST_SHIFT |
++ ISPPRV_AVE_ODDDIST_2 << ISPPRV_AVE_ODDDIST_SHIFT |
++ average;
++ else if (prev->params.cfa.format == OMAP3ISP_CFAFMT_RGBFOVEON)
++ reg = ISPPRV_AVE_EVENDIST_3 << ISPPRV_AVE_EVENDIST_SHIFT |
++ ISPPRV_AVE_ODDDIST_3 << ISPPRV_AVE_ODDDIST_SHIFT |
++ average;
++ isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE);
++}
++
++/*
++ * preview_config_input_size - Configure the input frame size
++ *
++ * The preview engine crops several rows and columns internally depending on
++ * which processing blocks are enabled. The driver assumes all those blocks are
++ * enabled when reporting source pad formats to userspace. If this assumption is
++ * not true, rows and columns must be manually cropped at the preview engine
++ * input to avoid overflows at the end of lines and frames.
++ */
++static void preview_config_input_size(struct isp_prev_device *prev)
++{
++ struct isp_device *isp = to_isp_device(prev);
++ struct prev_params *params = &prev->params;
++ struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK];
++ unsigned int sph = 0;
++ unsigned int eph = format->width - 1;
++ unsigned int slv = 0;
++ unsigned int elv = format->height - 1;
++
++ if (prev->input == PREVIEW_INPUT_CCDC) {
++ sph += 2;
++ eph -= 2;
++ }
++
++ /*
++ * Median filter 4 pixels
++ * Noise filter 4 pixels, 4 lines
++ * or faulty pixels correction
++ * CFA filter 4 pixels, 4 lines in Bayer mode
++ * 2 lines in other modes
++ * Color suppression 2 pixels
++ * or luma enhancement
++ * -------------------------------------------------------------
++ * Maximum total 14 pixels, 8 lines
++ */
++
++ if (!(params->features & PREV_CFA)) {
++ sph += 2;
++ eph -= 2;
++ slv += 2;
++ elv -= 2;
++ }
++ if (!(params->features & (PREV_DEFECT_COR | PREV_NOISE_FILTER))) {
++ sph += 2;
++ eph -= 2;
++ slv += 2;
++ elv -= 2;
++ }
++ if (!(params->features & PREV_HORZ_MEDIAN_FILTER)) {
++ sph += 2;
++ eph -= 2;
++ }
++ if (!(params->features & (PREV_CHROMA_SUPPRESS | PREV_LUMA_ENHANCE)))
++ sph += 2;
++
++ isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph,
++ OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO);
++ isp_reg_writel(isp, (slv << ISPPRV_VERT_INFO_SLV_SHIFT) | elv,
++ OMAP3_ISP_IOMEM_PREV, ISPPRV_VERT_INFO);
++}
++
++/*
++ * preview_config_inlineoffset - Configures the Read address line offset.
++ * @prev: Preview module
++ * @offset: Line offset
++ *
++ * According to the TRM, the line offset must be aligned on a 32 bytes boundary.
++ * However, a hardware bug requires the memory start address to be aligned on a
++ * 64 bytes boundary, so the offset probably should be aligned on 64 bytes as
++ * well.
++ */
++static void
++preview_config_inlineoffset(struct isp_prev_device *prev, u32 offset)
++{
++ struct isp_device *isp = to_isp_device(prev);
++
++ isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
++ ISPPRV_RADR_OFFSET);
++}
++
++/*
++ * preview_set_inaddr - Sets memory address of input frame.
++ * @addr: 32bit memory address aligned on 32byte boundary.
++ *
++ * Configures the memory address from which the input frame is to be read.
++ */
++static void preview_set_inaddr(struct isp_prev_device *prev, u32 addr)
++{
++ struct isp_device *isp = to_isp_device(prev);
++
++ isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_RSDR_ADDR);
++}
++
++/*
++ * preview_config_outlineoffset - Configures the Write address line offset.
++ * @offset: Line Offset for the preview output.
++ *
++ * The offset must be a multiple of 32 bytes.
++ */
++static void preview_config_outlineoffset(struct isp_prev_device *prev,
++ u32 offset)
++{
++ struct isp_device *isp = to_isp_device(prev);
++
++ isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
++ ISPPRV_WADD_OFFSET);
++}
++
++/*
++ * preview_set_outaddr - Sets the memory address to store output frame
++ * @addr: 32bit memory address aligned on 32byte boundary.
++ *
++ * Configures the memory address to which the output frame is written.
++ */
++static void preview_set_outaddr(struct isp_prev_device *prev, u32 addr)
++{
++ struct isp_device *isp = to_isp_device(prev);
++
++ isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_WSDR_ADDR);
++}
++
++static void preview_adjust_bandwidth(struct isp_prev_device *prev)
++{
++ struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity);
++ struct isp_device *isp = to_isp_device(prev);
++ const struct v4l2_mbus_framefmt *ifmt = &prev->formats[PREV_PAD_SINK];
++ unsigned long l3_ick = pipe->l3_ick;
++ struct v4l2_fract *timeperframe;
++ unsigned int cycles_per_frame;
++ unsigned int requests_per_frame;
++ unsigned int cycles_per_request;
++ unsigned int minimum;
++ unsigned int maximum;
++ unsigned int value;
++
++ if (prev->input != PREVIEW_INPUT_MEMORY) {
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
++ ISPSBL_SDR_REQ_PRV_EXP_MASK);
++ return;
++ }
++
++ /* Compute the minimum number of cycles per request, based on the
++ * pipeline maximum data rate. This is an absolute lower bound if we
++ * don't want SBL overflows, so round the value up.
++ */
++ cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1,
++ pipe->max_rate);
++ minimum = DIV_ROUND_UP(cycles_per_request, 32);
++
++ /* Compute the maximum number of cycles per request, based on the
++ * requested frame rate. This is a soft upper bound to achieve a frame
++ * rate equal or higher than the requested value, so round the value
++ * down.
++ */
++ timeperframe = &pipe->max_timeperframe;
++
++ requests_per_frame = DIV_ROUND_UP(ifmt->width * 2, 256) * ifmt->height;
++ cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator,
++ timeperframe->denominator);
++ cycles_per_request = cycles_per_frame / requests_per_frame;
++
++ maximum = cycles_per_request / 32;
++
++ value = max(minimum, maximum);
++
++ dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value);
++ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
++ ISPSBL_SDR_REQ_PRV_EXP_MASK,
++ value << ISPSBL_SDR_REQ_PRV_EXP_SHIFT);
++}
++
++/*
++ * omap3isp_preview_busy - Gets busy state of preview module.
++ */
++int omap3isp_preview_busy(struct isp_prev_device *prev)
++{
++ struct isp_device *isp = to_isp_device(prev);
++
++ return isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR)
++ & ISPPRV_PCR_BUSY;
++}
++
++/*
++ * omap3isp_preview_restore_context - Restores the values of preview registers
++ */
++void omap3isp_preview_restore_context(struct isp_device *isp)
++{
++ isp->isp_prev.update = PREV_FEATURES_END - 1;
++ preview_setup_hw(&isp->isp_prev);
++}
++
++/*
++ * preview_print_status - Dump preview module registers to the kernel log
++ */
++#define PREV_PRINT_REGISTER(isp, name)\
++ dev_dbg(isp->dev, "###PRV " #name "=0x%08x\n", \
++ isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_##name))
++
++static void preview_print_status(struct isp_prev_device *prev)
++{
++ struct isp_device *isp = to_isp_device(prev);
++
++ dev_dbg(isp->dev, "-------------Preview Register dump----------\n");
++
++ PREV_PRINT_REGISTER(isp, PCR);
++ PREV_PRINT_REGISTER(isp, HORZ_INFO);
++ PREV_PRINT_REGISTER(isp, VERT_INFO);
++ PREV_PRINT_REGISTER(isp, RSDR_ADDR);
++ PREV_PRINT_REGISTER(isp, RADR_OFFSET);
++ PREV_PRINT_REGISTER(isp, DSDR_ADDR);
++ PREV_PRINT_REGISTER(isp, DRKF_OFFSET);
++ PREV_PRINT_REGISTER(isp, WSDR_ADDR);
++ PREV_PRINT_REGISTER(isp, WADD_OFFSET);
++ PREV_PRINT_REGISTER(isp, AVE);
++ PREV_PRINT_REGISTER(isp, HMED);
++ PREV_PRINT_REGISTER(isp, NF);
++ PREV_PRINT_REGISTER(isp, WB_DGAIN);
++ PREV_PRINT_REGISTER(isp, WBGAIN);
++ PREV_PRINT_REGISTER(isp, WBSEL);
++ PREV_PRINT_REGISTER(isp, CFA);
++ PREV_PRINT_REGISTER(isp, BLKADJOFF);
++ PREV_PRINT_REGISTER(isp, RGB_MAT1);
++ PREV_PRINT_REGISTER(isp, RGB_MAT2);
++ PREV_PRINT_REGISTER(isp, RGB_MAT3);
++ PREV_PRINT_REGISTER(isp, RGB_MAT4);
++ PREV_PRINT_REGISTER(isp, RGB_MAT5);
++ PREV_PRINT_REGISTER(isp, RGB_OFF1);
++ PREV_PRINT_REGISTER(isp, RGB_OFF2);
++ PREV_PRINT_REGISTER(isp, CSC0);
++ PREV_PRINT_REGISTER(isp, CSC1);
++ PREV_PRINT_REGISTER(isp, CSC2);
++ PREV_PRINT_REGISTER(isp, CSC_OFFSET);
++ PREV_PRINT_REGISTER(isp, CNT_BRT);
++ PREV_PRINT_REGISTER(isp, CSUP);
++ PREV_PRINT_REGISTER(isp, SETUP_YC);
++ PREV_PRINT_REGISTER(isp, SET_TBL_ADDR);
++ PREV_PRINT_REGISTER(isp, CDC_THR0);
++ PREV_PRINT_REGISTER(isp, CDC_THR1);
++ PREV_PRINT_REGISTER(isp, CDC_THR2);
++ PREV_PRINT_REGISTER(isp, CDC_THR3);
++
++ dev_dbg(isp->dev, "--------------------------------------------\n");
++}
++
++/*
++ * preview_init_params - init image processing parameters.
++ * @prev: pointer to previewer private structure
++ * return none
++ */
++static void preview_init_params(struct isp_prev_device *prev)
++{
++ struct prev_params *params = &prev->params;
++ int i = 0;
++
++ /* Init values */
++ params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS;
++ params->brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS;
++ params->average = NO_AVE;
++ params->cfa.format = OMAP3ISP_CFAFMT_BAYER;
++ memcpy(params->cfa.table, cfa_coef_table,
++ sizeof(params->cfa.table));
++ params->cfa.gradthrs_horz = FLR_CFA_GRADTHRS_HORZ;
++ params->cfa.gradthrs_vert = FLR_CFA_GRADTHRS_VERT;
++ params->csup.gain = FLR_CSUP_GAIN;
++ params->csup.thres = FLR_CSUP_THRES;
++ params->csup.hypf_en = 0;
++ memcpy(params->luma.table, luma_enhance_table,
++ sizeof(params->luma.table));
++ params->nf.spread = FLR_NF_STRGTH;
++ memcpy(params->nf.table, noise_filter_table, sizeof(params->nf.table));
++ params->dcor.couplet_mode_en = 1;
++ for (i = 0; i < OMAP3ISP_PREV_DETECT_CORRECT_CHANNELS; i++)
++ params->dcor.detect_correct[i] = DEF_DETECT_CORRECT_VAL;
++ memcpy(params->gamma.blue, gamma_table, sizeof(params->gamma.blue));
++ memcpy(params->gamma.green, gamma_table, sizeof(params->gamma.green));
++ memcpy(params->gamma.red, gamma_table, sizeof(params->gamma.red));
++ params->wbal.dgain = FLR_WBAL_DGAIN;
++ params->wbal.coef0 = FLR_WBAL_COEF;
++ params->wbal.coef1 = FLR_WBAL_COEF;
++ params->wbal.coef2 = FLR_WBAL_COEF;
++ params->wbal.coef3 = FLR_WBAL_COEF;
++ params->blk_adj.red = FLR_BLKADJ_RED;
++ params->blk_adj.green = FLR_BLKADJ_GREEN;
++ params->blk_adj.blue = FLR_BLKADJ_BLUE;
++ params->rgb2rgb = flr_rgb2rgb;
++ params->rgb2ycbcr = flr_prev_csc;
++ params->yclimit.minC = ISPPRV_YC_MIN;
++ params->yclimit.maxC = ISPPRV_YC_MAX;
++ params->yclimit.minY = ISPPRV_YC_MIN;
++ params->yclimit.maxY = ISPPRV_YC_MAX;
++
++ params->features = PREV_CFA | PREV_DEFECT_COR | PREV_NOISE_FILTER
++ | PREV_GAMMA | PREV_BLKADJ | PREV_YCLIMITS
++ | PREV_RGB2RGB | PREV_COLOR_CONV | PREV_WB
++ | PREV_BRIGHTNESS | PREV_CONTRAST;
++
++ prev->update = PREV_FEATURES_END - 1;
++}
++
++/*
++ * preview_max_out_width - Handle previewer hardware ouput limitations
++ * @isp_revision : ISP revision
++ * returns maximum width output for current isp revision
++ */
++static unsigned int preview_max_out_width(struct isp_prev_device *prev)
++{
++ struct isp_device *isp = to_isp_device(prev);
++
++ switch (isp->revision) {
++ case ISP_REVISION_1_0:
++ return ISPPRV_MAXOUTPUT_WIDTH;
++
++ case ISP_REVISION_2_0:
++ default:
++ return ISPPRV_MAXOUTPUT_WIDTH_ES2;
++
++ case ISP_REVISION_15_0:
++ return ISPPRV_MAXOUTPUT_WIDTH_3630;
++ }
++}
++
++static void preview_configure(struct isp_prev_device *prev)
++{
++ struct isp_device *isp = to_isp_device(prev);
++ struct v4l2_mbus_framefmt *format;
++ unsigned int max_out_width;
++ unsigned int format_avg;
++
++ preview_setup_hw(prev);
++
++ if (prev->output & PREVIEW_OUTPUT_MEMORY)
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_SDRPORT);
++ else
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_SDRPORT);
++
++ if (prev->output & PREVIEW_OUTPUT_RESIZER)
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_RSZPORT);
++ else
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_RSZPORT);
++
++ /* PREV_PAD_SINK */
++ format = &prev->formats[PREV_PAD_SINK];
++
++ preview_adjust_bandwidth(prev);
++
++ preview_config_input_size(prev);
++
++ if (prev->input == PREVIEW_INPUT_CCDC)
++ preview_config_inlineoffset(prev, 0);
++ else
++ preview_config_inlineoffset(prev,
++ ALIGN(format->width, 0x20) * 2);
++
++ /* PREV_PAD_SOURCE */
++ format = &prev->formats[PREV_PAD_SOURCE];
++
++ if (prev->output & PREVIEW_OUTPUT_MEMORY)
++ preview_config_outlineoffset(prev,
++ ALIGN(format->width, 0x10) * 2);
++
++ max_out_width = preview_max_out_width(prev);
++
++ format_avg = fls(DIV_ROUND_UP(format->width, max_out_width) - 1);
++ preview_config_averager(prev, format_avg);
++ preview_config_ycpos(prev, format->code);
++}
++
++/* -----------------------------------------------------------------------------
++ * Interrupt handling
++ */
++
++static void preview_enable_oneshot(struct isp_prev_device *prev)
++{
++ struct isp_device *isp = to_isp_device(prev);
++
++ /* The PCR.SOURCE bit is automatically reset to 0 when the PCR.ENABLE
++ * bit is set. As the preview engine is used in single-shot mode, we
++ * need to set PCR.SOURCE before enabling the preview engine.
++ */
++ if (prev->input == PREVIEW_INPUT_MEMORY)
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_SOURCE);
++
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
++ ISPPRV_PCR_EN | ISPPRV_PCR_ONESHOT);
++}
++
++void omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev)
++{
++ /*
++ * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun
++ * condition, the module was paused and now we have a buffer queued
++ * on the output again. Restart the pipeline if running in continuous
++ * mode.
++ */
++ if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
++ prev->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
++ preview_enable_oneshot(prev);
++ isp_video_dmaqueue_flags_clr(&prev->video_out);
++ }
++}
++
++static void preview_isr_buffer(struct isp_prev_device *prev)
++{
++ struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity);
++ struct isp_buffer *buffer;
++ int restart = 0;
++
++ if (prev->input == PREVIEW_INPUT_MEMORY) {
++ buffer = omap3isp_video_buffer_next(&prev->video_in,
++ prev->error);
++ if (buffer != NULL)
++ preview_set_inaddr(prev, buffer->isp_addr);
++ pipe->state |= ISP_PIPELINE_IDLE_INPUT;
++ }
++
++ if (prev->output & PREVIEW_OUTPUT_MEMORY) {
++ buffer = omap3isp_video_buffer_next(&prev->video_out,
++ prev->error);
++ if (buffer != NULL) {
++ preview_set_outaddr(prev, buffer->isp_addr);
++ restart = 1;
++ }
++ pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
++ }
++
++ switch (prev->state) {
++ case ISP_PIPELINE_STREAM_SINGLESHOT:
++ if (isp_pipeline_ready(pipe))
++ omap3isp_pipeline_set_stream(pipe,
++ ISP_PIPELINE_STREAM_SINGLESHOT);
++ break;
++
++ case ISP_PIPELINE_STREAM_CONTINUOUS:
++ /* If an underrun occurs, the video queue operation handler will
++ * restart the preview engine. Otherwise restart it immediately.
++ */
++ if (restart)
++ preview_enable_oneshot(prev);
++ break;
++
++ case ISP_PIPELINE_STREAM_STOPPED:
++ default:
++ return;
++ }
++
++ prev->error = 0;
++}
++
++/*
++ * omap3isp_preview_isr - ISP preview engine interrupt handler
++ *
++ * Manage the preview engine video buffers and configure shadowed registers.
++ */
++void omap3isp_preview_isr(struct isp_prev_device *prev)
++{
++ unsigned long flags;
++
++ if (omap3isp_module_sync_is_stopping(&prev->wait, &prev->stopping))
++ return;
++
++ spin_lock_irqsave(&prev->lock, flags);
++ if (prev->shadow_update)
++ goto done;
++
++ preview_setup_hw(prev);
++ preview_config_input_size(prev);
++
++done:
++ spin_unlock_irqrestore(&prev->lock, flags);
++
++ if (prev->input == PREVIEW_INPUT_MEMORY ||
++ prev->output & PREVIEW_OUTPUT_MEMORY)
++ preview_isr_buffer(prev);
++ else if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS)
++ preview_enable_oneshot(prev);
++}
++
++/* -----------------------------------------------------------------------------
++ * ISP video operations
++ */
++
++static int preview_video_queue(struct isp_video *video,
++ struct isp_buffer *buffer)
++{
++ struct isp_prev_device *prev = &video->isp->isp_prev;
++
++ if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
++ preview_set_inaddr(prev, buffer->isp_addr);
++
++ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ preview_set_outaddr(prev, buffer->isp_addr);
++
++ return 0;
++}
++
++static const struct isp_video_operations preview_video_ops = {
++ .queue = preview_video_queue,
++};
++
++/* -----------------------------------------------------------------------------
++ * V4L2 subdev operations
++ */
++
++/*
++ * preview_s_ctrl - Handle set control subdev method
++ * @ctrl: pointer to v4l2 control structure
++ */
++static int preview_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct isp_prev_device *prev =
++ container_of(ctrl->handler, struct isp_prev_device, ctrls);
++
++ switch (ctrl->id) {
++ case V4L2_CID_BRIGHTNESS:
++ preview_update_brightness(prev, ctrl->val);
++ break;
++ case V4L2_CID_CONTRAST:
++ preview_update_contrast(prev, ctrl->val);
++ break;
++ }
++
++ return 0;
++}
++
++static const struct v4l2_ctrl_ops preview_ctrl_ops = {
++ .s_ctrl = preview_s_ctrl,
++};
++
++/*
++ * preview_ioctl - Handle preview module private ioctl's
++ * @prev: pointer to preview context structure
++ * @cmd: configuration command
++ * @arg: configuration argument
++ * return -EINVAL or zero on success
++ */
++static long preview_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
++{
++ struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
++
++ switch (cmd) {
++ case VIDIOC_OMAP3ISP_PRV_CFG:
++ return preview_config(prev, arg);
++
++ default:
++ return -ENOIOCTLCMD;
++ }
++}
++
++/*
++ * preview_set_stream - Enable/Disable streaming on preview subdev
++ * @sd : pointer to v4l2 subdev structure
++ * @enable: 1 == Enable, 0 == Disable
++ * return -EINVAL or zero on sucess
++ */
++static int preview_set_stream(struct v4l2_subdev *sd, int enable)
++{
++ struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
++ struct isp_video *video_out = &prev->video_out;
++ struct isp_device *isp = to_isp_device(prev);
++ struct device *dev = to_device(prev);
++ unsigned long flags;
++
++ if (prev->state == ISP_PIPELINE_STREAM_STOPPED) {
++ if (enable == ISP_PIPELINE_STREAM_STOPPED)
++ return 0;
++
++ omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
++ preview_configure(prev);
++ atomic_set(&prev->stopping, 0);
++ prev->error = 0;
++ preview_print_status(prev);
++ }
++
++ switch (enable) {
++ case ISP_PIPELINE_STREAM_CONTINUOUS:
++ if (prev->output & PREVIEW_OUTPUT_MEMORY)
++ omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
++
++ if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED ||
++ !(prev->output & PREVIEW_OUTPUT_MEMORY))
++ preview_enable_oneshot(prev);
++
++ isp_video_dmaqueue_flags_clr(video_out);
++ break;
++
++ case ISP_PIPELINE_STREAM_SINGLESHOT:
++ if (prev->input == PREVIEW_INPUT_MEMORY)
++ omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_READ);
++ if (prev->output & PREVIEW_OUTPUT_MEMORY)
++ omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
++
++ preview_enable_oneshot(prev);
++ break;
++
++ case ISP_PIPELINE_STREAM_STOPPED:
++ if (omap3isp_module_sync_idle(&sd->entity, &prev->wait,
++ &prev->stopping))
++ dev_dbg(dev, "%s: stop timeout.\n", sd->name);
++ spin_lock_irqsave(&prev->lock, flags);
++ omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_READ);
++ omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
++ omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
++ spin_unlock_irqrestore(&prev->lock, flags);
++ isp_video_dmaqueue_flags_clr(video_out);
++ break;
++ }
++
++ prev->state = enable;
++ return 0;
++}
++
++static struct v4l2_mbus_framefmt *
++__preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh,
++ unsigned int pad, enum v4l2_subdev_format_whence which)
++{
++ if (which == V4L2_SUBDEV_FORMAT_TRY)
++ return v4l2_subdev_get_try_format(fh, pad);
++ else
++ return &prev->formats[pad];
++}
++
++/* previewer format descriptions */
++static const unsigned int preview_input_fmts[] = {
++ V4L2_MBUS_FMT_SGRBG10_1X10,
++ V4L2_MBUS_FMT_SRGGB10_1X10,
++ V4L2_MBUS_FMT_SBGGR10_1X10,
++ V4L2_MBUS_FMT_SGBRG10_1X10,
++};
++
++static const unsigned int preview_output_fmts[] = {
++ V4L2_MBUS_FMT_UYVY8_1X16,
++ V4L2_MBUS_FMT_YUYV8_1X16,
++};
++
++/*
++ * preview_try_format - Handle try format by pad subdev method
++ * @prev: ISP preview device
++ * @fh : V4L2 subdev file handle
++ * @pad: pad num
++ * @fmt: pointer to v4l2 format structure
++ */
++static void preview_try_format(struct isp_prev_device *prev,
++ struct v4l2_subdev_fh *fh, unsigned int pad,
++ struct v4l2_mbus_framefmt *fmt,
++ enum v4l2_subdev_format_whence which)
++{
++ struct v4l2_mbus_framefmt *format;
++ unsigned int max_out_width;
++ enum v4l2_mbus_pixelcode pixelcode;
++ unsigned int i;
++
++ max_out_width = preview_max_out_width(prev);
++
++ switch (pad) {
++ case PREV_PAD_SINK:
++ /* When reading data from the CCDC, the input size has already
++ * been mangled by the CCDC output pad so it can be accepted
++ * as-is.
++ *
++ * When reading data from memory, clamp the requested width and
++ * height. The TRM doesn't specify a minimum input height, make
++ * sure we got enough lines to enable the noise filter and color
++ * filter array interpolation.
++ */
++ if (prev->input == PREVIEW_INPUT_MEMORY) {
++ fmt->width = clamp_t(u32, fmt->width, PREV_MIN_WIDTH,
++ max_out_width * 8);
++ fmt->height = clamp_t(u32, fmt->height, PREV_MIN_HEIGHT,
++ PREV_MAX_HEIGHT);
++ }
++
++ fmt->colorspace = V4L2_COLORSPACE_SRGB;
++
++ for (i = 0; i < ARRAY_SIZE(preview_input_fmts); i++) {
++ if (fmt->code == preview_input_fmts[i])
++ break;
++ }
++
++ /* If not found, use SGRBG10 as default */
++ if (i >= ARRAY_SIZE(preview_input_fmts))
++ fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
++ break;
++
++ case PREV_PAD_SOURCE:
++ pixelcode = fmt->code;
++ format = __preview_get_format(prev, fh, PREV_PAD_SINK, which);
++ memcpy(fmt, format, sizeof(*fmt));
++
++ /* The preview module output size is configurable through the
++ * input interface (horizontal and vertical cropping) and the
++ * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). In
++ * spite of this, hardcode the output size to the biggest
++ * possible value for simplicity reasons.
++ */
++ switch (pixelcode) {
++ case V4L2_MBUS_FMT_YUYV8_1X16:
++ case V4L2_MBUS_FMT_UYVY8_1X16:
++ fmt->code = pixelcode;
++ break;
++
++ default:
++ fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
++ break;
++ }
++
++ /* The TRM states (12.1.4.7.1.2) that 2 pixels must be cropped
++ * from the left and right sides when the input source is the
++ * CCDC. This seems not to be needed in practice, investigation
++ * is required.
++ */
++ if (prev->input == PREVIEW_INPUT_CCDC)
++ fmt->width -= 4;
++
++ /* The preview module can output a maximum of 3312 pixels
++ * horizontally due to fixed memory-line sizes. Compute the
++ * horizontal averaging factor accordingly. Note that the limit
++ * applies to the noise filter and CFA interpolation blocks, so
++ * it doesn't take cropping by further blocks into account.
++ *
++ * ES 1.0 hardware revision is limited to 1280 pixels
++ * horizontally.
++ */
++ fmt->width >>= fls(DIV_ROUND_UP(fmt->width, max_out_width) - 1);
++
++ /* Assume that all blocks are enabled and crop pixels and lines
++ * accordingly. See preview_config_input_size() for more
++ * information.
++ */
++ fmt->width -= 14;
++ fmt->height -= 8;
++
++ fmt->colorspace = V4L2_COLORSPACE_JPEG;
++ break;
++ }
++
++ fmt->field = V4L2_FIELD_NONE;
++}
++
++/*
++ * preview_enum_mbus_code - Handle pixel format enumeration
++ * @sd : pointer to v4l2 subdev structure
++ * @fh : V4L2 subdev file handle
++ * @code : pointer to v4l2_subdev_mbus_code_enum structure
++ * return -EINVAL or zero on success
++ */
++static int preview_enum_mbus_code(struct v4l2_subdev *sd,
++ struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_mbus_code_enum *code)
++{
++ switch (code->pad) {
++ case PREV_PAD_SINK:
++ if (code->index >= ARRAY_SIZE(preview_input_fmts))
++ return -EINVAL;
++
++ code->code = preview_input_fmts[code->index];
++ break;
++ case PREV_PAD_SOURCE:
++ if (code->index >= ARRAY_SIZE(preview_output_fmts))
++ return -EINVAL;
++
++ code->code = preview_output_fmts[code->index];
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int preview_enum_frame_size(struct v4l2_subdev *sd,
++ struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_frame_size_enum *fse)
++{
++ struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
++ struct v4l2_mbus_framefmt format;
++
++ if (fse->index != 0)
++ return -EINVAL;
++
++ format.code = fse->code;
++ format.width = 1;
++ format.height = 1;
++ preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
++ fse->min_width = format.width;
++ fse->min_height = format.height;
++
++ if (format.code != fse->code)
++ return -EINVAL;
++
++ format.code = fse->code;
++ format.width = -1;
++ format.height = -1;
++ preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
++ fse->max_width = format.width;
++ fse->max_height = format.height;
++
++ return 0;
++}
++
++/*
++ * preview_get_format - Handle get format by pads subdev method
++ * @sd : pointer to v4l2 subdev structure
++ * @fh : V4L2 subdev file handle
++ * @fmt: pointer to v4l2 subdev format structure
++ * return -EINVAL or zero on sucess
++ */
++static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_format *fmt)
++{
++ struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
++ struct v4l2_mbus_framefmt *format;
++
++ format = __preview_get_format(prev, fh, fmt->pad, fmt->which);
++ if (format == NULL)
++ return -EINVAL;
++
++ fmt->format = *format;
++ return 0;
++}
++
++/*
++ * preview_set_format - Handle set format by pads subdev method
++ * @sd : pointer to v4l2 subdev structure
++ * @fh : V4L2 subdev file handle
++ * @fmt: pointer to v4l2 subdev format structure
++ * return -EINVAL or zero on success
++ */
++static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_format *fmt)
++{
++ struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
++ struct v4l2_mbus_framefmt *format;
++
++ format = __preview_get_format(prev, fh, fmt->pad, fmt->which);
++ if (format == NULL)
++ return -EINVAL;
++
++ preview_try_format(prev, fh, fmt->pad, &fmt->format, fmt->which);
++ *format = fmt->format;
++
++ /* Propagate the format from sink to source */
++ if (fmt->pad == PREV_PAD_SINK) {
++ format = __preview_get_format(prev, fh, PREV_PAD_SOURCE,
++ fmt->which);
++ *format = fmt->format;
++ preview_try_format(prev, fh, PREV_PAD_SOURCE, format,
++ fmt->which);
++ }
++
++ return 0;
++}
++
++/*
++ * preview_init_formats - Initialize formats on all pads
++ * @sd: ISP preview V4L2 subdevice
++ * @fh: V4L2 subdev file handle
++ *
++ * Initialize all pad formats with default values. If fh is not NULL, try
++ * formats are initialized on the file handle. Otherwise active formats are
++ * initialized on the device.
++ */
++static int preview_init_formats(struct v4l2_subdev *sd,
++ struct v4l2_subdev_fh *fh)
++{
++ struct v4l2_subdev_format format;
++
++ memset(&format, 0, sizeof(format));
++ format.pad = PREV_PAD_SINK;
++ format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
++ format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
++ format.format.width = 4096;
++ format.format.height = 4096;
++ preview_set_format(sd, fh, &format);
++
++ return 0;
++}
++
++/* subdev core operations */
++static const struct v4l2_subdev_core_ops preview_v4l2_core_ops = {
++ .queryctrl = v4l2_subdev_queryctrl,
++ .querymenu = v4l2_subdev_querymenu,
++ .g_ctrl = v4l2_subdev_g_ctrl,
++ .s_ctrl = v4l2_subdev_s_ctrl,
++ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
++ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
++ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
++ .ioctl = preview_ioctl,
++};
++
++/* subdev file operations */
++static const struct v4l2_subdev_file_ops preview_v4l2_file_ops = {
++ .open = preview_init_formats,
++};
++
++/* subdev video operations */
++static const struct v4l2_subdev_video_ops preview_v4l2_video_ops = {
++ .s_stream = preview_set_stream,
++};
++
++/* subdev pad operations */
++static const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = {
++ .enum_mbus_code = preview_enum_mbus_code,
++ .enum_frame_size = preview_enum_frame_size,
++ .get_fmt = preview_get_format,
++ .set_fmt = preview_set_format,
++};
++
++/* subdev operations */
++static const struct v4l2_subdev_ops preview_v4l2_ops = {
++ .core = &preview_v4l2_core_ops,
++ .file = &preview_v4l2_file_ops,
++ .video = &preview_v4l2_video_ops,
++ .pad = &preview_v4l2_pad_ops,
++};
++
++/* -----------------------------------------------------------------------------
++ * Media entity operations
++ */
++
++/*
++ * preview_link_setup - Setup previewer connections.
++ * @entity : Pointer to media entity structure
++ * @local : Pointer to local pad array
++ * @remote : Pointer to remote pad array
++ * @flags : Link flags
++ * return -EINVAL or zero on success
++ */
++static int preview_link_setup(struct media_entity *entity,
++ const struct media_pad *local,
++ const struct media_pad *remote, u32 flags)
++{
++ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
++ struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
++
++ switch (local->index | media_entity_type(remote->entity)) {
++ case PREV_PAD_SINK | MEDIA_ENT_T_DEVNODE:
++ /* read from memory */
++ if (flags & MEDIA_LNK_FL_ENABLED) {
++ if (prev->input == PREVIEW_INPUT_CCDC)
++ return -EBUSY;
++ prev->input = PREVIEW_INPUT_MEMORY;
++ } else {
++ if (prev->input == PREVIEW_INPUT_MEMORY)
++ prev->input = PREVIEW_INPUT_NONE;
++ }
++ break;
++
++ case PREV_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
++ /* read from ccdc */
++ if (flags & MEDIA_LNK_FL_ENABLED) {
++ if (prev->input == PREVIEW_INPUT_MEMORY)
++ return -EBUSY;
++ prev->input = PREVIEW_INPUT_CCDC;
++ } else {
++ if (prev->input == PREVIEW_INPUT_CCDC)
++ prev->input = PREVIEW_INPUT_NONE;
++ }
++ break;
++
++ /*
++ * The ISP core doesn't support pipelines with multiple video outputs.
++ * Revisit this when it will be implemented, and return -EBUSY for now.
++ */
++
++ case PREV_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
++ /* write to memory */
++ if (flags & MEDIA_LNK_FL_ENABLED) {
++ if (prev->output & ~PREVIEW_OUTPUT_MEMORY)
++ return -EBUSY;
++ prev->output |= PREVIEW_OUTPUT_MEMORY;
++ } else {
++ prev->output &= ~PREVIEW_OUTPUT_MEMORY;
++ }
++ break;
++
++ case PREV_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
++ /* write to resizer */
++ if (flags & MEDIA_LNK_FL_ENABLED) {
++ if (prev->output & ~PREVIEW_OUTPUT_RESIZER)
++ return -EBUSY;
++ prev->output |= PREVIEW_OUTPUT_RESIZER;
++ } else {
++ prev->output &= ~PREVIEW_OUTPUT_RESIZER;
++ }
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++/* media operations */
++static const struct media_entity_operations preview_media_ops = {
++ .link_setup = preview_link_setup,
++};
++
++/*
++ * review_init_entities - Initialize subdev and media entity.
++ * @prev : Pointer to preview structure
++ * return -ENOMEM or zero on success
++ */
++static int preview_init_entities(struct isp_prev_device *prev)
++{
++ struct v4l2_subdev *sd = &prev->subdev;
++ struct media_pad *pads = prev->pads;
++ struct media_entity *me = &sd->entity;
++ int ret;
++
++ prev->input = PREVIEW_INPUT_NONE;
++
++ v4l2_subdev_init(sd, &preview_v4l2_ops);
++ strlcpy(sd->name, "OMAP3 ISP preview", sizeof(sd->name));
++ sd->grp_id = 1 << 16; /* group ID for isp subdevs */
++ v4l2_set_subdevdata(sd, prev);
++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
++
++ v4l2_ctrl_handler_init(&prev->ctrls, 3);
++ v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_BRIGHTNESS,
++ ISPPRV_BRIGHT_LOW, ISPPRV_BRIGHT_HIGH,
++ ISPPRV_BRIGHT_STEP, ISPPRV_BRIGHT_DEF);
++ v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_CONTRAST,
++ ISPPRV_CONTRAST_LOW, ISPPRV_CONTRAST_HIGH,
++ ISPPRV_CONTRAST_STEP, ISPPRV_CONTRAST_DEF);
++ v4l2_ctrl_handler_setup(&prev->ctrls);
++ sd->ctrl_handler = &prev->ctrls;
++
++ pads[PREV_PAD_SINK].flags = MEDIA_PAD_FL_INPUT;
++ pads[PREV_PAD_SOURCE].flags = MEDIA_PAD_FL_OUTPUT;
++
++ me->ops = &preview_media_ops;
++ ret = media_entity_init(me, PREV_PADS_NUM, pads, 0);
++ if (ret < 0)
++ return ret;
++
++ preview_init_formats(sd, NULL);
++
++ /* According to the OMAP34xx TRM, video buffers need to be aligned on a
++ * 32 bytes boundary. However, an undocumented hardware bug requires a
++ * 64 bytes boundary at the preview engine input.
++ */
++ prev->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
++ prev->video_in.ops = &preview_video_ops;
++ prev->video_in.isp = to_isp_device(prev);
++ prev->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
++ prev->video_in.bpl_alignment = 64;
++ prev->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ prev->video_out.ops = &preview_video_ops;
++ prev->video_out.isp = to_isp_device(prev);
++ prev->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
++ prev->video_out.bpl_alignment = 32;
++
++ ret = omap3isp_video_init(&prev->video_in, "preview");
++ if (ret < 0)
++ return ret;
++
++ ret = omap3isp_video_init(&prev->video_out, "preview");
++ if (ret < 0)
++ return ret;
++
++ /* Connect the video nodes to the previewer subdev. */
++ ret = media_entity_create_link(&prev->video_in.video.entity, 0,
++ &prev->subdev.entity, PREV_PAD_SINK, 0);
++ if (ret < 0)
++ return ret;
++
++ ret = media_entity_create_link(&prev->subdev.entity, PREV_PAD_SOURCE,
++ &prev->video_out.video.entity, 0, 0);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++void omap3isp_preview_unregister_entities(struct isp_prev_device *prev)
++{
++ media_entity_cleanup(&prev->subdev.entity);
++
++ v4l2_device_unregister_subdev(&prev->subdev);
++ v4l2_ctrl_handler_free(&prev->ctrls);
++ omap3isp_video_unregister(&prev->video_in);
++ omap3isp_video_unregister(&prev->video_out);
++}
++
++int omap3isp_preview_register_entities(struct isp_prev_device *prev,
++ struct v4l2_device *vdev)
++{
++ int ret;
++
++ /* Register the subdev and video nodes. */
++ ret = v4l2_device_register_subdev(vdev, &prev->subdev);
++ if (ret < 0)
++ goto error;
++
++ ret = omap3isp_video_register(&prev->video_in, vdev);
++ if (ret < 0)
++ goto error;
++
++ ret = omap3isp_video_register(&prev->video_out, vdev);
++ if (ret < 0)
++ goto error;
++
++ return 0;
++
++error:
++ omap3isp_preview_unregister_entities(prev);
++ return ret;
++}
++
++/* -----------------------------------------------------------------------------
++ * ISP previewer initialisation and cleanup
++ */
++
++void omap3isp_preview_cleanup(struct isp_device *isp)
++{
++}
++
++/*
++ * isp_preview_init - Previewer initialization.
++ * @dev : Pointer to ISP device
++ * return -ENOMEM or zero on success
++ */
++int omap3isp_preview_init(struct isp_device *isp)
++{
++ struct isp_prev_device *prev = &isp->isp_prev;
++ int ret;
++
++ spin_lock_init(&prev->lock);
++ init_waitqueue_head(&prev->wait);
++ preview_init_params(prev);
++
++ ret = preview_init_entities(prev);
++ if (ret < 0)
++ goto out;
++
++out:
++ if (ret)
++ omap3isp_preview_cleanup(isp);
++
++ return ret;
++}
+diff --git a/drivers/media/video/isp/isppreview.h b/drivers/media/video/isp/isppreview.h
+new file mode 100644
+index 0000000..e20c7c6
+--- /dev/null
++++ b/drivers/media/video/isp/isppreview.h
+@@ -0,0 +1,214 @@
++/*
++ * isppreview.h
++ *
++ * TI OMAP3 ISP - Preview module
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc.
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#ifndef OMAP3_ISP_PREVIEW_H
++#define OMAP3_ISP_PREVIEW_H
++
++#include <linux/omap3isp.h>
++#include <linux/types.h>
++#include <media/v4l2-ctrls.h>
++
++#include "ispvideo.h"
++
++#define ISPPRV_BRIGHT_STEP 0x1
++#define ISPPRV_BRIGHT_DEF 0x0
++#define ISPPRV_BRIGHT_LOW 0x0
++#define ISPPRV_BRIGHT_HIGH 0xFF
++#define ISPPRV_BRIGHT_UNITS 0x1
++
++#define ISPPRV_CONTRAST_STEP 0x1
++#define ISPPRV_CONTRAST_DEF 0x10
++#define ISPPRV_CONTRAST_LOW 0x0
++#define ISPPRV_CONTRAST_HIGH 0xFF
++#define ISPPRV_CONTRAST_UNITS 0x1
++
++#define NO_AVE 0x0
++#define AVE_2_PIX 0x1
++#define AVE_4_PIX 0x2
++#define AVE_8_PIX 0x3
++
++/* Features list */
++#define PREV_LUMA_ENHANCE OMAP3ISP_PREV_LUMAENH
++#define PREV_INVERSE_ALAW OMAP3ISP_PREV_INVALAW
++#define PREV_HORZ_MEDIAN_FILTER OMAP3ISP_PREV_HRZ_MED
++#define PREV_CFA OMAP3ISP_PREV_CFA
++#define PREV_CHROMA_SUPPRESS OMAP3ISP_PREV_CHROMA_SUPP
++#define PREV_WB OMAP3ISP_PREV_WB
++#define PREV_BLKADJ OMAP3ISP_PREV_BLKADJ
++#define PREV_RGB2RGB OMAP3ISP_PREV_RGB2RGB
++#define PREV_COLOR_CONV OMAP3ISP_PREV_COLOR_CONV
++#define PREV_YCLIMITS OMAP3ISP_PREV_YC_LIMIT
++#define PREV_DEFECT_COR OMAP3ISP_PREV_DEFECT_COR
++#define PREV_GAMMA_BYPASS OMAP3ISP_PREV_GAMMABYPASS
++#define PREV_DARK_FRAME_CAPTURE OMAP3ISP_PREV_DRK_FRM_CAPTURE
++#define PREV_DARK_FRAME_SUBTRACT OMAP3ISP_PREV_DRK_FRM_SUBTRACT
++#define PREV_LENS_SHADING OMAP3ISP_PREV_LENS_SHADING
++#define PREV_NOISE_FILTER OMAP3ISP_PREV_NF
++#define PREV_GAMMA OMAP3ISP_PREV_GAMMA
++
++#define PREV_CONTRAST (1 << 17)
++#define PREV_BRIGHTNESS (1 << 18)
++#define PREV_AVERAGER (1 << 19)
++#define PREV_FEATURES_END (1 << 20)
++
++enum preview_input_entity {
++ PREVIEW_INPUT_NONE,
++ PREVIEW_INPUT_CCDC,
++ PREVIEW_INPUT_MEMORY,
++};
++
++#define PREVIEW_OUTPUT_RESIZER (1 << 1)
++#define PREVIEW_OUTPUT_MEMORY (1 << 2)
++
++/* Configure byte layout of YUV image */
++enum preview_ycpos_mode {
++ YCPOS_YCrYCb = 0,
++ YCPOS_YCbYCr = 1,
++ YCPOS_CbYCrY = 2,
++ YCPOS_CrYCbY = 3
++};
++
++/*
++ * struct prev_params - Structure for all configuration
++ * @features: Set of features enabled.
++ * @cfa: CFA coefficients.
++ * @csup: Chroma suppression coefficients.
++ * @luma: Luma enhancement coefficients.
++ * @nf: Noise filter coefficients.
++ * @dcor: Noise filter coefficients.
++ * @gamma: Gamma coefficients.
++ * @wbal: White Balance parameters.
++ * @blk_adj: Black adjustment parameters.
++ * @rgb2rgb: RGB blending parameters.
++ * @rgb2ycbcr: RGB to ycbcr parameters.
++ * @hmed: Horizontal median filter.
++ * @yclimit: YC limits parameters.
++ * @average: Downsampling rate for averager.
++ * @contrast: Contrast.
++ * @brightness: Brightness.
++ */
++struct prev_params {
++ u32 features;
++ struct omap3isp_prev_cfa cfa;
++ struct omap3isp_prev_csup csup;
++ struct omap3isp_prev_luma luma;
++ struct omap3isp_prev_nf nf;
++ struct omap3isp_prev_dcor dcor;
++ struct omap3isp_prev_gtables gamma;
++ struct omap3isp_prev_wbal wbal;
++ struct omap3isp_prev_blkadj blk_adj;
++ struct omap3isp_prev_rgbtorgb rgb2rgb;
++ struct omap3isp_prev_csc rgb2ycbcr;
++ struct omap3isp_prev_hmed hmed;
++ struct omap3isp_prev_yclimit yclimit;
++ u8 average;
++ u8 contrast;
++ u8 brightness;
++};
++
++/*
++ * struct isptables_update - Structure for Table Configuration.
++ * @update: Specifies which tables should be updated.
++ * @flag: Specifies which tables should be enabled.
++ * @nf: Pointer to structure for Noise Filter
++ * @lsc: Pointer to LSC gain table. (currently not used)
++ * @gamma: Pointer to gamma correction tables.
++ * @cfa: Pointer to color filter array configuration.
++ * @wbal: Pointer to colour and digital gain configuration.
++ */
++struct isptables_update {
++ u32 update;
++ u32 flag;
++ struct omap3isp_prev_nf *nf;
++ u32 *lsc;
++ struct omap3isp_prev_gtables *gamma;
++ struct omap3isp_prev_cfa *cfa;
++ struct omap3isp_prev_wbal *wbal;
++};
++
++/* Sink and source previewer pads */
++#define PREV_PAD_SINK 0
++#define PREV_PAD_SOURCE 1
++#define PREV_PADS_NUM 2
++
++/*
++ * struct isp_prev_device - Structure for storing ISP Preview module information
++ * @subdev: V4L2 subdevice
++ * @pads: Media entity pads
++ * @formats: Active formats at the subdev pad
++ * @input: Module currently connected to the input pad
++ * @output: Bitmask of the active output
++ * @video_in: Input video entity
++ * @video_out: Output video entity
++ * @error: A hardware error occured during capture
++ * @params: Module configuration data
++ * @shadow_update: If set, update the hardware configured in the next interrupt
++ * @underrun: Whether the preview entity has queued buffers on the output
++ * @state: Current preview pipeline state
++ * @lock: Shadow update lock
++ * @update: Bitmask of the parameters to be updated
++ *
++ * This structure is used to store the OMAP ISP Preview module Information.
++ */
++struct isp_prev_device {
++ struct v4l2_subdev subdev;
++ struct media_pad pads[PREV_PADS_NUM];
++ struct v4l2_mbus_framefmt formats[PREV_PADS_NUM];
++
++ struct v4l2_ctrl_handler ctrls;
++
++ enum preview_input_entity input;
++ unsigned int output;
++ struct isp_video video_in;
++ struct isp_video video_out;
++ unsigned int error;
++
++ struct prev_params params;
++ unsigned int shadow_update:1;
++ enum isp_pipeline_stream_state state;
++ wait_queue_head_t wait;
++ atomic_t stopping;
++ spinlock_t lock;
++ u32 update;
++};
++
++struct isp_device;
++
++int omap3isp_preview_init(struct isp_device *isp);
++void omap3isp_preview_cleanup(struct isp_device *isp);
++
++int omap3isp_preview_register_entities(struct isp_prev_device *prv,
++ struct v4l2_device *vdev);
++void omap3isp_preview_unregister_entities(struct isp_prev_device *prv);
++
++void omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev);
++void omap3isp_preview_isr(struct isp_prev_device *prev);
++
++int omap3isp_preview_busy(struct isp_prev_device *isp_prev);
++
++void omap3isp_preview_restore_context(struct isp_device *isp);
++
++#endif /* OMAP3_ISP_PREVIEW_H */
+diff --git a/drivers/media/video/isp/ispqueue.c b/drivers/media/video/isp/ispqueue.c
+new file mode 100644
+index 0000000..af78c19
+--- /dev/null
++++ b/drivers/media/video/isp/ispqueue.c
+@@ -0,0 +1,1136 @@
++/*
++ * ispqueue.c
++ *
++ * TI OMAP3 ISP - Video buffers queue handling
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#include <asm/cacheflush.h>
++#include <linux/dma-mapping.h>
++#include <linux/mm.h>
++#include <linux/pagemap.h>
++#include <linux/poll.h>
++#include <linux/scatterlist.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++
++#include "ispqueue.h"
++
++/* -----------------------------------------------------------------------------
++ * Video buffers management
++ */
++
++/*
++ * isp_video_buffer_cache_sync - Keep the buffers coherent between CPU and ISP
++ *
++ * The typical operation required here is Cache Invalidation across
++ * the (user space) buffer address range. And this _must_ be done
++ * at QBUF stage (and *only* at QBUF).
++ *
++ * We try to use optimal cache invalidation function:
++ * - dmac_map_area:
++ * - used when the number of pages are _low_.
++ * - it becomes quite slow as the number of pages increase.
++ * - for 648x492 viewfinder (150 pages) it takes 1.3 ms.
++ * - for 5 Mpix buffer (2491 pages) it takes between 25-50 ms.
++ *
++ * - flush_cache_all:
++ * - used when the number of pages are _high_.
++ * - time taken in the range of 500-900 us.
++ * - has a higher penalty but, as whole dcache + icache is invalidated
++ */
++/*
++ * FIXME: dmac_inv_range crashes randomly on the user space buffer
++ * address. Fall back to flush_cache_all for now.
++ */
++#define ISP_CACHE_FLUSH_PAGES_MAX 0
++
++static void isp_video_buffer_cache_sync(struct isp_video_buffer *buf)
++{
++ if (buf->vbuf.m.userptr == 0 || buf->npages == 0 ||
++ buf->npages > ISP_CACHE_FLUSH_PAGES_MAX)
++ flush_cache_all();
++ else {
++ dmac_map_area((void *)buf->vbuf.m.userptr, buf->vbuf.length,
++ DMA_FROM_DEVICE);
++ outer_inv_range(buf->vbuf.m.userptr,
++ buf->vbuf.m.userptr + buf->vbuf.length);
++ }
++}
++
++/*
++ * isp_video_buffer_lock_vma - Prevent VMAs from being unmapped
++ *
++ * Lock the VMAs underlying the given buffer into memory. This avoids the
++ * userspace buffer mapping from being swapped out, making VIPT cache handling
++ * easier.
++ *
++ * Note that the pages will not be freed as the buffers have been locked to
++ * memory using by a call to get_user_pages(), but the userspace mapping could
++ * still disappear if the VMAs are not locked. This is caused by the memory
++ * management code trying to be as lock-less as possible, which results in the
++ * userspace mapping manager not finding out that the pages are locked under
++ * some conditions.
++ */
++static int isp_video_buffer_lock_vma(struct isp_video_buffer *buf, int lock)
++{
++ struct vm_area_struct *vma;
++ unsigned long start;
++ unsigned long end;
++ int ret = 0;
++
++ if (buf->vbuf.memory == V4L2_MEMORY_MMAP)
++ return 0;
++
++ /* We can be called from workqueue context if the current task dies to
++ * unlock the VMAs. In that case there's no current memory management
++ * context so unlocking can't be performed, but the VMAs have been or
++ * are getting destroyed anyway so it doesn't really matter.
++ */
++ if (!current || !current->mm)
++ return lock ? -EINVAL : 0;
++
++ start = buf->vbuf.m.userptr;
++ end = buf->vbuf.m.userptr + buf->vbuf.length - 1;
++
++ down_write(&current->mm->mmap_sem);
++ spin_lock(&current->mm->page_table_lock);
++
++ do {
++ vma = find_vma(current->mm, start);
++ if (vma == NULL) {
++ ret = -EFAULT;
++ goto out;
++ }
++
++ if (lock)
++ vma->vm_flags |= VM_LOCKED;
++ else
++ vma->vm_flags &= ~VM_LOCKED;
++
++ start = vma->vm_end + 1;
++ } while (vma->vm_end < end);
++
++ if (lock)
++ buf->vm_flags |= VM_LOCKED;
++ else
++ buf->vm_flags &= ~VM_LOCKED;
++
++out:
++ spin_unlock(&current->mm->page_table_lock);
++ up_write(&current->mm->mmap_sem);
++ return ret;
++}
++
++/*
++ * isp_video_buffer_sglist_kernel - Build a scatter list for a vmalloc'ed buffer
++ *
++ * Iterate over the vmalloc'ed area and create a scatter list entry for every
++ * page.
++ */
++static int isp_video_buffer_sglist_kernel(struct isp_video_buffer *buf)
++{
++ struct scatterlist *sglist;
++ unsigned int npages;
++ unsigned int i;
++ void *addr;
++
++ addr = buf->vaddr;
++ npages = PAGE_ALIGN(buf->vbuf.length) >> PAGE_SHIFT;
++
++ sglist = vmalloc(npages * sizeof(*sglist));
++ if (sglist == NULL)
++ return -ENOMEM;
++
++ sg_init_table(sglist, npages);
++
++ for (i = 0; i < npages; ++i, addr += PAGE_SIZE) {
++ struct page *page = vmalloc_to_page(addr);
++
++ if (page == NULL || PageHighMem(page)) {
++ vfree(sglist);
++ return -EINVAL;
++ }
++
++ sg_set_page(&sglist[i], page, PAGE_SIZE, 0);
++ }
++
++ buf->sglen = npages;
++ buf->sglist = sglist;
++
++ return 0;
++}
++
++/*
++ * isp_video_buffer_sglist_user - Build a scatter list for a userspace buffer
++ *
++ * Walk the buffer pages list and create a 1:1 mapping to a scatter list.
++ */
++static int isp_video_buffer_sglist_user(struct isp_video_buffer *buf)
++{
++ struct scatterlist *sglist;
++ unsigned int offset = buf->offset;
++ unsigned int i;
++
++ sglist = vmalloc(buf->npages * sizeof(*sglist));
++ if (sglist == NULL)
++ return -ENOMEM;
++
++ sg_init_table(sglist, buf->npages);
++
++ for (i = 0; i < buf->npages; ++i) {
++ if (PageHighMem(buf->pages[i])) {
++ vfree(sglist);
++ return -EINVAL;
++ }
++
++ sg_set_page(&sglist[i], buf->pages[i], PAGE_SIZE - offset,
++ offset);
++ offset = 0;
++ }
++
++ buf->sglen = buf->npages;
++ buf->sglist = sglist;
++
++ return 0;
++}
++
++/*
++ * isp_video_buffer_sglist_pfnmap - Build a scatter list for a VM_PFNMAP buffer
++ *
++ * Create a scatter list of physically contiguous pages starting at the buffer
++ * memory physical address.
++ */
++static int isp_video_buffer_sglist_pfnmap(struct isp_video_buffer *buf)
++{
++ struct scatterlist *sglist;
++ unsigned int offset = buf->offset;
++ unsigned long pfn = buf->paddr >> PAGE_SHIFT;
++ unsigned int i;
++
++ sglist = vmalloc(buf->npages * sizeof(*sglist));
++ if (sglist == NULL)
++ return -ENOMEM;
++
++ sg_init_table(sglist, buf->npages);
++
++ for (i = 0; i < buf->npages; ++i, ++pfn) {
++ sg_set_page(&sglist[i], pfn_to_page(pfn), PAGE_SIZE - offset,
++ offset);
++ /* PFNMAP buffers will not get DMA-mapped, set the DMA address
++ * manually.
++ */
++ sg_dma_address(&sglist[i]) = (pfn << PAGE_SHIFT) + offset;
++ offset = 0;
++ }
++
++ buf->sglen = buf->npages;
++ buf->sglist = sglist;
++
++ return 0;
++}
++
++/*
++ * isp_video_buffer_cleanup - Release pages for a userspace VMA.
++ *
++ * Release pages locked by a call isp_video_buffer_prepare_user and free the
++ * pages table.
++ */
++static void isp_video_buffer_cleanup(struct isp_video_buffer *buf)
++{
++ enum dma_data_direction direction;
++ unsigned int i;
++
++ if (buf->queue->ops->buffer_cleanup)
++ buf->queue->ops->buffer_cleanup(buf);
++
++ if (!(buf->vm_flags & VM_PFNMAP)) {
++ direction = buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE
++ ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
++ dma_unmap_sg(buf->queue->dev, buf->sglist, buf->sglen,
++ direction);
++ }
++
++ vfree(buf->sglist);
++ buf->sglist = NULL;
++ buf->sglen = 0;
++
++ if (buf->pages != NULL) {
++ isp_video_buffer_lock_vma(buf, 0);
++
++ for (i = 0; i < buf->npages; ++i)
++ page_cache_release(buf->pages[i]);
++
++ vfree(buf->pages);
++ buf->pages = NULL;
++ }
++
++ buf->npages = 0;
++}
++
++/*
++ * isp_video_buffer_prepare_user - Pin userspace VMA pages to memory.
++ *
++ * This function creates a list of pages for a userspace VMA. The number of
++ * pages is first computed based on the buffer size, and pages are then
++ * retrieved by a call to get_user_pages.
++ *
++ * Pages are pinned to memory by get_user_pages, making them available for DMA
++ * transfers. However, due to memory management optimization, it seems the
++ * get_user_pages doesn't guarantee that the pinned pages will not be written
++ * to swap and removed from the userspace mapping(s). When this happens, a page
++ * fault can be generated when accessing those unmapped pages.
++ *
++ * If the fault is triggered by a page table walk caused by VIPT cache
++ * management operations, the page fault handler might oops if the MM semaphore
++ * is held, as it can't handle kernel page faults in that case. To fix that, a
++ * fixup entry needs to be added to the cache management code, or the userspace
++ * VMA must be locked to avoid removing pages from the userspace mapping in the
++ * first place.
++ *
++ * If the number of pages retrieved is smaller than the number required by the
++ * buffer size, the function returns -EFAULT.
++ */
++static int isp_video_buffer_prepare_user(struct isp_video_buffer *buf)
++{
++ unsigned long data;
++ unsigned int first;
++ unsigned int last;
++ int ret;
++
++ data = buf->vbuf.m.userptr;
++ first = (data & PAGE_MASK) >> PAGE_SHIFT;
++ last = ((data + buf->vbuf.length - 1) & PAGE_MASK) >> PAGE_SHIFT;
++
++ buf->offset = data & ~PAGE_MASK;
++ buf->npages = last - first + 1;
++ buf->pages = vmalloc(buf->npages * sizeof(buf->pages[0]));
++ if (buf->pages == NULL)
++ return -ENOMEM;
++
++ down_read(&current->mm->mmap_sem);
++ ret = get_user_pages(current, current->mm, data & PAGE_MASK,
++ buf->npages,
++ buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
++ buf->pages, NULL);
++ up_read(&current->mm->mmap_sem);
++
++ if (ret != buf->npages) {
++ buf->npages = ret;
++ isp_video_buffer_cleanup(buf);
++ return -EFAULT;
++ }
++
++ ret = isp_video_buffer_lock_vma(buf, 1);
++ if (ret < 0)
++ isp_video_buffer_cleanup(buf);
++
++ return ret;
++}
++
++/*
++ * isp_video_buffer_prepare_pfnmap - Validate a VM_PFNMAP userspace buffer
++ *
++ * Userspace VM_PFNMAP buffers are supported only if they are contiguous in
++ * memory and if they span a single VMA.
++ *
++ * Return 0 if the buffer is valid, or -EFAULT otherwise.
++ */
++static int isp_video_buffer_prepare_pfnmap(struct isp_video_buffer *buf)
++{
++ struct vm_area_struct *vma;
++ unsigned long prev_pfn;
++ unsigned long this_pfn;
++ unsigned long start;
++ unsigned long end;
++ dma_addr_t pa;
++ int ret = -EFAULT;
++
++ start = buf->vbuf.m.userptr;
++ end = buf->vbuf.m.userptr + buf->vbuf.length - 1;
++
++ buf->offset = start & ~PAGE_MASK;
++ buf->npages = (end >> PAGE_SHIFT) - (start >> PAGE_SHIFT) + 1;
++ buf->pages = NULL;
++
++ down_read(&current->mm->mmap_sem);
++ vma = find_vma(current->mm, start);
++ if (vma == NULL || vma->vm_end < end)
++ goto done;
++
++ for (prev_pfn = 0; start <= end; start += PAGE_SIZE) {
++ ret = follow_pfn(vma, start, &this_pfn);
++ if (ret)
++ goto done;
++
++ if (prev_pfn == 0)
++ pa = this_pfn << PAGE_SHIFT;
++ else if (this_pfn != prev_pfn + 1) {
++ ret = -EFAULT;
++ goto done;
++ }
++
++ prev_pfn = this_pfn;
++ }
++
++ buf->paddr = pa + buf->offset;
++ ret = 0;
++
++done:
++ up_read(&current->mm->mmap_sem);
++ return ret;
++}
++
++/*
++ * isp_video_buffer_prepare_vm_flags - Get VMA flags for a userspace address
++ *
++ * This function locates the VMAs for the buffer's userspace address and checks
++ * that their flags match. The onlflag that we need to care for at the moment is
++ * VM_PFNMAP.
++ *
++ * The buffer vm_flags field is set to the first VMA flags.
++ *
++ * Return -EFAULT if no VMA can be found for part of the buffer, or if the VMAs
++ * have incompatible flags.
++ */
++static int isp_video_buffer_prepare_vm_flags(struct isp_video_buffer *buf)
++{
++ struct vm_area_struct *vma;
++ unsigned long start;
++ unsigned long end;
++ int ret = -EFAULT;
++
++ start = buf->vbuf.m.userptr;
++ end = buf->vbuf.m.userptr + buf->vbuf.length - 1;
++
++ down_read(&current->mm->mmap_sem);
++
++ do {
++ vma = find_vma(current->mm, start);
++ if (vma == NULL)
++ goto done;
++
++ if (start == buf->vbuf.m.userptr)
++ buf->vm_flags = vma->vm_flags;
++
++ if ((buf->vm_flags ^ vma->vm_flags) & VM_PFNMAP)
++ goto done;
++
++ start = vma->vm_end + 1;
++ } while (vma->vm_end < end);
++
++ ret = 0;
++
++done:
++ up_read(&current->mm->mmap_sem);
++ return ret;
++}
++
++/*
++ * isp_video_buffer_prepare - Make a buffer ready for operation
++ *
++ * Preparing a buffer involves:
++ *
++ * - validating VMAs (userspace buffers only)
++ * - locking pages and VMAs into memory (userspace buffers only)
++ * - building page and scatter-gather lists
++ * - mapping buffers for DMA operation
++ * - performing driver-specific preparation
++ *
++ * The function must be called in userspace context with a valid mm context
++ * (this excludes cleanup paths such as sys_close when the userspace process
++ * segfaults).
++ */
++static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
++{
++ enum dma_data_direction direction;
++ int ret;
++
++ switch (buf->vbuf.memory) {
++ case V4L2_MEMORY_MMAP:
++ ret = isp_video_buffer_sglist_kernel(buf);
++ break;
++
++ case V4L2_MEMORY_USERPTR:
++ ret = isp_video_buffer_prepare_vm_flags(buf);
++ if (ret < 0)
++ return ret;
++
++ if (buf->vm_flags & VM_PFNMAP) {
++ ret = isp_video_buffer_prepare_pfnmap(buf);
++ if (ret < 0)
++ return ret;
++
++ ret = isp_video_buffer_sglist_pfnmap(buf);
++ } else {
++ ret = isp_video_buffer_prepare_user(buf);
++ if (ret < 0)
++ return ret;
++
++ ret = isp_video_buffer_sglist_user(buf);
++ }
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ if (ret < 0)
++ goto done;
++
++ if (!(buf->vm_flags & VM_PFNMAP)) {
++ direction = buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE
++ ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
++ ret = dma_map_sg(buf->queue->dev, buf->sglist, buf->sglen,
++ direction);
++ if (ret != buf->sglen) {
++ ret = -EFAULT;
++ goto done;
++ }
++ }
++
++ if (buf->queue->ops->buffer_prepare)
++ ret = buf->queue->ops->buffer_prepare(buf);
++
++done:
++ if (ret < 0) {
++ isp_video_buffer_cleanup(buf);
++ return ret;
++ }
++
++ return ret;
++}
++
++/*
++ * isp_video_queue_query - Query the status of a given buffer
++ *
++ * Locking: must be called with the queue lock held.
++ */
++static void isp_video_buffer_query(struct isp_video_buffer *buf,
++ struct v4l2_buffer *vbuf)
++{
++ memcpy(vbuf, &buf->vbuf, sizeof(*vbuf));
++
++ if (buf->vma_use_count)
++ vbuf->flags |= V4L2_BUF_FLAG_MAPPED;
++
++ switch (buf->state) {
++ case ISP_BUF_STATE_ERROR:
++ vbuf->flags |= V4L2_BUF_FLAG_ERROR;
++ case ISP_BUF_STATE_DONE:
++ vbuf->flags |= V4L2_BUF_FLAG_DONE;
++ case ISP_BUF_STATE_QUEUED:
++ case ISP_BUF_STATE_ACTIVE:
++ vbuf->flags |= V4L2_BUF_FLAG_QUEUED;
++ break;
++ case ISP_BUF_STATE_IDLE:
++ default:
++ break;
++ }
++}
++
++/*
++ * isp_video_buffer_wait - Wait for a buffer to be ready
++ *
++ * In non-blocking mode, return immediately with 0 if the buffer is ready or
++ * -EAGAIN if the buffer is in the QUEUED or ACTIVE state.
++ *
++ * In blocking mode, wait (interruptibly but with no timeout) on the buffer wait
++ * queue using the same condition.
++ */
++static int isp_video_buffer_wait(struct isp_video_buffer *buf, int nonblocking)
++{
++ if (nonblocking) {
++ return (buf->state != ISP_BUF_STATE_QUEUED &&
++ buf->state != ISP_BUF_STATE_ACTIVE)
++ ? 0 : -EAGAIN;
++ }
++
++ return wait_event_interruptible(buf->wait,
++ buf->state != ISP_BUF_STATE_QUEUED &&
++ buf->state != ISP_BUF_STATE_ACTIVE);
++}
++
++/* -----------------------------------------------------------------------------
++ * Queue management
++ */
++
++/*
++ * isp_video_queue_free - Free video buffers memory
++ *
++ * Buffers can only be freed if the queue isn't streaming and if no buffer is
++ * mapped to userspace. Return -EBUSY if those conditions aren't statisfied.
++ *
++ * This function must be called with the queue lock held.
++ */
++static int isp_video_queue_free(struct isp_video_queue *queue)
++{
++ unsigned int i;
++
++ if (queue->streaming)
++ return -EBUSY;
++
++ for (i = 0; i < queue->count; ++i) {
++ if (queue->buffers[i]->vma_use_count != 0)
++ return -EBUSY;
++ }
++
++ for (i = 0; i < queue->count; ++i) {
++ struct isp_video_buffer *buf = queue->buffers[i];
++
++ isp_video_buffer_cleanup(buf);
++
++ vfree(buf->vaddr);
++ buf->vaddr = NULL;
++
++ kfree(buf);
++ queue->buffers[i] = NULL;
++ }
++
++ INIT_LIST_HEAD(&queue->queue);
++ queue->count = 0;
++ return 0;
++}
++
++/*
++ * isp_video_queue_alloc - Allocate video buffers memory
++ *
++ * This function must be called with the queue lock held.
++ */
++static int isp_video_queue_alloc(struct isp_video_queue *queue,
++ unsigned int nbuffers,
++ unsigned int size, enum v4l2_memory memory)
++{
++ struct isp_video_buffer *buf;
++ unsigned int i;
++ void *mem;
++ int ret;
++
++ /* Start by freeing the buffers. */
++ ret = isp_video_queue_free(queue);
++ if (ret < 0)
++ return ret;
++
++ /* Bail out of no buffers should be allocated. */
++ if (nbuffers == 0)
++ return 0;
++
++ /* Initialize the allocated buffers. */
++ for (i = 0; i < nbuffers; ++i) {
++ buf = kzalloc(queue->bufsize, GFP_KERNEL);
++ if (buf == NULL)
++ break;
++
++ if (memory == V4L2_MEMORY_MMAP) {
++ /* Allocate video buffers memory for mmap mode. Align
++ * the size to the page size.
++ */
++ mem = vmalloc_32_user(PAGE_ALIGN(size));
++ if (mem == NULL) {
++ kfree(buf);
++ break;
++ }
++
++ buf->vbuf.m.offset = i * PAGE_ALIGN(size);
++ buf->vaddr = mem;
++ }
++
++ buf->vbuf.index = i;
++ buf->vbuf.length = size;
++ buf->vbuf.type = queue->type;
++ buf->vbuf.field = V4L2_FIELD_NONE;
++ buf->vbuf.memory = memory;
++
++ buf->queue = queue;
++ init_waitqueue_head(&buf->wait);
++
++ queue->buffers[i] = buf;
++ }
++
++ if (i == 0)
++ return -ENOMEM;
++
++ queue->count = i;
++ return nbuffers;
++}
++
++/**
++ * omap3isp_video_queue_cleanup - Clean up the video buffers queue
++ * @queue: Video buffers queue
++ *
++ * Free all allocated resources and clean up the video buffers queue. The queue
++ * must not be busy (no ongoing video stream) and buffers must have been
++ * unmapped.
++ *
++ * Return 0 on success or -EBUSY if the queue is busy or buffers haven't been
++ * unmapped.
++ */
++int omap3isp_video_queue_cleanup(struct isp_video_queue *queue)
++{
++ return isp_video_queue_free(queue);
++}
++
++/**
++ * omap3isp_video_queue_init - Initialize the video buffers queue
++ * @queue: Video buffers queue
++ * @type: V4L2 buffer type (capture or output)
++ * @ops: Driver-specific queue operations
++ * @dev: Device used for DMA operations
++ * @bufsize: Size of the driver-specific buffer structure
++ *
++ * Initialize the video buffers queue with the supplied parameters.
++ *
++ * The queue type must be one of V4L2_BUF_TYPE_VIDEO_CAPTURE or
++ * V4L2_BUF_TYPE_VIDEO_OUTPUT. Other buffer types are not supported yet.
++ *
++ * Buffer objects will be allocated using the given buffer size to allow room
++ * for driver-specific fields. Driver-specific buffer structures must start
++ * with a struct isp_video_buffer field. Drivers with no driver-specific buffer
++ * structure must pass the size of the isp_video_buffer structure in the bufsize
++ * parameter.
++ *
++ * Return 0 on success.
++ */
++int omap3isp_video_queue_init(struct isp_video_queue *queue,
++ enum v4l2_buf_type type,
++ const struct isp_video_queue_operations *ops,
++ struct device *dev, unsigned int bufsize)
++{
++ INIT_LIST_HEAD(&queue->queue);
++ mutex_init(&queue->lock);
++ spin_lock_init(&queue->irqlock);
++
++ queue->type = type;
++ queue->ops = ops;
++ queue->dev = dev;
++ queue->bufsize = bufsize;
++
++ return 0;
++}
++
++/* -----------------------------------------------------------------------------
++ * V4L2 operations
++ */
++
++/**
++ * omap3isp_video_queue_reqbufs - Allocate video buffers memory
++ *
++ * This function is intended to be used as a VIDIOC_REQBUFS ioctl handler. It
++ * allocated video buffer objects and, for MMAP buffers, buffer memory.
++ *
++ * If the number of buffers is 0, all buffers are freed and the function returns
++ * without performing any allocation.
++ *
++ * If the number of buffers is not 0, currently allocated buffers (if any) are
++ * freed and the requested number of buffers are allocated. Depending on
++ * driver-specific requirements and on memory availability, a number of buffer
++ * smaller or bigger than requested can be allocated. This isn't considered as
++ * an error.
++ *
++ * Return 0 on success or one of the following error codes:
++ *
++ * -EINVAL if the buffer type or index are invalid
++ * -EBUSY if the queue is busy (streaming or buffers mapped)
++ * -ENOMEM if the buffers can't be allocated due to an out-of-memory condition
++ */
++int omap3isp_video_queue_reqbufs(struct isp_video_queue *queue,
++ struct v4l2_requestbuffers *rb)
++{
++ unsigned int nbuffers = rb->count;
++ unsigned int size;
++ int ret;
++
++ if (rb->type != queue->type)
++ return -EINVAL;
++
++ queue->ops->queue_prepare(queue, &nbuffers, &size);
++ if (size == 0)
++ return -EINVAL;
++
++ nbuffers = min_t(unsigned int, nbuffers, ISP_VIDEO_MAX_BUFFERS);
++
++ mutex_lock(&queue->lock);
++
++ ret = isp_video_queue_alloc(queue, nbuffers, size, rb->memory);
++ if (ret < 0)
++ goto done;
++
++ rb->count = ret;
++ ret = 0;
++
++done:
++ mutex_unlock(&queue->lock);
++ return ret;
++}
++
++/**
++ * omap3isp_video_queue_querybuf - Query the status of a buffer in a queue
++ *
++ * This function is intended to be used as a VIDIOC_QUERYBUF ioctl handler. It
++ * returns the status of a given video buffer.
++ *
++ * Return 0 on success or -EINVAL if the buffer type or index are invalid.
++ */
++int omap3isp_video_queue_querybuf(struct isp_video_queue *queue,
++ struct v4l2_buffer *vbuf)
++{
++ struct isp_video_buffer *buf;
++ int ret = 0;
++
++ if (vbuf->type != queue->type)
++ return -EINVAL;
++
++ mutex_lock(&queue->lock);
++
++ if (vbuf->index >= queue->count) {
++ ret = -EINVAL;
++ goto done;
++ }
++
++ buf = queue->buffers[vbuf->index];
++ isp_video_buffer_query(buf, vbuf);
++
++done:
++ mutex_unlock(&queue->lock);
++ return ret;
++}
++
++/**
++ * omap3isp_video_queue_qbuf - Queue a buffer
++ *
++ * This function is intended to be used as a VIDIOC_QBUF ioctl handler.
++ *
++ * The v4l2_buffer structure passed from userspace is first sanity tested. If
++ * sane, the buffer is then processed and added to the main queue and, if the
++ * queue is streaming, to the IRQ queue.
++ *
++ * Before being enqueued, USERPTR buffers are checked for address changes. If
++ * the buffer has a different userspace address, the old memory area is unlocked
++ * and the new memory area is locked.
++ */
++int omap3isp_video_queue_qbuf(struct isp_video_queue *queue,
++ struct v4l2_buffer *vbuf)
++{
++ struct isp_video_buffer *buf;
++ unsigned long flags;
++ int ret = -EINVAL;
++
++ if (vbuf->type != queue->type)
++ goto done;
++
++ mutex_lock(&queue->lock);
++
++ if (vbuf->index >= queue->count)
++ goto done;
++
++ buf = queue->buffers[vbuf->index];
++
++ if (vbuf->memory != buf->vbuf.memory)
++ goto done;
++
++ if (buf->state != ISP_BUF_STATE_IDLE)
++ goto done;
++
++ if (vbuf->memory == V4L2_MEMORY_USERPTR &&
++ vbuf->m.userptr != buf->vbuf.m.userptr) {
++ isp_video_buffer_cleanup(buf);
++ buf->vbuf.m.userptr = vbuf->m.userptr;
++ buf->prepared = 0;
++ }
++
++ if (!buf->prepared) {
++ ret = isp_video_buffer_prepare(buf);
++ if (ret < 0)
++ goto done;
++ buf->prepared = 1;
++ }
++
++ isp_video_buffer_cache_sync(buf);
++
++ buf->state = ISP_BUF_STATE_QUEUED;
++ list_add_tail(&buf->stream, &queue->queue);
++
++ if (queue->streaming) {
++ spin_lock_irqsave(&queue->irqlock, flags);
++ queue->ops->buffer_queue(buf);
++ spin_unlock_irqrestore(&queue->irqlock, flags);
++ }
++
++ ret = 0;
++
++done:
++ mutex_unlock(&queue->lock);
++ return ret;
++}
++
++/**
++ * omap3isp_video_queue_dqbuf - Dequeue a buffer
++ *
++ * This function is intended to be used as a VIDIOC_DQBUF ioctl handler.
++ *
++ * The v4l2_buffer structure passed from userspace is first sanity tested. If
++ * sane, the buffer is then processed and added to the main queue and, if the
++ * queue is streaming, to the IRQ queue.
++ *
++ * Before being enqueued, USERPTR buffers are checked for address changes. If
++ * the buffer has a different userspace address, the old memory area is unlocked
++ * and the new memory area is locked.
++ */
++int omap3isp_video_queue_dqbuf(struct isp_video_queue *queue,
++ struct v4l2_buffer *vbuf, int nonblocking)
++{
++ struct isp_video_buffer *buf;
++ int ret;
++
++ if (vbuf->type != queue->type)
++ return -EINVAL;
++
++ mutex_lock(&queue->lock);
++
++ if (list_empty(&queue->queue)) {
++ ret = -EINVAL;
++ goto done;
++ }
++
++ buf = list_first_entry(&queue->queue, struct isp_video_buffer, stream);
++ ret = isp_video_buffer_wait(buf, nonblocking);
++ if (ret < 0)
++ goto done;
++
++ list_del(&buf->stream);
++
++ isp_video_buffer_query(buf, vbuf);
++ buf->state = ISP_BUF_STATE_IDLE;
++ vbuf->flags &= ~V4L2_BUF_FLAG_QUEUED;
++
++done:
++ mutex_unlock(&queue->lock);
++ return ret;
++}
++
++/**
++ * omap3isp_video_queue_streamon - Start streaming
++ *
++ * This function is intended to be used as a VIDIOC_STREAMON ioctl handler. It
++ * starts streaming on the queue and calls the buffer_queue operation for all
++ * queued buffers.
++ *
++ * Return 0 on success.
++ */
++int omap3isp_video_queue_streamon(struct isp_video_queue *queue)
++{
++ struct isp_video_buffer *buf;
++ unsigned long flags;
++
++ mutex_lock(&queue->lock);
++
++ if (queue->streaming)
++ goto done;
++
++ queue->streaming = 1;
++
++ spin_lock_irqsave(&queue->irqlock, flags);
++ list_for_each_entry(buf, &queue->queue, stream)
++ queue->ops->buffer_queue(buf);
++ spin_unlock_irqrestore(&queue->irqlock, flags);
++
++done:
++ mutex_unlock(&queue->lock);
++ return 0;
++}
++
++/**
++ * omap3isp_video_queue_streamoff - Stop streaming
++ *
++ * This function is intended to be used as a VIDIOC_STREAMOFF ioctl handler. It
++ * stops streaming on the queue and wakes up all the buffers.
++ *
++ * Drivers must stop the hardware and synchronize with interrupt handlers and/or
++ * delayed works before calling this function to make sure no buffer will be
++ * touched by the driver and/or hardware.
++ */
++void omap3isp_video_queue_streamoff(struct isp_video_queue *queue)
++{
++ struct isp_video_buffer *buf;
++ unsigned long flags;
++ unsigned int i;
++
++ mutex_lock(&queue->lock);
++
++ if (!queue->streaming)
++ goto done;
++
++ queue->streaming = 0;
++
++ spin_lock_irqsave(&queue->irqlock, flags);
++ for (i = 0; i < queue->count; ++i) {
++ buf = queue->buffers[i];
++
++ if (buf->state == ISP_BUF_STATE_ACTIVE)
++ wake_up(&buf->wait);
++
++ buf->state = ISP_BUF_STATE_IDLE;
++ }
++ spin_unlock_irqrestore(&queue->irqlock, flags);
++
++ INIT_LIST_HEAD(&queue->queue);
++
++done:
++ mutex_unlock(&queue->lock);
++}
++
++/**
++ * omap3isp_video_queue_discard_done - Discard all buffers marked as DONE
++ *
++ * This function is intended to be used with suspend/resume operations. It
++ * discards all 'done' buffers as they would be too old to be requested after
++ * resume.
++ *
++ * Drivers must stop the hardware and synchronize with interrupt handlers and/or
++ * delayed works before calling this function to make sure no buffer will be
++ * touched by the driver and/or hardware.
++ */
++void omap3isp_video_queue_discard_done(struct isp_video_queue *queue)
++{
++ struct isp_video_buffer *buf;
++ unsigned int i;
++
++ mutex_lock(&queue->lock);
++
++ if (!queue->streaming)
++ goto done;
++
++ for (i = 0; i < queue->count; ++i) {
++ buf = queue->buffers[i];
++
++ if (buf->state == ISP_BUF_STATE_DONE)
++ buf->state = ISP_BUF_STATE_ERROR;
++ }
++
++done:
++ mutex_unlock(&queue->lock);
++}
++
++static void isp_video_queue_vm_open(struct vm_area_struct *vma)
++{
++ struct isp_video_buffer *buf = vma->vm_private_data;
++
++ buf->vma_use_count++;
++}
++
++static void isp_video_queue_vm_close(struct vm_area_struct *vma)
++{
++ struct isp_video_buffer *buf = vma->vm_private_data;
++
++ buf->vma_use_count--;
++}
++
++static const struct vm_operations_struct isp_video_queue_vm_ops = {
++ .open = isp_video_queue_vm_open,
++ .close = isp_video_queue_vm_close,
++};
++
++/**
++ * omap3isp_video_queue_mmap - Map buffers to userspace
++ *
++ * This function is intended to be used as an mmap() file operation handler. It
++ * maps a buffer to userspace based on the VMA offset.
++ *
++ * Only buffers of memory type MMAP are supported.
++ */
++int omap3isp_video_queue_mmap(struct isp_video_queue *queue,
++ struct vm_area_struct *vma)
++{
++ struct isp_video_buffer *uninitialized_var(buf);
++ unsigned long size;
++ unsigned int i;
++ int ret = 0;
++
++ mutex_lock(&queue->lock);
++
++ for (i = 0; i < queue->count; ++i) {
++ buf = queue->buffers[i];
++ if ((buf->vbuf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
++ break;
++ }
++
++ if (i == queue->count) {
++ ret = -EINVAL;
++ goto done;
++ }
++
++ size = vma->vm_end - vma->vm_start;
++
++ if (buf->vbuf.memory != V4L2_MEMORY_MMAP ||
++ size != PAGE_ALIGN(buf->vbuf.length)) {
++ ret = -EINVAL;
++ goto done;
++ }
++
++ ret = remap_vmalloc_range(vma, buf->vaddr, 0);
++ if (ret < 0)
++ goto done;
++
++ vma->vm_ops = &isp_video_queue_vm_ops;
++ vma->vm_private_data = buf;
++ isp_video_queue_vm_open(vma);
++
++done:
++ mutex_unlock(&queue->lock);
++ return ret;
++}
++
++/**
++ * omap3isp_video_queue_poll - Poll video queue state
++ *
++ * This function is intended to be used as a poll() file operation handler. It
++ * polls the state of the video buffer at the front of the queue and returns an
++ * events mask.
++ *
++ * If no buffer is present at the front of the queue, POLLERR is returned.
++ */
++unsigned int omap3isp_video_queue_poll(struct isp_video_queue *queue,
++ struct file *file, poll_table *wait)
++{
++ struct isp_video_buffer *buf;
++ unsigned int mask = 0;
++
++ mutex_lock(&queue->lock);
++ if (list_empty(&queue->queue)) {
++ mask |= POLLERR;
++ goto done;
++ }
++ buf = list_first_entry(&queue->queue, struct isp_video_buffer, stream);
++
++ poll_wait(file, &buf->wait, wait);
++ if (buf->state == ISP_BUF_STATE_DONE ||
++ buf->state == ISP_BUF_STATE_ERROR) {
++ if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ mask |= POLLIN | POLLRDNORM;
++ else
++ mask |= POLLOUT | POLLWRNORM;
++ }
++
++done:
++ mutex_unlock(&queue->lock);
++ return mask;
++}
+diff --git a/drivers/media/video/isp/ispqueue.h b/drivers/media/video/isp/ispqueue.h
+new file mode 100644
+index 0000000..f05aba3
+--- /dev/null
++++ b/drivers/media/video/isp/ispqueue.h
+@@ -0,0 +1,185 @@
++/*
++ * ispqueue.h
++ *
++ * TI OMAP3 ISP - Video buffers queue handling
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#ifndef OMAP3_ISP_QUEUE_H
++#define OMAP3_ISP_QUEUE_H
++
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/mutex.h>
++#include <linux/videodev2.h>
++#include <linux/wait.h>
++
++struct isp_video_queue;
++struct page;
++struct scatterlist;
++
++#define ISP_VIDEO_MAX_BUFFERS 16
++
++/**
++ * enum isp_video_buffer_state - ISP video buffer state
++ * @ISP_BUF_STATE_IDLE: The buffer is under userspace control (dequeued
++ * or not queued yet).
++ * @ISP_BUF_STATE_QUEUED: The buffer has been queued but isn't used by the
++ * device yet.
++ * @ISP_BUF_STATE_ACTIVE: The buffer is in use for an active video transfer.
++ * @ISP_BUF_STATE_ERROR: The device is done with the buffer and an error
++ * occured. For capture device the buffer likely contains corrupted data or
++ * no data at all.
++ * @ISP_BUF_STATE_DONE: The device is done with the buffer and no error occured.
++ * For capture devices the buffer contains valid data.
++ */
++enum isp_video_buffer_state {
++ ISP_BUF_STATE_IDLE,
++ ISP_BUF_STATE_QUEUED,
++ ISP_BUF_STATE_ACTIVE,
++ ISP_BUF_STATE_ERROR,
++ ISP_BUF_STATE_DONE,
++};
++
++/**
++ * struct isp_video_buffer - ISP video buffer
++ * @vma_use_count: Number of times the buffer is mmap'ed to userspace
++ * @stream: List head for insertion into main queue
++ * @queue: ISP buffers queue this buffer belongs to
++ * @prepared: Whether the buffer has been prepared
++ * @vaddr: Memory virtual address (for kernel buffers)
++ * @vm_flags: Buffer VMA flags (for userspace buffers)
++ * @offset: Offset inside the first page (for userspace buffers)
++ * @npages: Number of pages (for userspace buffers)
++ * @pages: Pages table (for userspace non-VM_PFNMAP buffers)
++ * @paddr: Memory physical address (for userspace VM_PFNMAP buffers)
++ * @sglen: Number of elements in the scatter list (for non-VM_PFNMAP buffers)
++ * @sglist: Scatter list (for non-VM_PFNMAP buffers)
++ * @vbuf: V4L2 buffer
++ * @irqlist: List head for insertion into IRQ queue
++ * @state: Current buffer state
++ * @wait: Wait queue to signal buffer completion
++ */
++struct isp_video_buffer {
++ unsigned long vma_use_count;
++ struct list_head stream;
++ struct isp_video_queue *queue;
++ unsigned int prepared:1;
++
++ /* For kernel buffers. */
++ void *vaddr;
++
++ /* For userspace buffers. */
++ unsigned long vm_flags;
++ unsigned long offset;
++ unsigned int npages;
++ struct page **pages;
++ dma_addr_t paddr;
++
++ /* For all buffers except VM_PFNMAP. */
++ unsigned int sglen;
++ struct scatterlist *sglist;
++
++ /* Touched by the interrupt handler. */
++ struct v4l2_buffer vbuf;
++ struct list_head irqlist;
++ enum isp_video_buffer_state state;
++ wait_queue_head_t wait;
++};
++
++#define to_isp_video_buffer(vb) container_of(vb, struct isp_video_buffer, vb)
++
++/**
++ * struct isp_video_queue_operations - Driver-specific operations
++ * @queue_prepare: Called before allocating buffers. Drivers should clamp the
++ * number of buffers according to their requirements, and must return the
++ * buffer size in bytes.
++ * @buffer_prepare: Called the first time a buffer is queued, or after changing
++ * the userspace memory address for a USERPTR buffer, with the queue lock
++ * held. Drivers should perform device-specific buffer preparation (such as
++ * mapping the buffer memory in an IOMMU). This operation is optional.
++ * @buffer_queue: Called when a buffer is being added to the queue with the
++ * queue irqlock spinlock held.
++ * @buffer_cleanup: Called before freeing buffers, or before changing the
++ * userspace memory address for a USERPTR buffer, with the queue lock held.
++ * Drivers must perform cleanup operations required to undo the
++ * buffer_prepare call. This operation is optional.
++ */
++struct isp_video_queue_operations {
++ void (*queue_prepare)(struct isp_video_queue *queue,
++ unsigned int *nbuffers, unsigned int *size);
++ int (*buffer_prepare)(struct isp_video_buffer *buf);
++ void (*buffer_queue)(struct isp_video_buffer *buf);
++ void (*buffer_cleanup)(struct isp_video_buffer *buf);
++};
++
++/**
++ * struct isp_video_queue - ISP video buffers queue
++ * @type: Type of video buffers handled by this queue
++ * @ops: Queue operations
++ * @dev: Device used for DMA operations
++ * @bufsize: Size of a driver-specific buffer object
++ * @count: Number of currently allocated buffers
++ * @buffers: ISP video buffers
++ * @lock: Mutex to protect access to the buffers, main queue and state
++ * @irqlock: Spinlock to protect access to the IRQ queue
++ * @streaming: Queue state, indicates whether the queue is streaming
++ * @queue: List of all queued buffers
++ */
++struct isp_video_queue {
++ enum v4l2_buf_type type;
++ const struct isp_video_queue_operations *ops;
++ struct device *dev;
++ unsigned int bufsize;
++
++ unsigned int count;
++ struct isp_video_buffer *buffers[ISP_VIDEO_MAX_BUFFERS];
++ struct mutex lock;
++ spinlock_t irqlock;
++
++ unsigned int streaming:1;
++
++ struct list_head queue;
++};
++
++int omap3isp_video_queue_cleanup(struct isp_video_queue *queue);
++int omap3isp_video_queue_init(struct isp_video_queue *queue,
++ enum v4l2_buf_type type,
++ const struct isp_video_queue_operations *ops,
++ struct device *dev, unsigned int bufsize);
++
++int omap3isp_video_queue_reqbufs(struct isp_video_queue *queue,
++ struct v4l2_requestbuffers *rb);
++int omap3isp_video_queue_querybuf(struct isp_video_queue *queue,
++ struct v4l2_buffer *vbuf);
++int omap3isp_video_queue_qbuf(struct isp_video_queue *queue,
++ struct v4l2_buffer *vbuf);
++int omap3isp_video_queue_dqbuf(struct isp_video_queue *queue,
++ struct v4l2_buffer *vbuf, int nonblocking);
++int omap3isp_video_queue_streamon(struct isp_video_queue *queue);
++void omap3isp_video_queue_streamoff(struct isp_video_queue *queue);
++void omap3isp_video_queue_discard_done(struct isp_video_queue *queue);
++int omap3isp_video_queue_mmap(struct isp_video_queue *queue,
++ struct vm_area_struct *vma);
++unsigned int omap3isp_video_queue_poll(struct isp_video_queue *queue,
++ struct file *file, poll_table *wait);
++
++#endif /* OMAP3_ISP_QUEUE_H */
+diff --git a/drivers/media/video/isp/ispreg.h b/drivers/media/video/isp/ispreg.h
+new file mode 100644
+index 0000000..e78c7e3
+--- /dev/null
++++ b/drivers/media/video/isp/ispreg.h
+@@ -0,0 +1,1589 @@
++/*
++ * ispreg.h
++ *
++ * TI OMAP3 ISP - Registers definitions
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#ifndef OMAP3_ISP_REG_H
++#define OMAP3_ISP_REG_H
++
++#include <plat/omap34xx.h>
++
++
++#define CM_CAM_MCLK_HZ 172800000 /* Hz */
++
++/* ISP Submodules offset */
++
++#define OMAP3ISP_REG_BASE OMAP3430_ISP_BASE
++#define OMAP3ISP_REG(offset) (OMAP3ISP_REG_BASE + (offset))
++
++#define OMAP3ISP_CCP2_REG_OFFSET 0x0400
++#define OMAP3ISP_CCP2_REG_BASE (OMAP3ISP_REG_BASE + \
++ OMAP3ISP_CCP2_REG_OFFSET)
++#define OMAP3ISP_CCP2_REG(offset) (OMAP3ISP_CCP2_REG_BASE + (offset))
++
++#define OMAP3ISP_CCDC_REG_OFFSET 0x0600
++#define OMAP3ISP_CCDC_REG_BASE (OMAP3ISP_REG_BASE + \
++ OMAP3ISP_CCDC_REG_OFFSET)
++#define OMAP3ISP_CCDC_REG(offset) (OMAP3ISP_CCDC_REG_BASE + (offset))
++
++#define OMAP3ISP_HIST_REG_OFFSET 0x0A00
++#define OMAP3ISP_HIST_REG_BASE (OMAP3ISP_REG_BASE + \
++ OMAP3ISP_HIST_REG_OFFSET)
++#define OMAP3ISP_HIST_REG(offset) (OMAP3ISP_HIST_REG_BASE + (offset))
++
++#define OMAP3ISP_H3A_REG_OFFSET 0x0C00
++#define OMAP3ISP_H3A_REG_BASE (OMAP3ISP_REG_BASE + \
++ OMAP3ISP_H3A_REG_OFFSET)
++#define OMAP3ISP_H3A_REG(offset) (OMAP3ISP_H3A_REG_BASE + (offset))
++
++#define OMAP3ISP_PREV_REG_OFFSET 0x0E00
++#define OMAP3ISP_PREV_REG_BASE (OMAP3ISP_REG_BASE + \
++ OMAP3ISP_PREV_REG_OFFSET)
++#define OMAP3ISP_PREV_REG(offset) (OMAP3ISP_PREV_REG_BASE + (offset))
++
++#define OMAP3ISP_RESZ_REG_OFFSET 0x1000
++#define OMAP3ISP_RESZ_REG_BASE (OMAP3ISP_REG_BASE + \
++ OMAP3ISP_RESZ_REG_OFFSET)
++#define OMAP3ISP_RESZ_REG(offset) (OMAP3ISP_RESZ_REG_BASE + (offset))
++
++#define OMAP3ISP_SBL_REG_OFFSET 0x1200
++#define OMAP3ISP_SBL_REG_BASE (OMAP3ISP_REG_BASE + \
++ OMAP3ISP_SBL_REG_OFFSET)
++#define OMAP3ISP_SBL_REG(offset) (OMAP3ISP_SBL_REG_BASE + (offset))
++
++#define OMAP3ISP_CSI2A_REGS1_REG_OFFSET 0x1800
++#define OMAP3ISP_CSI2A_REGS1_REG_BASE (OMAP3ISP_REG_BASE + \
++ OMAP3ISP_CSI2A_REGS1_REG_OFFSET)
++#define OMAP3ISP_CSI2A_REGS1_REG(offset) \
++ (OMAP3ISP_CSI2A_REGS1_REG_BASE + (offset))
++
++#define OMAP3ISP_CSIPHY2_REG_OFFSET 0x1970
++#define OMAP3ISP_CSIPHY2_REG_BASE (OMAP3ISP_REG_BASE + \
++ OMAP3ISP_CSIPHY2_REG_OFFSET)
++#define OMAP3ISP_CSIPHY2_REG(offset) (OMAP3ISP_CSIPHY2_REG_BASE + (offset))
++
++#define OMAP3ISP_CSI2A_REGS2_REG_OFFSET 0x19C0
++#define OMAP3ISP_CSI2A_REGS2_REG_BASE (OMAP3ISP_REG_BASE + \
++ OMAP3ISP_CSI2A_REGS2_REG_OFFSET)
++#define OMAP3ISP_CSI2A_REGS2_REG(offset) \
++ (OMAP3ISP_CSI2A_REGS2_REG_BASE + (offset))
++
++#define OMAP3ISP_CSI2C_REGS1_REG_OFFSET 0x1C00
++#define OMAP3ISP_CSI2C_REGS1_REG_BASE (OMAP3ISP_REG_BASE + \
++ OMAP3ISP_CSI2C_REGS1_REG_OFFSET)
++#define OMAP3ISP_CSI2C_REGS1_REG(offset) \
++ (OMAP3ISP_CSI2C_REGS1_REG_BASE + (offset))
++
++#define OMAP3ISP_CSIPHY1_REG_OFFSET 0x1D70
++#define OMAP3ISP_CSIPHY1_REG_BASE (OMAP3ISP_REG_BASE + \
++ OMAP3ISP_CSIPHY1_REG_OFFSET)
++#define OMAP3ISP_CSIPHY1_REG(offset) (OMAP3ISP_CSIPHY1_REG_BASE + (offset))
++
++#define OMAP3ISP_CSI2C_REGS2_REG_OFFSET 0x1DC0
++#define OMAP3ISP_CSI2C_REGS2_REG_BASE (OMAP3ISP_REG_BASE + \
++ OMAP3ISP_CSI2C_REGS2_REG_OFFSET)
++#define OMAP3ISP_CSI2C_REGS2_REG(offset) \
++ (OMAP3ISP_CSI2C_REGS2_REG_BASE + (offset))
++
++/* ISP module register offset */
++
++#define ISP_REVISION (0x000)
++#define ISP_SYSCONFIG (0x004)
++#define ISP_SYSSTATUS (0x008)
++#define ISP_IRQ0ENABLE (0x00C)
++#define ISP_IRQ0STATUS (0x010)
++#define ISP_IRQ1ENABLE (0x014)
++#define ISP_IRQ1STATUS (0x018)
++#define ISP_TCTRL_GRESET_LENGTH (0x030)
++#define ISP_TCTRL_PSTRB_REPLAY (0x034)
++#define ISP_CTRL (0x040)
++#define ISP_SECURE (0x044)
++#define ISP_TCTRL_CTRL (0x050)
++#define ISP_TCTRL_FRAME (0x054)
++#define ISP_TCTRL_PSTRB_DELAY (0x058)
++#define ISP_TCTRL_STRB_DELAY (0x05C)
++#define ISP_TCTRL_SHUT_DELAY (0x060)
++#define ISP_TCTRL_PSTRB_LENGTH (0x064)
++#define ISP_TCTRL_STRB_LENGTH (0x068)
++#define ISP_TCTRL_SHUT_LENGTH (0x06C)
++#define ISP_PING_PONG_ADDR (0x070)
++#define ISP_PING_PONG_MEM_RANGE (0x074)
++#define ISP_PING_PONG_BUF_SIZE (0x078)
++
++/* CCP2 receiver registers */
++
++#define ISPCCP2_REVISION (0x000)
++#define ISPCCP2_SYSCONFIG (0x004)
++#define ISPCCP2_SYSCONFIG_SOFT_RESET (1 << 1)
++#define ISPCCP2_SYSCONFIG_AUTO_IDLE 0x1
++#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT 12
++#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_FORCE \
++ (0x0 << ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
++#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_NO \
++ (0x1 << ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
++#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SMART \
++ (0x2 << ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
++#define ISPCCP2_SYSSTATUS (0x008)
++#define ISPCCP2_SYSSTATUS_RESET_DONE (1 << 0)
++#define ISPCCP2_LC01_IRQENABLE (0x00C)
++#define ISPCCP2_LC01_IRQSTATUS (0x010)
++#define ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ (1 << 11)
++#define ISPCCP2_LC01_IRQSTATUS_LC0_LE_IRQ (1 << 10)
++#define ISPCCP2_LC01_IRQSTATUS_LC0_LS_IRQ (1 << 9)
++#define ISPCCP2_LC01_IRQSTATUS_LC0_FE_IRQ (1 << 8)
++#define ISPCCP2_LC01_IRQSTATUS_LC0_COUNT_IRQ (1 << 7)
++#define ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ (1 << 5)
++#define ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ (1 << 4)
++#define ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ (1 << 3)
++#define ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ (1 << 2)
++#define ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ (1 << 1)
++#define ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ (1 << 0)
++
++#define ISPCCP2_LC23_IRQENABLE (0x014)
++#define ISPCCP2_LC23_IRQSTATUS (0x018)
++#define ISPCCP2_LCM_IRQENABLE (0x02C)
++#define ISPCCP2_LCM_IRQSTATUS_EOF_IRQ (1 << 0)
++#define ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ (1 << 1)
++#define ISPCCP2_LCM_IRQSTATUS (0x030)
++#define ISPCCP2_CTRL (0x040)
++#define ISPCCP2_CTRL_IF_EN (1 << 0)
++#define ISPCCP2_CTRL_PHY_SEL (1 << 1)
++#define ISPCCP2_CTRL_PHY_SEL_CLOCK (0 << 1)
++#define ISPCCP2_CTRL_PHY_SEL_STROBE (1 << 1)
++#define ISPCCP2_CTRL_PHY_SEL_MASK 0x1
++#define ISPCCP2_CTRL_PHY_SEL_SHIFT 1
++#define ISPCCP2_CTRL_IO_OUT_SEL (1 << 2)
++#define ISPCCP2_CTRL_MODE (1 << 4)
++#define ISPCCP2_CTRL_VP_CLK_FORCE_ON (1 << 9)
++#define ISPCCP2_CTRL_INV (1 << 10)
++#define ISPCCP2_CTRL_INV_MASK 0x1
++#define ISPCCP2_CTRL_INV_SHIFT 10
++#define ISPCCP2_CTRL_VP_ONLY_EN (1 << 11)
++#define ISPCCP2_CTRL_VP_CLK_POL (1 << 12)
++#define ISPCCP2_CTRL_VPCLK_DIV_SHIFT 15
++#define ISPCCP2_CTRL_VPCLK_DIV_MASK 0x1ffff /* [31:15] */
++#define ISPCCP2_CTRL_VP_OUT_CTRL_SHIFT 8 /* 3430 bits */
++#define ISPCCP2_CTRL_VP_OUT_CTRL_MASK 0x3 /* 3430 bits */
++#define ISPCCP2_DBG (0x044)
++#define ISPCCP2_GNQ (0x048)
++#define ISPCCP2_LCx_CTRL(x) ((0x050)+0x30*(x))
++#define ISPCCP2_LCx_CTRL_CHAN_EN (1 << 0)
++#define ISPCCP2_LCx_CTRL_CRC_EN (1 << 19)
++#define ISPCCP2_LCx_CTRL_CRC_MASK 0x1
++#define ISPCCP2_LCx_CTRL_CRC_SHIFT 2
++#define ISPCCP2_LCx_CTRL_CRC_SHIFT_15_0 19
++#define ISPCCP2_LCx_CTRL_REGION_EN (1 << 1)
++#define ISPCCP2_LCx_CTRL_REGION_MASK 0x1
++#define ISPCCP2_LCx_CTRL_REGION_SHIFT 1
++#define ISPCCP2_LCx_CTRL_FORMAT_MASK_15_0 0x3f
++#define ISPCCP2_LCx_CTRL_FORMAT_SHIFT_15_0 0x2
++#define ISPCCP2_LCx_CTRL_FORMAT_MASK 0x1f
++#define ISPCCP2_LCx_CTRL_FORMAT_SHIFT 0x3
++#define ISPCCP2_LCx_CODE(x) ((0x054)+0x30*(x))
++#define ISPCCP2_LCx_STAT_START(x) ((0x058)+0x30*(x))
++#define ISPCCP2_LCx_STAT_SIZE(x) ((0x05C)+0x30*(x))
++#define ISPCCP2_LCx_SOF_ADDR(x) ((0x060)+0x30*(x))
++#define ISPCCP2_LCx_EOF_ADDR(x) ((0x064)+0x30*(x))
++#define ISPCCP2_LCx_DAT_START(x) ((0x068)+0x30*(x))
++#define ISPCCP2_LCx_DAT_SIZE(x) ((0x06C)+0x30*(x))
++#define ISPCCP2_LCx_DAT_MASK 0xFFF
++#define ISPCCP2_LCx_DAT_SHIFT 16
++#define ISPCCP2_LCx_DAT_PING_ADDR(x) ((0x070)+0x30*(x))
++#define ISPCCP2_LCx_DAT_PONG_ADDR(x) ((0x074)+0x30*(x))
++#define ISPCCP2_LCx_DAT_OFST(x) ((0x078)+0x30*(x))
++#define ISPCCP2_LCM_CTRL (0x1D0)
++#define ISPCCP2_LCM_CTRL_CHAN_EN (1 << 0)
++#define ISPCCP2_LCM_CTRL_DST_PORT (1 << 2)
++#define ISPCCP2_LCM_CTRL_DST_PORT_SHIFT 2
++#define ISPCCP2_LCM_CTRL_READ_THROTTLE_SHIFT 3
++#define ISPCCP2_LCM_CTRL_READ_THROTTLE_MASK 0x11
++#define ISPCCP2_LCM_CTRL_BURST_SIZE_SHIFT 5
++#define ISPCCP2_LCM_CTRL_BURST_SIZE_MASK 0x7
++#define ISPCCP2_LCM_CTRL_SRC_FORMAT_SHIFT 16
++#define ISPCCP2_LCM_CTRL_SRC_FORMAT_MASK 0x7
++#define ISPCCP2_LCM_CTRL_SRC_DECOMPR_SHIFT 20
++#define ISPCCP2_LCM_CTRL_SRC_DECOMPR_MASK 0x3
++#define ISPCCP2_LCM_CTRL_SRC_DPCM_PRED (1 << 22)
++#define ISPCCP2_LCM_CTRL_SRC_PACK (1 << 23)
++#define ISPCCP2_LCM_CTRL_DST_FORMAT_SHIFT 24
++#define ISPCCP2_LCM_CTRL_DST_FORMAT_MASK 0x7
++#define ISPCCP2_LCM_VSIZE (0x1D4)
++#define ISPCCP2_LCM_VSIZE_SHIFT 16
++#define ISPCCP2_LCM_HSIZE (0x1D8)
++#define ISPCCP2_LCM_HSIZE_SHIFT 16
++#define ISPCCP2_LCM_PREFETCH (0x1DC)
++#define ISPCCP2_LCM_PREFETCH_SHIFT 3
++#define ISPCCP2_LCM_SRC_ADDR (0x1E0)
++#define ISPCCP2_LCM_SRC_OFST (0x1E4)
++#define ISPCCP2_LCM_DST_ADDR (0x1E8)
++#define ISPCCP2_LCM_DST_OFST (0x1EC)
++
++/* CCDC module register offset */
++
++#define ISPCCDC_PID (0x000)
++#define ISPCCDC_PCR (0x004)
++#define ISPCCDC_SYN_MODE (0x008)
++#define ISPCCDC_HD_VD_WID (0x00C)
++#define ISPCCDC_PIX_LINES (0x010)
++#define ISPCCDC_HORZ_INFO (0x014)
++#define ISPCCDC_VERT_START (0x018)
++#define ISPCCDC_VERT_LINES (0x01C)
++#define ISPCCDC_CULLING (0x020)
++#define ISPCCDC_HSIZE_OFF (0x024)
++#define ISPCCDC_SDOFST (0x028)
++#define ISPCCDC_SDR_ADDR (0x02C)
++#define ISPCCDC_CLAMP (0x030)
++#define ISPCCDC_DCSUB (0x034)
++#define ISPCCDC_COLPTN (0x038)
++#define ISPCCDC_BLKCMP (0x03C)
++#define ISPCCDC_FPC (0x040)
++#define ISPCCDC_FPC_ADDR (0x044)
++#define ISPCCDC_VDINT (0x048)
++#define ISPCCDC_ALAW (0x04C)
++#define ISPCCDC_REC656IF (0x050)
++#define ISPCCDC_CFG (0x054)
++#define ISPCCDC_FMTCFG (0x058)
++#define ISPCCDC_FMT_HORZ (0x05C)
++#define ISPCCDC_FMT_VERT (0x060)
++#define ISPCCDC_FMT_ADDR0 (0x064)
++#define ISPCCDC_FMT_ADDR1 (0x068)
++#define ISPCCDC_FMT_ADDR2 (0x06C)
++#define ISPCCDC_FMT_ADDR3 (0x070)
++#define ISPCCDC_FMT_ADDR4 (0x074)
++#define ISPCCDC_FMT_ADDR5 (0x078)
++#define ISPCCDC_FMT_ADDR6 (0x07C)
++#define ISPCCDC_FMT_ADDR7 (0x080)
++#define ISPCCDC_PRGEVEN0 (0x084)
++#define ISPCCDC_PRGEVEN1 (0x088)
++#define ISPCCDC_PRGODD0 (0x08C)
++#define ISPCCDC_PRGODD1 (0x090)
++#define ISPCCDC_VP_OUT (0x094)
++
++#define ISPCCDC_LSC_CONFIG (0x098)
++#define ISPCCDC_LSC_INITIAL (0x09C)
++#define ISPCCDC_LSC_TABLE_BASE (0x0A0)
++#define ISPCCDC_LSC_TABLE_OFFSET (0x0A4)
++
++/* SBL */
++#define ISPSBL_PCR 0x4
++#define ISPSBL_PCR_H3A_AEAWB_WBL_OVF (1 << 16)
++#define ISPSBL_PCR_H3A_AF_WBL_OVF (1 << 17)
++#define ISPSBL_PCR_RSZ4_WBL_OVF (1 << 18)
++#define ISPSBL_PCR_RSZ3_WBL_OVF (1 << 19)
++#define ISPSBL_PCR_RSZ2_WBL_OVF (1 << 20)
++#define ISPSBL_PCR_RSZ1_WBL_OVF (1 << 21)
++#define ISPSBL_PCR_PRV_WBL_OVF (1 << 22)
++#define ISPSBL_PCR_CCDC_WBL_OVF (1 << 23)
++#define ISPSBL_PCR_CCDCPRV_2_RSZ_OVF (1 << 24)
++#define ISPSBL_PCR_CSIA_WBL_OVF (1 << 25)
++#define ISPSBL_PCR_CSIB_WBL_OVF (1 << 26)
++#define ISPSBL_CCDC_WR_0 (0x028)
++#define ISPSBL_CCDC_WR_0_DATA_READY (1 << 21)
++#define ISPSBL_CCDC_WR_1 (0x02C)
++#define ISPSBL_CCDC_WR_2 (0x030)
++#define ISPSBL_CCDC_WR_3 (0x034)
++
++#define ISPSBL_SDR_REQ_EXP 0xF8
++#define ISPSBL_SDR_REQ_HIST_EXP_SHIFT 0
++#define ISPSBL_SDR_REQ_HIST_EXP_MASK (0x3FF)
++#define ISPSBL_SDR_REQ_RSZ_EXP_SHIFT 10
++#define ISPSBL_SDR_REQ_RSZ_EXP_MASK (0x3FF << ISPSBL_SDR_REQ_RSZ_EXP_SHIFT)
++#define ISPSBL_SDR_REQ_PRV_EXP_SHIFT 20
++#define ISPSBL_SDR_REQ_PRV_EXP_MASK (0x3FF << ISPSBL_SDR_REQ_PRV_EXP_SHIFT)
++
++/* Histogram registers */
++#define ISPHIST_PID (0x000)
++#define ISPHIST_PCR (0x004)
++#define ISPHIST_CNT (0x008)
++#define ISPHIST_WB_GAIN (0x00C)
++#define ISPHIST_R0_HORZ (0x010)
++#define ISPHIST_R0_VERT (0x014)
++#define ISPHIST_R1_HORZ (0x018)
++#define ISPHIST_R1_VERT (0x01C)
++#define ISPHIST_R2_HORZ (0x020)
++#define ISPHIST_R2_VERT (0x024)
++#define ISPHIST_R3_HORZ (0x028)
++#define ISPHIST_R3_VERT (0x02C)
++#define ISPHIST_ADDR (0x030)
++#define ISPHIST_DATA (0x034)
++#define ISPHIST_RADD (0x038)
++#define ISPHIST_RADD_OFF (0x03C)
++#define ISPHIST_H_V_INFO (0x040)
++
++/* H3A module registers */
++#define ISPH3A_PID (0x000)
++#define ISPH3A_PCR (0x004)
++#define ISPH3A_AEWWIN1 (0x04C)
++#define ISPH3A_AEWINSTART (0x050)
++#define ISPH3A_AEWINBLK (0x054)
++#define ISPH3A_AEWSUBWIN (0x058)
++#define ISPH3A_AEWBUFST (0x05C)
++#define ISPH3A_AFPAX1 (0x008)
++#define ISPH3A_AFPAX2 (0x00C)
++#define ISPH3A_AFPAXSTART (0x010)
++#define ISPH3A_AFIIRSH (0x014)
++#define ISPH3A_AFBUFST (0x018)
++#define ISPH3A_AFCOEF010 (0x01C)
++#define ISPH3A_AFCOEF032 (0x020)
++#define ISPH3A_AFCOEF054 (0x024)
++#define ISPH3A_AFCOEF076 (0x028)
++#define ISPH3A_AFCOEF098 (0x02C)
++#define ISPH3A_AFCOEF0010 (0x030)
++#define ISPH3A_AFCOEF110 (0x034)
++#define ISPH3A_AFCOEF132 (0x038)
++#define ISPH3A_AFCOEF154 (0x03C)
++#define ISPH3A_AFCOEF176 (0x040)
++#define ISPH3A_AFCOEF198 (0x044)
++#define ISPH3A_AFCOEF1010 (0x048)
++
++#define ISPPRV_PCR (0x004)
++#define ISPPRV_HORZ_INFO (0x008)
++#define ISPPRV_VERT_INFO (0x00C)
++#define ISPPRV_RSDR_ADDR (0x010)
++#define ISPPRV_RADR_OFFSET (0x014)
++#define ISPPRV_DSDR_ADDR (0x018)
++#define ISPPRV_DRKF_OFFSET (0x01C)
++#define ISPPRV_WSDR_ADDR (0x020)
++#define ISPPRV_WADD_OFFSET (0x024)
++#define ISPPRV_AVE (0x028)
++#define ISPPRV_HMED (0x02C)
++#define ISPPRV_NF (0x030)
++#define ISPPRV_WB_DGAIN (0x034)
++#define ISPPRV_WBGAIN (0x038)
++#define ISPPRV_WBSEL (0x03C)
++#define ISPPRV_CFA (0x040)
++#define ISPPRV_BLKADJOFF (0x044)
++#define ISPPRV_RGB_MAT1 (0x048)
++#define ISPPRV_RGB_MAT2 (0x04C)
++#define ISPPRV_RGB_MAT3 (0x050)
++#define ISPPRV_RGB_MAT4 (0x054)
++#define ISPPRV_RGB_MAT5 (0x058)
++#define ISPPRV_RGB_OFF1 (0x05C)
++#define ISPPRV_RGB_OFF2 (0x060)
++#define ISPPRV_CSC0 (0x064)
++#define ISPPRV_CSC1 (0x068)
++#define ISPPRV_CSC2 (0x06C)
++#define ISPPRV_CSC_OFFSET (0x070)
++#define ISPPRV_CNT_BRT (0x074)
++#define ISPPRV_CSUP (0x078)
++#define ISPPRV_SETUP_YC (0x07C)
++#define ISPPRV_SET_TBL_ADDR (0x080)
++#define ISPPRV_SET_TBL_DATA (0x084)
++#define ISPPRV_CDC_THR0 (0x090)
++#define ISPPRV_CDC_THR1 (ISPPRV_CDC_THR0 + (0x4))
++#define ISPPRV_CDC_THR2 (ISPPRV_CDC_THR0 + (0x4) * 2)
++#define ISPPRV_CDC_THR3 (ISPPRV_CDC_THR0 + (0x4) * 3)
++
++#define ISPPRV_REDGAMMA_TABLE_ADDR 0x0000
++#define ISPPRV_GREENGAMMA_TABLE_ADDR 0x0400
++#define ISPPRV_BLUEGAMMA_TABLE_ADDR 0x0800
++#define ISPPRV_NF_TABLE_ADDR 0x0C00
++#define ISPPRV_YENH_TABLE_ADDR 0x1000
++#define ISPPRV_CFA_TABLE_ADDR 0x1400
++
++#define ISPPRV_MAXOUTPUT_WIDTH 1280
++#define ISPPRV_MAXOUTPUT_WIDTH_ES2 3300
++#define ISPPRV_MAXOUTPUT_WIDTH_3630 4096
++#define ISPRSZ_MIN_OUTPUT 64
++#define ISPRSZ_MAX_OUTPUT 3312
++
++/* Resizer module register offset */
++#define ISPRSZ_PID (0x000)
++#define ISPRSZ_PCR (0x004)
++#define ISPRSZ_CNT (0x008)
++#define ISPRSZ_OUT_SIZE (0x00C)
++#define ISPRSZ_IN_START (0x010)
++#define ISPRSZ_IN_SIZE (0x014)
++#define ISPRSZ_SDR_INADD (0x018)
++#define ISPRSZ_SDR_INOFF (0x01C)
++#define ISPRSZ_SDR_OUTADD (0x020)
++#define ISPRSZ_SDR_OUTOFF (0x024)
++#define ISPRSZ_HFILT10 (0x028)
++#define ISPRSZ_HFILT32 (0x02C)
++#define ISPRSZ_HFILT54 (0x030)
++#define ISPRSZ_HFILT76 (0x034)
++#define ISPRSZ_HFILT98 (0x038)
++#define ISPRSZ_HFILT1110 (0x03C)
++#define ISPRSZ_HFILT1312 (0x040)
++#define ISPRSZ_HFILT1514 (0x044)
++#define ISPRSZ_HFILT1716 (0x048)
++#define ISPRSZ_HFILT1918 (0x04C)
++#define ISPRSZ_HFILT2120 (0x050)
++#define ISPRSZ_HFILT2322 (0x054)
++#define ISPRSZ_HFILT2524 (0x058)
++#define ISPRSZ_HFILT2726 (0x05C)
++#define ISPRSZ_HFILT2928 (0x060)
++#define ISPRSZ_HFILT3130 (0x064)
++#define ISPRSZ_VFILT10 (0x068)
++#define ISPRSZ_VFILT32 (0x06C)
++#define ISPRSZ_VFILT54 (0x070)
++#define ISPRSZ_VFILT76 (0x074)
++#define ISPRSZ_VFILT98 (0x078)
++#define ISPRSZ_VFILT1110 (0x07C)
++#define ISPRSZ_VFILT1312 (0x080)
++#define ISPRSZ_VFILT1514 (0x084)
++#define ISPRSZ_VFILT1716 (0x088)
++#define ISPRSZ_VFILT1918 (0x08C)
++#define ISPRSZ_VFILT2120 (0x090)
++#define ISPRSZ_VFILT2322 (0x094)
++#define ISPRSZ_VFILT2524 (0x098)
++#define ISPRSZ_VFILT2726 (0x09C)
++#define ISPRSZ_VFILT2928 (0x0A0)
++#define ISPRSZ_VFILT3130 (0x0A4)
++#define ISPRSZ_YENH (0x0A8)
++
++#define ISP_INT_CLR 0xFF113F11
++#define ISPPRV_PCR_EN 1
++#define ISPPRV_PCR_BUSY (1 << 1)
++#define ISPPRV_PCR_SOURCE (1 << 2)
++#define ISPPRV_PCR_ONESHOT (1 << 3)
++#define ISPPRV_PCR_WIDTH (1 << 4)
++#define ISPPRV_PCR_INVALAW (1 << 5)
++#define ISPPRV_PCR_DRKFEN (1 << 6)
++#define ISPPRV_PCR_DRKFCAP (1 << 7)
++#define ISPPRV_PCR_HMEDEN (1 << 8)
++#define ISPPRV_PCR_NFEN (1 << 9)
++#define ISPPRV_PCR_CFAEN (1 << 10)
++#define ISPPRV_PCR_CFAFMT_SHIFT 11
++#define ISPPRV_PCR_CFAFMT_MASK 0x7800
++#define ISPPRV_PCR_CFAFMT_BAYER (0 << 11)
++#define ISPPRV_PCR_CFAFMT_SONYVGA (1 << 11)
++#define ISPPRV_PCR_CFAFMT_RGBFOVEON (2 << 11)
++#define ISPPRV_PCR_CFAFMT_DNSPL (3 << 11)
++#define ISPPRV_PCR_CFAFMT_HONEYCOMB (4 << 11)
++#define ISPPRV_PCR_CFAFMT_RRGGBBFOVEON (5 << 11)
++#define ISPPRV_PCR_YNENHEN (1 << 15)
++#define ISPPRV_PCR_SUPEN (1 << 16)
++#define ISPPRV_PCR_YCPOS_SHIFT 17
++#define ISPPRV_PCR_YCPOS_YCrYCb (0 << 17)
++#define ISPPRV_PCR_YCPOS_YCbYCr (1 << 17)
++#define ISPPRV_PCR_YCPOS_CbYCrY (2 << 17)
++#define ISPPRV_PCR_YCPOS_CrYCbY (3 << 17)
++#define ISPPRV_PCR_RSZPORT (1 << 19)
++#define ISPPRV_PCR_SDRPORT (1 << 20)
++#define ISPPRV_PCR_SCOMP_EN (1 << 21)
++#define ISPPRV_PCR_SCOMP_SFT_SHIFT (22)
++#define ISPPRV_PCR_SCOMP_SFT_MASK (7 << 22)
++#define ISPPRV_PCR_GAMMA_BYPASS (1 << 26)
++#define ISPPRV_PCR_DCOREN (1 << 27)
++#define ISPPRV_PCR_DCCOUP (1 << 28)
++#define ISPPRV_PCR_DRK_FAIL (1 << 31)
++
++#define ISPPRV_HORZ_INFO_EPH_SHIFT 0
++#define ISPPRV_HORZ_INFO_EPH_MASK 0x3fff
++#define ISPPRV_HORZ_INFO_SPH_SHIFT 16
++#define ISPPRV_HORZ_INFO_SPH_MASK 0x3fff0
++
++#define ISPPRV_VERT_INFO_ELV_SHIFT 0
++#define ISPPRV_VERT_INFO_ELV_MASK 0x3fff
++#define ISPPRV_VERT_INFO_SLV_SHIFT 16
++#define ISPPRV_VERT_INFO_SLV_MASK 0x3fff0
++
++#define ISPPRV_AVE_EVENDIST_SHIFT 2
++#define ISPPRV_AVE_EVENDIST_1 0x0
++#define ISPPRV_AVE_EVENDIST_2 0x1
++#define ISPPRV_AVE_EVENDIST_3 0x2
++#define ISPPRV_AVE_EVENDIST_4 0x3
++#define ISPPRV_AVE_ODDDIST_SHIFT 4
++#define ISPPRV_AVE_ODDDIST_1 0x0
++#define ISPPRV_AVE_ODDDIST_2 0x1
++#define ISPPRV_AVE_ODDDIST_3 0x2
++#define ISPPRV_AVE_ODDDIST_4 0x3
++
++#define ISPPRV_HMED_THRESHOLD_SHIFT 0
++#define ISPPRV_HMED_EVENDIST (1 << 8)
++#define ISPPRV_HMED_ODDDIST (1 << 9)
++
++#define ISPPRV_WBGAIN_COEF0_SHIFT 0
++#define ISPPRV_WBGAIN_COEF1_SHIFT 8
++#define ISPPRV_WBGAIN_COEF2_SHIFT 16
++#define ISPPRV_WBGAIN_COEF3_SHIFT 24
++
++#define ISPPRV_WBSEL_COEF0 0x0
++#define ISPPRV_WBSEL_COEF1 0x1
++#define ISPPRV_WBSEL_COEF2 0x2
++#define ISPPRV_WBSEL_COEF3 0x3
++
++#define ISPPRV_WBSEL_N0_0_SHIFT 0
++#define ISPPRV_WBSEL_N0_1_SHIFT 2
++#define ISPPRV_WBSEL_N0_2_SHIFT 4
++#define ISPPRV_WBSEL_N0_3_SHIFT 6
++#define ISPPRV_WBSEL_N1_0_SHIFT 8
++#define ISPPRV_WBSEL_N1_1_SHIFT 10
++#define ISPPRV_WBSEL_N1_2_SHIFT 12
++#define ISPPRV_WBSEL_N1_3_SHIFT 14
++#define ISPPRV_WBSEL_N2_0_SHIFT 16
++#define ISPPRV_WBSEL_N2_1_SHIFT 18
++#define ISPPRV_WBSEL_N2_2_SHIFT 20
++#define ISPPRV_WBSEL_N2_3_SHIFT 22
++#define ISPPRV_WBSEL_N3_0_SHIFT 24
++#define ISPPRV_WBSEL_N3_1_SHIFT 26
++#define ISPPRV_WBSEL_N3_2_SHIFT 28
++#define ISPPRV_WBSEL_N3_3_SHIFT 30
++
++#define ISPPRV_CFA_GRADTH_HOR_SHIFT 0
++#define ISPPRV_CFA_GRADTH_VER_SHIFT 8
++
++#define ISPPRV_BLKADJOFF_B_SHIFT 0
++#define ISPPRV_BLKADJOFF_G_SHIFT 8
++#define ISPPRV_BLKADJOFF_R_SHIFT 16
++
++#define ISPPRV_RGB_MAT1_MTX_RR_SHIFT 0
++#define ISPPRV_RGB_MAT1_MTX_GR_SHIFT 16
++
++#define ISPPRV_RGB_MAT2_MTX_BR_SHIFT 0
++#define ISPPRV_RGB_MAT2_MTX_RG_SHIFT 16
++
++#define ISPPRV_RGB_MAT3_MTX_GG_SHIFT 0
++#define ISPPRV_RGB_MAT3_MTX_BG_SHIFT 16
++
++#define ISPPRV_RGB_MAT4_MTX_RB_SHIFT 0
++#define ISPPRV_RGB_MAT4_MTX_GB_SHIFT 16
++
++#define ISPPRV_RGB_MAT5_MTX_BB_SHIFT 0
++
++#define ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT 0
++#define ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT 16
++
++#define ISPPRV_RGB_OFF2_MTX_OFFB_SHIFT 0
++
++#define ISPPRV_CSC0_RY_SHIFT 0
++#define ISPPRV_CSC0_GY_SHIFT 10
++#define ISPPRV_CSC0_BY_SHIFT 20
++
++#define ISPPRV_CSC1_RCB_SHIFT 0
++#define ISPPRV_CSC1_GCB_SHIFT 10
++#define ISPPRV_CSC1_BCB_SHIFT 20
++
++#define ISPPRV_CSC2_RCR_SHIFT 0
++#define ISPPRV_CSC2_GCR_SHIFT 10
++#define ISPPRV_CSC2_BCR_SHIFT 20
++
++#define ISPPRV_CSC_OFFSET_CR_SHIFT 0
++#define ISPPRV_CSC_OFFSET_CB_SHIFT 8
++#define ISPPRV_CSC_OFFSET_Y_SHIFT 16
++
++#define ISPPRV_CNT_BRT_BRT_SHIFT 0
++#define ISPPRV_CNT_BRT_CNT_SHIFT 8
++
++#define ISPPRV_CONTRAST_MAX 0x10
++#define ISPPRV_CONTRAST_MIN 0xFF
++#define ISPPRV_BRIGHT_MIN 0x00
++#define ISPPRV_BRIGHT_MAX 0xFF
++
++#define ISPPRV_CSUP_CSUPG_SHIFT 0
++#define ISPPRV_CSUP_THRES_SHIFT 8
++#define ISPPRV_CSUP_HPYF_SHIFT 16
++
++#define ISPPRV_SETUP_YC_MINC_SHIFT 0
++#define ISPPRV_SETUP_YC_MAXC_SHIFT 8
++#define ISPPRV_SETUP_YC_MINY_SHIFT 16
++#define ISPPRV_SETUP_YC_MAXY_SHIFT 24
++#define ISPPRV_YC_MAX 0xFF
++#define ISPPRV_YC_MIN 0x0
++
++/* Define bit fields within selected registers */
++#define ISP_REVISION_SHIFT 0
++
++#define ISP_SYSCONFIG_AUTOIDLE (1 << 0)
++#define ISP_SYSCONFIG_SOFTRESET (1 << 1)
++#define ISP_SYSCONFIG_MIDLEMODE_SHIFT 12
++#define ISP_SYSCONFIG_MIDLEMODE_FORCESTANDBY 0x0
++#define ISP_SYSCONFIG_MIDLEMODE_NOSTANBY 0x1
++#define ISP_SYSCONFIG_MIDLEMODE_SMARTSTANDBY 0x2
++
++#define ISP_SYSSTATUS_RESETDONE 0
++
++#define IRQ0ENABLE_CSIA_IRQ (1 << 0)
++#define IRQ0ENABLE_CSIC_IRQ (1 << 1)
++#define IRQ0ENABLE_CCP2_LCM_IRQ (1 << 3)
++#define IRQ0ENABLE_CCP2_LC0_IRQ (1 << 4)
++#define IRQ0ENABLE_CCP2_LC1_IRQ (1 << 5)
++#define IRQ0ENABLE_CCP2_LC2_IRQ (1 << 6)
++#define IRQ0ENABLE_CCP2_LC3_IRQ (1 << 7)
++#define IRQ0ENABLE_CSIB_IRQ (IRQ0ENABLE_CCP2_LCM_IRQ | \
++ IRQ0ENABLE_CCP2_LC0_IRQ | \
++ IRQ0ENABLE_CCP2_LC1_IRQ | \
++ IRQ0ENABLE_CCP2_LC2_IRQ | \
++ IRQ0ENABLE_CCP2_LC3_IRQ)
++
++#define IRQ0ENABLE_CCDC_VD0_IRQ (1 << 8)
++#define IRQ0ENABLE_CCDC_VD1_IRQ (1 << 9)
++#define IRQ0ENABLE_CCDC_VD2_IRQ (1 << 10)
++#define IRQ0ENABLE_CCDC_ERR_IRQ (1 << 11)
++#define IRQ0ENABLE_H3A_AF_DONE_IRQ (1 << 12)
++#define IRQ0ENABLE_H3A_AWB_DONE_IRQ (1 << 13)
++#define IRQ0ENABLE_HIST_DONE_IRQ (1 << 16)
++#define IRQ0ENABLE_CCDC_LSC_DONE_IRQ (1 << 17)
++#define IRQ0ENABLE_CCDC_LSC_PREF_COMP_IRQ (1 << 18)
++#define IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ (1 << 19)
++#define IRQ0ENABLE_PRV_DONE_IRQ (1 << 20)
++#define IRQ0ENABLE_RSZ_DONE_IRQ (1 << 24)
++#define IRQ0ENABLE_OVF_IRQ (1 << 25)
++#define IRQ0ENABLE_PING_IRQ (1 << 26)
++#define IRQ0ENABLE_PONG_IRQ (1 << 27)
++#define IRQ0ENABLE_MMU_ERR_IRQ (1 << 28)
++#define IRQ0ENABLE_OCP_ERR_IRQ (1 << 29)
++#define IRQ0ENABLE_SEC_ERR_IRQ (1 << 30)
++#define IRQ0ENABLE_HS_VS_IRQ (1 << 31)
++
++#define IRQ0STATUS_CSIA_IRQ (1 << 0)
++#define IRQ0STATUS_CSI2C_IRQ (1 << 1)
++#define IRQ0STATUS_CCP2_LCM_IRQ (1 << 3)
++#define IRQ0STATUS_CCP2_LC0_IRQ (1 << 4)
++#define IRQ0STATUS_CSIB_IRQ (IRQ0STATUS_CCP2_LCM_IRQ | \
++ IRQ0STATUS_CCP2_LC0_IRQ)
++
++#define IRQ0STATUS_CSIB_LC1_IRQ (1 << 5)
++#define IRQ0STATUS_CSIB_LC2_IRQ (1 << 6)
++#define IRQ0STATUS_CSIB_LC3_IRQ (1 << 7)
++#define IRQ0STATUS_CCDC_VD0_IRQ (1 << 8)
++#define IRQ0STATUS_CCDC_VD1_IRQ (1 << 9)
++#define IRQ0STATUS_CCDC_VD2_IRQ (1 << 10)
++#define IRQ0STATUS_CCDC_ERR_IRQ (1 << 11)
++#define IRQ0STATUS_H3A_AF_DONE_IRQ (1 << 12)
++#define IRQ0STATUS_H3A_AWB_DONE_IRQ (1 << 13)
++#define IRQ0STATUS_HIST_DONE_IRQ (1 << 16)
++#define IRQ0STATUS_CCDC_LSC_DONE_IRQ (1 << 17)
++#define IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ (1 << 18)
++#define IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ (1 << 19)
++#define IRQ0STATUS_PRV_DONE_IRQ (1 << 20)
++#define IRQ0STATUS_RSZ_DONE_IRQ (1 << 24)
++#define IRQ0STATUS_OVF_IRQ (1 << 25)
++#define IRQ0STATUS_PING_IRQ (1 << 26)
++#define IRQ0STATUS_PONG_IRQ (1 << 27)
++#define IRQ0STATUS_MMU_ERR_IRQ (1 << 28)
++#define IRQ0STATUS_OCP_ERR_IRQ (1 << 29)
++#define IRQ0STATUS_SEC_ERR_IRQ (1 << 30)
++#define IRQ0STATUS_HS_VS_IRQ (1 << 31)
++
++#define TCTRL_GRESET_LEN 0
++
++#define TCTRL_PSTRB_REPLAY_DELAY 0
++#define TCTRL_PSTRB_REPLAY_COUNTER_SHIFT 25
++
++#define ISPCTRL_PAR_SER_CLK_SEL_PARALLEL 0x0
++#define ISPCTRL_PAR_SER_CLK_SEL_CSIA 0x1
++#define ISPCTRL_PAR_SER_CLK_SEL_CSIB 0x2
++#define ISPCTRL_PAR_SER_CLK_SEL_CSIC 0x3
++#define ISPCTRL_PAR_SER_CLK_SEL_MASK 0x3
++
++#define ISPCTRL_PAR_BRIDGE_SHIFT 2
++#define ISPCTRL_PAR_BRIDGE_DISABLE (0x0 << 2)
++#define ISPCTRL_PAR_BRIDGE_LENDIAN (0x2 << 2)
++#define ISPCTRL_PAR_BRIDGE_BENDIAN (0x3 << 2)
++#define ISPCTRL_PAR_BRIDGE_MASK (0x3 << 2)
++
++#define ISPCTRL_PAR_CLK_POL_SHIFT 4
++#define ISPCTRL_PAR_CLK_POL_INV (1 << 4)
++#define ISPCTRL_PING_PONG_EN (1 << 5)
++#define ISPCTRL_SHIFT_SHIFT 6
++#define ISPCTRL_SHIFT_0 (0x0 << 6)
++#define ISPCTRL_SHIFT_2 (0x1 << 6)
++#define ISPCTRL_SHIFT_4 (0x2 << 6)
++#define ISPCTRL_SHIFT_MASK (0x3 << 6)
++
++#define ISPCTRL_CCDC_CLK_EN (1 << 8)
++#define ISPCTRL_SCMP_CLK_EN (1 << 9)
++#define ISPCTRL_H3A_CLK_EN (1 << 10)
++#define ISPCTRL_HIST_CLK_EN (1 << 11)
++#define ISPCTRL_PREV_CLK_EN (1 << 12)
++#define ISPCTRL_RSZ_CLK_EN (1 << 13)
++#define ISPCTRL_SYNC_DETECT_SHIFT 14
++#define ISPCTRL_SYNC_DETECT_HSFALL (0x0 << ISPCTRL_SYNC_DETECT_SHIFT)
++#define ISPCTRL_SYNC_DETECT_HSRISE (0x1 << ISPCTRL_SYNC_DETECT_SHIFT)
++#define ISPCTRL_SYNC_DETECT_VSFALL (0x2 << ISPCTRL_SYNC_DETECT_SHIFT)
++#define ISPCTRL_SYNC_DETECT_VSRISE (0x3 << ISPCTRL_SYNC_DETECT_SHIFT)
++#define ISPCTRL_SYNC_DETECT_MASK (0x3 << ISPCTRL_SYNC_DETECT_SHIFT)
++
++#define ISPCTRL_CCDC_RAM_EN (1 << 16)
++#define ISPCTRL_PREV_RAM_EN (1 << 17)
++#define ISPCTRL_SBL_RD_RAM_EN (1 << 18)
++#define ISPCTRL_SBL_WR1_RAM_EN (1 << 19)
++#define ISPCTRL_SBL_WR0_RAM_EN (1 << 20)
++#define ISPCTRL_SBL_AUTOIDLE (1 << 21)
++#define ISPCTRL_SBL_SHARED_WPORTC (1 << 26)
++#define ISPCTRL_SBL_SHARED_RPORTA (1 << 27)
++#define ISPCTRL_SBL_SHARED_RPORTB (1 << 28)
++#define ISPCTRL_JPEG_FLUSH (1 << 30)
++#define ISPCTRL_CCDC_FLUSH (1 << 31)
++
++#define ISPSECURE_SECUREMODE 0
++
++#define ISPTCTRL_CTRL_DIV_LOW 0x0
++#define ISPTCTRL_CTRL_DIV_HIGH 0x1
++#define ISPTCTRL_CTRL_DIV_BYPASS 0x1F
++
++#define ISPTCTRL_CTRL_DIVA_SHIFT 0
++#define ISPTCTRL_CTRL_DIVA_MASK (0x1F << ISPTCTRL_CTRL_DIVA_SHIFT)
++
++#define ISPTCTRL_CTRL_DIVB_SHIFT 5
++#define ISPTCTRL_CTRL_DIVB_MASK (0x1F << ISPTCTRL_CTRL_DIVB_SHIFT)
++
++#define ISPTCTRL_CTRL_DIVC_SHIFT 10
++#define ISPTCTRL_CTRL_DIVC_NOCLOCK (0x0 << 10)
++
++#define ISPTCTRL_CTRL_SHUTEN (1 << 21)
++#define ISPTCTRL_CTRL_PSTRBEN (1 << 22)
++#define ISPTCTRL_CTRL_STRBEN (1 << 23)
++#define ISPTCTRL_CTRL_SHUTPOL (1 << 24)
++#define ISPTCTRL_CTRL_STRBPSTRBPOL (1 << 26)
++
++#define ISPTCTRL_CTRL_INSEL_SHIFT 27
++#define ISPTCTRL_CTRL_INSEL_PARALLEL (0x0 << 27)
++#define ISPTCTRL_CTRL_INSEL_CSIA (0x1 << 27)
++#define ISPTCTRL_CTRL_INSEL_CSIB (0x2 << 27)
++
++#define ISPTCTRL_CTRL_GRESETEn (1 << 29)
++#define ISPTCTRL_CTRL_GRESETPOL (1 << 30)
++#define ISPTCTRL_CTRL_GRESETDIR (1 << 31)
++
++#define ISPTCTRL_FRAME_SHUT_SHIFT 0
++#define ISPTCTRL_FRAME_PSTRB_SHIFT 6
++#define ISPTCTRL_FRAME_STRB_SHIFT 12
++
++#define ISPCCDC_PID_PREV_SHIFT 0
++#define ISPCCDC_PID_CID_SHIFT 8
++#define ISPCCDC_PID_TID_SHIFT 16
++
++#define ISPCCDC_PCR_EN 1
++#define ISPCCDC_PCR_BUSY (1 << 1)
++
++#define ISPCCDC_SYN_MODE_VDHDOUT 0x1
++#define ISPCCDC_SYN_MODE_FLDOUT (1 << 1)
++#define ISPCCDC_SYN_MODE_VDPOL (1 << 2)
++#define ISPCCDC_SYN_MODE_HDPOL (1 << 3)
++#define ISPCCDC_SYN_MODE_FLDPOL (1 << 4)
++#define ISPCCDC_SYN_MODE_EXWEN (1 << 5)
++#define ISPCCDC_SYN_MODE_DATAPOL (1 << 6)
++#define ISPCCDC_SYN_MODE_FLDMODE (1 << 7)
++#define ISPCCDC_SYN_MODE_DATSIZ_MASK (0x7 << 8)
++#define ISPCCDC_SYN_MODE_DATSIZ_8_16 (0x0 << 8)
++#define ISPCCDC_SYN_MODE_DATSIZ_12 (0x4 << 8)
++#define ISPCCDC_SYN_MODE_DATSIZ_11 (0x5 << 8)
++#define ISPCCDC_SYN_MODE_DATSIZ_10 (0x6 << 8)
++#define ISPCCDC_SYN_MODE_DATSIZ_8 (0x7 << 8)
++#define ISPCCDC_SYN_MODE_PACK8 (1 << 11)
++#define ISPCCDC_SYN_MODE_INPMOD_MASK (3 << 12)
++#define ISPCCDC_SYN_MODE_INPMOD_RAW (0 << 12)
++#define ISPCCDC_SYN_MODE_INPMOD_YCBCR16 (1 << 12)
++#define ISPCCDC_SYN_MODE_INPMOD_YCBCR8 (2 << 12)
++#define ISPCCDC_SYN_MODE_LPF (1 << 14)
++#define ISPCCDC_SYN_MODE_FLDSTAT (1 << 15)
++#define ISPCCDC_SYN_MODE_VDHDEN (1 << 16)
++#define ISPCCDC_SYN_MODE_WEN (1 << 17)
++#define ISPCCDC_SYN_MODE_VP2SDR (1 << 18)
++#define ISPCCDC_SYN_MODE_SDR2RSZ (1 << 19)
++
++#define ISPCCDC_HD_VD_WID_VDW_SHIFT 0
++#define ISPCCDC_HD_VD_WID_HDW_SHIFT 16
++
++#define ISPCCDC_PIX_LINES_HLPRF_SHIFT 0
++#define ISPCCDC_PIX_LINES_PPLN_SHIFT 16
++
++#define ISPCCDC_HORZ_INFO_NPH_SHIFT 0
++#define ISPCCDC_HORZ_INFO_NPH_MASK 0xFFFF8000
++#define ISPCCDC_HORZ_INFO_SPH_MASK 0x1000FFFF
++#define ISPCCDC_HORZ_INFO_SPH_SHIFT 16
++
++#define ISPCCDC_VERT_START_SLV0_SHIFT 16
++#define ISPCCDC_VERT_START_SLV0_MASK 0x1000FFFF
++#define ISPCCDC_VERT_START_SLV1_SHIFT 0
++
++#define ISPCCDC_VERT_LINES_NLV_MASK 0xFFFF8000
++#define ISPCCDC_VERT_LINES_NLV_SHIFT 0
++
++#define ISPCCDC_CULLING_CULV_SHIFT 0
++#define ISPCCDC_CULLING_CULHODD_SHIFT 16
++#define ISPCCDC_CULLING_CULHEVN_SHIFT 24
++
++#define ISPCCDC_HSIZE_OFF_SHIFT 0
++
++#define ISPCCDC_SDOFST_FINV (1 << 14)
++#define ISPCCDC_SDOFST_FOFST_1L 0
++#define ISPCCDC_SDOFST_FOFST_4L (3 << 12)
++#define ISPCCDC_SDOFST_LOFST3_SHIFT 0
++#define ISPCCDC_SDOFST_LOFST2_SHIFT 3
++#define ISPCCDC_SDOFST_LOFST1_SHIFT 6
++#define ISPCCDC_SDOFST_LOFST0_SHIFT 9
++#define EVENEVEN 1
++#define ODDEVEN 2
++#define EVENODD 3
++#define ODDODD 4
++
++#define ISPCCDC_CLAMP_OBGAIN_SHIFT 0
++#define ISPCCDC_CLAMP_OBST_SHIFT 10
++#define ISPCCDC_CLAMP_OBSLN_SHIFT 25
++#define ISPCCDC_CLAMP_OBSLEN_SHIFT 28
++#define ISPCCDC_CLAMP_CLAMPEN (1 << 31)
++
++#define ISPCCDC_COLPTN_R_Ye 0x0
++#define ISPCCDC_COLPTN_Gr_Cy 0x1
++#define ISPCCDC_COLPTN_Gb_G 0x2
++#define ISPCCDC_COLPTN_B_Mg 0x3
++#define ISPCCDC_COLPTN_CP0PLC0_SHIFT 0
++#define ISPCCDC_COLPTN_CP0PLC1_SHIFT 2
++#define ISPCCDC_COLPTN_CP0PLC2_SHIFT 4
++#define ISPCCDC_COLPTN_CP0PLC3_SHIFT 6
++#define ISPCCDC_COLPTN_CP1PLC0_SHIFT 8
++#define ISPCCDC_COLPTN_CP1PLC1_SHIFT 10
++#define ISPCCDC_COLPTN_CP1PLC2_SHIFT 12
++#define ISPCCDC_COLPTN_CP1PLC3_SHIFT 14
++#define ISPCCDC_COLPTN_CP2PLC0_SHIFT 16
++#define ISPCCDC_COLPTN_CP2PLC1_SHIFT 18
++#define ISPCCDC_COLPTN_CP2PLC2_SHIFT 20
++#define ISPCCDC_COLPTN_CP2PLC3_SHIFT 22
++#define ISPCCDC_COLPTN_CP3PLC0_SHIFT 24
++#define ISPCCDC_COLPTN_CP3PLC1_SHIFT 26
++#define ISPCCDC_COLPTN_CP3PLC2_SHIFT 28
++#define ISPCCDC_COLPTN_CP3PLC3_SHIFT 30
++
++#define ISPCCDC_BLKCMP_B_MG_SHIFT 0
++#define ISPCCDC_BLKCMP_GB_G_SHIFT 8
++#define ISPCCDC_BLKCMP_GR_CY_SHIFT 16
++#define ISPCCDC_BLKCMP_R_YE_SHIFT 24
++
++#define ISPCCDC_FPC_FPNUM_SHIFT 0
++#define ISPCCDC_FPC_FPCEN (1 << 15)
++#define ISPCCDC_FPC_FPERR (1 << 16)
++
++#define ISPCCDC_VDINT_1_SHIFT 0
++#define ISPCCDC_VDINT_0_SHIFT 16
++#define ISPCCDC_VDINT_0_MASK 0x7FFF
++#define ISPCCDC_VDINT_1_MASK 0x7FFF
++
++#define ISPCCDC_ALAW_GWDI_12_3 (0x3 << 0)
++#define ISPCCDC_ALAW_GWDI_11_2 (0x4 << 0)
++#define ISPCCDC_ALAW_GWDI_10_1 (0x5 << 0)
++#define ISPCCDC_ALAW_GWDI_9_0 (0x6 << 0)
++#define ISPCCDC_ALAW_CCDTBL (1 << 3)
++
++#define ISPCCDC_REC656IF_R656ON 1
++#define ISPCCDC_REC656IF_ECCFVH (1 << 1)
++
++#define ISPCCDC_CFG_BW656 (1 << 5)
++#define ISPCCDC_CFG_FIDMD_SHIFT 6
++#define ISPCCDC_CFG_WENLOG (1 << 8)
++#define ISPCCDC_CFG_WENLOG_AND (0 << 8)
++#define ISPCCDC_CFG_WENLOG_OR (1 << 8)
++#define ISPCCDC_CFG_Y8POS (1 << 11)
++#define ISPCCDC_CFG_BSWD (1 << 12)
++#define ISPCCDC_CFG_MSBINVI (1 << 13)
++#define ISPCCDC_CFG_VDLC (1 << 15)
++
++#define ISPCCDC_FMTCFG_FMTEN 0x1
++#define ISPCCDC_FMTCFG_LNALT (1 << 1)
++#define ISPCCDC_FMTCFG_LNUM_SHIFT 2
++#define ISPCCDC_FMTCFG_PLEN_ODD_SHIFT 4
++#define ISPCCDC_FMTCFG_PLEN_EVEN_SHIFT 8
++#define ISPCCDC_FMTCFG_VPIN_MASK 0x00007000
++#define ISPCCDC_FMTCFG_VPIN_12_3 (0x3 << 12)
++#define ISPCCDC_FMTCFG_VPIN_11_2 (0x4 << 12)
++#define ISPCCDC_FMTCFG_VPIN_10_1 (0x5 << 12)
++#define ISPCCDC_FMTCFG_VPIN_9_0 (0x6 << 12)
++#define ISPCCDC_FMTCFG_VPEN (1 << 15)
++
++#define ISPCCDC_FMTCFG_VPIF_FRQ_MASK 0x003f0000
++#define ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT 16
++#define ISPCCDC_FMTCFG_VPIF_FRQ_BY2 (0x0 << 16)
++#define ISPCCDC_FMTCFG_VPIF_FRQ_BY3 (0x1 << 16)
++#define ISPCCDC_FMTCFG_VPIF_FRQ_BY4 (0x2 << 16)
++#define ISPCCDC_FMTCFG_VPIF_FRQ_BY5 (0x3 << 16)
++#define ISPCCDC_FMTCFG_VPIF_FRQ_BY6 (0x4 << 16)
++
++#define ISPCCDC_FMT_HORZ_FMTLNH_SHIFT 0
++#define ISPCCDC_FMT_HORZ_FMTSPH_SHIFT 16
++
++#define ISPCCDC_FMT_VERT_FMTLNV_SHIFT 0
++#define ISPCCDC_FMT_VERT_FMTSLV_SHIFT 16
++
++#define ISPCCDC_FMT_HORZ_FMTSPH_MASK 0x1FFF0000
++#define ISPCCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF
++
++#define ISPCCDC_FMT_VERT_FMTSLV_MASK 0x1FFF0000
++#define ISPCCDC_FMT_VERT_FMTLNV_MASK 0x1FFF
++
++#define ISPCCDC_VP_OUT_HORZ_ST_SHIFT 0
++#define ISPCCDC_VP_OUT_HORZ_NUM_SHIFT 4
++#define ISPCCDC_VP_OUT_VERT_NUM_SHIFT 17
++
++#define ISPRSZ_PID_PREV_SHIFT 0
++#define ISPRSZ_PID_CID_SHIFT 8
++#define ISPRSZ_PID_TID_SHIFT 16
++
++#define ISPRSZ_PCR_ENABLE (1 << 0)
++#define ISPRSZ_PCR_BUSY (1 << 1)
++#define ISPRSZ_PCR_ONESHOT (1 << 2)
++
++#define ISPRSZ_CNT_HRSZ_SHIFT 0
++#define ISPRSZ_CNT_HRSZ_MASK \
++ (0x3FF << ISPRSZ_CNT_HRSZ_SHIFT)
++#define ISPRSZ_CNT_VRSZ_SHIFT 10
++#define ISPRSZ_CNT_VRSZ_MASK \
++ (0x3FF << ISPRSZ_CNT_VRSZ_SHIFT)
++#define ISPRSZ_CNT_HSTPH_SHIFT 20
++#define ISPRSZ_CNT_HSTPH_MASK (0x7 << ISPRSZ_CNT_HSTPH_SHIFT)
++#define ISPRSZ_CNT_VSTPH_SHIFT 23
++#define ISPRSZ_CNT_VSTPH_MASK (0x7 << ISPRSZ_CNT_VSTPH_SHIFT)
++#define ISPRSZ_CNT_YCPOS (1 << 26)
++#define ISPRSZ_CNT_INPTYP (1 << 27)
++#define ISPRSZ_CNT_INPSRC (1 << 28)
++#define ISPRSZ_CNT_CBILIN (1 << 29)
++
++#define ISPRSZ_OUT_SIZE_HORZ_SHIFT 0
++#define ISPRSZ_OUT_SIZE_HORZ_MASK \
++ (0xFFF << ISPRSZ_OUT_SIZE_HORZ_SHIFT)
++#define ISPRSZ_OUT_SIZE_VERT_SHIFT 16
++#define ISPRSZ_OUT_SIZE_VERT_MASK \
++ (0xFFF << ISPRSZ_OUT_SIZE_VERT_SHIFT)
++
++#define ISPRSZ_IN_START_HORZ_ST_SHIFT 0
++#define ISPRSZ_IN_START_HORZ_ST_MASK \
++ (0x1FFF << ISPRSZ_IN_START_HORZ_ST_SHIFT)
++#define ISPRSZ_IN_START_VERT_ST_SHIFT 16
++#define ISPRSZ_IN_START_VERT_ST_MASK \
++ (0x1FFF << ISPRSZ_IN_START_VERT_ST_SHIFT)
++
++#define ISPRSZ_IN_SIZE_HORZ_SHIFT 0
++#define ISPRSZ_IN_SIZE_HORZ_MASK \
++ (0x1FFF << ISPRSZ_IN_SIZE_HORZ_SHIFT)
++#define ISPRSZ_IN_SIZE_VERT_SHIFT 16
++#define ISPRSZ_IN_SIZE_VERT_MASK \
++ (0x1FFF << ISPRSZ_IN_SIZE_VERT_SHIFT)
++
++#define ISPRSZ_SDR_INADD_ADDR_SHIFT 0
++#define ISPRSZ_SDR_INADD_ADDR_MASK 0xFFFFFFFF
++
++#define ISPRSZ_SDR_INOFF_OFFSET_SHIFT 0
++#define ISPRSZ_SDR_INOFF_OFFSET_MASK \
++ (0xFFFF << ISPRSZ_SDR_INOFF_OFFSET_SHIFT)
++
++#define ISPRSZ_SDR_OUTADD_ADDR_SHIFT 0
++#define ISPRSZ_SDR_OUTADD_ADDR_MASK 0xFFFFFFFF
++
++
++#define ISPRSZ_SDR_OUTOFF_OFFSET_SHIFT 0
++#define ISPRSZ_SDR_OUTOFF_OFFSET_MASK \
++ (0xFFFF << ISPRSZ_SDR_OUTOFF_OFFSET_SHIFT)
++
++#define ISPRSZ_HFILT_COEF0_SHIFT 0
++#define ISPRSZ_HFILT_COEF0_MASK \
++ (0x3FF << ISPRSZ_HFILT_COEF0_SHIFT)
++#define ISPRSZ_HFILT_COEF1_SHIFT 16
++#define ISPRSZ_HFILT_COEF1_MASK \
++ (0x3FF << ISPRSZ_HFILT_COEF1_SHIFT)
++
++#define ISPRSZ_HFILT32_COEF2_SHIFT 0
++#define ISPRSZ_HFILT32_COEF2_MASK 0x3FF
++#define ISPRSZ_HFILT32_COEF3_SHIFT 16
++#define ISPRSZ_HFILT32_COEF3_MASK 0x3FF0000
++
++#define ISPRSZ_HFILT54_COEF4_SHIFT 0
++#define ISPRSZ_HFILT54_COEF4_MASK 0x3FF
++#define ISPRSZ_HFILT54_COEF5_SHIFT 16
++#define ISPRSZ_HFILT54_COEF5_MASK 0x3FF0000
++
++#define ISPRSZ_HFILT76_COEFF6_SHIFT 0
++#define ISPRSZ_HFILT76_COEFF6_MASK 0x3FF
++#define ISPRSZ_HFILT76_COEFF7_SHIFT 16
++#define ISPRSZ_HFILT76_COEFF7_MASK 0x3FF0000
++
++#define ISPRSZ_HFILT98_COEFF8_SHIFT 0
++#define ISPRSZ_HFILT98_COEFF8_MASK 0x3FF
++#define ISPRSZ_HFILT98_COEFF9_SHIFT 16
++#define ISPRSZ_HFILT98_COEFF9_MASK 0x3FF0000
++
++#define ISPRSZ_HFILT1110_COEF10_SHIFT 0
++#define ISPRSZ_HFILT1110_COEF10_MASK 0x3FF
++#define ISPRSZ_HFILT1110_COEF11_SHIFT 16
++#define ISPRSZ_HFILT1110_COEF11_MASK 0x3FF0000
++
++#define ISPRSZ_HFILT1312_COEFF12_SHIFT 0
++#define ISPRSZ_HFILT1312_COEFF12_MASK 0x3FF
++#define ISPRSZ_HFILT1312_COEFF13_SHIFT 16
++#define ISPRSZ_HFILT1312_COEFF13_MASK 0x3FF0000
++
++#define ISPRSZ_HFILT1514_COEFF14_SHIFT 0
++#define ISPRSZ_HFILT1514_COEFF14_MASK 0x3FF
++#define ISPRSZ_HFILT1514_COEFF15_SHIFT 16
++#define ISPRSZ_HFILT1514_COEFF15_MASK 0x3FF0000
++
++#define ISPRSZ_HFILT1716_COEF16_SHIFT 0
++#define ISPRSZ_HFILT1716_COEF16_MASK 0x3FF
++#define ISPRSZ_HFILT1716_COEF17_SHIFT 16
++#define ISPRSZ_HFILT1716_COEF17_MASK 0x3FF0000
++
++#define ISPRSZ_HFILT1918_COEF18_SHIFT 0
++#define ISPRSZ_HFILT1918_COEF18_MASK 0x3FF
++#define ISPRSZ_HFILT1918_COEF19_SHIFT 16
++#define ISPRSZ_HFILT1918_COEF19_MASK 0x3FF0000
++
++#define ISPRSZ_HFILT2120_COEF20_SHIFT 0
++#define ISPRSZ_HFILT2120_COEF20_MASK 0x3FF
++#define ISPRSZ_HFILT2120_COEF21_SHIFT 16
++#define ISPRSZ_HFILT2120_COEF21_MASK 0x3FF0000
++
++#define ISPRSZ_HFILT2322_COEF22_SHIFT 0
++#define ISPRSZ_HFILT2322_COEF22_MASK 0x3FF
++#define ISPRSZ_HFILT2322_COEF23_SHIFT 16
++#define ISPRSZ_HFILT2322_COEF23_MASK 0x3FF0000
++
++#define ISPRSZ_HFILT2524_COEF24_SHIFT 0
++#define ISPRSZ_HFILT2524_COEF24_MASK 0x3FF
++#define ISPRSZ_HFILT2524_COEF25_SHIFT 16
++#define ISPRSZ_HFILT2524_COEF25_MASK 0x3FF0000
++
++#define ISPRSZ_HFILT2726_COEF26_SHIFT 0
++#define ISPRSZ_HFILT2726_COEF26_MASK 0x3FF
++#define ISPRSZ_HFILT2726_COEF27_SHIFT 16
++#define ISPRSZ_HFILT2726_COEF27_MASK 0x3FF0000
++
++#define ISPRSZ_HFILT2928_COEF28_SHIFT 0
++#define ISPRSZ_HFILT2928_COEF28_MASK 0x3FF
++#define ISPRSZ_HFILT2928_COEF29_SHIFT 16
++#define ISPRSZ_HFILT2928_COEF29_MASK 0x3FF0000
++
++#define ISPRSZ_HFILT3130_COEF30_SHIFT 0
++#define ISPRSZ_HFILT3130_COEF30_MASK 0x3FF
++#define ISPRSZ_HFILT3130_COEF31_SHIFT 16
++#define ISPRSZ_HFILT3130_COEF31_MASK 0x3FF0000
++
++#define ISPRSZ_VFILT_COEF0_SHIFT 0
++#define ISPRSZ_VFILT_COEF0_MASK \
++ (0x3FF << ISPRSZ_VFILT_COEF0_SHIFT)
++#define ISPRSZ_VFILT_COEF1_SHIFT 16
++#define ISPRSZ_VFILT_COEF1_MASK \
++ (0x3FF << ISPRSZ_VFILT_COEF1_SHIFT)
++
++#define ISPRSZ_VFILT10_COEF0_SHIFT 0
++#define ISPRSZ_VFILT10_COEF0_MASK 0x3FF
++#define ISPRSZ_VFILT10_COEF1_SHIFT 16
++#define ISPRSZ_VFILT10_COEF1_MASK 0x3FF0000
++
++#define ISPRSZ_VFILT32_COEF2_SHIFT 0
++#define ISPRSZ_VFILT32_COEF2_MASK 0x3FF
++#define ISPRSZ_VFILT32_COEF3_SHIFT 16
++#define ISPRSZ_VFILT32_COEF3_MASK 0x3FF0000
++
++#define ISPRSZ_VFILT54_COEF4_SHIFT 0
++#define ISPRSZ_VFILT54_COEF4_MASK 0x3FF
++#define ISPRSZ_VFILT54_COEF5_SHIFT 16
++#define ISPRSZ_VFILT54_COEF5_MASK 0x3FF0000
++
++#define ISPRSZ_VFILT76_COEFF6_SHIFT 0
++#define ISPRSZ_VFILT76_COEFF6_MASK 0x3FF
++#define ISPRSZ_VFILT76_COEFF7_SHIFT 16
++#define ISPRSZ_VFILT76_COEFF7_MASK 0x3FF0000
++
++#define ISPRSZ_VFILT98_COEFF8_SHIFT 0
++#define ISPRSZ_VFILT98_COEFF8_MASK 0x3FF
++#define ISPRSZ_VFILT98_COEFF9_SHIFT 16
++#define ISPRSZ_VFILT98_COEFF9_MASK 0x3FF0000
++
++#define ISPRSZ_VFILT1110_COEF10_SHIFT 0
++#define ISPRSZ_VFILT1110_COEF10_MASK 0x3FF
++#define ISPRSZ_VFILT1110_COEF11_SHIFT 16
++#define ISPRSZ_VFILT1110_COEF11_MASK 0x3FF0000
++
++#define ISPRSZ_VFILT1312_COEFF12_SHIFT 0
++#define ISPRSZ_VFILT1312_COEFF12_MASK 0x3FF
++#define ISPRSZ_VFILT1312_COEFF13_SHIFT 16
++#define ISPRSZ_VFILT1312_COEFF13_MASK 0x3FF0000
++
++#define ISPRSZ_VFILT1514_COEFF14_SHIFT 0
++#define ISPRSZ_VFILT1514_COEFF14_MASK 0x3FF
++#define ISPRSZ_VFILT1514_COEFF15_SHIFT 16
++#define ISPRSZ_VFILT1514_COEFF15_MASK 0x3FF0000
++
++#define ISPRSZ_VFILT1716_COEF16_SHIFT 0
++#define ISPRSZ_VFILT1716_COEF16_MASK 0x3FF
++#define ISPRSZ_VFILT1716_COEF17_SHIFT 16
++#define ISPRSZ_VFILT1716_COEF17_MASK 0x3FF0000
++
++#define ISPRSZ_VFILT1918_COEF18_SHIFT 0
++#define ISPRSZ_VFILT1918_COEF18_MASK 0x3FF
++#define ISPRSZ_VFILT1918_COEF19_SHIFT 16
++#define ISPRSZ_VFILT1918_COEF19_MASK 0x3FF0000
++
++#define ISPRSZ_VFILT2120_COEF20_SHIFT 0
++#define ISPRSZ_VFILT2120_COEF20_MASK 0x3FF
++#define ISPRSZ_VFILT2120_COEF21_SHIFT 16
++#define ISPRSZ_VFILT2120_COEF21_MASK 0x3FF0000
++
++#define ISPRSZ_VFILT2322_COEF22_SHIFT 0
++#define ISPRSZ_VFILT2322_COEF22_MASK 0x3FF
++#define ISPRSZ_VFILT2322_COEF23_SHIFT 16
++#define ISPRSZ_VFILT2322_COEF23_MASK 0x3FF0000
++
++#define ISPRSZ_VFILT2524_COEF24_SHIFT 0
++#define ISPRSZ_VFILT2524_COEF24_MASK 0x3FF
++#define ISPRSZ_VFILT2524_COEF25_SHIFT 16
++#define ISPRSZ_VFILT2524_COEF25_MASK 0x3FF0000
++
++#define ISPRSZ_VFILT2726_COEF26_SHIFT 0
++#define ISPRSZ_VFILT2726_COEF26_MASK 0x3FF
++#define ISPRSZ_VFILT2726_COEF27_SHIFT 16
++#define ISPRSZ_VFILT2726_COEF27_MASK 0x3FF0000
++
++#define ISPRSZ_VFILT2928_COEF28_SHIFT 0
++#define ISPRSZ_VFILT2928_COEF28_MASK 0x3FF
++#define ISPRSZ_VFILT2928_COEF29_SHIFT 16
++#define ISPRSZ_VFILT2928_COEF29_MASK 0x3FF0000
++
++#define ISPRSZ_VFILT3130_COEF30_SHIFT 0
++#define ISPRSZ_VFILT3130_COEF30_MASK 0x3FF
++#define ISPRSZ_VFILT3130_COEF31_SHIFT 16
++#define ISPRSZ_VFILT3130_COEF31_MASK 0x3FF0000
++
++#define ISPRSZ_YENH_CORE_SHIFT 0
++#define ISPRSZ_YENH_CORE_MASK \
++ (0xFF << ISPRSZ_YENH_CORE_SHIFT)
++#define ISPRSZ_YENH_SLOP_SHIFT 8
++#define ISPRSZ_YENH_SLOP_MASK \
++ (0xF << ISPRSZ_YENH_SLOP_SHIFT)
++#define ISPRSZ_YENH_GAIN_SHIFT 12
++#define ISPRSZ_YENH_GAIN_MASK \
++ (0xF << ISPRSZ_YENH_GAIN_SHIFT)
++#define ISPRSZ_YENH_ALGO_SHIFT 16
++#define ISPRSZ_YENH_ALGO_MASK \
++ (0x3 << ISPRSZ_YENH_ALGO_SHIFT)
++
++#define ISPH3A_PCR_AEW_ALAW_EN_SHIFT 1
++#define ISPH3A_PCR_AF_MED_TH_SHIFT 3
++#define ISPH3A_PCR_AF_RGBPOS_SHIFT 11
++#define ISPH3A_PCR_AEW_AVE2LMT_SHIFT 22
++#define ISPH3A_PCR_AEW_AVE2LMT_MASK 0xFFC00000
++#define ISPH3A_PCR_BUSYAF (1 << 15)
++#define ISPH3A_PCR_BUSYAEAWB (1 << 18)
++
++#define ISPH3A_AEWWIN1_WINHC_SHIFT 0
++#define ISPH3A_AEWWIN1_WINHC_MASK 0x3F
++#define ISPH3A_AEWWIN1_WINVC_SHIFT 6
++#define ISPH3A_AEWWIN1_WINVC_MASK 0x1FC0
++#define ISPH3A_AEWWIN1_WINW_SHIFT 13
++#define ISPH3A_AEWWIN1_WINW_MASK 0xFE000
++#define ISPH3A_AEWWIN1_WINH_SHIFT 24
++#define ISPH3A_AEWWIN1_WINH_MASK 0x7F000000
++
++#define ISPH3A_AEWINSTART_WINSH_SHIFT 0
++#define ISPH3A_AEWINSTART_WINSH_MASK 0x0FFF
++#define ISPH3A_AEWINSTART_WINSV_SHIFT 16
++#define ISPH3A_AEWINSTART_WINSV_MASK 0x0FFF0000
++
++#define ISPH3A_AEWINBLK_WINH_SHIFT 0
++#define ISPH3A_AEWINBLK_WINH_MASK 0x7F
++#define ISPH3A_AEWINBLK_WINSV_SHIFT 16
++#define ISPH3A_AEWINBLK_WINSV_MASK 0x0FFF0000
++
++#define ISPH3A_AEWSUBWIN_AEWINCH_SHIFT 0
++#define ISPH3A_AEWSUBWIN_AEWINCH_MASK 0x0F
++#define ISPH3A_AEWSUBWIN_AEWINCV_SHIFT 8
++#define ISPH3A_AEWSUBWIN_AEWINCV_MASK 0x0F00
++
++#define ISPHIST_PCR_ENABLE_SHIFT 0
++#define ISPHIST_PCR_ENABLE_MASK 0x01
++#define ISPHIST_PCR_ENABLE (1 << ISPHIST_PCR_ENABLE_SHIFT)
++#define ISPHIST_PCR_BUSY 0x02
++
++#define ISPHIST_CNT_DATASIZE_SHIFT 8
++#define ISPHIST_CNT_DATASIZE_MASK 0x0100
++#define ISPHIST_CNT_CLEAR_SHIFT 7
++#define ISPHIST_CNT_CLEAR_MASK 0x080
++#define ISPHIST_CNT_CLEAR (1 << ISPHIST_CNT_CLEAR_SHIFT)
++#define ISPHIST_CNT_CFA_SHIFT 6
++#define ISPHIST_CNT_CFA_MASK 0x040
++#define ISPHIST_CNT_BINS_SHIFT 4
++#define ISPHIST_CNT_BINS_MASK 0x030
++#define ISPHIST_CNT_SOURCE_SHIFT 3
++#define ISPHIST_CNT_SOURCE_MASK 0x08
++#define ISPHIST_CNT_SHIFT_SHIFT 0
++#define ISPHIST_CNT_SHIFT_MASK 0x07
++
++#define ISPHIST_WB_GAIN_WG00_SHIFT 24
++#define ISPHIST_WB_GAIN_WG00_MASK 0xFF000000
++#define ISPHIST_WB_GAIN_WG01_SHIFT 16
++#define ISPHIST_WB_GAIN_WG01_MASK 0xFF0000
++#define ISPHIST_WB_GAIN_WG02_SHIFT 8
++#define ISPHIST_WB_GAIN_WG02_MASK 0xFF00
++#define ISPHIST_WB_GAIN_WG03_SHIFT 0
++#define ISPHIST_WB_GAIN_WG03_MASK 0xFF
++
++#define ISPHIST_REG_START_END_MASK 0x3FFF
++#define ISPHIST_REG_START_SHIFT 16
++#define ISPHIST_REG_END_SHIFT 0
++#define ISPHIST_REG_START_MASK (ISPHIST_REG_START_END_MASK << \
++ ISPHIST_REG_START_SHIFT)
++#define ISPHIST_REG_END_MASK (ISPHIST_REG_START_END_MASK << \
++ ISPHIST_REG_END_SHIFT)
++
++#define ISPHIST_REG_MASK (ISPHIST_REG_START_MASK | \
++ ISPHIST_REG_END_MASK)
++
++#define ISPHIST_ADDR_SHIFT 0
++#define ISPHIST_ADDR_MASK 0x3FF
++
++#define ISPHIST_DATA_SHIFT 0
++#define ISPHIST_DATA_MASK 0xFFFFF
++
++#define ISPHIST_RADD_SHIFT 0
++#define ISPHIST_RADD_MASK 0xFFFFFFFF
++
++#define ISPHIST_RADD_OFF_SHIFT 0
++#define ISPHIST_RADD_OFF_MASK 0xFFFF
++
++#define ISPHIST_HV_INFO_HSIZE_SHIFT 16
++#define ISPHIST_HV_INFO_HSIZE_MASK 0x3FFF0000
++#define ISPHIST_HV_INFO_VSIZE_SHIFT 0
++#define ISPHIST_HV_INFO_VSIZE_MASK 0x3FFF
++
++#define ISPHIST_HV_INFO_MASK 0x3FFF3FFF
++
++#define ISPCCDC_LSC_ENABLE 1
++#define ISPCCDC_LSC_BUSY (1 << 7)
++#define ISPCCDC_LSC_GAIN_MODE_N_MASK 0x700
++#define ISPCCDC_LSC_GAIN_MODE_N_SHIFT 8
++#define ISPCCDC_LSC_GAIN_MODE_M_MASK 0x3800
++#define ISPCCDC_LSC_GAIN_MODE_M_SHIFT 12
++#define ISPCCDC_LSC_GAIN_FORMAT_MASK 0xE
++#define ISPCCDC_LSC_GAIN_FORMAT_SHIFT 1
++#define ISPCCDC_LSC_AFTER_REFORMATTER_MASK (1<<6)
++
++#define ISPCCDC_LSC_INITIAL_X_MASK 0x3F
++#define ISPCCDC_LSC_INITIAL_X_SHIFT 0
++#define ISPCCDC_LSC_INITIAL_Y_MASK 0x3F0000
++#define ISPCCDC_LSC_INITIAL_Y_SHIFT 16
++
++/* -----------------------------------------------------------------------------
++ * CSI2 receiver registers (ES2.0)
++ */
++
++#define ISPCSI2_REVISION (0x000)
++#define ISPCSI2_SYSCONFIG (0x010)
++#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT 12
++#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK \
++ (0x3 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
++#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_FORCE \
++ (0x0 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
++#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_NO \
++ (0x1 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
++#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SMART \
++ (0x2 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
++#define ISPCSI2_SYSCONFIG_SOFT_RESET (1 << 1)
++#define ISPCSI2_SYSCONFIG_AUTO_IDLE (1 << 0)
++
++#define ISPCSI2_SYSSTATUS (0x014)
++#define ISPCSI2_SYSSTATUS_RESET_DONE (1 << 0)
++
++#define ISPCSI2_IRQSTATUS (0x018)
++#define ISPCSI2_IRQSTATUS_OCP_ERR_IRQ (1 << 14)
++#define ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ (1 << 13)
++#define ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ (1 << 12)
++#define ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ (1 << 11)
++#define ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ (1 << 10)
++#define ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ (1 << 9)
++#define ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ (1 << 8)
++#define ISPCSI2_IRQSTATUS_CONTEXT(n) (1 << (n))
++
++#define ISPCSI2_IRQENABLE (0x01c)
++#define ISPCSI2_CTRL (0x040)
++#define ISPCSI2_CTRL_VP_CLK_EN (1 << 15)
++#define ISPCSI2_CTRL_VP_ONLY_EN (1 << 11)
++#define ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT 8
++#define ISPCSI2_CTRL_VP_OUT_CTRL_MASK \
++ (3 << ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT)
++#define ISPCSI2_CTRL_DBG_EN (1 << 7)
++#define ISPCSI2_CTRL_BURST_SIZE_SHIFT 5
++#define ISPCSI2_CTRL_BURST_SIZE_MASK \
++ (3 << ISPCSI2_CTRL_BURST_SIZE_SHIFT)
++#define ISPCSI2_CTRL_FRAME (1 << 3)
++#define ISPCSI2_CTRL_ECC_EN (1 << 2)
++#define ISPCSI2_CTRL_SECURE (1 << 1)
++#define ISPCSI2_CTRL_IF_EN (1 << 0)
++
++#define ISPCSI2_DBG_H (0x044)
++#define ISPCSI2_GNQ (0x048)
++#define ISPCSI2_PHY_CFG (0x050)
++#define ISPCSI2_PHY_CFG_RESET_CTRL (1 << 30)
++#define ISPCSI2_PHY_CFG_RESET_DONE (1 << 29)
++#define ISPCSI2_PHY_CFG_PWR_CMD_SHIFT 27
++#define ISPCSI2_PHY_CFG_PWR_CMD_MASK \
++ (0x3 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT)
++#define ISPCSI2_PHY_CFG_PWR_CMD_OFF \
++ (0x0 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT)
++#define ISPCSI2_PHY_CFG_PWR_CMD_ON \
++ (0x1 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT)
++#define ISPCSI2_PHY_CFG_PWR_CMD_ULPW \
++ (0x2 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT)
++#define ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT 25
++#define ISPCSI2_PHY_CFG_PWR_STATUS_MASK \
++ (0x3 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT)
++#define ISPCSI2_PHY_CFG_PWR_STATUS_OFF \
++ (0x0 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT)
++#define ISPCSI2_PHY_CFG_PWR_STATUS_ON \
++ (0x1 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT)
++#define ISPCSI2_PHY_CFG_PWR_STATUS_ULPW \
++ (0x2 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT)
++#define ISPCSI2_PHY_CFG_PWR_AUTO (1 << 24)
++
++#define ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n) (3 + ((n) * 4))
++#define ISPCSI2_PHY_CFG_DATA_POL_MASK(n) \
++ (0x1 << ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n))
++#define ISPCSI2_PHY_CFG_DATA_POL_PN(n) \
++ (0x0 << ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n))
++#define ISPCSI2_PHY_CFG_DATA_POL_NP(n) \
++ (0x1 << ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n))
++
++#define ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n) ((n) * 4)
++#define ISPCSI2_PHY_CFG_DATA_POSITION_MASK(n) \
++ (0x7 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n))
++#define ISPCSI2_PHY_CFG_DATA_POSITION_NC(n) \
++ (0x0 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n))
++#define ISPCSI2_PHY_CFG_DATA_POSITION_1(n) \
++ (0x1 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n))
++#define ISPCSI2_PHY_CFG_DATA_POSITION_2(n) \
++ (0x2 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n))
++#define ISPCSI2_PHY_CFG_DATA_POSITION_3(n) \
++ (0x3 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n))
++#define ISPCSI2_PHY_CFG_DATA_POSITION_4(n) \
++ (0x4 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n))
++#define ISPCSI2_PHY_CFG_DATA_POSITION_5(n) \
++ (0x5 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n))
++
++#define ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT 3
++#define ISPCSI2_PHY_CFG_CLOCK_POL_MASK \
++ (0x1 << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT)
++#define ISPCSI2_PHY_CFG_CLOCK_POL_PN \
++ (0x0 << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT)
++#define ISPCSI2_PHY_CFG_CLOCK_POL_NP \
++ (0x1 << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT)
++
++#define ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT 0
++#define ISPCSI2_PHY_CFG_CLOCK_POSITION_MASK \
++ (0x7 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT)
++#define ISPCSI2_PHY_CFG_CLOCK_POSITION_1 \
++ (0x1 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT)
++#define ISPCSI2_PHY_CFG_CLOCK_POSITION_2 \
++ (0x2 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT)
++#define ISPCSI2_PHY_CFG_CLOCK_POSITION_3 \
++ (0x3 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT)
++#define ISPCSI2_PHY_CFG_CLOCK_POSITION_4 \
++ (0x4 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT)
++#define ISPCSI2_PHY_CFG_CLOCK_POSITION_5 \
++ (0x5 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT)
++
++#define ISPCSI2_PHY_IRQSTATUS (0x054)
++#define ISPCSI2_PHY_IRQSTATUS_STATEALLULPMEXIT (1 << 26)
++#define ISPCSI2_PHY_IRQSTATUS_STATEALLULPMENTER (1 << 25)
++#define ISPCSI2_PHY_IRQSTATUS_STATEULPM5 (1 << 24)
++#define ISPCSI2_PHY_IRQSTATUS_STATEULPM4 (1 << 23)
++#define ISPCSI2_PHY_IRQSTATUS_STATEULPM3 (1 << 22)
++#define ISPCSI2_PHY_IRQSTATUS_STATEULPM2 (1 << 21)
++#define ISPCSI2_PHY_IRQSTATUS_STATEULPM1 (1 << 20)
++#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL5 (1 << 19)
++#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL4 (1 << 18)
++#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL3 (1 << 17)
++#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL2 (1 << 16)
++#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL1 (1 << 15)
++#define ISPCSI2_PHY_IRQSTATUS_ERRESC5 (1 << 14)
++#define ISPCSI2_PHY_IRQSTATUS_ERRESC4 (1 << 13)
++#define ISPCSI2_PHY_IRQSTATUS_ERRESC3 (1 << 12)
++#define ISPCSI2_PHY_IRQSTATUS_ERRESC2 (1 << 11)
++#define ISPCSI2_PHY_IRQSTATUS_ERRESC1 (1 << 10)
++#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS5 (1 << 9)
++#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS4 (1 << 8)
++#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS3 (1 << 7)
++#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS2 (1 << 6)
++#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS1 (1 << 5)
++#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS5 (1 << 4)
++#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS4 (1 << 3)
++#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS3 (1 << 2)
++#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS2 (1 << 1)
++#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS1 1
++
++#define ISPCSI2_SHORT_PACKET (0x05c)
++#define ISPCSI2_PHY_IRQENABLE (0x060)
++#define ISPCSI2_PHY_IRQENABLE_STATEALLULPMEXIT (1 << 26)
++#define ISPCSI2_PHY_IRQENABLE_STATEALLULPMENTER (1 << 25)
++#define ISPCSI2_PHY_IRQENABLE_STATEULPM5 (1 << 24)
++#define ISPCSI2_PHY_IRQENABLE_STATEULPM4 (1 << 23)
++#define ISPCSI2_PHY_IRQENABLE_STATEULPM3 (1 << 22)
++#define ISPCSI2_PHY_IRQENABLE_STATEULPM2 (1 << 21)
++#define ISPCSI2_PHY_IRQENABLE_STATEULPM1 (1 << 20)
++#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL5 (1 << 19)
++#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL4 (1 << 18)
++#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL3 (1 << 17)
++#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL2 (1 << 16)
++#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL1 (1 << 15)
++#define ISPCSI2_PHY_IRQENABLE_ERRESC5 (1 << 14)
++#define ISPCSI2_PHY_IRQENABLE_ERRESC4 (1 << 13)
++#define ISPCSI2_PHY_IRQENABLE_ERRESC3 (1 << 12)
++#define ISPCSI2_PHY_IRQENABLE_ERRESC2 (1 << 11)
++#define ISPCSI2_PHY_IRQENABLE_ERRESC1 (1 << 10)
++#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS5 (1 << 9)
++#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS4 (1 << 8)
++#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS3 (1 << 7)
++#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS2 (1 << 6)
++#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS1 (1 << 5)
++#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS5 (1 << 4)
++#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS4 (1 << 3)
++#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS3 (1 << 2)
++#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS2 (1 << 1)
++#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS1 (1 << 0)
++
++#define ISPCSI2_DBG_P (0x068)
++#define ISPCSI2_TIMING (0x06c)
++#define ISPCSI2_TIMING_FORCE_RX_MODE_IO(n) (1 << ((16 * ((n) - 1)) + 15))
++#define ISPCSI2_TIMING_STOP_STATE_X16_IO(n) (1 << ((16 * ((n) - 1)) + 14))
++#define ISPCSI2_TIMING_STOP_STATE_X4_IO(n) (1 << ((16 * ((n) - 1)) + 13))
++#define ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(n) (16 * ((n) - 1))
++#define ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(n) \
++ (0x1fff << ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(n))
++
++#define ISPCSI2_CTX_CTRL1(n) ((0x070) + 0x20 * (n))
++#define ISPCSI2_CTX_CTRL1_COUNT_SHIFT 8
++#define ISPCSI2_CTX_CTRL1_COUNT_MASK \
++ (0xff << ISPCSI2_CTX_CTRL1_COUNT_SHIFT)
++#define ISPCSI2_CTX_CTRL1_EOF_EN (1 << 7)
++#define ISPCSI2_CTX_CTRL1_EOL_EN (1 << 6)
++#define ISPCSI2_CTX_CTRL1_CS_EN (1 << 5)
++#define ISPCSI2_CTX_CTRL1_COUNT_UNLOCK (1 << 4)
++#define ISPCSI2_CTX_CTRL1_PING_PONG (1 << 3)
++#define ISPCSI2_CTX_CTRL1_CTX_EN (1 << 0)
++
++#define ISPCSI2_CTX_CTRL2(n) ((0x074) + 0x20 * (n))
++#define ISPCSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT 13
++#define ISPCSI2_CTX_CTRL2_USER_DEF_MAP_MASK \
++ (0x3 << ISPCSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT)
++#define ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT 11
++#define ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK \
++ (0x3 << ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT)
++#define ISPCSI2_CTX_CTRL2_DPCM_PRED (1 << 10)
++#define ISPCSI2_CTX_CTRL2_FORMAT_SHIFT 0
++#define ISPCSI2_CTX_CTRL2_FORMAT_MASK \
++ (0x3ff << ISPCSI2_CTX_CTRL2_FORMAT_SHIFT)
++#define ISPCSI2_CTX_CTRL2_FRAME_SHIFT 16
++#define ISPCSI2_CTX_CTRL2_FRAME_MASK \
++ (0xffff << ISPCSI2_CTX_CTRL2_FRAME_SHIFT)
++
++#define ISPCSI2_CTX_DAT_OFST(n) ((0x078) + 0x20 * (n))
++#define ISPCSI2_CTX_DAT_OFST_OFST_SHIFT 0
++#define ISPCSI2_CTX_DAT_OFST_OFST_MASK \
++ (0x1ffe0 << ISPCSI2_CTX_DAT_OFST_OFST_SHIFT)
++
++#define ISPCSI2_CTX_DAT_PING_ADDR(n) ((0x07c) + 0x20 * (n))
++#define ISPCSI2_CTX_DAT_PONG_ADDR(n) ((0x080) + 0x20 * (n))
++#define ISPCSI2_CTX_IRQENABLE(n) ((0x084) + 0x20 * (n))
++#define ISPCSI2_CTX_IRQENABLE_ECC_CORRECTION_IRQ (1 << 8)
++#define ISPCSI2_CTX_IRQENABLE_LINE_NUMBER_IRQ (1 << 7)
++#define ISPCSI2_CTX_IRQENABLE_FRAME_NUMBER_IRQ (1 << 6)
++#define ISPCSI2_CTX_IRQENABLE_CS_IRQ (1 << 5)
++#define ISPCSI2_CTX_IRQENABLE_LE_IRQ (1 << 3)
++#define ISPCSI2_CTX_IRQENABLE_LS_IRQ (1 << 2)
++#define ISPCSI2_CTX_IRQENABLE_FE_IRQ (1 << 1)
++#define ISPCSI2_CTX_IRQENABLE_FS_IRQ (1 << 0)
++
++#define ISPCSI2_CTX_IRQSTATUS(n) ((0x088) + 0x20 * (n))
++#define ISPCSI2_CTX_IRQSTATUS_ECC_CORRECTION_IRQ (1 << 8)
++#define ISPCSI2_CTX_IRQSTATUS_LINE_NUMBER_IRQ (1 << 7)
++#define ISPCSI2_CTX_IRQSTATUS_FRAME_NUMBER_IRQ (1 << 6)
++#define ISPCSI2_CTX_IRQSTATUS_CS_IRQ (1 << 5)
++#define ISPCSI2_CTX_IRQSTATUS_LE_IRQ (1 << 3)
++#define ISPCSI2_CTX_IRQSTATUS_LS_IRQ (1 << 2)
++#define ISPCSI2_CTX_IRQSTATUS_FE_IRQ (1 << 1)
++#define ISPCSI2_CTX_IRQSTATUS_FS_IRQ (1 << 0)
++
++#define ISPCSI2_CTX_CTRL3(n) ((0x08c) + 0x20 * (n))
++#define ISPCSI2_CTX_CTRL3_ALPHA_SHIFT 5
++#define ISPCSI2_CTX_CTRL3_ALPHA_MASK \
++ (0x3fff << ISPCSI2_CTX_CTRL3_ALPHA_SHIFT)
++
++/* This instance is for OMAP3630 only */
++#define ISPCSI2_CTX_TRANSCODEH(n) (0x000 + 0x8 * (n))
++#define ISPCSI2_CTX_TRANSCODEH_HCOUNT_SHIFT 16
++#define ISPCSI2_CTX_TRANSCODEH_HCOUNT_MASK \
++ (0x1fff << ISPCSI2_CTX_TRANSCODEH_HCOUNT_SHIFT)
++#define ISPCSI2_CTX_TRANSCODEH_HSKIP_SHIFT 0
++#define ISPCSI2_CTX_TRANSCODEH_HSKIP_MASK \
++ (0x1fff << ISPCSI2_CTX_TRANSCODEH_HCOUNT_SHIFT)
++#define ISPCSI2_CTX_TRANSCODEV(n) (0x004 + 0x8 * (n))
++#define ISPCSI2_CTX_TRANSCODEV_VCOUNT_SHIFT 16
++#define ISPCSI2_CTX_TRANSCODEV_VCOUNT_MASK \
++ (0x1fff << ISPCSI2_CTX_TRANSCODEV_VCOUNT_SHIFT)
++#define ISPCSI2_CTX_TRANSCODEV_VSKIP_SHIFT 0
++#define ISPCSI2_CTX_TRANSCODEV_VSKIP_MASK \
++ (0x1fff << ISPCSI2_CTX_TRANSCODEV_VCOUNT_SHIFT)
++
++/* -----------------------------------------------------------------------------
++ * CSI PHY registers
++ */
++
++#define ISPCSIPHY_REG0 (0x000)
++#define ISPCSIPHY_REG0_THS_TERM_SHIFT 8
++#define ISPCSIPHY_REG0_THS_TERM_MASK \
++ (0xff << ISPCSIPHY_REG0_THS_TERM_SHIFT)
++#define ISPCSIPHY_REG0_THS_SETTLE_SHIFT 0
++#define ISPCSIPHY_REG0_THS_SETTLE_MASK \
++ (0xff << ISPCSIPHY_REG0_THS_SETTLE_SHIFT)
++
++#define ISPCSIPHY_REG1 (0x004)
++#define ISPCSIPHY_REG1_RESET_DONE_CTRLCLK (1 << 29)
++/* This field is for OMAP3630 only */
++#define ISPCSIPHY_REG1_CLOCK_MISS_DETECTOR_STATUS (1 << 25)
++#define ISPCSIPHY_REG1_TCLK_TERM_SHIFT 18
++#define ISPCSIPHY_REG1_TCLK_TERM_MASK \
++ (0x7f << ISPCSIPHY_REG1_TCLK_TERM_SHIFT)
++#define ISPCSIPHY_REG1_DPHY_HS_SYNC_PATTERN_SHIFT 10
++#define ISPCSIPHY_REG1_DPHY_HS_SYNC_PATTERN_MASK \
++ (0xff << ISPCSIPHY_REG1_DPHY_HS_SYNC_PATTERN)
++/* This field is for OMAP3430 only */
++#define ISPCSIPHY_REG1_TCLK_MISS_SHIFT 8
++#define ISPCSIPHY_REG1_TCLK_MISS_MASK \
++ (0x3 << ISPCSIPHY_REG1_TCLK_MISS_SHIFT)
++/* This field is for OMAP3630 only */
++#define ISPCSIPHY_REG1_CTRLCLK_DIV_FACTOR_SHIFT 8
++#define ISPCSIPHY_REG1_CTRLCLK_DIV_FACTOR_MASK \
++ (0x3 << ISPCSIPHY_REG1_CTRLCLK_DIV_FACTOR_SHIFT)
++#define ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT 0
++#define ISPCSIPHY_REG1_TCLK_SETTLE_MASK \
++ (0xff << ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT)
++
++/* This register is for OMAP3630 only */
++#define ISPCSIPHY_REG2 (0x008)
++#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC0_SHIFT 30
++#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC0_MASK \
++ (0x3 << ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC0_SHIFT)
++#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC1_SHIFT 28
++#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC1_MASK \
++ (0x3 << ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC1_SHIFT)
++#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC2_SHIFT 26
++#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC2_MASK \
++ (0x3 << ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC2_SHIFT)
++#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC3_SHIFT 24
++#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC3_MASK \
++ (0x3 << ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC3_SHIFT)
++#define ISPCSIPHY_REG2_CCP2_SYNC_PATTERN_SHIFT 0
++#define ISPCSIPHY_REG2_CCP2_SYNC_PATTERN_MASK \
++ (0x7fffff << ISPCSIPHY_REG2_CCP2_SYNC_PATTERN_SHIFT)
++
++#endif /* OMAP3_ISP_REG_H */
+diff --git a/drivers/media/video/isp/ispresizer.c b/drivers/media/video/isp/ispresizer.c
+new file mode 100644
+index 0000000..a696450
+--- /dev/null
++++ b/drivers/media/video/isp/ispresizer.c
+@@ -0,0 +1,1710 @@
++/*
++ * ispresizer.c
++ *
++ * TI OMAP3 ISP - Resizer module
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#include <linux/device.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++
++#include "isp.h"
++#include "ispreg.h"
++#include "ispresizer.h"
++
++/*
++ * Resizer Constants
++ */
++#define MIN_RESIZE_VALUE 64
++#define MID_RESIZE_VALUE 512
++#define MAX_RESIZE_VALUE 1024
++
++#define MIN_IN_WIDTH 32
++#define MIN_IN_HEIGHT 32
++#define MAX_IN_WIDTH_MEMORY_MODE 4095
++#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES1 1280
++#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES2 4095
++#define MAX_IN_HEIGHT 4095
++
++#define MIN_OUT_WIDTH 16
++#define MIN_OUT_HEIGHT 2
++#define MAX_OUT_HEIGHT 4095
++
++/*
++ * Resizer Use Constraints
++ * "TRM ES3.1, table 12-46"
++ */
++#define MAX_4TAP_OUT_WIDTH_ES1 1280
++#define MAX_7TAP_OUT_WIDTH_ES1 640
++#define MAX_4TAP_OUT_WIDTH_ES2 3312
++#define MAX_7TAP_OUT_WIDTH_ES2 1650
++#define MAX_4TAP_OUT_WIDTH_3630 4096
++#define MAX_7TAP_OUT_WIDTH_3630 2048
++
++/*
++ * Constants for ratio calculation
++ */
++#define RESIZE_DIVISOR 256
++#define DEFAULT_PHASE 1
++
++/*
++ * Default (and only) configuration of filter coefficients.
++ * 7-tap mode is for scale factors 0.25x to 0.5x.
++ * 4-tap mode is for scale factors 0.5x to 4.0x.
++ * There shouldn't be any reason to recalculate these, EVER.
++ */
++static const struct isprsz_coef filter_coefs = {
++ /* For 8-phase 4-tap horizontal filter: */
++ {
++ 0x0000, 0x0100, 0x0000, 0x0000,
++ 0x03FA, 0x00F6, 0x0010, 0x0000,
++ 0x03F9, 0x00DB, 0x002C, 0x0000,
++ 0x03FB, 0x00B3, 0x0053, 0x03FF,
++ 0x03FD, 0x0082, 0x0084, 0x03FD,
++ 0x03FF, 0x0053, 0x00B3, 0x03FB,
++ 0x0000, 0x002C, 0x00DB, 0x03F9,
++ 0x0000, 0x0010, 0x00F6, 0x03FA
++ },
++ /* For 8-phase 4-tap vertical filter: */
++ {
++ 0x0000, 0x0100, 0x0000, 0x0000,
++ 0x03FA, 0x00F6, 0x0010, 0x0000,
++ 0x03F9, 0x00DB, 0x002C, 0x0000,
++ 0x03FB, 0x00B3, 0x0053, 0x03FF,
++ 0x03FD, 0x0082, 0x0084, 0x03FD,
++ 0x03FF, 0x0053, 0x00B3, 0x03FB,
++ 0x0000, 0x002C, 0x00DB, 0x03F9,
++ 0x0000, 0x0010, 0x00F6, 0x03FA
++ },
++ /* For 4-phase 7-tap horizontal filter: */
++ #define DUMMY 0
++ {
++ 0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY,
++ 0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY,
++ 0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY,
++ 0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY
++ },
++ /* For 4-phase 7-tap vertical filter: */
++ {
++ 0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY,
++ 0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY,
++ 0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY,
++ 0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY
++ }
++ /*
++ * The dummy padding is required in 7-tap mode because of how the
++ * registers are arranged physically.
++ */
++ #undef DUMMY
++};
++
++/*
++ * __resizer_get_format - helper function for getting resizer format
++ * @res : pointer to resizer private structure
++ * @pad : pad number
++ * @fh : V4L2 subdev file handle
++ * @which : wanted subdev format
++ * return zero
++ */
++static struct v4l2_mbus_framefmt *
++__resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
++ unsigned int pad, enum v4l2_subdev_format_whence which)
++{
++ if (which == V4L2_SUBDEV_FORMAT_TRY)
++ return v4l2_subdev_get_try_format(fh, pad);
++ else
++ return &res->formats[pad];
++}
++
++/*
++ * __resizer_get_crop - helper function for getting resizer crop rectangle
++ * @res : pointer to resizer private structure
++ * @fh : V4L2 subdev file handle
++ * @which : wanted subdev crop rectangle
++ */
++static struct v4l2_rect *
++__resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
++ enum v4l2_subdev_format_whence which)
++{
++ if (which == V4L2_SUBDEV_FORMAT_TRY)
++ return v4l2_subdev_get_try_crop(fh, RESZ_PAD_SINK);
++ else
++ return &res->crop.request;
++}
++
++/*
++ * resizer_set_filters - Set resizer filters
++ * @res: Device context.
++ * @h_coeff: horizontal coefficient
++ * @v_coeff: vertical coefficient
++ * Return none
++ */
++static void resizer_set_filters(struct isp_res_device *res, const u16 *h_coeff,
++ const u16 *v_coeff)
++{
++ struct isp_device *isp = to_isp_device(res);
++ u32 startaddr_h, startaddr_v, tmp_h, tmp_v;
++ int i;
++
++ startaddr_h = ISPRSZ_HFILT10;
++ startaddr_v = ISPRSZ_VFILT10;
++
++ for (i = 0; i < COEFF_CNT; i += 2) {
++ tmp_h = h_coeff[i] |
++ (h_coeff[i + 1] << ISPRSZ_HFILT_COEF1_SHIFT);
++ tmp_v = v_coeff[i] |
++ (v_coeff[i + 1] << ISPRSZ_VFILT_COEF1_SHIFT);
++ isp_reg_writel(isp, tmp_h, OMAP3_ISP_IOMEM_RESZ, startaddr_h);
++ isp_reg_writel(isp, tmp_v, OMAP3_ISP_IOMEM_RESZ, startaddr_v);
++ startaddr_h += 4;
++ startaddr_v += 4;
++ }
++}
++
++/*
++ * resizer_set_bilinear - Chrominance horizontal algorithm select
++ * @res: Device context.
++ * @type: Filtering interpolation type.
++ *
++ * Filtering that is same as luminance processing is
++ * intended only for downsampling, and bilinear interpolation
++ * is intended only for upsampling.
++ */
++static void resizer_set_bilinear(struct isp_res_device *res,
++ enum resizer_chroma_algo type)
++{
++ struct isp_device *isp = to_isp_device(res);
++
++ if (type == RSZ_BILINEAR)
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
++ ISPRSZ_CNT_CBILIN);
++ else
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
++ ISPRSZ_CNT_CBILIN);
++}
++
++/*
++ * resizer_set_ycpos - Luminance and chrominance order
++ * @res: Device context.
++ * @order: order type.
++ */
++static void resizer_set_ycpos(struct isp_res_device *res,
++ enum v4l2_mbus_pixelcode pixelcode)
++{
++ struct isp_device *isp = to_isp_device(res);
++
++ switch (pixelcode) {
++ case V4L2_MBUS_FMT_YUYV8_1X16:
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
++ ISPRSZ_CNT_YCPOS);
++ break;
++ case V4L2_MBUS_FMT_UYVY8_1X16:
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
++ ISPRSZ_CNT_YCPOS);
++ break;
++ default:
++ return;
++ }
++}
++
++/*
++ * resizer_set_phase - Setup horizontal and vertical starting phase
++ * @res: Device context.
++ * @h_phase: horizontal phase parameters.
++ * @v_phase: vertical phase parameters.
++ *
++ * Horizontal and vertical phase range is 0 to 7
++ */
++static void resizer_set_phase(struct isp_res_device *res, u32 h_phase,
++ u32 v_phase)
++{
++ struct isp_device *isp = to_isp_device(res);
++ u32 rgval = 0;
++
++ rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
++ ~(ISPRSZ_CNT_HSTPH_MASK | ISPRSZ_CNT_VSTPH_MASK);
++ rgval |= (h_phase << ISPRSZ_CNT_HSTPH_SHIFT) & ISPRSZ_CNT_HSTPH_MASK;
++ rgval |= (v_phase << ISPRSZ_CNT_VSTPH_SHIFT) & ISPRSZ_CNT_VSTPH_MASK;
++
++ isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT);
++}
++
++/*
++ * resizer_set_luma - Setup luminance enhancer parameters
++ * @res: Device context.
++ * @luma: Structure for luminance enhancer parameters.
++ *
++ * Algorithm select:
++ * 0x0: Disable
++ * 0x1: [-1 2 -1]/2 high-pass filter
++ * 0x2: [-1 -2 6 -2 -1]/4 high-pass filter
++ *
++ * Maximum gain:
++ * The data is coded in U4Q4 representation.
++ *
++ * Slope:
++ * The data is coded in U4Q4 representation.
++ *
++ * Coring offset:
++ * The data is coded in U8Q0 representation.
++ *
++ * The new luminance value is computed as:
++ * Y += HPF(Y) x max(GAIN, (HPF(Y) - CORE) x SLOP + 8) >> 4.
++ */
++static void resizer_set_luma(struct isp_res_device *res,
++ struct resizer_luma_yenh *luma)
++{
++ struct isp_device *isp = to_isp_device(res);
++ u32 rgval = 0;
++
++ rgval = (luma->algo << ISPRSZ_YENH_ALGO_SHIFT)
++ & ISPRSZ_YENH_ALGO_MASK;
++ rgval |= (luma->gain << ISPRSZ_YENH_GAIN_SHIFT)
++ & ISPRSZ_YENH_GAIN_MASK;
++ rgval |= (luma->slope << ISPRSZ_YENH_SLOP_SHIFT)
++ & ISPRSZ_YENH_SLOP_MASK;
++ rgval |= (luma->core << ISPRSZ_YENH_CORE_SHIFT)
++ & ISPRSZ_YENH_CORE_MASK;
++
++ isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH);
++}
++
++/*
++ * resizer_set_source - Input source select
++ * @res: Device context.
++ * @source: Input source type
++ *
++ * If this field is set to RESIZER_INPUT_VP, the resizer input is fed from
++ * Preview/CCDC engine, otherwise from memory.
++ */
++static void resizer_set_source(struct isp_res_device *res,
++ enum resizer_input_entity source)
++{
++ struct isp_device *isp = to_isp_device(res);
++
++ if (source == RESIZER_INPUT_MEMORY)
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
++ ISPRSZ_CNT_INPSRC);
++ else
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
++ ISPRSZ_CNT_INPSRC);
++}
++
++/*
++ * resizer_set_ratio - Setup horizontal and vertical resizing value
++ * @res: Device context.
++ * @ratio: Structure for ratio parameters.
++ *
++ * Resizing range from 64 to 1024
++ */
++static void resizer_set_ratio(struct isp_res_device *res,
++ const struct resizer_ratio *ratio)
++{
++ struct isp_device *isp = to_isp_device(res);
++ const u16 *h_filter, *v_filter;
++ u32 rgval = 0;
++
++ rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
++ ~(ISPRSZ_CNT_HRSZ_MASK | ISPRSZ_CNT_VRSZ_MASK);
++ rgval |= ((ratio->horz - 1) << ISPRSZ_CNT_HRSZ_SHIFT)
++ & ISPRSZ_CNT_HRSZ_MASK;
++ rgval |= ((ratio->vert - 1) << ISPRSZ_CNT_VRSZ_SHIFT)
++ & ISPRSZ_CNT_VRSZ_MASK;
++ isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT);
++
++ /* prepare horizontal filter coefficients */
++ if (ratio->horz > MID_RESIZE_VALUE)
++ h_filter = &filter_coefs.h_filter_coef_7tap[0];
++ else
++ h_filter = &filter_coefs.h_filter_coef_4tap[0];
++
++ /* prepare vertical filter coefficients */
++ if (ratio->vert > MID_RESIZE_VALUE)
++ v_filter = &filter_coefs.v_filter_coef_7tap[0];
++ else
++ v_filter = &filter_coefs.v_filter_coef_4tap[0];
++
++ resizer_set_filters(res, h_filter, v_filter);
++}
++
++/*
++ * resizer_set_dst_size - Setup the output height and width
++ * @res: Device context.
++ * @width: Output width.
++ * @height: Output height.
++ *
++ * Width :
++ * The value must be EVEN.
++ *
++ * Height:
++ * The number of bytes written to SDRAM must be
++ * a multiple of 16-bytes if the vertical resizing factor
++ * is greater than 1x (upsizing)
++ */
++static void resizer_set_output_size(struct isp_res_device *res,
++ u32 width, u32 height)
++{
++ struct isp_device *isp = to_isp_device(res);
++ u32 rgval = 0;
++
++ dev_dbg(isp->dev, "Output size[w/h]: %dx%d\n", width, height);
++ rgval = (width << ISPRSZ_OUT_SIZE_HORZ_SHIFT)
++ & ISPRSZ_OUT_SIZE_HORZ_MASK;
++ rgval |= (height << ISPRSZ_OUT_SIZE_VERT_SHIFT)
++ & ISPRSZ_OUT_SIZE_VERT_MASK;
++ isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_OUT_SIZE);
++}
++
++/*
++ * resizer_set_output_offset - Setup memory offset for the output lines.
++ * @res: Device context.
++ * @offset: Memory offset.
++ *
++ * The 5 LSBs are forced to be zeros by the hardware to align on a 32-byte
++ * boundary; the 5 LSBs are read-only. For optimal use of SDRAM bandwidth,
++ * the SDRAM line offset must be set on a 256-byte boundary
++ */
++static void resizer_set_output_offset(struct isp_res_device *res, u32 offset)
++{
++ struct isp_device *isp = to_isp_device(res);
++
++ isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF);
++}
++
++/*
++ * resizer_set_start - Setup vertical and horizontal start position
++ * @res: Device context.
++ * @left: Horizontal start position.
++ * @top: Vertical start position.
++ *
++ * Vertical start line:
++ * This field makes sense only when the resizer obtains its input
++ * from the preview engine/CCDC
++ *
++ * Horizontal start pixel:
++ * Pixels are coded on 16 bits for YUV and 8 bits for color separate data.
++ * When the resizer gets its input from SDRAM, this field must be set
++ * to <= 15 for YUV 16-bit data and <= 31 for 8-bit color separate data
++ */
++static void resizer_set_start(struct isp_res_device *res, u32 left, u32 top)
++{
++ struct isp_device *isp = to_isp_device(res);
++ u32 rgval = 0;
++
++ rgval = (left << ISPRSZ_IN_START_HORZ_ST_SHIFT)
++ & ISPRSZ_IN_START_HORZ_ST_MASK;
++ rgval |= (top << ISPRSZ_IN_START_VERT_ST_SHIFT)
++ & ISPRSZ_IN_START_VERT_ST_MASK;
++
++ isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START);
++}
++
++/*
++ * resizer_set_input_size - Setup the input size
++ * @res: Device context.
++ * @width: The range is 0 to 4095 pixels
++ * @height: The range is 0 to 4095 lines
++ */
++static void resizer_set_input_size(struct isp_res_device *res,
++ u32 width, u32 height)
++{
++ struct isp_device *isp = to_isp_device(res);
++ u32 rgval = 0;
++
++ dev_dbg(isp->dev, "Input size[w/h]: %dx%d\n", width, height);
++
++ rgval = (width << ISPRSZ_IN_SIZE_HORZ_SHIFT)
++ & ISPRSZ_IN_SIZE_HORZ_MASK;
++ rgval |= (height << ISPRSZ_IN_SIZE_VERT_SHIFT)
++ & ISPRSZ_IN_SIZE_VERT_MASK;
++
++ isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_SIZE);
++}
++
++/*
++ * resizer_set_src_offs - Setup the memory offset for the input lines
++ * @res: Device context.
++ * @offset: Memory offset.
++ *
++ * The 5 LSBs are forced to be zeros by the hardware to align on a 32-byte
++ * boundary; the 5 LSBs are read-only. This field must be programmed to be
++ * 0x0 if the resizer input is from preview engine/CCDC.
++ */
++static void resizer_set_input_offset(struct isp_res_device *res, u32 offset)
++{
++ struct isp_device *isp = to_isp_device(res);
++
++ isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF);
++}
++
++/*
++ * resizer_set_intype - Input type select
++ * @res: Device context.
++ * @type: Pixel format type.
++ */
++static void resizer_set_intype(struct isp_res_device *res,
++ enum resizer_colors_type type)
++{
++ struct isp_device *isp = to_isp_device(res);
++
++ if (type == RSZ_COLOR8)
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
++ ISPRSZ_CNT_INPTYP);
++ else
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
++ ISPRSZ_CNT_INPTYP);
++}
++
++/*
++ * __resizer_set_inaddr - Helper function for set input address
++ * @res : pointer to resizer private data structure
++ * @addr: input address
++ * return none
++ */
++static void __resizer_set_inaddr(struct isp_res_device *res, u32 addr)
++{
++ struct isp_device *isp = to_isp_device(res);
++
++ isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD);
++}
++
++/*
++ * The data rate at the horizontal resizer output must not exceed half the
++ * functional clock or 100 MP/s, whichever is lower. According to the TRM
++ * there's no similar requirement for the vertical resizer output. However
++ * experience showed that vertical upscaling by 4 leads to SBL overflows (with
++ * data rates at the resizer output exceeding 300 MP/s). Limiting the resizer
++ * output data rate to the functional clock or 200 MP/s, whichever is lower,
++ * seems to get rid of SBL overflows.
++ *
++ * The maximum data rate at the output of the horizontal resizer can thus be
++ * computed with
++ *
++ * max intermediate rate <= L3 clock * input height / output height
++ * max intermediate rate <= L3 clock / 2
++ *
++ * The maximum data rate at the resizer input is then
++ *
++ * max input rate <= max intermediate rate * input width / output width
++ *
++ * where the input width and height are the resizer input crop rectangle size.
++ * The TRM doesn't clearly explain if that's a maximum instant data rate or a
++ * maximum average data rate.
++ */
++void omap3isp_resizer_max_rate(struct isp_res_device *res,
++ unsigned int *max_rate)
++{
++ struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
++ const struct v4l2_mbus_framefmt *ofmt = &res->formats[RESZ_PAD_SOURCE];
++ unsigned long limit = min(pipe->l3_ick, 200000000UL);
++ unsigned long clock;
++
++ clock = div_u64((u64)limit * res->crop.active.height, ofmt->height);
++ clock = min(clock, limit / 2);
++ *max_rate = div_u64((u64)clock * res->crop.active.width, ofmt->width);
++}
++
++/*
++ * When the resizer processes images from memory, the driver must slow down read
++ * requests on the input to at least comply with the internal data rate
++ * requirements. If the application real-time requirements can cope with slower
++ * processing, the resizer can be slowed down even more to put less pressure on
++ * the overall system.
++ *
++ * When the resizer processes images on the fly (either from the CCDC or the
++ * preview module), the same data rate requirements apply but they can't be
++ * enforced at the resizer level. The image input module (sensor, CCP2 or
++ * preview module) must not provide image data faster than the resizer can
++ * process.
++ *
++ * For live image pipelines, the data rate is set by the frame format, size and
++ * rate. The sensor output frame rate must not exceed the maximum resizer data
++ * rate.
++ *
++ * The resizer slows down read requests by inserting wait cycles in the SBL
++ * requests. The maximum number of 256-byte requests per second can be computed
++ * as (the data rate is multiplied by 2 to convert from pixels per second to
++ * bytes per second)
++ *
++ * request per second = data rate * 2 / 256
++ * cycles per request = cycles per second / requests per second
++ *
++ * The number of cycles per second is controlled by the L3 clock, leading to
++ *
++ * cycles per request = L3 frequency / 2 * 256 / data rate
++ */
++static void resizer_adjust_bandwidth(struct isp_res_device *res)
++{
++ struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
++ struct isp_device *isp = to_isp_device(res);
++ unsigned long l3_ick = pipe->l3_ick;
++ struct v4l2_fract *timeperframe;
++ unsigned int cycles_per_frame;
++ unsigned int requests_per_frame;
++ unsigned int cycles_per_request;
++ unsigned int granularity;
++ unsigned int minimum;
++ unsigned int maximum;
++ unsigned int value;
++
++ if (res->input != RESIZER_INPUT_MEMORY) {
++ isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
++ ISPSBL_SDR_REQ_RSZ_EXP_MASK);
++ return;
++ }
++
++ switch (isp->revision) {
++ case ISP_REVISION_1_0:
++ case ISP_REVISION_2_0:
++ default:
++ granularity = 1024;
++ break;
++
++ case ISP_REVISION_15_0:
++ granularity = 32;
++ break;
++ }
++
++ /* Compute the minimum number of cycles per request, based on the
++ * pipeline maximum data rate. This is an absolute lower bound if we
++ * don't want SBL overflows, so round the value up.
++ */
++ cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1,
++ pipe->max_rate);
++ minimum = DIV_ROUND_UP(cycles_per_request, granularity);
++
++ /* Compute the maximum number of cycles per request, based on the
++ * requested frame rate. This is a soft upper bound to achieve a frame
++ * rate equal or higher than the requested value, so round the value
++ * down.
++ */
++ timeperframe = &pipe->max_timeperframe;
++
++ requests_per_frame = DIV_ROUND_UP(res->crop.active.width * 2, 256)
++ * res->crop.active.height;
++ cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator,
++ timeperframe->denominator);
++ cycles_per_request = cycles_per_frame / requests_per_frame;
++
++ maximum = cycles_per_request / granularity;
++
++ value = max(minimum, maximum);
++
++ dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value);
++ isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
++ ISPSBL_SDR_REQ_RSZ_EXP_MASK,
++ value << ISPSBL_SDR_REQ_RSZ_EXP_SHIFT);
++}
++
++/*
++ * omap3isp_resizer_busy - Checks if ISP resizer is busy.
++ *
++ * Returns busy field from ISPRSZ_PCR register.
++ */
++int omap3isp_resizer_busy(struct isp_res_device *res)
++{
++ struct isp_device *isp = to_isp_device(res);
++
++ return isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) &
++ ISPRSZ_PCR_BUSY;
++}
++
++/*
++ * resizer_set_inaddr - Sets the memory address of the input frame.
++ * @addr: 32bit memory address aligned on 32byte boundary.
++ */
++static void resizer_set_inaddr(struct isp_res_device *res, u32 addr)
++{
++ res->addr_base = addr;
++
++ /* This will handle crop settings in stream off state */
++ if (res->crop_offset)
++ addr += res->crop_offset & ~0x1f;
++
++ __resizer_set_inaddr(res, addr);
++}
++
++/*
++ * Configures the memory address to which the output frame is written.
++ * @addr: 32bit memory address aligned on 32byte boundary.
++ * Note: For SBL efficiency reasons the address should be on a 256-byte
++ * boundary.
++ */
++static void resizer_set_outaddr(struct isp_res_device *res, u32 addr)
++{
++ struct isp_device *isp = to_isp_device(res);
++
++ /*
++ * Set output address. This needs to be in its own function
++ * because it changes often.
++ */
++ isp_reg_writel(isp, addr << ISPRSZ_SDR_OUTADD_ADDR_SHIFT,
++ OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD);
++}
++
++/*
++ * resizer_print_status - Prints the values of the resizer module registers.
++ */
++#define RSZ_PRINT_REGISTER(isp, name)\
++ dev_dbg(isp->dev, "###RSZ " #name "=0x%08x\n", \
++ isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_##name))
++
++static void resizer_print_status(struct isp_res_device *res)
++{
++ struct isp_device *isp = to_isp_device(res);
++
++ dev_dbg(isp->dev, "-------------Resizer Register dump----------\n");
++
++ RSZ_PRINT_REGISTER(isp, PCR);
++ RSZ_PRINT_REGISTER(isp, CNT);
++ RSZ_PRINT_REGISTER(isp, OUT_SIZE);
++ RSZ_PRINT_REGISTER(isp, IN_START);
++ RSZ_PRINT_REGISTER(isp, IN_SIZE);
++ RSZ_PRINT_REGISTER(isp, SDR_INADD);
++ RSZ_PRINT_REGISTER(isp, SDR_INOFF);
++ RSZ_PRINT_REGISTER(isp, SDR_OUTADD);
++ RSZ_PRINT_REGISTER(isp, SDR_OUTOFF);
++ RSZ_PRINT_REGISTER(isp, YENH);
++
++ dev_dbg(isp->dev, "--------------------------------------------\n");
++}
++
++/*
++ * resizer_calc_ratios - Helper function for calculate resizer ratios
++ * @res: pointer to resizer private data structure
++ * @input: input frame size
++ * @output: output frame size
++ * @ratio : return calculated ratios
++ * return none
++ *
++ * The resizer uses a polyphase sample rate converter. The upsampling filter
++ * has a fixed number of phases that depend on the resizing ratio. As the ratio
++ * computation depends on the number of phases, we need to compute a first
++ * approximation and then refine it.
++ *
++ * The input/output/ratio relationship is given by the OMAP34xx TRM:
++ *
++ * - 8-phase, 4-tap mode (RSZ = 64 ~ 512)
++ * iw = (32 * sph + (ow - 1) * hrsz + 16) >> 8 + 7
++ * ih = (32 * spv + (oh - 1) * vrsz + 16) >> 8 + 4
++ * - 4-phase, 7-tap mode (RSZ = 513 ~ 1024)
++ * iw = (64 * sph + (ow - 1) * hrsz + 32) >> 8 + 7
++ * ih = (64 * spv + (oh - 1) * vrsz + 32) >> 8 + 7
++ *
++ * iw and ih are the input width and height after cropping. Those equations need
++ * to be satisfied exactly for the resizer to work correctly.
++ *
++ * Reverting the equations, we can compute the resizing ratios with
++ *
++ * - 8-phase, 4-tap mode
++ * hrsz = ((iw - 7) * 256 - 16 - 32 * sph) / (ow - 1)
++ * vrsz = ((ih - 4) * 256 - 16 - 32 * spv) / (oh - 1)
++ * - 4-phase, 7-tap mode
++ * hrsz = ((iw - 7) * 256 - 32 - 64 * sph) / (ow - 1)
++ * vrsz = ((ih - 7) * 256 - 32 - 64 * spv) / (oh - 1)
++ *
++ * The ratios are integer values, and must be rounded down to ensure that the
++ * cropped input size is not bigger than the uncropped input size. As the ratio
++ * in 7-tap mode is always smaller than the ratio in 4-tap mode, we can use the
++ * 7-tap mode equations to compute a ratio approximation.
++ *
++ * We first clamp the output size according to the hardware capabilitie to avoid
++ * auto-cropping the input more than required to satisfy the TRM equations. The
++ * minimum output size is achieved with a scaling factor of 1024. It is thus
++ * computed using the 7-tap equations.
++ *
++ * min ow = ((iw - 7) * 256 - 32 - 64 * sph) / 1024 + 1
++ * min oh = ((ih - 7) * 256 - 32 - 64 * spv) / 1024 + 1
++ *
++ * Similarly, the maximum output size is achieved with a scaling factor of 64
++ * and computed using the 4-tap equations.
++ *
++ * max ow = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / 64 + 1
++ * max oh = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1
++ *
++ * The additional +255 term compensates for the round down operation performed
++ * by the TRM equations when shifting the value right by 8 bits.
++ *
++ * We then compute and clamp the ratios (x1/4 ~ x4). Clamping the output size to
++ * the maximum value guarantees that the ratio value will never be smaller than
++ * the minimum, but it could still slightly exceed the maximum. Clamping the
++ * ratio will thus result in a resizing factor slightly larger than the
++ * requested value.
++ *
++ * To accomodate that, and make sure the TRM equations are satisfied exactly, we
++ * compute the input crop rectangle as the last step.
++ *
++ * As if the situation wasn't complex enough, the maximum output width depends
++ * on the vertical resizing ratio. Fortunately, the output height doesn't
++ * depend on the horizontal resizing ratio. We can then start by computing the
++ * output height and the vertical ratio, and then move to computing the output
++ * width and the horizontal ratio.
++ */
++static void resizer_calc_ratios(struct isp_res_device *res,
++ struct v4l2_rect *input,
++ struct v4l2_mbus_framefmt *output,
++ struct resizer_ratio *ratio)
++{
++ struct isp_device *isp = to_isp_device(res);
++ const unsigned int spv = DEFAULT_PHASE;
++ const unsigned int sph = DEFAULT_PHASE;
++ unsigned int upscaled_width;
++ unsigned int upscaled_height;
++ unsigned int min_width;
++ unsigned int min_height;
++ unsigned int max_width;
++ unsigned int max_height;
++ unsigned int width_alignment;
++
++ /*
++ * Clamp the output height based on the hardware capabilities and
++ * compute the vertical resizing ratio.
++ */
++ min_height = ((input->height - 7) * 256 - 32 - 64 * spv) / 1024 + 1;
++ min_height = max_t(unsigned int, min_height, MIN_OUT_HEIGHT);
++ max_height = ((input->height - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1;
++ max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT);
++ output->height = clamp(output->height, min_height, max_height);
++
++ ratio->vert = ((input->height - 7) * 256 - 32 - 64 * spv)
++ / (output->height - 1);
++ ratio->vert = clamp_t(unsigned int, ratio->vert,
++ MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
++
++ if (ratio->vert <= MID_RESIZE_VALUE) {
++ upscaled_height = (output->height - 1) * ratio->vert
++ + 32 * spv + 16;
++ input->height = (upscaled_height >> 8) + 4;
++ } else {
++ upscaled_height = (output->height - 1) * ratio->vert
++ + 64 * spv + 32;
++ input->height = (upscaled_height >> 8) + 7;
++ }
++
++ /*
++ * Compute the minimum and maximum output widths based on the hardware
++ * capabilities. The maximum depends on the vertical resizing ratio.
++ */
++ min_width = ((input->width - 7) * 256 - 32 - 64 * sph) / 1024 + 1;
++ min_width = max_t(unsigned int, min_width, MIN_OUT_WIDTH);
++
++ if (ratio->vert <= MID_RESIZE_VALUE) {
++ switch (isp->revision) {
++ case ISP_REVISION_1_0:
++ max_width = MAX_4TAP_OUT_WIDTH_ES1;
++ break;
++
++ case ISP_REVISION_2_0:
++ default:
++ max_width = MAX_4TAP_OUT_WIDTH_ES2;
++ break;
++
++ case ISP_REVISION_15_0:
++ max_width = MAX_4TAP_OUT_WIDTH_3630;
++ break;
++ }
++ } else {
++ switch (isp->revision) {
++ case ISP_REVISION_1_0:
++ max_width = MAX_7TAP_OUT_WIDTH_ES1;
++ break;
++
++ case ISP_REVISION_2_0:
++ default:
++ max_width = MAX_7TAP_OUT_WIDTH_ES2;
++ break;
++
++ case ISP_REVISION_15_0:
++ max_width = MAX_7TAP_OUT_WIDTH_3630;
++ break;
++ }
++ }
++ max_width = min(((input->width - 7) * 256 + 255 - 16 - 32 * sph) / 64
++ + 1, max_width);
++
++ /*
++ * The output width must be even, and must be a multiple of 16 bytes
++ * when upscaling vertically. Clamp the output width to the valid range.
++ * Take the alignment into account (the maximum width in 7-tap mode on
++ * ES2 isn't a multiple of 8) and align the result up to make sure it
++ * won't be smaller than the minimum.
++ */
++ width_alignment = ratio->vert < 256 ? 8 : 2;
++ output->width = clamp(output->width, min_width,
++ max_width & ~(width_alignment - 1));
++ output->width = ALIGN(output->width, width_alignment);
++
++ ratio->horz = ((input->width - 7) * 256 - 32 - 64 * sph)
++ / (output->width - 1);
++ ratio->horz = clamp_t(unsigned int, ratio->horz,
++ MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
++
++ if (ratio->horz <= MID_RESIZE_VALUE) {
++ upscaled_width = (output->width - 1) * ratio->horz
++ + 32 * sph + 16;
++ input->width = (upscaled_width >> 8) + 7;
++ } else {
++ upscaled_width = (output->width - 1) * ratio->horz
++ + 64 * sph + 32;
++ input->width = (upscaled_width >> 8) + 7;
++ }
++}
++
++/*
++ * resizer_set_crop_params - Setup hardware with cropping parameters
++ * @res : resizer private structure
++ * @crop_rect : current crop rectangle
++ * @ratio : resizer ratios
++ * return none
++ */
++static void resizer_set_crop_params(struct isp_res_device *res,
++ const struct v4l2_mbus_framefmt *input,
++ const struct v4l2_mbus_framefmt *output)
++{
++ resizer_set_ratio(res, &res->ratio);
++
++ /* Set chrominance horizontal algorithm */
++ if (res->ratio.horz >= RESIZE_DIVISOR)
++ resizer_set_bilinear(res, RSZ_THE_SAME);
++ else
++ resizer_set_bilinear(res, RSZ_BILINEAR);
++
++ resizer_adjust_bandwidth(res);
++
++ if (res->input == RESIZER_INPUT_MEMORY) {
++ /* Calculate additional offset for crop */
++ res->crop_offset = (res->crop.active.top * input->width +
++ res->crop.active.left) * 2;
++ /*
++ * Write lowest 4 bits of horizontal pixel offset (in pixels),
++ * vertical start must be 0.
++ */
++ resizer_set_start(res, (res->crop_offset / 2) & 0xf, 0);
++
++ /*
++ * Set start (read) address for cropping, in bytes.
++ * Lowest 5 bits must be zero.
++ */
++ __resizer_set_inaddr(res,
++ res->addr_base + (res->crop_offset & ~0x1f));
++ } else {
++ /*
++ * Set vertical start line and horizontal starting pixel.
++ * If the input is from CCDC/PREV, horizontal start field is
++ * in bytes (twice number of pixels).
++ */
++ resizer_set_start(res, res->crop.active.left * 2,
++ res->crop.active.top);
++ /* Input address and offset must be 0 for preview/ccdc input */
++ __resizer_set_inaddr(res, 0);
++ resizer_set_input_offset(res, 0);
++ }
++
++ /* Set the input size */
++ resizer_set_input_size(res, res->crop.active.width,
++ res->crop.active.height);
++}
++
++static void resizer_configure(struct isp_res_device *res)
++{
++ struct v4l2_mbus_framefmt *informat, *outformat;
++ struct resizer_luma_yenh luma = {0, 0, 0, 0};
++
++ resizer_set_source(res, res->input);
++
++ informat = &res->formats[RESZ_PAD_SINK];
++ outformat = &res->formats[RESZ_PAD_SOURCE];
++
++ /* RESZ_PAD_SINK */
++ if (res->input == RESIZER_INPUT_VP)
++ resizer_set_input_offset(res, 0);
++ else
++ resizer_set_input_offset(res, ALIGN(informat->width, 0x10) * 2);
++
++ /* YUV422 interleaved, default phase, no luma enhancement */
++ resizer_set_intype(res, RSZ_YUV422);
++ resizer_set_ycpos(res, informat->code);
++ resizer_set_phase(res, DEFAULT_PHASE, DEFAULT_PHASE);
++ resizer_set_luma(res, &luma);
++
++ /* RESZ_PAD_SOURCE */
++ resizer_set_output_offset(res, ALIGN(outformat->width * 2, 32));
++ resizer_set_output_size(res, outformat->width, outformat->height);
++
++ resizer_set_crop_params(res, informat, outformat);
++}
++
++/* -----------------------------------------------------------------------------
++ * Interrupt handling
++ */
++
++static void resizer_enable_oneshot(struct isp_res_device *res)
++{
++ struct isp_device *isp = to_isp_device(res);
++
++ isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR,
++ ISPRSZ_PCR_ENABLE | ISPRSZ_PCR_ONESHOT);
++}
++
++void omap3isp_resizer_isr_frame_sync(struct isp_res_device *res)
++{
++ /*
++ * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun
++ * condition, the module was paused and now we have a buffer queued
++ * on the output again. Restart the pipeline if running in continuous
++ * mode.
++ */
++ if (res->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
++ res->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
++ resizer_enable_oneshot(res);
++ isp_video_dmaqueue_flags_clr(&res->video_out);
++ }
++}
++
++static void resizer_isr_buffer(struct isp_res_device *res)
++{
++ struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
++ struct isp_buffer *buffer;
++ int restart = 0;
++
++ if (res->state == ISP_PIPELINE_STREAM_STOPPED)
++ return;
++
++ /* Complete the output buffer and, if reading from memory, the input
++ * buffer.
++ */
++ buffer = omap3isp_video_buffer_next(&res->video_out, res->error);
++ if (buffer != NULL) {
++ resizer_set_outaddr(res, buffer->isp_addr);
++ restart = 1;
++ }
++
++ pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
++
++ if (res->input == RESIZER_INPUT_MEMORY) {
++ buffer = omap3isp_video_buffer_next(&res->video_in, 0);
++ if (buffer != NULL)
++ resizer_set_inaddr(res, buffer->isp_addr);
++ pipe->state |= ISP_PIPELINE_IDLE_INPUT;
++ }
++
++ if (res->state == ISP_PIPELINE_STREAM_SINGLESHOT) {
++ if (isp_pipeline_ready(pipe))
++ omap3isp_pipeline_set_stream(pipe,
++ ISP_PIPELINE_STREAM_SINGLESHOT);
++ } else {
++ /* If an underrun occurs, the video queue operation handler will
++ * restart the resizer. Otherwise restart it immediately.
++ */
++ if (restart)
++ resizer_enable_oneshot(res);
++ }
++
++ res->error = 0;
++}
++
++/*
++ * omap3isp_resizer_isr - ISP resizer interrupt handler
++ *
++ * Manage the resizer video buffers and configure shadowed and busy-locked
++ * registers.
++ */
++void omap3isp_resizer_isr(struct isp_res_device *res)
++{
++ struct v4l2_mbus_framefmt *informat, *outformat;
++
++ if (omap3isp_module_sync_is_stopping(&res->wait, &res->stopping))
++ return;
++
++ if (res->applycrop) {
++ outformat = __resizer_get_format(res, NULL, RESZ_PAD_SOURCE,
++ V4L2_SUBDEV_FORMAT_ACTIVE);
++ informat = __resizer_get_format(res, NULL, RESZ_PAD_SINK,
++ V4L2_SUBDEV_FORMAT_ACTIVE);
++ resizer_set_crop_params(res, informat, outformat);
++ res->applycrop = 0;
++ }
++
++ resizer_isr_buffer(res);
++}
++
++/* -----------------------------------------------------------------------------
++ * ISP video operations
++ */
++
++static int resizer_video_queue(struct isp_video *video,
++ struct isp_buffer *buffer)
++{
++ struct isp_res_device *res = &video->isp->isp_res;
++
++ if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
++ resizer_set_inaddr(res, buffer->isp_addr);
++
++ /*
++ * We now have a buffer queued on the output. Despite what the
++ * TRM says, the resizer can't be restarted immediately.
++ * Enabling it in one shot mode in the middle of a frame (or at
++ * least asynchronously to the frame) results in the output
++ * being shifted randomly left/right and up/down, as if the
++ * hardware didn't synchronize itself to the beginning of the
++ * frame correctly.
++ *
++ * Restart the resizer on the next sync interrupt if running in
++ * continuous mode or when starting the stream.
++ */
++ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ resizer_set_outaddr(res, buffer->isp_addr);
++
++ return 0;
++}
++
++static const struct isp_video_operations resizer_video_ops = {
++ .queue = resizer_video_queue,
++};
++
++/* -----------------------------------------------------------------------------
++ * V4L2 subdev operations
++ */
++
++/*
++ * resizer_set_stream - Enable/Disable streaming on resizer subdev
++ * @sd: ISP resizer V4L2 subdev
++ * @enable: 1 == Enable, 0 == Disable
++ *
++ * The resizer hardware can't be enabled without a memory buffer to write to.
++ * As the s_stream operation is called in response to a STREAMON call without
++ * any buffer queued yet, just update the state field and return immediately.
++ * The resizer will be enabled in resizer_video_queue().
++ */
++static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
++{
++ struct isp_res_device *res = v4l2_get_subdevdata(sd);
++ struct isp_video *video_out = &res->video_out;
++ struct isp_device *isp = to_isp_device(res);
++ struct device *dev = to_device(res);
++
++ if (res->state == ISP_PIPELINE_STREAM_STOPPED) {
++ if (enable == ISP_PIPELINE_STREAM_STOPPED)
++ return 0;
++
++ omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_RESIZER);
++ resizer_configure(res);
++ res->error = 0;
++ resizer_print_status(res);
++ }
++
++ switch (enable) {
++ case ISP_PIPELINE_STREAM_CONTINUOUS:
++ omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
++ if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
++ resizer_enable_oneshot(res);
++ isp_video_dmaqueue_flags_clr(video_out);
++ }
++ break;
++
++ case ISP_PIPELINE_STREAM_SINGLESHOT:
++ if (res->input == RESIZER_INPUT_MEMORY)
++ omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_READ);
++ omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
++
++ resizer_enable_oneshot(res);
++ break;
++
++ case ISP_PIPELINE_STREAM_STOPPED:
++ if (omap3isp_module_sync_idle(&sd->entity, &res->wait,
++ &res->stopping))
++ dev_dbg(dev, "%s: module stop timeout.\n", sd->name);
++ omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_RESIZER_READ |
++ OMAP3_ISP_SBL_RESIZER_WRITE);
++ omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_RESIZER);
++ isp_video_dmaqueue_flags_clr(video_out);
++ break;
++ }
++
++ res->state = enable;
++ return 0;
++}
++
++/*
++ * resizer_g_crop - handle get crop subdev operation
++ * @sd : pointer to v4l2 subdev structure
++ * @pad : subdev pad
++ * @crop : pointer to crop structure
++ * @which : active or try format
++ * return zero
++ */
++static int resizer_g_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_crop *crop)
++{
++ struct isp_res_device *res = v4l2_get_subdevdata(sd);
++ struct v4l2_mbus_framefmt *format;
++ struct resizer_ratio ratio;
++
++ /* Only sink pad has crop capability */
++ if (crop->pad != RESZ_PAD_SINK)
++ return -EINVAL;
++
++ format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, crop->which);
++ crop->rect = *__resizer_get_crop(res, fh, crop->which);
++ resizer_calc_ratios(res, &crop->rect, format, &ratio);
++
++ return 0;
++}
++
++/*
++ * resizer_try_crop - mangles crop parameters.
++ */
++static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
++ const struct v4l2_mbus_framefmt *source,
++ struct v4l2_rect *crop)
++{
++ const unsigned int spv = DEFAULT_PHASE;
++ const unsigned int sph = DEFAULT_PHASE;
++
++ /* Crop rectangle is constrained to the output size so that zoom ratio
++ * cannot exceed +/-4.0.
++ */
++ unsigned int min_width =
++ ((32 * sph + (source->width - 1) * 64 + 16) >> 8) + 7;
++ unsigned int min_height =
++ ((32 * spv + (source->height - 1) * 64 + 16) >> 8) + 4;
++ unsigned int max_width =
++ ((64 * sph + (source->width - 1) * 1024 + 32) >> 8) + 7;
++ unsigned int max_height =
++ ((64 * spv + (source->height - 1) * 1024 + 32) >> 8) + 7;
++
++ crop->width = clamp_t(u32, crop->width, min_width, max_width);
++ crop->height = clamp_t(u32, crop->height, min_height, max_height);
++
++ /* Crop can not go beyond of the input rectangle */
++ crop->left = clamp_t(u32, crop->left, 0, sink->width - MIN_IN_WIDTH);
++ crop->width = clamp_t(u32, crop->width, MIN_IN_WIDTH,
++ sink->width - crop->left);
++ crop->top = clamp_t(u32, crop->top, 0, sink->height - MIN_IN_HEIGHT);
++ crop->height = clamp_t(u32, crop->height, MIN_IN_HEIGHT,
++ sink->height - crop->top);
++}
++
++/*
++ * resizer_s_crop - handle set crop subdev operation
++ * @sd : pointer to v4l2 subdev structure
++ * @pad : subdev pad
++ * @crop : pointer to crop structure
++ * @which : active or try format
++ * return -EINVAL or zero when succeed
++ */
++static int resizer_s_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_crop *crop)
++{
++ struct isp_res_device *res = v4l2_get_subdevdata(sd);
++ struct isp_device *isp = to_isp_device(res);
++ struct v4l2_mbus_framefmt *format_sink, *format_source;
++ struct resizer_ratio ratio;
++
++ /* Only sink pad has crop capability */
++ if (crop->pad != RESZ_PAD_SINK)
++ return -EINVAL;
++
++ format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
++ crop->which);
++ format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
++ crop->which);
++
++ dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__,
++ crop->rect.left, crop->rect.top, crop->rect.width,
++ crop->rect.height, crop->which);
++
++ dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__,
++ format_sink->width, format_sink->height,
++ format_source->width, format_source->height);
++
++ resizer_try_crop(format_sink, format_source, &crop->rect);
++ *__resizer_get_crop(res, fh, crop->which) = crop->rect;
++ resizer_calc_ratios(res, &crop->rect, format_source, &ratio);
++
++ if (crop->which == V4L2_SUBDEV_FORMAT_TRY)
++ return 0;
++
++ res->ratio = ratio;
++ res->crop.active = crop->rect;
++
++ /*
++ * s_crop can be called while streaming is on. In this case
++ * the crop values will be set in the next IRQ.
++ */
++ if (res->state != ISP_PIPELINE_STREAM_STOPPED)
++ res->applycrop = 1;
++
++ return 0;
++}
++
++/* resizer pixel formats */
++static const unsigned int resizer_formats[] = {
++ V4L2_MBUS_FMT_UYVY8_1X16,
++ V4L2_MBUS_FMT_YUYV8_1X16,
++};
++
++static unsigned int resizer_max_in_width(struct isp_res_device *res)
++{
++ struct isp_device *isp = to_isp_device(res);
++
++ if (res->input == RESIZER_INPUT_MEMORY) {
++ return MAX_IN_WIDTH_MEMORY_MODE;
++ } else {
++ if (isp->revision == ISP_REVISION_1_0)
++ return MAX_IN_WIDTH_ONTHEFLY_MODE_ES1;
++ else
++ return MAX_IN_WIDTH_ONTHEFLY_MODE_ES2;
++ }
++}
++
++/*
++ * resizer_try_format - Handle try format by pad subdev method
++ * @res : ISP resizer device
++ * @fh : V4L2 subdev file handle
++ * @pad : pad num
++ * @fmt : pointer to v4l2 format structure
++ * @which : wanted subdev format
++ */
++static void resizer_try_format(struct isp_res_device *res,
++ struct v4l2_subdev_fh *fh, unsigned int pad,
++ struct v4l2_mbus_framefmt *fmt,
++ enum v4l2_subdev_format_whence which)
++{
++ struct v4l2_mbus_framefmt *format;
++ struct resizer_ratio ratio;
++ struct v4l2_rect crop;
++
++ switch (pad) {
++ case RESZ_PAD_SINK:
++ if (fmt->code != V4L2_MBUS_FMT_YUYV8_1X16 &&
++ fmt->code != V4L2_MBUS_FMT_UYVY8_1X16)
++ fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
++
++ fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
++ resizer_max_in_width(res));
++ fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
++ MAX_IN_HEIGHT);
++ break;
++
++ case RESZ_PAD_SOURCE:
++ format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which);
++ fmt->code = format->code;
++
++ crop = *__resizer_get_crop(res, fh, which);
++ resizer_calc_ratios(res, &crop, fmt, &ratio);
++ break;
++ }
++
++ fmt->colorspace = V4L2_COLORSPACE_JPEG;
++ fmt->field = V4L2_FIELD_NONE;
++}
++
++/*
++ * resizer_enum_mbus_code - Handle pixel format enumeration
++ * @sd : pointer to v4l2 subdev structure
++ * @fh : V4L2 subdev file handle
++ * @code : pointer to v4l2_subdev_mbus_code_enum structure
++ * return -EINVAL or zero on success
++ */
++static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
++ struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_mbus_code_enum *code)
++{
++ struct isp_res_device *res = v4l2_get_subdevdata(sd);
++ struct v4l2_mbus_framefmt *format;
++
++ if (code->pad == RESZ_PAD_SINK) {
++ if (code->index >= ARRAY_SIZE(resizer_formats))
++ return -EINVAL;
++
++ code->code = resizer_formats[code->index];
++ } else {
++ if (code->index != 0)
++ return -EINVAL;
++
++ format = __resizer_get_format(res, fh, RESZ_PAD_SINK,
++ V4L2_SUBDEV_FORMAT_TRY);
++ code->code = format->code;
++ }
++
++ return 0;
++}
++
++static int resizer_enum_frame_size(struct v4l2_subdev *sd,
++ struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_frame_size_enum *fse)
++{
++ struct isp_res_device *res = v4l2_get_subdevdata(sd);
++ struct v4l2_mbus_framefmt format;
++
++ if (fse->index != 0)
++ return -EINVAL;
++
++ format.code = fse->code;
++ format.width = 1;
++ format.height = 1;
++ resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
++ fse->min_width = format.width;
++ fse->min_height = format.height;
++
++ if (format.code != fse->code)
++ return -EINVAL;
++
++ format.code = fse->code;
++ format.width = -1;
++ format.height = -1;
++ resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
++ fse->max_width = format.width;
++ fse->max_height = format.height;
++
++ return 0;
++}
++
++/*
++ * resizer_get_format - Handle get format by pads subdev method
++ * @sd : pointer to v4l2 subdev structure
++ * @fh : V4L2 subdev file handle
++ * @fmt : pointer to v4l2 subdev format structure
++ * return -EINVAL or zero on sucess
++ */
++static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_format *fmt)
++{
++ struct isp_res_device *res = v4l2_get_subdevdata(sd);
++ struct v4l2_mbus_framefmt *format;
++
++ format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
++ if (format == NULL)
++ return -EINVAL;
++
++ fmt->format = *format;
++ return 0;
++}
++
++/*
++ * resizer_set_format - Handle set format by pads subdev method
++ * @sd : pointer to v4l2 subdev structure
++ * @fh : V4L2 subdev file handle
++ * @fmt : pointer to v4l2 subdev format structure
++ * return -EINVAL or zero on success
++ */
++static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
++ struct v4l2_subdev_format *fmt)
++{
++ struct isp_res_device *res = v4l2_get_subdevdata(sd);
++ struct v4l2_mbus_framefmt *format;
++ struct v4l2_rect *crop;
++
++ format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
++ if (format == NULL)
++ return -EINVAL;
++
++ resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which);
++ *format = fmt->format;
++
++ if (fmt->pad == RESZ_PAD_SINK) {
++ /* reset crop rectangle */
++ crop = __resizer_get_crop(res, fh, fmt->which);
++ crop->left = 0;
++ crop->top = 0;
++ crop->width = fmt->format.width;
++ crop->height = fmt->format.height;
++
++ /* Propagate the format from sink to source */
++ format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
++ fmt->which);
++ *format = fmt->format;
++ resizer_try_format(res, fh, RESZ_PAD_SOURCE, format,
++ fmt->which);
++ }
++
++ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
++ /* Compute and store the active crop rectangle and resizer
++ * ratios. format already points to the source pad active
++ * format.
++ */
++ res->crop.active = res->crop.request;
++ resizer_calc_ratios(res, &res->crop.active, format,
++ &res->ratio);
++ }
++
++ return 0;
++}
++
++/*
++ * resizer_init_formats - Initialize formats on all pads
++ * @sd: ISP resizer V4L2 subdevice
++ * @fh: V4L2 subdev file handle
++ *
++ * Initialize all pad formats with default values. If fh is not NULL, try
++ * formats are initialized on the file handle. Otherwise active formats are
++ * initialized on the device.
++ */
++static int resizer_init_formats(struct v4l2_subdev *sd,
++ struct v4l2_subdev_fh *fh)
++{
++ struct v4l2_subdev_format format;
++
++ memset(&format, 0, sizeof(format));
++ format.pad = RESZ_PAD_SINK;
++ format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
++ format.format.code = V4L2_MBUS_FMT_YUYV8_1X16;
++ format.format.width = 4096;
++ format.format.height = 4096;
++ resizer_set_format(sd, fh, &format);
++
++ return 0;
++}
++
++/* subdev core operations */
++static const struct v4l2_subdev_core_ops resizer_v4l2_core_ops = {
++ .queryctrl = v4l2_subdev_queryctrl,
++ .querymenu = v4l2_subdev_querymenu,
++ .g_ctrl = v4l2_subdev_g_ctrl,
++ .s_ctrl = v4l2_subdev_s_ctrl,
++ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
++ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
++ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
++};
++
++/* subdev file operations */
++static const struct v4l2_subdev_file_ops resizer_v4l2_file_ops = {
++ .open = resizer_init_formats,
++};
++
++/* subdev video operations */
++static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
++ .s_stream = resizer_set_stream,
++};
++
++/* subdev pad operations */
++static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
++ .enum_mbus_code = resizer_enum_mbus_code,
++ .enum_frame_size = resizer_enum_frame_size,
++ .get_fmt = resizer_get_format,
++ .set_fmt = resizer_set_format,
++ .get_crop = resizer_g_crop,
++ .set_crop = resizer_s_crop,
++};
++
++/* subdev operations */
++static const struct v4l2_subdev_ops resizer_v4l2_ops = {
++ .core = &resizer_v4l2_core_ops,
++ .file = &resizer_v4l2_file_ops,
++ .video = &resizer_v4l2_video_ops,
++ .pad = &resizer_v4l2_pad_ops,
++};
++
++
++/* -----------------------------------------------------------------------------
++ * Media entity operations
++ */
++
++/*
++ * resizer_link_setup - Setup resizer connections.
++ * @entity : Pointer to media entity structure
++ * @local : Pointer to local pad array
++ * @remote : Pointer to remote pad array
++ * @flags : Link flags
++ * return -EINVAL or zero on success
++ */
++static int resizer_link_setup(struct media_entity *entity,
++ const struct media_pad *local,
++ const struct media_pad *remote, u32 flags)
++{
++ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
++ struct isp_res_device *res = v4l2_get_subdevdata(sd);
++
++ switch (local->index | media_entity_type(remote->entity)) {
++ case RESZ_PAD_SINK | MEDIA_ENT_T_DEVNODE:
++ /* read from memory */
++ if (flags & MEDIA_LNK_FL_ENABLED) {
++ if (res->input == RESIZER_INPUT_VP)
++ return -EBUSY;
++ res->input = RESIZER_INPUT_MEMORY;
++ } else {
++ if (res->input == RESIZER_INPUT_MEMORY)
++ res->input = RESIZER_INPUT_NONE;
++ }
++ break;
++
++ case RESZ_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
++ /* read from ccdc or previewer */
++ if (flags & MEDIA_LNK_FL_ENABLED) {
++ if (res->input == RESIZER_INPUT_MEMORY)
++ return -EBUSY;
++ res->input = RESIZER_INPUT_VP;
++ } else {
++ if (res->input == RESIZER_INPUT_VP)
++ res->input = RESIZER_INPUT_NONE;
++ }
++ break;
++
++ case RESZ_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
++ /* resizer always write to memory */
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++/* media operations */
++static const struct media_entity_operations resizer_media_ops = {
++ .link_setup = resizer_link_setup,
++};
++
++/*
++ * resizer_init_entities - Initialize resizer subdev and media entity.
++ * @res : Pointer to resizer device structure
++ * return -ENOMEM or zero on success
++ */
++static int resizer_init_entities(struct isp_res_device *res)
++{
++ struct v4l2_subdev *sd = &res->subdev;
++ struct media_pad *pads = res->pads;
++ struct media_entity *me = &sd->entity;
++ int ret;
++
++ res->input = RESIZER_INPUT_NONE;
++
++ v4l2_subdev_init(sd, &resizer_v4l2_ops);
++ strlcpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name));
++ sd->grp_id = 1 << 16; /* group ID for isp subdevs */
++ v4l2_set_subdevdata(sd, res);
++ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
++
++ v4l2_ctrl_handler_init(&res->ctrls, 1);
++ sd->ctrl_handler = &res->ctrls;
++
++ pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_INPUT;
++ pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_OUTPUT;
++
++ me->ops = &resizer_media_ops;
++ ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0);
++ if (ret < 0)
++ return ret;
++
++ resizer_init_formats(sd, NULL);
++
++ res->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
++ res->video_in.ops = &resizer_video_ops;
++ res->video_in.isp = to_isp_device(res);
++ res->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
++ res->video_in.bpl_alignment = 32;
++ res->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ res->video_out.ops = &resizer_video_ops;
++ res->video_out.isp = to_isp_device(res);
++ res->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
++ res->video_out.bpl_alignment = 32;
++
++ ret = omap3isp_video_init(&res->video_in, "resizer");
++ if (ret < 0)
++ return ret;
++
++ ret = omap3isp_video_init(&res->video_out, "resizer");
++ if (ret < 0)
++ return ret;
++
++ /* Connect the video nodes to the resizer subdev. */
++ ret = media_entity_create_link(&res->video_in.video.entity, 0,
++ &res->subdev.entity, RESZ_PAD_SINK, 0);
++ if (ret < 0)
++ return ret;
++
++ ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE,
++ &res->video_out.video.entity, 0, 0);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++void omap3isp_resizer_unregister_entities(struct isp_res_device *res)
++{
++ media_entity_cleanup(&res->subdev.entity);
++
++ v4l2_device_unregister_subdev(&res->subdev);
++ v4l2_ctrl_handler_free(&res->ctrls);
++ omap3isp_video_unregister(&res->video_in);
++ omap3isp_video_unregister(&res->video_out);
++}
++
++int omap3isp_resizer_register_entities(struct isp_res_device *res,
++ struct v4l2_device *vdev)
++{
++ int ret;
++
++ /* Register the subdev and video nodes. */
++ ret = v4l2_device_register_subdev(vdev, &res->subdev);
++ if (ret < 0)
++ goto error;
++
++ ret = omap3isp_video_register(&res->video_in, vdev);
++ if (ret < 0)
++ goto error;
++
++ ret = omap3isp_video_register(&res->video_out, vdev);
++ if (ret < 0)
++ goto error;
++
++ return 0;
++
++error:
++ omap3isp_resizer_unregister_entities(res);
++ return ret;
++}
++
++/* -----------------------------------------------------------------------------
++ * ISP resizer initialization and cleanup
++ */
++
++void omap3isp_resizer_cleanup(struct isp_device *isp)
++{
++}
++
++/*
++ * isp_resizer_init - Resizer initialization.
++ * @isp : Pointer to ISP device
++ * return -ENOMEM or zero on success
++ */
++int omap3isp_resizer_init(struct isp_device *isp)
++{
++ struct isp_res_device *res = &isp->isp_res;
++ int ret;
++
++ init_waitqueue_head(&res->wait);
++ atomic_set(&res->stopping, 0);
++ ret = resizer_init_entities(res);
++ if (ret < 0)
++ goto out;
++
++out:
++ if (ret)
++ omap3isp_resizer_cleanup(isp);
++
++ return ret;
++}
+diff --git a/drivers/media/video/isp/ispresizer.h b/drivers/media/video/isp/ispresizer.h
+new file mode 100644
+index 0000000..39d188f
+--- /dev/null
++++ b/drivers/media/video/isp/ispresizer.h
+@@ -0,0 +1,150 @@
++/*
++ * ispresizer.h
++ *
++ * TI OMAP3 ISP - Resizer module
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#ifndef OMAP3_ISP_RESIZER_H
++#define OMAP3_ISP_RESIZER_H
++
++#include <linux/types.h>
++#include <media/v4l2-ctrls.h>
++
++/*
++ * Constants for filter coefficents count
++ */
++#define COEFF_CNT 32
++
++/*
++ * struct isprsz_coef - Structure for resizer filter coeffcients.
++ * @h_filter_coef_4tap: Horizontal filter coefficients for 8-phase/4-tap
++ * mode (.5x-4x)
++ * @v_filter_coef_4tap: Vertical filter coefficients for 8-phase/4-tap
++ * mode (.5x-4x)
++ * @h_filter_coef_7tap: Horizontal filter coefficients for 4-phase/7-tap
++ * mode (.25x-.5x)
++ * @v_filter_coef_7tap: Vertical filter coefficients for 4-phase/7-tap
++ * mode (.25x-.5x)
++ */
++struct isprsz_coef {
++ u16 h_filter_coef_4tap[32];
++ u16 v_filter_coef_4tap[32];
++ /* Every 8th value is a dummy value in the following arrays: */
++ u16 h_filter_coef_7tap[32];
++ u16 v_filter_coef_7tap[32];
++};
++
++/* Chrominance horizontal algorithm */
++enum resizer_chroma_algo {
++ RSZ_THE_SAME = 0, /* Chrominance the same as Luminance */
++ RSZ_BILINEAR = 1, /* Chrominance uses bilinear interpolation */
++};
++
++/* Resizer input type select */
++enum resizer_colors_type {
++ RSZ_YUV422 = 0, /* YUV422 color is interleaved */
++ RSZ_COLOR8 = 1, /* Color separate data on 8 bits */
++};
++
++/*
++ * Structure for horizontal and vertical resizing value
++ */
++struct resizer_ratio {
++ u32 horz;
++ u32 vert;
++};
++
++/*
++ * Structure for luminance enhancer parameters.
++ */
++struct resizer_luma_yenh {
++ u8 algo; /* algorithm select. */
++ u8 gain; /* maximum gain. */
++ u8 slope; /* slope. */
++ u8 core; /* core offset. */
++};
++
++enum resizer_input_entity {
++ RESIZER_INPUT_NONE,
++ RESIZER_INPUT_VP, /* input video port - prev or ccdc */
++ RESIZER_INPUT_MEMORY,
++};
++
++/* Sink and source resizer pads */
++#define RESZ_PAD_SINK 0
++#define RESZ_PAD_SOURCE 1
++#define RESZ_PADS_NUM 2
++
++/*
++ * struct isp_res_device - OMAP3 ISP resizer module
++ * @crop.request: Crop rectangle requested by the user
++ * @crop.active: Active crop rectangle (based on hardware requirements)
++ */
++struct isp_res_device {
++ struct v4l2_subdev subdev;
++ struct media_pad pads[RESZ_PADS_NUM];
++ struct v4l2_mbus_framefmt formats[RESZ_PADS_NUM];
++
++ struct v4l2_ctrl_handler ctrls;
++
++ enum resizer_input_entity input;
++ struct isp_video video_in;
++ struct isp_video video_out;
++ unsigned int error;
++
++ u32 addr_base; /* stored source buffer address in memory mode */
++ u32 crop_offset; /* additional offset for crop in memory mode */
++ struct resizer_ratio ratio;
++ int pm_state;
++ unsigned int applycrop:1;
++ enum isp_pipeline_stream_state state;
++ wait_queue_head_t wait;
++ atomic_t stopping;
++
++ struct {
++ struct v4l2_rect request;
++ struct v4l2_rect active;
++ } crop;
++};
++
++struct isp_device;
++
++int omap3isp_resizer_init(struct isp_device *isp);
++void omap3isp_resizer_cleanup(struct isp_device *isp);
++
++int omap3isp_resizer_register_entities(struct isp_res_device *res,
++ struct v4l2_device *vdev);
++void omap3isp_resizer_unregister_entities(struct isp_res_device *res);
++void omap3isp_resizer_isr_frame_sync(struct isp_res_device *res);
++void omap3isp_resizer_isr(struct isp_res_device *isp_res);
++
++void omap3isp_resizer_max_rate(struct isp_res_device *res,
++ unsigned int *max_rate);
++
++void omap3isp_resizer_suspend(struct isp_res_device *isp_res);
++
++void omap3isp_resizer_resume(struct isp_res_device *isp_res);
++
++int omap3isp_resizer_busy(struct isp_res_device *isp_res);
++
++#endif /* OMAP3_ISP_RESIZER_H */
+diff --git a/drivers/media/video/isp/ispstat.c b/drivers/media/video/isp/ispstat.c
+new file mode 100644
+index 0000000..3406572
+--- /dev/null
++++ b/drivers/media/video/isp/ispstat.c
+@@ -0,0 +1,1100 @@
++/*
++ * ispstat.c
++ *
++ * TI OMAP3 ISP - Statistics core
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc
++ *
++ * Contacts: David Cohen <david.cohen@nokia.com>
++ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#include <linux/dma-mapping.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++
++#include "isp.h"
++
++#define IS_COHERENT_BUF(stat) ((stat)->dma_ch >= 0)
++
++/*
++ * MAGIC_SIZE must always be the greatest common divisor of
++ * AEWB_PACKET_SIZE and AF_PAXEL_SIZE.
++ */
++#define MAGIC_SIZE 16
++#define MAGIC_NUM 0x55
++
++/* HACK: AF module seems to be writing one more paxel data than it should. */
++#define AF_EXTRA_DATA OMAP3ISP_AF_PAXEL_SIZE
++
++/*
++ * HACK: H3A modules go to an invalid state after have a SBL overflow. It makes
++ * the next buffer to start to be written in the same point where the overflow
++ * occurred instead of the configured address. The only known way to make it to
++ * go back to a valid state is having a valid buffer processing. Of course it
++ * requires at least a doubled buffer size to avoid an access to invalid memory
++ * region. But it does not fix everything. It may happen more than one
++ * consecutive SBL overflows. In that case, it might be unpredictable how many
++ * buffers the allocated memory should fit. For that case, a recover
++ * configuration was created. It produces the minimum buffer size for each H3A
++ * module and decrease the change for more SBL overflows. This recover state
++ * will be enabled every time a SBL overflow occur. As the output buffer size
++ * isn't big, it's possible to have an extra size able to fit many recover
++ * buffers making it extreamily unlikely to have an access to invalid memory
++ * region.
++ */
++#define NUM_H3A_RECOVER_BUFS 10
++
++/*
++ * HACK: Because of HW issues the generic layer sometimes need to have
++ * different behaviour for different statistic modules.
++ */
++#define IS_H3A_AF(stat) ((stat) == &(stat)->isp->isp_af)
++#define IS_H3A_AEWB(stat) ((stat) == &(stat)->isp->isp_aewb)
++#define IS_H3A(stat) (IS_H3A_AF(stat) || IS_H3A_AEWB(stat))
++
++static void __isp_stat_buf_sync_magic(struct ispstat *stat,
++ struct ispstat_buffer *buf,
++ u32 buf_size, enum dma_data_direction dir,
++ void (*dma_sync)(struct device *,
++ dma_addr_t, unsigned long, size_t,
++ enum dma_data_direction))
++{
++ struct device *dev = stat->isp->dev;
++ struct page *pg;
++ dma_addr_t dma_addr;
++ u32 offset;
++
++ /* Initial magic words */
++ pg = vmalloc_to_page(buf->virt_addr);
++ dma_addr = page_to_dma(dev, pg);
++ dma_sync(dev, dma_addr, 0, MAGIC_SIZE, dir);
++
++ /* Final magic words */
++ pg = vmalloc_to_page(buf->virt_addr + buf_size);
++ dma_addr = page_to_dma(dev, pg);
++ offset = ((u32)buf->virt_addr + buf_size) & ~PAGE_MASK;
++ dma_sync(dev, dma_addr, offset, MAGIC_SIZE, dir);
++}
++
++static void isp_stat_buf_sync_magic_for_device(struct ispstat *stat,
++ struct ispstat_buffer *buf,
++ u32 buf_size,
++ enum dma_data_direction dir)
++{
++ if (IS_COHERENT_BUF(stat))
++ return;
++
++ __isp_stat_buf_sync_magic(stat, buf, buf_size, dir,
++ dma_sync_single_range_for_device);
++}
++
++static void isp_stat_buf_sync_magic_for_cpu(struct ispstat *stat,
++ struct ispstat_buffer *buf,
++ u32 buf_size,
++ enum dma_data_direction dir)
++{
++ if (IS_COHERENT_BUF(stat))
++ return;
++
++ __isp_stat_buf_sync_magic(stat, buf, buf_size, dir,
++ dma_sync_single_range_for_cpu);
++}
++
++static int isp_stat_buf_check_magic(struct ispstat *stat,
++ struct ispstat_buffer *buf)
++{
++ const u32 buf_size = IS_H3A_AF(stat) ?
++ buf->buf_size + AF_EXTRA_DATA : buf->buf_size;
++ u8 *w;
++ u8 *end;
++ int ret = -EINVAL;
++
++ isp_stat_buf_sync_magic_for_cpu(stat, buf, buf_size, DMA_FROM_DEVICE);
++
++ /* Checking initial magic numbers. They shouldn't be here anymore. */
++ for (w = buf->virt_addr, end = w + MAGIC_SIZE; w < end; w++)
++ if (likely(*w != MAGIC_NUM))
++ ret = 0;
++
++ if (ret) {
++ dev_dbg(stat->isp->dev, "%s: beginning magic check does not "
++ "match.\n", stat->subdev.name);
++ return ret;
++ }
++
++ /* Checking magic numbers at the end. They must be still here. */
++ for (w = buf->virt_addr + buf_size, end = w + MAGIC_SIZE;
++ w < end; w++) {
++ if (unlikely(*w != MAGIC_NUM)) {
++ dev_dbg(stat->isp->dev, "%s: endding magic check does "
++ "not match.\n", stat->subdev.name);
++ return -EINVAL;
++ }
++ }
++
++ isp_stat_buf_sync_magic_for_device(stat, buf, buf_size,
++ DMA_FROM_DEVICE);
++
++ return 0;
++}
++
++static void isp_stat_buf_insert_magic(struct ispstat *stat,
++ struct ispstat_buffer *buf)
++{
++ const u32 buf_size = IS_H3A_AF(stat) ?
++ stat->buf_size + AF_EXTRA_DATA : stat->buf_size;
++
++ isp_stat_buf_sync_magic_for_cpu(stat, buf, buf_size, DMA_FROM_DEVICE);
++
++ /*
++ * Inserting MAGIC_NUM at the beginning and end of the buffer.
++ * buf->buf_size is set only after the buffer is queued. For now the
++ * right buf_size for the current configuration is pointed by
++ * stat->buf_size.
++ */
++ memset(buf->virt_addr, MAGIC_NUM, MAGIC_SIZE);
++ memset(buf->virt_addr + buf_size, MAGIC_NUM, MAGIC_SIZE);
++
++ isp_stat_buf_sync_magic_for_device(stat, buf, buf_size,
++ DMA_BIDIRECTIONAL);
++}
++
++static void isp_stat_buf_sync_for_device(struct ispstat *stat,
++ struct ispstat_buffer *buf)
++{
++ if (IS_COHERENT_BUF(stat))
++ return;
++
++ dma_sync_sg_for_device(stat->isp->dev, buf->iovm->sgt->sgl,
++ buf->iovm->sgt->nents, DMA_FROM_DEVICE);
++}
++
++static void isp_stat_buf_sync_for_cpu(struct ispstat *stat,
++ struct ispstat_buffer *buf)
++{
++ if (IS_COHERENT_BUF(stat))
++ return;
++
++ dma_sync_sg_for_cpu(stat->isp->dev, buf->iovm->sgt->sgl,
++ buf->iovm->sgt->nents, DMA_FROM_DEVICE);
++}
++
++static void isp_stat_buf_clear(struct ispstat *stat)
++{
++ int i;
++
++ for (i = 0; i < STAT_MAX_BUFS; i++)
++ stat->buf[i].empty = 1;
++}
++
++static struct ispstat_buffer *
++__isp_stat_buf_find(struct ispstat *stat, int look_empty)
++{
++ struct ispstat_buffer *found = NULL;
++ int i;
++
++ for (i = 0; i < STAT_MAX_BUFS; i++) {
++ struct ispstat_buffer *curr = &stat->buf[i];
++
++ /*
++ * Don't select the buffer which is being copied to
++ * userspace or used by the module.
++ */
++ if (curr == stat->locked_buf || curr == stat->active_buf)
++ continue;
++
++ /* Don't select uninitialised buffers if it's not required */
++ if (!look_empty && curr->empty)
++ continue;
++
++ /* Pick uninitialised buffer over anything else if look_empty */
++ if (curr->empty) {
++ found = curr;
++ break;
++ }
++
++ /* Choose the oldest buffer */
++ if (!found ||
++ (s32)curr->frame_number - (s32)found->frame_number < 0)
++ found = curr;
++ }
++
++ return found;
++}
++
++static inline struct ispstat_buffer *
++isp_stat_buf_find_oldest(struct ispstat *stat)
++{
++ return __isp_stat_buf_find(stat, 0);
++}
++
++static inline struct ispstat_buffer *
++isp_stat_buf_find_oldest_or_empty(struct ispstat *stat)
++{
++ return __isp_stat_buf_find(stat, 1);
++}
++
++static int isp_stat_buf_queue(struct ispstat *stat)
++{
++ if (!stat->active_buf)
++ return STAT_NO_BUF;
++
++ do_gettimeofday(&stat->active_buf->ts);
++
++ stat->active_buf->buf_size = stat->buf_size;
++ if (isp_stat_buf_check_magic(stat, stat->active_buf)) {
++ dev_dbg(stat->isp->dev, "%s: data wasn't properly written.\n",
++ stat->subdev.name);
++ return STAT_NO_BUF;
++ }
++ stat->active_buf->config_counter = stat->config_counter;
++ stat->active_buf->frame_number = stat->frame_number;
++ stat->active_buf->empty = 0;
++ stat->active_buf = NULL;
++
++ return STAT_BUF_DONE;
++}
++
++/* Get next free buffer to write the statistics to and mark it active. */
++static void isp_stat_buf_next(struct ispstat *stat)
++{
++ if (unlikely(stat->active_buf))
++ /* Overwriting unused active buffer */
++ dev_dbg(stat->isp->dev, "%s: new buffer requested without "
++ "queuing active one.\n",
++ stat->subdev.name);
++ else
++ stat->active_buf = isp_stat_buf_find_oldest_or_empty(stat);
++}
++
++static void isp_stat_buf_release(struct ispstat *stat)
++{
++ unsigned long flags;
++
++ isp_stat_buf_sync_for_device(stat, stat->locked_buf);
++ spin_lock_irqsave(&stat->isp->stat_lock, flags);
++ stat->locked_buf = NULL;
++ spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
++}
++
++/* Get buffer to userspace. */
++static struct ispstat_buffer *isp_stat_buf_get(struct ispstat *stat,
++ struct omap3isp_stat_data *data)
++{
++ int rval = 0;
++ unsigned long flags;
++ struct ispstat_buffer *buf;
++
++ spin_lock_irqsave(&stat->isp->stat_lock, flags);
++
++ while (1) {
++ buf = isp_stat_buf_find_oldest(stat);
++ if (!buf) {
++ spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
++ dev_dbg(stat->isp->dev, "%s: cannot find a buffer.\n",
++ stat->subdev.name);
++ return ERR_PTR(-EBUSY);
++ }
++ if (isp_stat_buf_check_magic(stat, buf)) {
++ dev_dbg(stat->isp->dev, "%s: current buffer has "
++ "corrupted data\n.", stat->subdev.name);
++ /* Mark empty because it doesn't have valid data. */
++ buf->empty = 1;
++ } else {
++ /* Buffer isn't corrupted. */
++ break;
++ }
++ }
++
++ stat->locked_buf = buf;
++
++ spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
++
++ if (buf->buf_size > data->buf_size) {
++ dev_warn(stat->isp->dev, "%s: userspace's buffer size is "
++ "not enough.\n", stat->subdev.name);
++ isp_stat_buf_release(stat);
++ return ERR_PTR(-EINVAL);
++ }
++
++ isp_stat_buf_sync_for_cpu(stat, buf);
++
++ rval = copy_to_user(data->buf,
++ buf->virt_addr,
++ buf->buf_size);
++
++ if (rval) {
++ dev_info(stat->isp->dev,
++ "%s: failed copying %d bytes of stat data\n",
++ stat->subdev.name, rval);
++ buf = ERR_PTR(-EFAULT);
++ isp_stat_buf_release(stat);
++ }
++
++ return buf;
++}
++
++static void isp_stat_bufs_free(struct ispstat *stat)
++{
++ struct isp_device *isp = stat->isp;
++ int i;
++
++ for (i = 0; i < STAT_MAX_BUFS; i++) {
++ struct ispstat_buffer *buf = &stat->buf[i];
++
++ if (!IS_COHERENT_BUF(stat)) {
++ if (IS_ERR_OR_NULL((void *)buf->iommu_addr))
++ continue;
++ if (buf->iovm)
++ dma_unmap_sg(isp->dev, buf->iovm->sgt->sgl,
++ buf->iovm->sgt->nents,
++ DMA_FROM_DEVICE);
++ iommu_vfree(isp->iommu, buf->iommu_addr);
++ } else {
++ if (!buf->virt_addr)
++ continue;
++ dma_free_coherent(stat->isp->dev, stat->buf_alloc_size,
++ buf->virt_addr, buf->dma_addr);
++ }
++ buf->iommu_addr = 0;
++ buf->iovm = NULL;
++ buf->dma_addr = 0;
++ buf->virt_addr = NULL;
++ buf->empty = 1;
++ }
++
++ dev_dbg(stat->isp->dev, "%s: all buffers were freed.\n",
++ stat->subdev.name);
++
++ stat->buf_alloc_size = 0;
++ stat->active_buf = NULL;
++}
++
++static int isp_stat_bufs_alloc_iommu(struct ispstat *stat, unsigned int size)
++{
++ struct isp_device *isp = stat->isp;
++ int i;
++
++ stat->buf_alloc_size = size;
++
++ for (i = 0; i < STAT_MAX_BUFS; i++) {
++ struct ispstat_buffer *buf = &stat->buf[i];
++ struct iovm_struct *iovm;
++
++ WARN_ON(buf->dma_addr);
++ buf->iommu_addr = iommu_vmalloc(isp->iommu, 0, size,
++ IOMMU_FLAG);
++ if (IS_ERR((void *)buf->iommu_addr)) {
++ dev_err(stat->isp->dev,
++ "%s: Can't acquire memory for "
++ "buffer %d\n", stat->subdev.name, i);
++ isp_stat_bufs_free(stat);
++ return -ENOMEM;
++ }
++
++ iovm = find_iovm_area(isp->iommu, buf->iommu_addr);
++ if (!iovm ||
++ !dma_map_sg(isp->dev, iovm->sgt->sgl, iovm->sgt->nents,
++ DMA_FROM_DEVICE)) {
++ isp_stat_bufs_free(stat);
++ return -ENOMEM;
++ }
++ buf->iovm = iovm;
++
++ buf->virt_addr = da_to_va(stat->isp->iommu,
++ (u32)buf->iommu_addr);
++ buf->empty = 1;
++ dev_dbg(stat->isp->dev, "%s: buffer[%d] allocated."
++ "iommu_addr=0x%08lx virt_addr=0x%08lx",
++ stat->subdev.name, i, buf->iommu_addr,
++ (unsigned long)buf->virt_addr);
++ }
++
++ return 0;
++}
++
++static int isp_stat_bufs_alloc_dma(struct ispstat *stat, unsigned int size)
++{
++ int i;
++
++ stat->buf_alloc_size = size;
++
++ for (i = 0; i < STAT_MAX_BUFS; i++) {
++ struct ispstat_buffer *buf = &stat->buf[i];
++
++ WARN_ON(buf->iommu_addr);
++ buf->virt_addr = dma_alloc_coherent(stat->isp->dev, size,
++ &buf->dma_addr, GFP_KERNEL | GFP_DMA);
++
++ if (!buf->virt_addr || !buf->dma_addr) {
++ dev_info(stat->isp->dev,
++ "%s: Can't acquire memory for "
++ "DMA buffer %d\n", stat->subdev.name, i);
++ isp_stat_bufs_free(stat);
++ return -ENOMEM;
++ }
++ buf->empty = 1;
++
++ dev_dbg(stat->isp->dev, "%s: buffer[%d] allocated."
++ "dma_addr=0x%08lx virt_addr=0x%08lx\n",
++ stat->subdev.name, i, (unsigned long)buf->dma_addr,
++ (unsigned long)buf->virt_addr);
++ }
++
++ return 0;
++}
++
++static int isp_stat_bufs_alloc(struct ispstat *stat, u32 size)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&stat->isp->stat_lock, flags);
++
++ BUG_ON(stat->locked_buf != NULL);
++
++ /* Are the old buffers big enough? */
++ if (stat->buf_alloc_size >= size) {
++ spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
++ return 0;
++ }
++
++ if (stat->state != ISPSTAT_DISABLED || stat->buf_processing) {
++ dev_info(stat->isp->dev,
++ "%s: trying to allocate memory when busy\n",
++ stat->subdev.name);
++ spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
++ return -EBUSY;
++ }
++
++ spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
++
++ isp_stat_bufs_free(stat);
++
++ if (IS_COHERENT_BUF(stat))
++ return isp_stat_bufs_alloc_dma(stat, size);
++ else
++ return isp_stat_bufs_alloc_iommu(stat, size);
++}
++
++static void isp_stat_queue_event(struct ispstat *stat, int err)
++{
++ struct video_device *vdev = &stat->subdev.devnode;
++ struct v4l2_event event;
++ struct omap3isp_stat_event_status *status = (void *)event.u.data;
++
++ memset(&event, 0, sizeof(event));
++ if (!err) {
++ status->frame_number = stat->frame_number;
++ status->config_counter = stat->config_counter;
++ } else {
++ status->buf_err = 1;
++ }
++ event.type = stat->event_type;
++ v4l2_event_queue(vdev, &event);
++}
++
++
++/*
++ * omap3isp_stat_request_statistics - Request statistics.
++ * @data: Pointer to return statistics data.
++ *
++ * Returns 0 if successful.
++ */
++int omap3isp_stat_request_statistics(struct ispstat *stat,
++ struct omap3isp_stat_data *data)
++{
++ struct ispstat_buffer *buf;
++
++ if (stat->state != ISPSTAT_ENABLED) {
++ dev_dbg(stat->isp->dev, "%s: engine not enabled.\n",
++ stat->subdev.name);
++ return -EINVAL;
++ }
++
++ mutex_lock(&stat->ioctl_lock);
++ buf = isp_stat_buf_get(stat, data);
++ if (IS_ERR(buf)) {
++ mutex_unlock(&stat->ioctl_lock);
++ return PTR_ERR(buf);
++ }
++
++ data->ts = buf->ts;
++ data->config_counter = buf->config_counter;
++ data->frame_number = buf->frame_number;
++ data->buf_size = buf->buf_size;
++
++ /*
++ * Deprecated. Number of new buffers is always equal to number of
++ * queued events without error flag. By setting it to 0, userspace
++ * won't try to request new buffer without receiving new event.
++ * This field must go away in future.
++ */
++ data->new_bufs = 0;
++
++ buf->empty = 1;
++ isp_stat_buf_release(stat);
++ mutex_unlock(&stat->ioctl_lock);
++
++ return 0;
++}
++
++/*
++ * omap3isp_stat_config - Receives new statistic engine configuration.
++ * @new_conf: Pointer to config structure.
++ *
++ * Returns 0 if successful, -EINVAL if new_conf pointer is NULL, -ENOMEM if
++ * was unable to allocate memory for the buffer, or other errors if parameters
++ * are invalid.
++ */
++int omap3isp_stat_config(struct ispstat *stat, void *new_conf)
++{
++ int ret;
++ unsigned long irqflags;
++ struct ispstat_generic_config *user_cfg = new_conf;
++ u32 buf_size = user_cfg->buf_size;
++
++ if (!new_conf) {
++ dev_dbg(stat->isp->dev, "%s: configuration is NULL\n",
++ stat->subdev.name);
++ return -EINVAL;
++ }
++
++ mutex_lock(&stat->ioctl_lock);
++
++ dev_dbg(stat->isp->dev, "%s: configuring module with buffer "
++ "size=0x%08lx\n", stat->subdev.name, (unsigned long)buf_size);
++
++ ret = stat->ops->validate_params(stat, new_conf);
++ if (ret) {
++ mutex_unlock(&stat->ioctl_lock);
++ dev_dbg(stat->isp->dev, "%s: configuration values are "
++ "invalid.\n", stat->subdev.name);
++ return ret;
++ }
++
++ if (buf_size != user_cfg->buf_size)
++ dev_dbg(stat->isp->dev, "%s: driver has corrected buffer size "
++ "request to 0x%08lx\n", stat->subdev.name,
++ (unsigned long)user_cfg->buf_size);
++
++ /*
++ * Hack: H3A modules may need a doubled buffer size to avoid access
++ * to a invalid memory address after a SBL overflow.
++ * The buffer size is always PAGE_ALIGNED.
++ * Hack 2: MAGIC_SIZE is added to buf_size so a magic word can be
++ * inserted at the end to data integrity check purpose.
++ * Hack 3: AF module writes one paxel data more than it should, so
++ * the buffer allocation must consider it to avoid invalid memory
++ * access.
++ * Hack 4: H3A need to allocate extra space for the recover state.
++ */
++ if (IS_H3A(stat)) {
++ buf_size = user_cfg->buf_size * 2 + MAGIC_SIZE;
++ if (IS_H3A_AF(stat))
++ /*
++ * Adding one extra paxel data size for each recover
++ * buffer + 2 regular ones.
++ */
++ buf_size += AF_EXTRA_DATA * (NUM_H3A_RECOVER_BUFS + 2);
++ if (stat->recover_priv) {
++ struct ispstat_generic_config *recover_cfg =
++ stat->recover_priv;
++ buf_size += recover_cfg->buf_size *
++ NUM_H3A_RECOVER_BUFS;
++ }
++ buf_size = PAGE_ALIGN(buf_size);
++ } else { /* Histogram */
++ buf_size = PAGE_ALIGN(user_cfg->buf_size + MAGIC_SIZE);
++ }
++
++ ret = isp_stat_bufs_alloc(stat, buf_size);
++ if (ret) {
++ mutex_unlock(&stat->ioctl_lock);
++ return ret;
++ }
++
++ spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
++ stat->ops->set_params(stat, new_conf);
++ spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
++
++ /*
++ * Returning the right future config_counter for this setup, so
++ * userspace can *know* when it has been applied.
++ */
++ user_cfg->config_counter = stat->config_counter + stat->inc_config;
++
++ /* Module has a valid configuration. */
++ stat->configured = 1;
++ dev_dbg(stat->isp->dev, "%s: module has been successfully "
++ "configured.\n", stat->subdev.name);
++
++ mutex_unlock(&stat->ioctl_lock);
++
++ return 0;
++}
++
++/*
++ * isp_stat_buf_process - Process statistic buffers.
++ * @buf_state: points out if buffer is ready to be processed. It's necessary
++ * because histogram needs to copy the data from internal memory
++ * before be able to process the buffer.
++ */
++static int isp_stat_buf_process(struct ispstat *stat, int buf_state)
++{
++ int ret = STAT_NO_BUF;
++
++ if (!atomic_add_unless(&stat->buf_err, -1, 0) &&
++ buf_state == STAT_BUF_DONE && stat->state == ISPSTAT_ENABLED) {
++ ret = isp_stat_buf_queue(stat);
++ isp_stat_buf_next(stat);
++ }
++
++ return ret;
++}
++
++int omap3isp_stat_pcr_busy(struct ispstat *stat)
++{
++ return stat->ops->busy(stat);
++}
++
++int omap3isp_stat_busy(struct ispstat *stat)
++{
++ return omap3isp_stat_pcr_busy(stat) | stat->buf_processing |
++ (stat->state != ISPSTAT_DISABLED);
++}
++
++/*
++ * isp_stat_pcr_enable - Disables/Enables statistic engines.
++ * @pcr_enable: 0/1 - Disables/Enables the engine.
++ *
++ * Must be called from ISP driver when the module is idle and synchronized
++ * with CCDC.
++ */
++static void isp_stat_pcr_enable(struct ispstat *stat, u8 pcr_enable)
++{
++ if ((stat->state != ISPSTAT_ENABLING &&
++ stat->state != ISPSTAT_ENABLED) && pcr_enable)
++ /* Userspace has disabled the module. Aborting. */
++ return;
++
++ stat->ops->enable(stat, pcr_enable);
++ if (stat->state == ISPSTAT_DISABLING && !pcr_enable)
++ stat->state = ISPSTAT_DISABLED;
++ else if (stat->state == ISPSTAT_ENABLING && pcr_enable)
++ stat->state = ISPSTAT_ENABLED;
++}
++
++void omap3isp_stat_suspend(struct ispstat *stat)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&stat->isp->stat_lock, flags);
++
++ if (stat->state != ISPSTAT_DISABLED)
++ stat->ops->enable(stat, 0);
++ if (stat->state == ISPSTAT_ENABLED)
++ stat->state = ISPSTAT_SUSPENDED;
++
++ spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
++}
++
++void omap3isp_stat_resume(struct ispstat *stat)
++{
++ /* Module will be re-enabled with its pipeline */
++ if (stat->state == ISPSTAT_SUSPENDED)
++ stat->state = ISPSTAT_ENABLING;
++}
++
++static void isp_stat_try_enable(struct ispstat *stat)
++{
++ unsigned long irqflags;
++
++ if (stat->priv == NULL)
++ /* driver wasn't initialised */
++ return;
++
++ spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
++ if (stat->state == ISPSTAT_ENABLING && !stat->buf_processing &&
++ stat->buf_alloc_size) {
++ /*
++ * Userspace's requested to enable the engine but it wasn't yet.
++ * Let's do that now.
++ */
++ stat->update = 1;
++ isp_stat_buf_next(stat);
++ stat->ops->setup_regs(stat, stat->priv);
++ isp_stat_buf_insert_magic(stat, stat->active_buf);
++
++ /*
++ * H3A module has some hw issues which forces the driver to
++ * ignore next buffers even if it was disabled in the meantime.
++ * On the other hand, Histogram shouldn't ignore buffers anymore
++ * if it's being enabled.
++ */
++ if (!IS_H3A(stat))
++ atomic_set(&stat->buf_err, 0);
++
++ isp_stat_pcr_enable(stat, 1);
++ spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
++ dev_dbg(stat->isp->dev, "%s: module is enabled.\n",
++ stat->subdev.name);
++ } else {
++ spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
++ }
++}
++
++void omap3isp_stat_isr_frame_sync(struct ispstat *stat)
++{
++ isp_stat_try_enable(stat);
++}
++
++void omap3isp_stat_sbl_overflow(struct ispstat *stat)
++{
++ unsigned long irqflags;
++
++ spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
++ /*
++ * Due to a H3A hw issue which prevents the next buffer to start from
++ * the correct memory address, 2 buffers must be ignored.
++ */
++ atomic_set(&stat->buf_err, 2);
++
++ /*
++ * If more than one SBL overflow happen in a row, H3A module may access
++ * invalid memory region.
++ * stat->sbl_ovl_recover is set to tell to the driver to temporarily use
++ * a soft configuration which helps to avoid consecutive overflows.
++ */
++ if (stat->recover_priv)
++ stat->sbl_ovl_recover = 1;
++ spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
++}
++
++/*
++ * omap3isp_stat_enable - Disable/Enable statistic engine as soon as possible
++ * @enable: 0/1 - Disables/Enables the engine.
++ *
++ * Client should configure all the module registers before this.
++ * This function can be called from a userspace request.
++ */
++int omap3isp_stat_enable(struct ispstat *stat, u8 enable)
++{
++ unsigned long irqflags;
++
++ dev_dbg(stat->isp->dev, "%s: user wants to %s module.\n",
++ stat->subdev.name, enable ? "enable" : "disable");
++
++ /* Prevent enabling while configuring */
++ mutex_lock(&stat->ioctl_lock);
++
++ spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
++
++ if (!stat->configured && enable) {
++ spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
++ mutex_unlock(&stat->ioctl_lock);
++ dev_dbg(stat->isp->dev, "%s: cannot enable module as it's "
++ "never been successfully configured so far.\n",
++ stat->subdev.name);
++ return -EINVAL;
++ }
++
++ if (enable) {
++ if (stat->state == ISPSTAT_DISABLING)
++ /* Previous disabling request wasn't done yet */
++ stat->state = ISPSTAT_ENABLED;
++ else if (stat->state == ISPSTAT_DISABLED)
++ /* Module is now being enabled */
++ stat->state = ISPSTAT_ENABLING;
++ } else {
++ if (stat->state == ISPSTAT_ENABLING) {
++ /* Previous enabling request wasn't done yet */
++ stat->state = ISPSTAT_DISABLED;
++ } else if (stat->state == ISPSTAT_ENABLED) {
++ /* Module is now being disabled */
++ stat->state = ISPSTAT_DISABLING;
++ isp_stat_buf_clear(stat);
++ }
++ }
++
++ spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
++ mutex_unlock(&stat->ioctl_lock);
++
++ return 0;
++}
++
++int omap3isp_stat_s_stream(struct v4l2_subdev *subdev, int enable)
++{
++ struct ispstat *stat = v4l2_get_subdevdata(subdev);
++
++ if (enable) {
++ /*
++ * Only set enable PCR bit if the module was previously
++ * enabled through ioct.
++ */
++ isp_stat_try_enable(stat);
++ } else {
++ unsigned long flags;
++ /* Disable PCR bit and config enable field */
++ omap3isp_stat_enable(stat, 0);
++ spin_lock_irqsave(&stat->isp->stat_lock, flags);
++ stat->ops->enable(stat, 0);
++ spin_unlock_irqrestore(&stat->isp->stat_lock, flags);
++
++ /*
++ * If module isn't busy, a new interrupt may come or not to
++ * set the state to DISABLED. As Histogram needs to read its
++ * internal memory to clear it, let interrupt handler
++ * responsible of changing state to DISABLED. If the last
++ * interrupt is coming, it's still safe as the handler will
++ * ignore the second time when state is already set to DISABLED.
++ * It's necessary to synchronize Histogram with streamoff, once
++ * the module may be considered idle before last SDMA transfer
++ * starts if we return here.
++ */
++ if (!omap3isp_stat_pcr_busy(stat))
++ omap3isp_stat_isr(stat);
++
++ dev_dbg(stat->isp->dev, "%s: module is being disabled\n",
++ stat->subdev.name);
++ }
++
++ return 0;
++}
++
++/*
++ * __stat_isr - Interrupt handler for statistic drivers
++ */
++static void __stat_isr(struct ispstat *stat, int from_dma)
++{
++ int ret = STAT_BUF_DONE;
++ int buf_processing;
++ unsigned long irqflags;
++ struct isp_pipeline *pipe;
++
++ /*
++ * stat->buf_processing must be set before disable module. It's
++ * necessary to not inform too early the buffers aren't busy in case
++ * of SDMA is going to be used.
++ */
++ spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
++ if (stat->state == ISPSTAT_DISABLED) {
++ spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
++ return;
++ }
++ buf_processing = stat->buf_processing;
++ stat->buf_processing = 1;
++ stat->ops->enable(stat, 0);
++
++ if (buf_processing && !from_dma) {
++ if (stat->state == ISPSTAT_ENABLED) {
++ spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
++ dev_err(stat->isp->dev,
++ "%s: interrupt occurred when module was still "
++ "processing a buffer.\n", stat->subdev.name);
++ ret = STAT_NO_BUF;
++ goto out;
++ } else {
++ /*
++ * Interrupt handler was called from streamoff when
++ * the module wasn't busy anymore to ensure it is being
++ * disabled after process last buffer. If such buffer
++ * processing has already started, no need to do
++ * anything else.
++ */
++ spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
++ return;
++ }
++ }
++ spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
++
++ /* If it's busy we can't process this buffer anymore */
++ if (!omap3isp_stat_pcr_busy(stat)) {
++ if (!from_dma && stat->ops->buf_process)
++ /* Module still need to copy data to buffer. */
++ ret = stat->ops->buf_process(stat);
++ if (ret == STAT_BUF_WAITING_DMA)
++ /* Buffer is not ready yet */
++ return;
++
++ spin_lock_irqsave(&stat->isp->stat_lock, irqflags);
++
++ /*
++ * Histogram needs to read its internal memory to clear it
++ * before be disabled. For that reason, common statistic layer
++ * can return only after call stat's buf_process() operator.
++ */
++ if (stat->state == ISPSTAT_DISABLING) {
++ stat->state = ISPSTAT_DISABLED;
++ spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
++ stat->buf_processing = 0;
++ return;
++ }
++ pipe = to_isp_pipeline(&stat->subdev.entity);
++ stat->frame_number = atomic_read(&pipe->frame_number);
++
++ /*
++ * Before this point, 'ret' stores the buffer's status if it's
++ * ready to be processed. Afterwards, it holds the status if
++ * it was processed successfully.
++ */
++ ret = isp_stat_buf_process(stat, ret);
++
++ if (likely(!stat->sbl_ovl_recover)) {
++ stat->ops->setup_regs(stat, stat->priv);
++ } else {
++ /*
++ * Using recover config to increase the chance to have
++ * a good buffer processing and make the H3A module to
++ * go back to a valid state.
++ */
++ stat->update = 1;
++ stat->ops->setup_regs(stat, stat->recover_priv);
++ stat->sbl_ovl_recover = 0;
++
++ /*
++ * Set 'update' in case of the module needs to use
++ * regular configuration after next buffer.
++ */
++ stat->update = 1;
++ }
++
++ isp_stat_buf_insert_magic(stat, stat->active_buf);
++
++ /*
++ * Hack: H3A modules may access invalid memory address or send
++ * corrupted data to userspace if more than 1 SBL overflow
++ * happens in a row without re-writing its buffer's start memory
++ * address in the meantime. Such situation is avoided if the
++ * module is not immediately re-enabled when the ISR misses the
++ * timing to process the buffer and to setup the registers.
++ * Because of that, pcr_enable(1) was moved to inside this 'if'
++ * block. But the next interruption will still happen as during
++ * pcr_enable(0) the module was busy.
++ */
++ isp_stat_pcr_enable(stat, 1);
++ spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags);
++ } else {
++ /*
++ * If a SBL overflow occurs and the H3A driver misses the timing
++ * to process the buffer, stat->buf_err is set and won't be
++ * cleared now. So the next buffer will be correctly ignored.
++ * It's necessary due to a hw issue which makes the next H3A
++ * buffer to start from the memory address where the previous
++ * one stopped, instead of start where it was configured to.
++ * Do not "stat->buf_err = 0" here.
++ */
++
++ if (stat->ops->buf_process)
++ /*
++ * Driver may need to erase current data prior to
++ * process a new buffer. If it misses the timing, the
++ * next buffer might be wrong. So should be ignored.
++ * It happens only for Histogram.
++ */
++ atomic_set(&stat->buf_err, 1);
++
++ ret = STAT_NO_BUF;
++ dev_dbg(stat->isp->dev, "%s: cannot process buffer, "
++ "device is busy.\n", stat->subdev.name);
++ }
++
++out:
++ stat->buf_processing = 0;
++ isp_stat_queue_event(stat, ret != STAT_BUF_DONE);
++}
++
++void omap3isp_stat_isr(struct ispstat *stat)
++{
++ __stat_isr(stat, 0);
++}
++
++void omap3isp_stat_dma_isr(struct ispstat *stat)
++{
++ __stat_isr(stat, 1);
++}
++
++static int isp_stat_init_entities(struct ispstat *stat, const char *name,
++ const struct v4l2_subdev_ops *sd_ops)
++{
++ struct v4l2_subdev *subdev = &stat->subdev;
++ struct media_entity *me = &subdev->entity;
++
++ v4l2_subdev_init(subdev, sd_ops);
++ snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "OMAP3 ISP %s", name);
++ subdev->grp_id = 1 << 16; /* group ID for isp subdevs */
++ subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
++ subdev->nevents = STAT_NEVENTS;
++ v4l2_set_subdevdata(subdev, stat);
++
++ stat->pad.flags = MEDIA_PAD_FL_INPUT;
++ me->ops = NULL;
++
++ return media_entity_init(me, 1, &stat->pad, 0);
++}
++
++int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev,
++ struct v4l2_fh *fh,
++ struct v4l2_event_subscription *sub)
++{
++ struct ispstat *stat = v4l2_get_subdevdata(subdev);
++
++ if (sub->type != stat->event_type)
++ return -EINVAL;
++
++ return v4l2_event_subscribe(fh, sub);
++}
++
++int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev,
++ struct v4l2_fh *fh,
++ struct v4l2_event_subscription *sub)
++{
++ return v4l2_event_unsubscribe(fh, sub);
++}
++
++void omap3isp_stat_unregister_entities(struct ispstat *stat)
++{
++ media_entity_cleanup(&stat->subdev.entity);
++ v4l2_device_unregister_subdev(&stat->subdev);
++}
++
++int omap3isp_stat_register_entities(struct ispstat *stat,
++ struct v4l2_device *vdev)
++{
++ return v4l2_device_register_subdev(vdev, &stat->subdev);
++}
++
++int omap3isp_stat_init(struct ispstat *stat, const char *name,
++ const struct v4l2_subdev_ops *sd_ops)
++{
++ stat->buf = kcalloc(STAT_MAX_BUFS, sizeof(*stat->buf), GFP_KERNEL);
++ if (!stat->buf)
++ return -ENOMEM;
++ isp_stat_buf_clear(stat);
++ mutex_init(&stat->ioctl_lock);
++ atomic_set(&stat->buf_err, 0);
++
++ return isp_stat_init_entities(stat, name, sd_ops);
++}
++
++void omap3isp_stat_free(struct ispstat *stat)
++{
++ isp_stat_bufs_free(stat);
++ kfree(stat->buf);
++}
+diff --git a/drivers/media/video/isp/ispstat.h b/drivers/media/video/isp/ispstat.h
+new file mode 100644
+index 0000000..5298d33
+--- /dev/null
++++ b/drivers/media/video/isp/ispstat.h
+@@ -0,0 +1,169 @@
++/*
++ * ispstat.h
++ *
++ * TI OMAP3 ISP - Statistics core
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc
++ *
++ * Contacts: David Cohen <david.cohen@nokia.com>
++ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#ifndef OMAP3_ISP_STAT_H
++#define OMAP3_ISP_STAT_H
++
++#include <linux/types.h>
++#include <linux/omap3isp.h>
++#include <plat/dma.h>
++#include <media/v4l2-event.h>
++
++#include "isp.h"
++#include "ispvideo.h"
++
++#define STAT_MAX_BUFS 5
++#define STAT_NEVENTS 8
++
++#define STAT_BUF_DONE 0 /* Buffer is ready */
++#define STAT_NO_BUF 1 /* An error has occurred */
++#define STAT_BUF_WAITING_DMA 2 /* Histogram only: DMA is running */
++
++struct ispstat;
++
++struct ispstat_buffer {
++ unsigned long iommu_addr;
++ struct iovm_struct *iovm;
++ void *virt_addr;
++ dma_addr_t dma_addr;
++ struct timeval ts;
++ u32 buf_size;
++ u32 frame_number;
++ u16 config_counter;
++ u8 empty;
++};
++
++struct ispstat_ops {
++ /*
++ * Validate new params configuration.
++ * new_conf->buf_size value must be changed to the exact buffer size
++ * necessary for the new configuration if it's smaller.
++ */
++ int (*validate_params)(struct ispstat *stat, void *new_conf);
++
++ /*
++ * Save new params configuration.
++ * stat->priv->buf_size value must be set to the exact buffer size for
++ * the new configuration.
++ * stat->update is set to 1 if new configuration is different than
++ * current one.
++ */
++ void (*set_params)(struct ispstat *stat, void *new_conf);
++
++ /* Apply stored configuration. */
++ void (*setup_regs)(struct ispstat *stat, void *priv);
++
++ /* Enable/Disable module. */
++ void (*enable)(struct ispstat *stat, int enable);
++
++ /* Verify is module is busy. */
++ int (*busy)(struct ispstat *stat);
++
++ /* Used for specific operations during generic buf process task. */
++ int (*buf_process)(struct ispstat *stat);
++};
++
++enum ispstat_state_t {
++ ISPSTAT_DISABLED = 0,
++ ISPSTAT_DISABLING,
++ ISPSTAT_ENABLED,
++ ISPSTAT_ENABLING,
++ ISPSTAT_SUSPENDED,
++};
++
++struct ispstat {
++ struct v4l2_subdev subdev;
++ struct media_pad pad; /* sink pad */
++
++ /* Control */
++ unsigned configured:1;
++ unsigned update:1;
++ unsigned buf_processing:1;
++ unsigned sbl_ovl_recover:1;
++ u8 inc_config;
++ atomic_t buf_err;
++ enum ispstat_state_t state; /* enabling/disabling state */
++ struct omap_dma_channel_params dma_config;
++ struct isp_device *isp;
++ void *priv; /* pointer to priv config struct */
++ void *recover_priv; /* pointer to recover priv configuration */
++ struct mutex ioctl_lock; /* serialize private ioctl */
++
++ const struct ispstat_ops *ops;
++
++ /* Buffer */
++ u8 wait_acc_frames;
++ u16 config_counter;
++ u32 frame_number;
++ u32 buf_size;
++ u32 buf_alloc_size;
++ int dma_ch;
++ unsigned long event_type;
++ struct ispstat_buffer *buf;
++ struct ispstat_buffer *active_buf;
++ struct ispstat_buffer *locked_buf;
++};
++
++struct ispstat_generic_config {
++ /*
++ * Fields must be in the same order as in:
++ * - isph3a_aewb_config
++ * - isph3a_af_config
++ * - isphist_config
++ */
++ u32 buf_size;
++ u16 config_counter;
++};
++
++int omap3isp_stat_config(struct ispstat *stat, void *new_conf);
++int omap3isp_stat_request_statistics(struct ispstat *stat,
++ struct omap3isp_stat_data *data);
++int omap3isp_stat_init(struct ispstat *stat, const char *name,
++ const struct v4l2_subdev_ops *sd_ops);
++void omap3isp_stat_free(struct ispstat *stat);
++int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev,
++ struct v4l2_fh *fh,
++ struct v4l2_event_subscription *sub);
++int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev,
++ struct v4l2_fh *fh,
++ struct v4l2_event_subscription *sub);
++int omap3isp_stat_s_stream(struct v4l2_subdev *subdev, int enable);
++
++int omap3isp_stat_busy(struct ispstat *stat);
++int omap3isp_stat_pcr_busy(struct ispstat *stat);
++void omap3isp_stat_suspend(struct ispstat *stat);
++void omap3isp_stat_resume(struct ispstat *stat);
++int omap3isp_stat_enable(struct ispstat *stat, u8 enable);
++void omap3isp_stat_sbl_overflow(struct ispstat *stat);
++void omap3isp_stat_isr(struct ispstat *stat);
++void omap3isp_stat_isr_frame_sync(struct ispstat *stat);
++void omap3isp_stat_dma_isr(struct ispstat *stat);
++int omap3isp_stat_register_entities(struct ispstat *stat,
++ struct v4l2_device *vdev);
++void omap3isp_stat_unregister_entities(struct ispstat *stat);
++
++#endif /* OMAP3_ISP_STAT_H */
+diff --git a/drivers/media/video/isp/ispvideo.c b/drivers/media/video/isp/ispvideo.c
+new file mode 100644
+index 0000000..ef0adb0
+--- /dev/null
++++ b/drivers/media/video/isp/ispvideo.c
+@@ -0,0 +1,1264 @@
++/*
++ * ispvideo.c
++ *
++ * TI OMAP3 ISP - Generic video node
++ *
++ * Copyright (C) 2009-2010 Nokia Corporation
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#include <asm/cacheflush.h>
++#include <linux/clk.h>
++#include <linux/mm.h>
++#include <linux/pagemap.h>
++#include <linux/scatterlist.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <media/v4l2-dev.h>
++#include <media/v4l2-ioctl.h>
++#include <plat/iommu.h>
++#include <plat/iovmm.h>
++#include <plat/omap-pm.h>
++
++#include "ispvideo.h"
++#include "isp.h"
++
++
++/* -----------------------------------------------------------------------------
++ * Helper functions
++ */
++
++static struct isp_format_info formats[] = {
++ { V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
++ V4L2_MBUS_FMT_Y8_1X8, V4L2_PIX_FMT_GREY, 8, },
++ { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
++ V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10DPCM8, 8, },
++ { V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10,
++ V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10, 10, },
++ { V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG10_1X10,
++ V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10, 10, },
++ { V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10,
++ V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10, 10, },
++ { V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10,
++ V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10, 10, },
++ { V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR10_1X10,
++ V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12, 12, },
++ { V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG10_1X10,
++ V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12, 12, },
++ { V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG10_1X10,
++ V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12, 12, },
++ { V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB10_1X10,
++ V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12, 12, },
++ { V4L2_MBUS_FMT_UYVY8_1X16, V4L2_MBUS_FMT_UYVY8_1X16,
++ V4L2_MBUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 16, },
++ { V4L2_MBUS_FMT_YUYV8_1X16, V4L2_MBUS_FMT_YUYV8_1X16,
++ V4L2_MBUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 16, },
++};
++
++const struct isp_format_info *
++omap3isp_video_format_info(enum v4l2_mbus_pixelcode code)
++{
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_SIZE(formats); ++i) {
++ if (formats[i].code == code)
++ return &formats[i];
++ }
++
++ return NULL;
++}
++
++/*
++ * isp_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format
++ * @video: ISP video instance
++ * @mbus: v4l2_mbus_framefmt format (input)
++ * @pix: v4l2_pix_format format (output)
++ *
++ * Fill the output pix structure with information from the input mbus format.
++ * The bytesperline and sizeimage fields are computed from the requested bytes
++ * per line value in the pix format and information from the video instance.
++ *
++ * Return the number of padding bytes at end of line.
++ */
++static unsigned int isp_video_mbus_to_pix(const struct isp_video *video,
++ const struct v4l2_mbus_framefmt *mbus,
++ struct v4l2_pix_format *pix)
++{
++ unsigned int bpl = pix->bytesperline;
++ unsigned int min_bpl;
++ unsigned int i;
++
++ memset(pix, 0, sizeof(*pix));
++ pix->width = mbus->width;
++ pix->height = mbus->height;
++
++ for (i = 0; i < ARRAY_SIZE(formats); ++i) {
++ if (formats[i].code == mbus->code)
++ break;
++ }
++
++ if (WARN_ON(i == ARRAY_SIZE(formats)))
++ return 0;
++
++ min_bpl = pix->width * ALIGN(formats[i].bpp, 8) / 8;
++
++ /* Clamp the requested bytes per line value. If the maximum bytes per
++ * line value is zero, the module doesn't support user configurable line
++ * sizes. Override the requested value with the minimum in that case.
++ */
++ if (video->bpl_max)
++ bpl = clamp(bpl, min_bpl, video->bpl_max);
++ else
++ bpl = min_bpl;
++
++ if (!video->bpl_zero_padding || bpl != min_bpl)
++ bpl = ALIGN(bpl, video->bpl_alignment);
++
++ pix->pixelformat = formats[i].pixelformat;
++ pix->bytesperline = bpl;
++ pix->sizeimage = pix->bytesperline * pix->height;
++ pix->colorspace = mbus->colorspace;
++ pix->field = mbus->field;
++
++ return bpl - min_bpl;
++}
++
++static void isp_video_pix_to_mbus(const struct v4l2_pix_format *pix,
++ struct v4l2_mbus_framefmt *mbus)
++{
++ unsigned int i;
++
++ memset(mbus, 0, sizeof(*mbus));
++ mbus->width = pix->width;
++ mbus->height = pix->height;
++
++ for (i = 0; i < ARRAY_SIZE(formats); ++i) {
++ if (formats[i].pixelformat == pix->pixelformat)
++ break;
++ }
++
++ if (WARN_ON(i == ARRAY_SIZE(formats)))
++ return;
++
++ mbus->code = formats[i].code;
++ mbus->colorspace = pix->colorspace;
++ mbus->field = pix->field;
++}
++
++static struct v4l2_subdev *
++isp_video_remote_subdev(struct isp_video *video, u32 *pad)
++{
++ struct media_pad *remote;
++
++ remote = media_entity_remote_source(&video->pad);
++
++ if (remote == NULL ||
++ media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
++ return NULL;
++
++ if (pad)
++ *pad = remote->index;
++
++ return media_entity_to_v4l2_subdev(remote->entity);
++}
++
++/* Return a pointer to the ISP video instance at the far end of the pipeline. */
++static struct isp_video *
++isp_video_far_end(struct isp_video *video)
++{
++ struct media_entity_graph graph;
++ struct media_entity *entity = &video->video.entity;
++ struct media_device *mdev = entity->parent;
++ struct isp_video *far_end = NULL;
++
++ mutex_lock(&mdev->graph_mutex);
++ media_entity_graph_walk_start(&graph, entity);
++
++ while ((entity = media_entity_graph_walk_next(&graph))) {
++ if (entity == &video->video.entity)
++ continue;
++
++ if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
++ continue;
++
++ far_end = to_isp_video(media_entity_to_video_device(entity));
++ if (far_end->type != video->type)
++ break;
++
++ far_end = NULL;
++ }
++
++ mutex_unlock(&mdev->graph_mutex);
++ return far_end;
++}
++
++/*
++ * Validate a pipeline by checking both ends of all links for format
++ * discrepancies.
++ *
++ * Compute the minimum time per frame value as the maximum of time per frame
++ * limits reported by every block in the pipeline.
++ *
++ * Return 0 if all formats match, or -EPIPE if at least one link is found with
++ * different formats on its two ends.
++ */
++static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
++{
++ struct isp_device *isp = pipe->output->isp;
++ struct v4l2_subdev_format fmt_source;
++ struct v4l2_subdev_format fmt_sink;
++ struct media_pad *pad;
++ struct v4l2_subdev *subdev;
++ int ret;
++
++ pipe->max_rate = pipe->l3_ick;
++
++ subdev = isp_video_remote_subdev(pipe->output, NULL);
++ if (subdev == NULL)
++ return -EPIPE;
++
++ while (1) {
++ /* Retrieve the sink format */
++ pad = &subdev->entity.pads[0];
++ if (!(pad->flags & MEDIA_PAD_FL_INPUT))
++ break;
++
++ fmt_sink.pad = pad->index;
++ fmt_sink.which = V4L2_SUBDEV_FORMAT_ACTIVE;
++ ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_sink);
++ if (ret < 0 && ret != -ENOIOCTLCMD)
++ return -EPIPE;
++
++ /* Update the maximum frame rate */
++ if (subdev == &isp->isp_res.subdev)
++ omap3isp_resizer_max_rate(&isp->isp_res,
++ &pipe->max_rate);
++
++ /* Check ccdc maximum data rate when data comes from sensor
++ * TODO: Include ccdc rate in pipe->max_rate and compare the
++ * total pipe rate with the input data rate from sensor.
++ */
++ if (subdev == &isp->isp_ccdc.subdev && pipe->input == NULL) {
++ unsigned int rate = UINT_MAX;
++
++ omap3isp_ccdc_max_rate(&isp->isp_ccdc, &rate);
++ if (isp->isp_ccdc.vpcfg.pixelclk > rate)
++ return -ENOSPC;
++ }
++
++ /* Retrieve the source format */
++ pad = media_entity_remote_source(pad);
++ if (pad == NULL ||
++ media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
++ break;
++
++ subdev = media_entity_to_v4l2_subdev(pad->entity);
++
++ fmt_source.pad = pad->index;
++ fmt_source.which = V4L2_SUBDEV_FORMAT_ACTIVE;
++ ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_source);
++ if (ret < 0 && ret != -ENOIOCTLCMD)
++ return -EPIPE;
++
++ /* Check if the two ends match */
++ if (fmt_source.format.code != fmt_sink.format.code ||
++ fmt_source.format.width != fmt_sink.format.width ||
++ fmt_source.format.height != fmt_sink.format.height)
++ return -EPIPE;
++ }
++
++ return 0;
++}
++
++static int
++__isp_video_get_format(struct isp_video *video, struct v4l2_format *format)
++{
++ struct v4l2_subdev_format fmt;
++ struct v4l2_subdev *subdev;
++ u32 pad;
++ int ret;
++
++ subdev = isp_video_remote_subdev(video, &pad);
++ if (subdev == NULL)
++ return -EINVAL;
++
++ mutex_lock(&video->mutex);
++
++ fmt.pad = pad;
++ fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
++ ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
++ if (ret == -ENOIOCTLCMD)
++ ret = -EINVAL;
++
++ mutex_unlock(&video->mutex);
++
++ if (ret)
++ return ret;
++
++ format->type = video->type;
++ return isp_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix);
++}
++
++static int
++isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh)
++{
++ struct v4l2_format format;
++ int ret;
++
++ memcpy(&format, &vfh->format, sizeof(format));
++ ret = __isp_video_get_format(video, &format);
++ if (ret < 0)
++ return ret;
++
++ if (vfh->format.fmt.pix.pixelformat != format.fmt.pix.pixelformat ||
++ vfh->format.fmt.pix.height != format.fmt.pix.height ||
++ vfh->format.fmt.pix.width != format.fmt.pix.width ||
++ vfh->format.fmt.pix.bytesperline != format.fmt.pix.bytesperline ||
++ vfh->format.fmt.pix.sizeimage != format.fmt.pix.sizeimage)
++ return -EINVAL;
++
++ return ret;
++}
++
++/* -----------------------------------------------------------------------------
++ * IOMMU management
++ */
++
++#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8)
++
++/*
++ * ispmmu_vmap - Wrapper for Virtual memory mapping of a scatter gather list
++ * @dev: Device pointer specific to the OMAP3 ISP.
++ * @sglist: Pointer to source Scatter gather list to allocate.
++ * @sglen: Number of elements of the scatter-gatter list.
++ *
++ * Returns a resulting mapped device address by the ISP MMU, or -ENOMEM if
++ * we ran out of memory.
++ */
++static dma_addr_t
++ispmmu_vmap(struct isp_device *isp, const struct scatterlist *sglist, int sglen)
++{
++ struct sg_table *sgt;
++ u32 da;
++
++ sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
++ if (sgt == NULL)
++ return -ENOMEM;
++
++ sgt->sgl = (struct scatterlist *)sglist;
++ sgt->nents = sglen;
++ sgt->orig_nents = sglen;
++
++ da = iommu_vmap(isp->iommu, 0, sgt, IOMMU_FLAG);
++ if (IS_ERR_VALUE(da))
++ kfree(sgt);
++
++ return da;
++}
++
++/*
++ * ispmmu_vunmap - Unmap a device address from the ISP MMU
++ * @dev: Device pointer specific to the OMAP3 ISP.
++ * @da: Device address generated from a ispmmu_vmap call.
++ */
++static void ispmmu_vunmap(struct isp_device *isp, dma_addr_t da)
++{
++ struct sg_table *sgt;
++
++ sgt = iommu_vunmap(isp->iommu, (u32)da);
++ kfree(sgt);
++}
++
++/* -----------------------------------------------------------------------------
++ * Video queue operations
++ */
++
++static void isp_video_queue_prepare(struct isp_video_queue *queue,
++ unsigned int *nbuffers, unsigned int *size)
++{
++ struct isp_video_fh *vfh =
++ container_of(queue, struct isp_video_fh, queue);
++ struct isp_video *video = vfh->video;
++
++ *size = vfh->format.fmt.pix.sizeimage;
++ if (*size == 0)
++ return;
++
++ *nbuffers = min(*nbuffers, video->capture_mem / PAGE_ALIGN(*size));
++}
++
++static void isp_video_buffer_cleanup(struct isp_video_buffer *buf)
++{
++ struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
++ struct isp_buffer *buffer = to_isp_buffer(buf);
++ struct isp_video *video = vfh->video;
++
++ if (buffer->isp_addr) {
++ ispmmu_vunmap(video->isp, buffer->isp_addr);
++ buffer->isp_addr = 0;
++ }
++}
++
++static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
++{
++ struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
++ struct isp_buffer *buffer = to_isp_buffer(buf);
++ struct isp_video *video = vfh->video;
++ unsigned long addr;
++
++ addr = ispmmu_vmap(video->isp, buf->sglist, buf->sglen);
++ if (IS_ERR_VALUE(addr))
++ return -EIO;
++
++ if (!IS_ALIGNED(addr, 32)) {
++ dev_dbg(video->isp->dev, "Buffer address must be "
++ "aligned to 32 bytes boundary.\n");
++ ispmmu_vunmap(video->isp, buffer->isp_addr);
++ return -EINVAL;
++ }
++
++ buf->vbuf.bytesused = vfh->format.fmt.pix.sizeimage;
++ buffer->isp_addr = addr;
++ return 0;
++}
++
++/*
++ * isp_video_buffer_queue - Add buffer to streaming queue
++ * @buf: Video buffer
++ *
++ * In memory-to-memory mode, start streaming on the pipeline if buffers are
++ * queued on both the input and the output, if the pipeline isn't already busy.
++ * If the pipeline is busy, it will be restarted in the output module interrupt
++ * handler.
++ */
++static void isp_video_buffer_queue(struct isp_video_buffer *buf)
++{
++ struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue);
++ struct isp_buffer *buffer = to_isp_buffer(buf);
++ struct isp_video *video = vfh->video;
++ struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
++ enum isp_pipeline_state state;
++ unsigned long flags;
++ unsigned int empty;
++ unsigned int start;
++
++ empty = list_empty(&video->dmaqueue);
++ list_add_tail(&buffer->buffer.irqlist, &video->dmaqueue);
++
++ if (empty) {
++ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ state = ISP_PIPELINE_QUEUE_OUTPUT;
++ else
++ state = ISP_PIPELINE_QUEUE_INPUT;
++
++ spin_lock_irqsave(&pipe->lock, flags);
++ pipe->state |= state;
++ video->ops->queue(video, buffer);
++ video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED;
++
++ start = isp_pipeline_ready(pipe);
++ if (start)
++ pipe->state |= ISP_PIPELINE_STREAM;
++ spin_unlock_irqrestore(&pipe->lock, flags);
++
++ if (start)
++ omap3isp_pipeline_set_stream(pipe,
++ ISP_PIPELINE_STREAM_SINGLESHOT);
++ }
++}
++
++static const struct isp_video_queue_operations isp_video_queue_ops = {
++ .queue_prepare = &isp_video_queue_prepare,
++ .buffer_prepare = &isp_video_buffer_prepare,
++ .buffer_queue = &isp_video_buffer_queue,
++ .buffer_cleanup = &isp_video_buffer_cleanup,
++};
++
++/*
++ * omap3isp_video_buffer_next - Complete the current buffer and return the next
++ * @video: ISP video object
++ * @error: Whether an error occured during capture
++ *
++ * Remove the current video buffer from the DMA queue and fill its timestamp,
++ * field count and state fields before waking up its completion handler.
++ *
++ * The buffer state is set to VIDEOBUF_DONE if no error occured (@error is 0)
++ * or VIDEOBUF_ERROR otherwise (@error is non-zero).
++ *
++ * The DMA queue is expected to contain at least one buffer.
++ *
++ * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is
++ * empty.
++ */
++struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video,
++ unsigned int error)
++{
++ struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
++ struct isp_video_queue *queue = video->queue;
++ enum isp_pipeline_state state;
++ struct isp_video_buffer *buf;
++ unsigned long flags;
++ struct timespec ts;
++
++ spin_lock_irqsave(&queue->irqlock, flags);
++ if (WARN_ON(list_empty(&video->dmaqueue))) {
++ spin_unlock_irqrestore(&queue->irqlock, flags);
++ return NULL;
++ }
++
++ buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer,
++ irqlist);
++ list_del(&buf->irqlist);
++ spin_unlock_irqrestore(&queue->irqlock, flags);
++
++ ktime_get_ts(&ts);
++ buf->vbuf.timestamp.tv_sec = ts.tv_sec;
++ buf->vbuf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
++
++ /* Do frame number propagation only if this is the output video node.
++ * Frame number either comes from the CSI receivers or it gets
++ * incremented here if H3A is not active.
++ * Note: There is no guarantee that the output buffer will finish
++ * first, so the input number might lag behind by 1 in some cases.
++ */
++ if (video == pipe->output && !pipe->do_propagation)
++ buf->vbuf.sequence = atomic_inc_return(&pipe->frame_number);
++ else
++ buf->vbuf.sequence = atomic_read(&pipe->frame_number);
++
++ buf->state = error ? ISP_BUF_STATE_ERROR : ISP_BUF_STATE_DONE;
++
++ wake_up(&buf->wait);
++
++ if (list_empty(&video->dmaqueue)) {
++ if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ state = ISP_PIPELINE_QUEUE_OUTPUT
++ | ISP_PIPELINE_STREAM;
++ else
++ state = ISP_PIPELINE_QUEUE_INPUT
++ | ISP_PIPELINE_STREAM;
++
++ spin_lock_irqsave(&pipe->lock, flags);
++ pipe->state &= ~state;
++ if (video->pipe.stream_state == ISP_PIPELINE_STREAM_CONTINUOUS)
++ video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
++ spin_unlock_irqrestore(&pipe->lock, flags);
++ return NULL;
++ }
++
++ if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->input != NULL) {
++ spin_lock_irqsave(&pipe->lock, flags);
++ pipe->state &= ~ISP_PIPELINE_STREAM;
++ spin_unlock_irqrestore(&pipe->lock, flags);
++ }
++
++ buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer,
++ irqlist);
++ buf->state = ISP_BUF_STATE_ACTIVE;
++ return to_isp_buffer(buf);
++}
++
++/*
++ * omap3isp_video_resume - Perform resume operation on the buffers
++ * @video: ISP video object
++ * @continuous: Pipeline is in single shot mode if 0 or continous mode otherwise
++ *
++ * This function is intended to be used on suspend/resume scenario. It
++ * requests video queue layer to discard buffers marked as DONE if it's in
++ * continuous mode and requests ISP modules to queue again the ACTIVE buffer
++ * if there's any.
++ */
++void omap3isp_video_resume(struct isp_video *video, int continuous)
++{
++ struct isp_buffer *buf = NULL;
++
++ if (continuous && video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ omap3isp_video_queue_discard_done(video->queue);
++
++ if (!list_empty(&video->dmaqueue)) {
++ buf = list_first_entry(&video->dmaqueue,
++ struct isp_buffer, buffer.irqlist);
++ video->ops->queue(video, buf);
++ video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED;
++ } else {
++ if (continuous)
++ video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
++ }
++}
++
++/* -----------------------------------------------------------------------------
++ * V4L2 ioctls
++ */
++
++static int
++isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
++{
++ struct isp_video *video = video_drvdata(file);
++
++ strlcpy(cap->driver, ISP_VIDEO_DRIVER_NAME, sizeof(cap->driver));
++ strlcpy(cap->card, video->video.name, sizeof(cap->card));
++ strlcpy(cap->bus_info, "media", sizeof(cap->bus_info));
++ cap->version = ISP_VIDEO_DRIVER_VERSION;
++
++ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
++ else
++ cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
++
++ return 0;
++}
++
++static int
++isp_video_get_format(struct file *file, void *fh, struct v4l2_format *format)
++{
++ struct isp_video_fh *vfh = to_isp_video_fh(fh);
++ struct isp_video *video = video_drvdata(file);
++
++ if (format->type != video->type)
++ return -EINVAL;
++
++ mutex_lock(&video->mutex);
++ *format = vfh->format;
++ mutex_unlock(&video->mutex);
++
++ return 0;
++}
++
++static int
++isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format)
++{
++ struct isp_video_fh *vfh = to_isp_video_fh(fh);
++ struct isp_video *video = video_drvdata(file);
++ struct v4l2_mbus_framefmt fmt;
++
++ if (format->type != video->type)
++ return -EINVAL;
++
++ mutex_lock(&video->mutex);
++
++ /* Fill the bytesperline and sizeimage fields by converting to media bus
++ * format and back to pixel format.
++ */
++ isp_video_pix_to_mbus(&format->fmt.pix, &fmt);
++ isp_video_mbus_to_pix(video, &fmt, &format->fmt.pix);
++
++ vfh->format = *format;
++
++ mutex_unlock(&video->mutex);
++ return 0;
++}
++
++static int
++isp_video_try_format(struct file *file, void *fh, struct v4l2_format *format)
++{
++ struct isp_video *video = video_drvdata(file);
++ struct v4l2_subdev_format fmt;
++ struct v4l2_subdev *subdev;
++ u32 pad;
++ int ret;
++
++ if (format->type != video->type)
++ return -EINVAL;
++
++ subdev = isp_video_remote_subdev(video, &pad);
++ if (subdev == NULL)
++ return -EINVAL;
++
++ isp_video_pix_to_mbus(&format->fmt.pix, &fmt.format);
++
++ fmt.pad = pad;
++ fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
++ ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
++ if (ret)
++ return ret == -ENOIOCTLCMD ? -EINVAL : ret;
++
++ isp_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix);
++ return 0;
++}
++
++static int
++isp_video_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap)
++{
++ struct isp_video *video = video_drvdata(file);
++ struct v4l2_subdev *subdev;
++ int ret;
++
++ subdev = isp_video_remote_subdev(video, NULL);
++ if (subdev == NULL)
++ return -EINVAL;
++
++ mutex_lock(&video->mutex);
++ ret = v4l2_subdev_call(subdev, video, cropcap, cropcap);
++ mutex_unlock(&video->mutex);
++
++ return ret == -ENOIOCTLCMD ? -EINVAL : ret;
++}
++
++static int
++isp_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop)
++{
++ struct isp_video *video = video_drvdata(file);
++ struct v4l2_subdev_format format;
++ struct v4l2_subdev *subdev;
++ u32 pad;
++ int ret;
++
++ subdev = isp_video_remote_subdev(video, &pad);
++ if (subdev == NULL)
++ return -EINVAL;
++
++ /* Try the get crop operation first and fallback to get format if not
++ * implemented.
++ */
++ ret = v4l2_subdev_call(subdev, video, g_crop, crop);
++ if (ret != -ENOIOCTLCMD)
++ return ret;
++
++ format.pad = pad;
++ format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
++ ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &format);
++ if (ret < 0)
++ return ret == -ENOIOCTLCMD ? -EINVAL : ret;
++
++ crop->c.left = 0;
++ crop->c.top = 0;
++ crop->c.width = format.format.width;
++ crop->c.height = format.format.height;
++
++ return 0;
++}
++
++static int
++isp_video_set_crop(struct file *file, void *fh, struct v4l2_crop *crop)
++{
++ struct isp_video *video = video_drvdata(file);
++ struct v4l2_subdev *subdev;
++ int ret;
++
++ subdev = isp_video_remote_subdev(video, NULL);
++ if (subdev == NULL)
++ return -EINVAL;
++
++ mutex_lock(&video->mutex);
++ ret = v4l2_subdev_call(subdev, video, s_crop, crop);
++ mutex_unlock(&video->mutex);
++
++ return ret == -ENOIOCTLCMD ? -EINVAL : ret;
++}
++
++static int
++isp_video_get_param(struct file *file, void *fh, struct v4l2_streamparm *a)
++{
++ struct isp_video_fh *vfh = to_isp_video_fh(fh);
++ struct isp_video *video = video_drvdata(file);
++
++ if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
++ video->type != a->type)
++ return -EINVAL;
++
++ memset(a, 0, sizeof(*a));
++ a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
++ a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
++ a->parm.output.timeperframe = vfh->timeperframe;
++
++ return 0;
++}
++
++static int
++isp_video_set_param(struct file *file, void *fh, struct v4l2_streamparm *a)
++{
++ struct isp_video_fh *vfh = to_isp_video_fh(fh);
++ struct isp_video *video = video_drvdata(file);
++
++ if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
++ video->type != a->type)
++ return -EINVAL;
++
++ if (a->parm.output.timeperframe.denominator == 0)
++ a->parm.output.timeperframe.denominator = 1;
++
++ vfh->timeperframe = a->parm.output.timeperframe;
++
++ return 0;
++}
++
++static int
++isp_video_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb)
++{
++ struct isp_video_fh *vfh = to_isp_video_fh(fh);
++
++ return omap3isp_video_queue_reqbufs(&vfh->queue, rb);
++}
++
++static int
++isp_video_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
++{
++ struct isp_video_fh *vfh = to_isp_video_fh(fh);
++
++ return omap3isp_video_queue_querybuf(&vfh->queue, b);
++}
++
++static int
++isp_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
++{
++ struct isp_video_fh *vfh = to_isp_video_fh(fh);
++
++ return omap3isp_video_queue_qbuf(&vfh->queue, b);
++}
++
++static int
++isp_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
++{
++ struct isp_video_fh *vfh = to_isp_video_fh(fh);
++
++ return omap3isp_video_queue_dqbuf(&vfh->queue, b,
++ file->f_flags & O_NONBLOCK);
++}
++
++/*
++ * Stream management
++ *
++ * Every ISP pipeline has a single input and a single output. The input can be
++ * either a sensor or a video node. The output is always a video node.
++ *
++ * As every pipeline has an output video node, the ISP video objects at the
++ * pipeline output stores the pipeline state. It tracks the streaming state of
++ * both the input and output, as well as the availability of buffers.
++ *
++ * In sensor-to-memory mode, frames are always available at the pipeline input.
++ * Starting the sensor usually requires I2C transfers and must be done in
++ * interruptible context. The pipeline is started and stopped synchronously
++ * to the stream on/off commands. All modules in the pipeline will get their
++ * subdev set stream handler called. The module at the end of the pipeline must
++ * delay starting the hardware until buffers are available at its output.
++ *
++ * In memory-to-memory mode, starting/stopping the stream requires
++ * synchronization between the input and output. ISP modules can't be stopped
++ * in the middle of a frame, and at least some of the modules seem to become
++ * busy as soon as they're started, even if they don't receive a frame start
++ * event. For that reason frames need to be processed in single-shot mode. The
++ * driver needs to wait until a frame is completely processed and written to
++ * memory before restarting the pipeline for the next frame. Pipelined
++ * processing might be possible but requires more testing.
++ *
++ * Stream start must be delayed until buffers are available at both the input
++ * and output. The pipeline must be started in the videobuf queue callback with
++ * the buffers queue spinlock held. The modules subdev set stream operation must
++ * not sleep.
++ */
++static int
++isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
++{
++ struct isp_video_fh *vfh = to_isp_video_fh(fh);
++ struct isp_video *video = video_drvdata(file);
++ enum isp_pipeline_state state;
++ struct isp_pipeline *pipe;
++ struct isp_video *far_end;
++ unsigned long flags;
++ int ret;
++
++ if (type != video->type)
++ return -EINVAL;
++
++ mutex_lock(&video->stream_lock);
++
++ if (video->streaming) {
++ mutex_unlock(&video->stream_lock);
++ return -EBUSY;
++ }
++
++ /* Start streaming on the pipeline. No link touching an entity in the
++ * pipeline can be activated or deactivated once streaming is started.
++ */
++ pipe = video->video.entity.pipe
++ ? to_isp_pipeline(&video->video.entity) : &video->pipe;
++ media_entity_pipeline_start(&video->video.entity, &pipe->pipe);
++
++ /* Verify that the currently configured format matches the output of
++ * the connected subdev.
++ */
++ ret = isp_video_check_format(video, vfh);
++ if (ret < 0)
++ goto error;
++
++ video->bpl_padding = ret;
++ video->bpl_value = vfh->format.fmt.pix.bytesperline;
++
++ /* Find the ISP video node connected at the far end of the pipeline and
++ * update the pipeline.
++ */
++ far_end = isp_video_far_end(video);
++
++ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
++ state = ISP_PIPELINE_STREAM_OUTPUT | ISP_PIPELINE_IDLE_OUTPUT;
++ pipe->input = far_end;
++ pipe->output = video;
++ } else {
++ if (far_end == NULL) {
++ ret = -EPIPE;
++ goto error;
++ }
++
++ state = ISP_PIPELINE_STREAM_INPUT | ISP_PIPELINE_IDLE_INPUT;
++ pipe->input = video;
++ pipe->output = far_end;
++ }
++
++ /* Make sure the interconnect clock runs fast enough.
++ *
++ * Formula from: resource34xx.c set_opp()
++ * If MPU freq is above 500MHz, make sure the interconnect
++ * is at 100Mhz or above.
++ * throughput in KiB/s for 100 Mhz = 100 * 1000 * 4.
++ *
++ * We want to be fast enough then set OCP clock to be max as
++ * possible, in that case 185Mhz then:
++ * throughput in KiB/s for 185Mhz = 185 * 1000 * 4 = 740000 KiB/s
++ */
++ omap_pm_set_min_bus_tput(video->isp->dev, OCP_INITIATOR_AGENT, 740000);
++ pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]);
++
++ /* Validate the pipeline and update its state. */
++ ret = isp_video_validate_pipeline(pipe);
++ if (ret < 0)
++ goto error;
++
++ spin_lock_irqsave(&pipe->lock, flags);
++ pipe->state &= ~ISP_PIPELINE_STREAM;
++ pipe->state |= state;
++ spin_unlock_irqrestore(&pipe->lock, flags);
++
++ /* Set the maximum time per frame as the value requested by userspace.
++ * This is a soft limit that can be overridden if the hardware doesn't
++ * support the request limit.
++ */
++ if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
++ pipe->max_timeperframe = vfh->timeperframe;
++
++ video->queue = &vfh->queue;
++ INIT_LIST_HEAD(&video->dmaqueue);
++ atomic_set(&pipe->frame_number, -1);
++
++ ret = omap3isp_video_queue_streamon(&vfh->queue);
++ if (ret < 0)
++ goto error;
++
++ /* In sensor-to-memory mode, the stream can be started synchronously
++ * to the stream on command. In memory-to-memory mode, it will be
++ * started when buffers are queued on both the input and output.
++ */
++ if (pipe->input == NULL) {
++ ret = omap3isp_pipeline_set_stream(pipe,
++ ISP_PIPELINE_STREAM_CONTINUOUS);
++ if (ret < 0)
++ goto error;
++ spin_lock_irqsave(&video->queue->irqlock, flags);
++ if (list_empty(&video->dmaqueue))
++ video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
++ spin_unlock_irqrestore(&video->queue->irqlock, flags);
++ }
++
++error:
++ if (ret < 0) {
++ omap3isp_video_queue_streamoff(&vfh->queue);
++ omap_pm_set_min_bus_tput(video->isp->dev,
++ OCP_INITIATOR_AGENT, 0);
++ media_entity_pipeline_stop(&video->video.entity);
++ video->queue = NULL;
++ }
++
++ if (!ret)
++ video->streaming = 1;
++
++ mutex_unlock(&video->stream_lock);
++ return ret;
++}
++
++static int
++isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
++{
++ struct isp_video_fh *vfh = to_isp_video_fh(fh);
++ struct isp_video *video = video_drvdata(file);
++ struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity);
++ enum isp_pipeline_state state;
++ unsigned int streaming;
++ unsigned long flags;
++
++ if (type != video->type)
++ return -EINVAL;
++
++ mutex_lock(&video->stream_lock);
++
++ /* Make sure we're not streaming yet. */
++ mutex_lock(&vfh->queue.lock);
++ streaming = vfh->queue.streaming;
++ mutex_unlock(&vfh->queue.lock);
++
++ if (!streaming)
++ goto done;
++
++ /* Update the pipeline state. */
++ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ state = ISP_PIPELINE_STREAM_OUTPUT
++ | ISP_PIPELINE_QUEUE_OUTPUT;
++ else
++ state = ISP_PIPELINE_STREAM_INPUT
++ | ISP_PIPELINE_QUEUE_INPUT;
++
++ spin_lock_irqsave(&pipe->lock, flags);
++ pipe->state &= ~state;
++ spin_unlock_irqrestore(&pipe->lock, flags);
++
++ /* Stop the stream. */
++ omap3isp_pipeline_set_stream(pipe, ISP_PIPELINE_STREAM_STOPPED);
++ omap3isp_video_queue_streamoff(&vfh->queue);
++ video->queue = NULL;
++ video->streaming = 0;
++
++ omap_pm_set_min_bus_tput(video->isp->dev, OCP_INITIATOR_AGENT, 0);
++ media_entity_pipeline_stop(&video->video.entity);
++
++done:
++ mutex_unlock(&video->stream_lock);
++ return 0;
++}
++
++static int
++isp_video_enum_input(struct file *file, void *fh, struct v4l2_input *input)
++{
++ if (input->index > 0)
++ return -EINVAL;
++
++ strlcpy(input->name, "camera", sizeof(input->name));
++ input->type = V4L2_INPUT_TYPE_CAMERA;
++
++ return 0;
++}
++
++static int
++isp_video_g_input(struct file *file, void *fh, unsigned int *input)
++{
++ *input = 0;
++
++ return 0;
++}
++
++static int
++isp_video_s_input(struct file *file, void *fh, unsigned int input)
++{
++ return input == 0 ? 0 : -EINVAL;
++}
++
++static const struct v4l2_ioctl_ops isp_video_ioctl_ops = {
++ .vidioc_querycap = isp_video_querycap,
++ .vidioc_g_fmt_vid_cap = isp_video_get_format,
++ .vidioc_s_fmt_vid_cap = isp_video_set_format,
++ .vidioc_try_fmt_vid_cap = isp_video_try_format,
++ .vidioc_g_fmt_vid_out = isp_video_get_format,
++ .vidioc_s_fmt_vid_out = isp_video_set_format,
++ .vidioc_try_fmt_vid_out = isp_video_try_format,
++ .vidioc_cropcap = isp_video_cropcap,
++ .vidioc_g_crop = isp_video_get_crop,
++ .vidioc_s_crop = isp_video_set_crop,
++ .vidioc_g_parm = isp_video_get_param,
++ .vidioc_s_parm = isp_video_set_param,
++ .vidioc_reqbufs = isp_video_reqbufs,
++ .vidioc_querybuf = isp_video_querybuf,
++ .vidioc_qbuf = isp_video_qbuf,
++ .vidioc_dqbuf = isp_video_dqbuf,
++ .vidioc_streamon = isp_video_streamon,
++ .vidioc_streamoff = isp_video_streamoff,
++ .vidioc_enum_input = isp_video_enum_input,
++ .vidioc_g_input = isp_video_g_input,
++ .vidioc_s_input = isp_video_s_input,
++};
++
++/* -----------------------------------------------------------------------------
++ * V4L2 file operations
++ */
++
++static int isp_video_open(struct file *file)
++{
++ struct isp_video *video = video_drvdata(file);
++ struct isp_video_fh *handle;
++ int ret = 0;
++
++ handle = kzalloc(sizeof(*handle), GFP_KERNEL);
++ if (handle == NULL)
++ return -ENOMEM;
++
++ v4l2_fh_init(&handle->vfh, &video->video);
++ v4l2_fh_add(&handle->vfh);
++
++ /* If this is the first user, initialise the pipeline. */
++ if (omap3isp_get(video->isp) == NULL) {
++ ret = -EBUSY;
++ goto done;
++ }
++
++ ret = omap3isp_pipeline_pm_use(&video->video.entity, 1);
++ if (ret < 0) {
++ omap3isp_put(video->isp);
++ goto done;
++ }
++
++ omap3isp_video_queue_init(&handle->queue, video->type,
++ &isp_video_queue_ops, video->isp->dev,
++ sizeof(struct isp_buffer));
++
++ memset(&handle->format, 0, sizeof(handle->format));
++ handle->format.type = video->type;
++ handle->timeperframe.denominator = 1;
++
++ handle->video = video;
++ file->private_data = &handle->vfh;
++
++done:
++ if (ret < 0) {
++ v4l2_fh_del(&handle->vfh);
++ kfree(handle);
++ }
++
++ return ret;
++}
++
++static int isp_video_release(struct file *file)
++{
++ struct isp_video *video = video_drvdata(file);
++ struct v4l2_fh *vfh = file->private_data;
++ struct isp_video_fh *handle = to_isp_video_fh(vfh);
++
++ /* Disable streaming and free the buffers queue resources. */
++ isp_video_streamoff(file, vfh, video->type);
++
++ mutex_lock(&handle->queue.lock);
++ omap3isp_video_queue_cleanup(&handle->queue);
++ mutex_unlock(&handle->queue.lock);
++
++ omap3isp_pipeline_pm_use(&video->video.entity, 0);
++
++ /* Release the file handle. */
++ v4l2_fh_del(vfh);
++ kfree(handle);
++ file->private_data = NULL;
++
++ omap3isp_put(video->isp);
++
++ return 0;
++}
++
++static unsigned int isp_video_poll(struct file *file, poll_table *wait)
++{
++ struct isp_video_fh *vfh = to_isp_video_fh(file->private_data);
++ struct isp_video_queue *queue = &vfh->queue;
++
++ return omap3isp_video_queue_poll(queue, file, wait);
++}
++
++static int isp_video_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ struct isp_video_fh *vfh = to_isp_video_fh(file->private_data);
++
++ return omap3isp_video_queue_mmap(&vfh->queue, vma);
++}
++
++static struct v4l2_file_operations isp_video_fops = {
++ .owner = THIS_MODULE,
++ .unlocked_ioctl = video_ioctl2,
++ .open = isp_video_open,
++ .release = isp_video_release,
++ .poll = isp_video_poll,
++ .mmap = isp_video_mmap,
++};
++
++/* -----------------------------------------------------------------------------
++ * ISP video core
++ */
++
++static const struct isp_video_operations isp_video_dummy_ops = {
++};
++
++int omap3isp_video_init(struct isp_video *video, const char *name)
++{
++ const char *direction;
++ int ret;
++
++ switch (video->type) {
++ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
++ direction = "output";
++ video->pad.flags = MEDIA_PAD_FL_INPUT;
++ break;
++ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
++ direction = "input";
++ video->pad.flags = MEDIA_PAD_FL_OUTPUT;
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ ret = media_entity_init(&video->video.entity, 1, &video->pad, 0);
++ if (ret < 0)
++ return ret;
++
++ mutex_init(&video->mutex);
++ atomic_set(&video->active, 0);
++
++ spin_lock_init(&video->pipe.lock);
++ mutex_init(&video->stream_lock);
++
++ /* Initialize the video device. */
++ if (video->ops == NULL)
++ video->ops = &isp_video_dummy_ops;
++
++ video->video.fops = &isp_video_fops;
++ snprintf(video->video.name, sizeof(video->video.name),
++ "OMAP3 ISP %s %s", name, direction);
++ video->video.vfl_type = VFL_TYPE_GRABBER;
++ video->video.release = video_device_release_empty;
++ video->video.ioctl_ops = &isp_video_ioctl_ops;
++ video->pipe.stream_state = ISP_PIPELINE_STREAM_STOPPED;
++
++ video_set_drvdata(&video->video, video);
++
++ return 0;
++}
++
++int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev)
++{
++ int ret;
++
++ video->video.v4l2_dev = vdev;
++
++ ret = video_register_device(&video->video, VFL_TYPE_GRABBER, -1);
++ if (ret < 0)
++ printk(KERN_ERR "%s: could not register video device (%d)\n",
++ __func__, ret);
++
++ return ret;
++}
++
++void omap3isp_video_unregister(struct isp_video *video)
++{
++ if (video_is_registered(&video->video)) {
++ media_entity_cleanup(&video->video.entity);
++ video_unregister_device(&video->video);
++ }
++}
+diff --git a/drivers/media/video/isp/ispvideo.h b/drivers/media/video/isp/ispvideo.h
+new file mode 100644
+index 0000000..41c8fb9
+--- /dev/null
++++ b/drivers/media/video/isp/ispvideo.h
+@@ -0,0 +1,202 @@
++/*
++ * ispvideo.h
++ *
++ * TI OMAP3 ISP - Generic video node
++ *
++ * Copyright (C) 2009-2010 Nokia Corporation
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#ifndef OMAP3_ISP_VIDEO_H
++#define OMAP3_ISP_VIDEO_H
++
++#include <linux/v4l2-mediabus.h>
++#include <linux/version.h>
++#include <media/media-entity.h>
++#include <media/v4l2-dev.h>
++#include <media/v4l2-fh.h>
++
++#include "ispqueue.h"
++
++#define ISP_VIDEO_DRIVER_NAME "ispvideo"
++#define ISP_VIDEO_DRIVER_VERSION KERNEL_VERSION(0, 0, 1)
++
++struct isp_device;
++struct isp_video;
++struct v4l2_mbus_framefmt;
++struct v4l2_pix_format;
++
++/*
++ * struct isp_format_info - ISP media bus format information
++ * @code: V4L2 media bus format code
++ * @truncated: V4L2 media bus format code for the same format truncated to 10
++ * bits. Identical to @code if the format is 10 bits wide or less.
++ * @uncompressed: V4L2 media bus format code for the corresponding uncompressed
++ * format. Identical to @code if the format is not DPCM compressed.
++ * @pixelformat: V4L2 pixel format FCC identifier
++ * @bpp: Bits per pixel
++ */
++struct isp_format_info {
++ enum v4l2_mbus_pixelcode code;
++ enum v4l2_mbus_pixelcode truncated;
++ enum v4l2_mbus_pixelcode uncompressed;
++ u32 pixelformat;
++ unsigned int bpp;
++};
++
++enum isp_pipeline_stream_state {
++ ISP_PIPELINE_STREAM_STOPPED = 0,
++ ISP_PIPELINE_STREAM_CONTINUOUS = 1,
++ ISP_PIPELINE_STREAM_SINGLESHOT = 2,
++};
++
++enum isp_pipeline_state {
++ /* The stream has been started on the input video node. */
++ ISP_PIPELINE_STREAM_INPUT = 1,
++ /* The stream has been started on the output video node. */
++ ISP_PIPELINE_STREAM_OUTPUT = 2,
++ /* At least one buffer is queued on the input video node. */
++ ISP_PIPELINE_QUEUE_INPUT = 4,
++ /* At least one buffer is queued on the output video node. */
++ ISP_PIPELINE_QUEUE_OUTPUT = 8,
++ /* The input entity is idle, ready to be started. */
++ ISP_PIPELINE_IDLE_INPUT = 16,
++ /* The output entity is idle, ready to be started. */
++ ISP_PIPELINE_IDLE_OUTPUT = 32,
++ /* The pipeline is currently streaming. */
++ ISP_PIPELINE_STREAM = 64,
++};
++
++struct isp_pipeline {
++ struct media_pipeline pipe;
++ spinlock_t lock;
++ unsigned int state;
++ enum isp_pipeline_stream_state stream_state;
++ struct isp_video *input;
++ struct isp_video *output;
++ unsigned long l3_ick;
++ unsigned int max_rate;
++ atomic_t frame_number;
++ bool do_propagation; /* of frame number */
++ struct v4l2_fract max_timeperframe;
++};
++
++#define to_isp_pipeline(__e) \
++ container_of((__e)->pipe, struct isp_pipeline, pipe)
++
++static inline int isp_pipeline_ready(struct isp_pipeline *pipe)
++{
++ return pipe->state == (ISP_PIPELINE_STREAM_INPUT |
++ ISP_PIPELINE_STREAM_OUTPUT |
++ ISP_PIPELINE_QUEUE_INPUT |
++ ISP_PIPELINE_QUEUE_OUTPUT |
++ ISP_PIPELINE_IDLE_INPUT |
++ ISP_PIPELINE_IDLE_OUTPUT);
++}
++
++/*
++ * struct isp_buffer - ISP buffer
++ * @buffer: ISP video buffer
++ * @isp_addr: MMU mapped address (a.k.a. device address) of the buffer.
++ */
++struct isp_buffer {
++ struct isp_video_buffer buffer;
++ dma_addr_t isp_addr;
++};
++
++#define to_isp_buffer(buf) container_of(buf, struct isp_buffer, buffer)
++
++enum isp_video_dmaqueue_flags {
++ /* Set if DMA queue becomes empty when ISP_PIPELINE_STREAM_CONTINUOUS */
++ ISP_VIDEO_DMAQUEUE_UNDERRUN = (1 << 0),
++ /* Set when queuing buffer to an empty DMA queue */
++ ISP_VIDEO_DMAQUEUE_QUEUED = (1 << 1),
++};
++
++#define isp_video_dmaqueue_flags_clr(video) \
++ ({ (video)->dmaqueue_flags = 0; })
++
++/*
++ * struct isp_video_operations - ISP video operations
++ * @queue: Resume streaming when a buffer is queued. Called on VIDIOC_QBUF
++ * if there was no buffer previously queued.
++ */
++struct isp_video_operations {
++ int(*queue)(struct isp_video *video, struct isp_buffer *buffer);
++};
++
++struct isp_video {
++ struct video_device video;
++ enum v4l2_buf_type type;
++ struct media_pad pad;
++
++ struct mutex mutex;
++ atomic_t active;
++
++ struct isp_device *isp;
++
++ unsigned int capture_mem;
++ unsigned int bpl_alignment; /* alignment value */
++ unsigned int bpl_zero_padding; /* whether the alignment is optional */
++ unsigned int bpl_max; /* maximum bytes per line value */
++ unsigned int bpl_value; /* bytes per line value */
++ unsigned int bpl_padding; /* padding at end of line */
++
++ /* Entity video node streaming */
++ unsigned int streaming:1;
++
++ /* Pipeline state */
++ struct isp_pipeline pipe;
++ struct mutex stream_lock;
++
++ /* Video buffers queue */
++ struct isp_video_queue *queue;
++ struct list_head dmaqueue;
++ enum isp_video_dmaqueue_flags dmaqueue_flags;
++
++ const struct isp_video_operations *ops;
++};
++
++#define to_isp_video(vdev) container_of(vdev, struct isp_video, video)
++
++struct isp_video_fh {
++ struct v4l2_fh vfh;
++ struct isp_video *video;
++ struct isp_video_queue queue;
++ struct v4l2_format format;
++ struct v4l2_fract timeperframe;
++};
++
++#define to_isp_video_fh(fh) container_of(fh, struct isp_video_fh, vfh)
++#define isp_video_queue_to_isp_video_fh(q) \
++ container_of(q, struct isp_video_fh, queue)
++
++int omap3isp_video_init(struct isp_video *video, const char *name);
++int omap3isp_video_register(struct isp_video *video,
++ struct v4l2_device *vdev);
++void omap3isp_video_unregister(struct isp_video *video);
++struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video,
++ unsigned int error);
++void omap3isp_video_resume(struct isp_video *video, int continuous);
++struct media_pad *omap3isp_video_remote_pad(struct isp_video *video);
++
++const struct isp_format_info *
++omap3isp_video_format_info(enum v4l2_mbus_pixelcode code);
++
++#endif /* OMAP3_ISP_VIDEO_H */
+diff --git a/drivers/media/video/isp/luma_enhance_table.h b/drivers/media/video/isp/luma_enhance_table.h
+new file mode 100644
+index 0000000..56d93c2
+--- /dev/null
++++ b/drivers/media/video/isp/luma_enhance_table.h
+@@ -0,0 +1,154 @@
++/*
++ * luma_enhance_table.h
++ *
++ * TI OMAP3 ISP - Luminance enhancement table
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc.
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1047552,
++1048575,
++1047551,
++1046527,
++1045503,
++1044479,
++1043455,
++1042431,
++1041407,
++1040383,
++1039359,
++1038335,
++1037311,
++1036287,
++1035263,
++1034239,
++1033215,
++1032191,
++1031167,
++1030143,
++1028096,
++1028096,
++1028096,
++1028096,
++1028096,
++1028096,
++1028096,
++1028096,
++1028096,
++1028096,
++1028100,
++1032196,
++1036292,
++1040388,
++1044484,
++0,
++0,
++0,
++5,
++5125,
++10245,
++15365,
++20485,
++25605,
++30720,
++30720,
++30720,
++30720,
++30720,
++30720,
++30720,
++30720,
++30720,
++30720,
++30720,
++31743,
++30719,
++29695,
++28671,
++27647,
++26623,
++25599,
++24575,
++23551,
++22527,
++21503,
++20479,
++19455,
++18431,
++17407,
++16383,
++15359,
++14335,
++13311,
++12287,
++11263,
++10239,
++9215,
++8191,
++7167,
++6143,
++5119,
++4095,
++3071,
++1024,
++1024,
++1024,
++1024,
++1024,
++1024,
++1024,
++1024,
++1024,
++1024,
++1024,
++1024,
++1024,
++1024,
++1024,
++1024,
++1024
+diff --git a/drivers/media/video/isp/noise_filter_table.h b/drivers/media/video/isp/noise_filter_table.h
+new file mode 100644
+index 0000000..4b4c085
+--- /dev/null
++++ b/drivers/media/video/isp/noise_filter_table.h
+@@ -0,0 +1,90 @@
++/*
++ * noise_filter_table.h
++ *
++ * TI OMAP3 ISP - Noise filter table
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc.
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++16,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31,
++31
+diff --git a/include/linux/Kbuild b/include/linux/Kbuild
+index c0db7f4..f65f612 100644
+--- a/include/linux/Kbuild
++++ b/include/linux/Kbuild
+@@ -272,6 +272,7 @@ header-y += nfsacl.h
+ header-y += nl80211.h
+ header-y += nubus.h
+ header-y += nvram.h
++header-y += omap3isp.h
+ header-y += omapfb.h
+ header-y += oom.h
+ header-y += param.h
+diff --git a/include/linux/omap3isp.h b/include/linux/omap3isp.h
+new file mode 100644
+index 0000000..ab249b2
+--- /dev/null
++++ b/include/linux/omap3isp.h
+@@ -0,0 +1,631 @@
++/*
++ * omap3isp.h
++ *
++ * TI OMAP3 ISP - User-space API
++ *
++ * Copyright (C) 2010 Nokia Corporation
++ * Copyright (C) 2009 Texas Instruments, Inc.
++ *
++ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
++ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#ifndef OMAP3_ISP_USER_H
++#define OMAP3_ISP_USER_H
++
++#include <linux/types.h>
++
++/* Private IOCTLs */
++
++#define VIDIOC_OMAP3ISP_CCDC_CFG \
++ _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct omap3isp_ccdc_update_config)
++#define VIDIOC_OMAP3ISP_PRV_CFG \
++ _IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct omap3isp_prev_update_config)
++#define VIDIOC_OMAP3ISP_AEWB_CFG \
++ _IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct omap3isp_h3a_aewb_config)
++#define VIDIOC_OMAP3ISP_HIST_CFG \
++ _IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct omap3isp_hist_config)
++#define VIDIOC_OMAP3ISP_AF_CFG \
++ _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct omap3isp_h3a_af_config)
++#define VIDIOC_OMAP3ISP_STAT_REQ \
++ _IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct omap3isp_stat_data)
++#define VIDIOC_OMAP3ISP_STAT_EN \
++ _IOWR('V', BASE_VIDIOC_PRIVATE + 7, unsigned long)
++
++/* Events */
++
++#define V4L2_EVENT_OMAP3ISP_CLASS (V4L2_EVENT_PRIVATE_START | 0x100)
++#define V4L2_EVENT_OMAP3ISP_AEWB (V4L2_EVENT_OMAP3ISP_CLASS | 0x1)
++#define V4L2_EVENT_OMAP3ISP_AF (V4L2_EVENT_OMAP3ISP_CLASS | 0x2)
++#define V4L2_EVENT_OMAP3ISP_HIST (V4L2_EVENT_OMAP3ISP_CLASS | 0x3)
++#define V4L2_EVENT_OMAP3ISP_HS_VS (V4L2_EVENT_OMAP3ISP_CLASS | 0x4)
++
++struct omap3isp_stat_event_status {
++ __u32 frame_number;
++ __u16 config_counter;
++ __u8 buf_err;
++};
++
++/* AE/AWB related structures and flags*/
++
++/* H3A Range Constants */
++#define OMAP3ISP_AEWB_MAX_SATURATION_LIM 1023
++#define OMAP3ISP_AEWB_MIN_WIN_H 2
++#define OMAP3ISP_AEWB_MAX_WIN_H 256
++#define OMAP3ISP_AEWB_MIN_WIN_W 6
++#define OMAP3ISP_AEWB_MAX_WIN_W 256
++#define OMAP3ISP_AEWB_MIN_WINVC 1
++#define OMAP3ISP_AEWB_MIN_WINHC 1
++#define OMAP3ISP_AEWB_MAX_WINVC 128
++#define OMAP3ISP_AEWB_MAX_WINHC 36
++#define OMAP3ISP_AEWB_MAX_WINSTART 4095
++#define OMAP3ISP_AEWB_MIN_SUB_INC 2
++#define OMAP3ISP_AEWB_MAX_SUB_INC 32
++#define OMAP3ISP_AEWB_MAX_BUF_SIZE 83600
++
++#define OMAP3ISP_AF_IIRSH_MIN 0
++#define OMAP3ISP_AF_IIRSH_MAX 4095
++#define OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MIN 1
++#define OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MAX 36
++#define OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MIN 1
++#define OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MAX 128
++#define OMAP3ISP_AF_PAXEL_INCREMENT_MIN 2
++#define OMAP3ISP_AF_PAXEL_INCREMENT_MAX 32
++#define OMAP3ISP_AF_PAXEL_HEIGHT_MIN 2
++#define OMAP3ISP_AF_PAXEL_HEIGHT_MAX 256
++#define OMAP3ISP_AF_PAXEL_WIDTH_MIN 16
++#define OMAP3ISP_AF_PAXEL_WIDTH_MAX 256
++#define OMAP3ISP_AF_PAXEL_HZSTART_MIN 1
++#define OMAP3ISP_AF_PAXEL_HZSTART_MAX 4095
++#define OMAP3ISP_AF_PAXEL_VTSTART_MIN 0
++#define OMAP3ISP_AF_PAXEL_VTSTART_MAX 4095
++#define OMAP3ISP_AF_THRESHOLD_MAX 255
++#define OMAP3ISP_AF_COEF_MAX 4095
++#define OMAP3ISP_AF_PAXEL_SIZE 48
++#define OMAP3ISP_AF_MAX_BUF_SIZE 221184
++
++/**
++ * struct omap3isp_h3a_aewb_config - AE AWB configuration reset values
++ * saturation_limit: Saturation limit.
++ * @win_height: Window Height. Range 2 - 256, even values only.
++ * @win_width: Window Width. Range 6 - 256, even values only.
++ * @ver_win_count: Vertical Window Count. Range 1 - 128.
++ * @hor_win_count: Horizontal Window Count. Range 1 - 36.
++ * @ver_win_start: Vertical Window Start. Range 0 - 4095.
++ * @hor_win_start: Horizontal Window Start. Range 0 - 4095.
++ * @blk_ver_win_start: Black Vertical Windows Start. Range 0 - 4095.
++ * @blk_win_height: Black Window Height. Range 2 - 256, even values only.
++ * @subsample_ver_inc: Subsample Vertical points increment Range 2 - 32, even
++ * values only.
++ * @subsample_hor_inc: Subsample Horizontal points increment Range 2 - 32, even
++ * values only.
++ * @alaw_enable: AEW ALAW EN flag.
++ * @aewb_enable: AE AWB stats generation EN flag.
++ */
++struct omap3isp_h3a_aewb_config {
++ /*
++ * Common fields.
++ * They should be the first ones and must be in the same order as in
++ * ispstat_generic_config struct.
++ */
++ __u32 buf_size;
++ __u16 config_counter;
++
++ /* Private fields */
++ __u16 saturation_limit;
++ __u16 win_height;
++ __u16 win_width;
++ __u16 ver_win_count;
++ __u16 hor_win_count;
++ __u16 ver_win_start;
++ __u16 hor_win_start;
++ __u16 blk_ver_win_start;
++ __u16 blk_win_height;
++ __u16 subsample_ver_inc;
++ __u16 subsample_hor_inc;
++ __u8 alaw_enable;
++};
++
++/**
++ * struct omap3isp_stat_data - Statistic data sent to or received from user
++ * @buf: Pointer to pass to user.
++ * @frame_number: Frame number of requested stats.
++ * @cur_frame: Current frame number being processed.
++ * @buf_size: Buffer size requested and returned.
++ * @ts: Timestamp of returned framestats.
++ */
++struct omap3isp_stat_data {
++ struct timeval ts;
++ void __user *buf;
++ __u32 buf_size;
++ __u16 frame_number;
++ __u16 cur_frame;
++ __u16 config_counter;
++ __u16 new_bufs; /* Deprecated */
++};
++
++
++/* Histogram related structs */
++
++/* Flags for number of bins */
++#define OMAP3ISP_HIST_BINS_32 0
++#define OMAP3ISP_HIST_BINS_64 1
++#define OMAP3ISP_HIST_BINS_128 2
++#define OMAP3ISP_HIST_BINS_256 3
++
++/* Number of bins * 4 colors * 4-bytes word */
++#define OMAP3ISP_HIST_MEM_SIZE_BINS(n) ((1 << ((n)+5))*4*4)
++
++#define OMAP3ISP_HIST_MEM_SIZE 1024
++#define OMAP3ISP_HIST_MIN_REGIONS 1
++#define OMAP3ISP_HIST_MAX_REGIONS 4
++#define OMAP3ISP_HIST_MAX_WB_GAIN 255
++#define OMAP3ISP_HIST_MIN_WB_GAIN 0
++#define OMAP3ISP_HIST_MAX_BIT_WIDTH 14
++#define OMAP3ISP_HIST_MIN_BIT_WIDTH 8
++#define OMAP3ISP_HIST_MAX_WG 4
++#define OMAP3ISP_HIST_MAX_BUF_SIZE 4096
++
++/* Source */
++#define OMAP3ISP_HIST_SOURCE_CCDC 0
++#define OMAP3ISP_HIST_SOURCE_MEM 1
++
++/* CFA pattern */
++#define OMAP3ISP_HIST_CFA_BAYER 0
++#define OMAP3ISP_HIST_CFA_FOVEONX3 1
++
++struct omap3isp_hist_region {
++ __u16 h_start;
++ __u16 h_end;
++ __u16 v_start;
++ __u16 v_end;
++};
++
++struct omap3isp_hist_config {
++ /*
++ * Common fields.
++ * They should be the first ones and must be in the same order as in
++ * ispstat_generic_config struct.
++ */
++ __u32 buf_size;
++ __u16 config_counter;
++
++ __u8 num_acc_frames; /* Num of image frames to be processed and
++ accumulated for each histogram frame */
++ __u16 hist_bins; /* number of bins: 32, 64, 128, or 256 */
++ __u8 cfa; /* BAYER or FOVEON X3 */
++ __u8 wg[OMAP3ISP_HIST_MAX_WG]; /* White Balance Gain */
++ __u8 num_regions; /* number of regions to be configured */
++ struct omap3isp_hist_region region[OMAP3ISP_HIST_MAX_REGIONS];
++};
++
++/* Auto Focus related structs */
++
++#define OMAP3ISP_AF_NUM_COEF 11
++
++enum omap3isp_h3a_af_fvmode {
++ OMAP3ISP_AF_MODE_SUMMED = 0,
++ OMAP3ISP_AF_MODE_PEAK = 1
++};
++
++/* Red, Green, and blue pixel location in the AF windows */
++enum omap3isp_h3a_af_rgbpos {
++ OMAP3ISP_AF_GR_GB_BAYER = 0, /* GR and GB as Bayer pattern */
++ OMAP3ISP_AF_RG_GB_BAYER = 1, /* RG and GB as Bayer pattern */
++ OMAP3ISP_AF_GR_BG_BAYER = 2, /* GR and BG as Bayer pattern */
++ OMAP3ISP_AF_RG_BG_BAYER = 3, /* RG and BG as Bayer pattern */
++ OMAP3ISP_AF_GG_RB_CUSTOM = 4, /* GG and RB as custom pattern */
++ OMAP3ISP_AF_RB_GG_CUSTOM = 5 /* RB and GG as custom pattern */
++};
++
++/* Contains the information regarding the Horizontal Median Filter */
++struct omap3isp_h3a_af_hmf {
++ __u8 enable; /* Status of Horizontal Median Filter */
++ __u8 threshold; /* Threshhold Value for Horizontal Median Filter */
++};
++
++/* Contains the information regarding the IIR Filters */
++struct omap3isp_h3a_af_iir {
++ __u16 h_start; /* IIR horizontal start */
++ __u16 coeff_set0[OMAP3ISP_AF_NUM_COEF]; /* Filter coefficient, set 0 */
++ __u16 coeff_set1[OMAP3ISP_AF_NUM_COEF]; /* Filter coefficient, set 1 */
++};
++
++/* Contains the information regarding the Paxels Structure in AF Engine */
++struct omap3isp_h3a_af_paxel {
++ __u16 h_start; /* Horizontal Start Position */
++ __u16 v_start; /* Vertical Start Position */
++ __u8 width; /* Width of the Paxel */
++ __u8 height; /* Height of the Paxel */
++ __u8 h_cnt; /* Horizontal Count */
++ __u8 v_cnt; /* vertical Count */
++ __u8 line_inc; /* Line Increment */
++};
++
++/* Contains the parameters required for hardware set up of AF Engine */
++struct omap3isp_h3a_af_config {
++ /*
++ * Common fields.
++ * They should be the first ones and must be in the same order as in
++ * ispstat_generic_config struct.
++ */
++ __u32 buf_size;
++ __u16 config_counter;
++
++ struct omap3isp_h3a_af_hmf hmf; /* HMF configurations */
++ struct omap3isp_h3a_af_iir iir; /* IIR filter configurations */
++ struct omap3isp_h3a_af_paxel paxel; /* Paxel parameters */
++ enum omap3isp_h3a_af_rgbpos rgb_pos; /* RGB Positions */
++ enum omap3isp_h3a_af_fvmode fvmode; /* Accumulator mode */
++ __u8 alaw_enable; /* AF ALAW status */
++};
++
++/* ISP CCDC structs */
++
++/* Abstraction layer CCDC configurations */
++#define OMAP3ISP_CCDC_ALAW (1 << 0)
++#define OMAP3ISP_CCDC_LPF (1 << 1)
++#define OMAP3ISP_CCDC_BLCLAMP (1 << 2)
++#define OMAP3ISP_CCDC_BCOMP (1 << 3)
++#define OMAP3ISP_CCDC_FPC (1 << 4)
++#define OMAP3ISP_CCDC_CULL (1 << 5)
++#define OMAP3ISP_CCDC_CONFIG_LSC (1 << 7)
++#define OMAP3ISP_CCDC_TBL_LSC (1 << 8)
++
++#define OMAP3ISP_RGB_MAX 3
++
++/* Enumeration constants for Alaw input width */
++enum omap3isp_alaw_ipwidth {
++ OMAP3ISP_ALAW_BIT12_3 = 0x3,
++ OMAP3ISP_ALAW_BIT11_2 = 0x4,
++ OMAP3ISP_ALAW_BIT10_1 = 0x5,
++ OMAP3ISP_ALAW_BIT9_0 = 0x6
++};
++
++/**
++ * struct omap3isp_ccdc_lsc_config - LSC configuration
++ * @offset: Table Offset of the gain table.
++ * @gain_mode_n: Vertical dimension of a paxel in LSC configuration.
++ * @gain_mode_m: Horizontal dimension of a paxel in LSC configuration.
++ * @gain_format: Gain table format.
++ * @fmtsph: Start pixel horizontal from start of the HS sync pulse.
++ * @fmtlnh: Number of pixels in horizontal direction to use for the data
++ * reformatter.
++ * @fmtslv: Start line from start of VS sync pulse for the data reformatter.
++ * @fmtlnv: Number of lines in vertical direction for the data reformatter.
++ * @initial_x: X position, in pixels, of the first active pixel in reference
++ * to the first active paxel. Must be an even number.
++ * @initial_y: Y position, in pixels, of the first active pixel in reference
++ * to the first active paxel. Must be an even number.
++ * @size: Size of LSC gain table. Filled when loaded from userspace.
++ */
++struct omap3isp_ccdc_lsc_config {
++ __u16 offset;
++ __u8 gain_mode_n;
++ __u8 gain_mode_m;
++ __u8 gain_format;
++ __u16 fmtsph;
++ __u16 fmtlnh;
++ __u16 fmtslv;
++ __u16 fmtlnv;
++ __u8 initial_x;
++ __u8 initial_y;
++ __u32 size;
++};
++
++/**
++ * struct omap3isp_ccdc_bclamp - Optical & Digital black clamp subtract
++ * @obgain: Optical black average gain.
++ * @obstpixel: Start Pixel w.r.t. HS pulse in Optical black sample.
++ * @oblines: Optical Black Sample lines.
++ * @oblen: Optical Black Sample Length.
++ * @dcsubval: Digital Black Clamp subtract value.
++ */
++struct omap3isp_ccdc_bclamp {
++ __u8 obgain;
++ __u8 obstpixel;
++ __u8 oblines;
++ __u8 oblen;
++ __u16 dcsubval;
++};
++
++/**
++ * struct omap3isp_ccdc_fpc - Faulty Pixels Correction
++ * @fpnum: Number of faulty pixels to be corrected in the frame.
++ * @fpcaddr: Memory address of the FPC Table
++ */
++struct omap3isp_ccdc_fpc {
++ __u16 fpnum;
++ __u32 fpcaddr;
++};
++
++/**
++ * struct omap3isp_ccdc_blcomp - Black Level Compensation parameters
++ * @b_mg: B/Mg pixels. 2's complement. -128 to +127.
++ * @gb_g: Gb/G pixels. 2's complement. -128 to +127.
++ * @gr_cy: Gr/Cy pixels. 2's complement. -128 to +127.
++ * @r_ye: R/Ye pixels. 2's complement. -128 to +127.
++ */
++struct omap3isp_ccdc_blcomp {
++ __u8 b_mg;
++ __u8 gb_g;
++ __u8 gr_cy;
++ __u8 r_ye;
++};
++
++/**
++ * omap3isp_ccdc_culling - Culling parameters
++ * @v_pattern: Vertical culling pattern.
++ * @h_odd: Horizontal Culling pattern for odd lines.
++ * @h_even: Horizontal Culling pattern for even lines.
++ */
++struct omap3isp_ccdc_culling {
++ __u8 v_pattern;
++ __u16 h_odd;
++ __u16 h_even;
++};
++
++/**
++ * omap3isp_ccdc_update_config - CCDC configuration
++ * @update: Specifies which CCDC registers should be updated.
++ * @flag: Specifies which CCDC functions should be enabled.
++ * @alawip: Enable/Disable A-Law compression.
++ * @bclamp: Black clamp control register.
++ * @blcomp: Black level compensation value for RGrGbB Pixels. 2's complement.
++ * @fpc: Number of faulty pixels corrected in the frame, address of FPC table.
++ * @cull: Cull control register.
++ * @lsc: Pointer to LSC gain table.
++ */
++struct omap3isp_ccdc_update_config {
++ __u16 update;
++ __u16 flag;
++ enum omap3isp_alaw_ipwidth alawip;
++ struct omap3isp_ccdc_bclamp __user *bclamp;
++ struct omap3isp_ccdc_blcomp __user *blcomp;
++ struct omap3isp_ccdc_fpc __user *fpc;
++ struct omap3isp_ccdc_lsc_config __user *lsc_cfg;
++ struct omap3isp_ccdc_culling __user *cull;
++ __u8 __user *lsc;
++};
++
++/* Preview configurations */
++#define OMAP3ISP_PREV_LUMAENH (1 << 0)
++#define OMAP3ISP_PREV_INVALAW (1 << 1)
++#define OMAP3ISP_PREV_HRZ_MED (1 << 2)
++#define OMAP3ISP_PREV_CFA (1 << 3)
++#define OMAP3ISP_PREV_CHROMA_SUPP (1 << 4)
++#define OMAP3ISP_PREV_WB (1 << 5)
++#define OMAP3ISP_PREV_BLKADJ (1 << 6)
++#define OMAP3ISP_PREV_RGB2RGB (1 << 7)
++#define OMAP3ISP_PREV_COLOR_CONV (1 << 8)
++#define OMAP3ISP_PREV_YC_LIMIT (1 << 9)
++#define OMAP3ISP_PREV_DEFECT_COR (1 << 10)
++#define OMAP3ISP_PREV_GAMMABYPASS (1 << 11)
++#define OMAP3ISP_PREV_DRK_FRM_CAPTURE (1 << 12)
++#define OMAP3ISP_PREV_DRK_FRM_SUBTRACT (1 << 13)
++#define OMAP3ISP_PREV_LENS_SHADING (1 << 14)
++#define OMAP3ISP_PREV_NF (1 << 15)
++#define OMAP3ISP_PREV_GAMMA (1 << 16)
++
++#define OMAP3ISP_PREV_NF_TBL_SIZE 64
++#define OMAP3ISP_PREV_CFA_TBL_SIZE 576
++#define OMAP3ISP_PREV_GAMMA_TBL_SIZE 1024
++#define OMAP3ISP_PREV_YENH_TBL_SIZE 128
++
++#define OMAP3ISP_PREV_DETECT_CORRECT_CHANNELS 4
++
++/**
++ * struct omap3isp_prev_hmed - Horizontal Median Filter
++ * @odddist: Distance between consecutive pixels of same color in the odd line.
++ * @evendist: Distance between consecutive pixels of same color in the even
++ * line.
++ * @thres: Horizontal median filter threshold.
++ */
++struct omap3isp_prev_hmed {
++ __u8 odddist;
++ __u8 evendist;
++ __u8 thres;
++};
++
++/*
++ * Enumeration for CFA Formats supported by preview
++ */
++enum omap3isp_cfa_fmt {
++ OMAP3ISP_CFAFMT_BAYER,
++ OMAP3ISP_CFAFMT_SONYVGA,
++ OMAP3ISP_CFAFMT_RGBFOVEON,
++ OMAP3ISP_CFAFMT_DNSPL,
++ OMAP3ISP_CFAFMT_HONEYCOMB,
++ OMAP3ISP_CFAFMT_RRGGBBFOVEON
++};
++
++/**
++ * struct omap3isp_prev_cfa - CFA Interpolation
++ * @format: CFA Format Enum value supported by preview.
++ * @gradthrs_vert: CFA Gradient Threshold - Vertical.
++ * @gradthrs_horz: CFA Gradient Threshold - Horizontal.
++ * @table: Pointer to the CFA table.
++ */
++struct omap3isp_prev_cfa {
++ enum omap3isp_cfa_fmt format;
++ __u8 gradthrs_vert;
++ __u8 gradthrs_horz;
++ __u32 table[OMAP3ISP_PREV_CFA_TBL_SIZE];
++};
++
++/**
++ * struct omap3isp_prev_csup - Chrominance Suppression
++ * @gain: Gain.
++ * @thres: Threshold.
++ * @hypf_en: Flag to enable/disable the High Pass Filter.
++ */
++struct omap3isp_prev_csup {
++ __u8 gain;
++ __u8 thres;
++ __u8 hypf_en;
++};
++
++/**
++ * struct omap3isp_prev_wbal - White Balance
++ * @dgain: Digital gain (U10Q8).
++ * @coef3: White balance gain - COEF 3 (U8Q5).
++ * @coef2: White balance gain - COEF 2 (U8Q5).
++ * @coef1: White balance gain - COEF 1 (U8Q5).
++ * @coef0: White balance gain - COEF 0 (U8Q5).
++ */
++struct omap3isp_prev_wbal {
++ __u16 dgain;
++ __u8 coef3;
++ __u8 coef2;
++ __u8 coef1;
++ __u8 coef0;
++};
++
++/**
++ * struct omap3isp_prev_blkadj - Black Level Adjustment
++ * @red: Black level offset adjustment for Red in 2's complement format
++ * @green: Black level offset adjustment for Green in 2's complement format
++ * @blue: Black level offset adjustment for Blue in 2's complement format
++ */
++struct omap3isp_prev_blkadj {
++ /*Black level offset adjustment for Red in 2's complement format */
++ __u8 red;
++ /*Black level offset adjustment for Green in 2's complement format */
++ __u8 green;
++ /* Black level offset adjustment for Blue in 2's complement format */
++ __u8 blue;
++};
++
++/**
++ * struct omap3isp_prev_rgbtorgb - RGB to RGB Blending
++ * @matrix: Blending values(S12Q8 format)
++ * [RR] [GR] [BR]
++ * [RG] [GG] [BG]
++ * [RB] [GB] [BB]
++ * @offset: Blending offset value for R,G,B in 2's complement integer format.
++ */
++struct omap3isp_prev_rgbtorgb {
++ __u16 matrix[OMAP3ISP_RGB_MAX][OMAP3ISP_RGB_MAX];
++ __u16 offset[OMAP3ISP_RGB_MAX];
++};
++
++/**
++ * struct omap3isp_prev_csc - Color Space Conversion from RGB-YCbYCr
++ * @matrix: Color space conversion coefficients(S10Q8)
++ * [CSCRY] [CSCGY] [CSCBY]
++ * [CSCRCB] [CSCGCB] [CSCBCB]
++ * [CSCRCR] [CSCGCR] [CSCBCR]
++ * @offset: CSC offset values for Y offset, CB offset and CR offset respectively
++ */
++struct omap3isp_prev_csc {
++ __u16 matrix[OMAP3ISP_RGB_MAX][OMAP3ISP_RGB_MAX];
++ __s16 offset[OMAP3ISP_RGB_MAX];
++};
++
++/**
++ * struct omap3isp_prev_yclimit - Y, C Value Limit
++ * @minC: Minimum C value
++ * @maxC: Maximum C value
++ * @minY: Minimum Y value
++ * @maxY: Maximum Y value
++ */
++struct omap3isp_prev_yclimit {
++ __u8 minC;
++ __u8 maxC;
++ __u8 minY;
++ __u8 maxY;
++};
++
++/**
++ * struct omap3isp_prev_dcor - Defect correction
++ * @couplet_mode_en: Flag to enable or disable the couplet dc Correction in NF
++ * @detect_correct: Thresholds for correction bit 0:10 detect 16:25 correct
++ */
++struct omap3isp_prev_dcor {
++ __u8 couplet_mode_en;
++ __u32 detect_correct[OMAP3ISP_PREV_DETECT_CORRECT_CHANNELS];
++};
++
++/**
++ * struct omap3isp_prev_nf - Noise Filter
++ * @spread: Spread value to be used in Noise Filter
++ * @table: Pointer to the Noise Filter table
++ */
++struct omap3isp_prev_nf {
++ __u8 spread;
++ __u32 table[OMAP3ISP_PREV_NF_TBL_SIZE];
++};
++
++/**
++ * struct omap3isp_prev_gtables - Gamma correction tables
++ * @red: Array for red gamma table.
++ * @green: Array for green gamma table.
++ * @blue: Array for blue gamma table.
++ */
++struct omap3isp_prev_gtables {
++ __u32 red[OMAP3ISP_PREV_GAMMA_TBL_SIZE];
++ __u32 green[OMAP3ISP_PREV_GAMMA_TBL_SIZE];
++ __u32 blue[OMAP3ISP_PREV_GAMMA_TBL_SIZE];
++};
++
++/**
++ * struct omap3isp_prev_luma - Luma enhancement
++ * @table: Array for luma enhancement table.
++ */
++struct omap3isp_prev_luma {
++ __u32 table[OMAP3ISP_PREV_YENH_TBL_SIZE];
++};
++
++/**
++ * struct omap3isp_prev_update_config - Preview engine configuration (user)
++ * @update: Specifies which ISP Preview registers should be updated.
++ * @flag: Specifies which ISP Preview functions should be enabled.
++ * @shading_shift: 3bit value of shift used in shading compensation.
++ * @luma: Pointer to luma enhancement structure.
++ * @hmed: Pointer to structure containing the odd and even distance.
++ * between the pixels in the image along with the filter threshold.
++ * @cfa: Pointer to structure containing the CFA interpolation table, CFA.
++ * format in the image, vertical and horizontal gradient threshold.
++ * @csup: Pointer to Structure for Chrominance Suppression coefficients.
++ * @wbal: Pointer to structure for White Balance.
++ * @blkadj: Pointer to structure for Black Adjustment.
++ * @rgb2rgb: Pointer to structure for RGB to RGB Blending.
++ * @csc: Pointer to structure for Color Space Conversion from RGB-YCbYCr.
++ * @yclimit: Pointer to structure for Y, C Value Limit.
++ * @dcor: Pointer to structure for defect correction.
++ * @nf: Pointer to structure for Noise Filter
++ * @gamma: Pointer to gamma structure.
++ */
++struct omap3isp_prev_update_config {
++ __u32 update;
++ __u32 flag;
++ __u32 shading_shift;
++ struct omap3isp_prev_luma __user *luma;
++ struct omap3isp_prev_hmed __user *hmed;
++ struct omap3isp_prev_cfa __user *cfa;
++ struct omap3isp_prev_csup __user *csup;
++ struct omap3isp_prev_wbal __user *wbal;
++ struct omap3isp_prev_blkadj __user *blkadj;
++ struct omap3isp_prev_rgbtorgb __user *rgb2rgb;
++ struct omap3isp_prev_csc __user *csc;
++ struct omap3isp_prev_yclimit __user *yclimit;
++ struct omap3isp_prev_dcor __user *dcor;
++ struct omap3isp_prev_nf __user *nf;
++ struct omap3isp_prev_gtables __user *gamma;
++};
++
++#endif /* OMAP3_ISP_USER_H */
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/new/0001-OMAP-Enable-Magic-SysRq-on-serial-console-ttyOx.patch b/extras/recipes-kernel/linux/linux-omap/new/0001-OMAP-Enable-Magic-SysRq-on-serial-console-ttyOx.patch
new file mode 100644
index 00000000..e157d360
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/new/0001-OMAP-Enable-Magic-SysRq-on-serial-console-ttyOx.patch
@@ -0,0 +1,35 @@
+From a43b9359708691eb3aec983da36461720fb4a556 Mon Sep 17 00:00:00 2001
+From: Thomas Weber <weber@corscience.de>
+Date: Wed, 19 Jan 2011 09:41:01 +0100
+Subject: [PATCH] OMAP: Enable Magic SysRq on serial console ttyOx
+
+Magic SysRq key is not working for OMAP on new serial
+console ttyOx because SUPPORT_SYSRQ is not defined
+for omap-serial.
+
+This patch defines SUPPORT_SYSRQ in omap-serial and
+enables handling of Magic SysRq character.
+
+Signed-off-by: Thomas Weber <weber@corscience.de>
+---
+ drivers/serial/omap-serial.c | 4 ++++
+ 1 files changed, 4 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/serial/omap-serial.c b/drivers/serial/omap-serial.c
+index 1201eff..907be9b 100644
+--- a/drivers/serial/omap-serial.c
++++ b/drivers/serial/omap-serial.c
+@@ -20,6 +20,10 @@
+ * this driver as required for the omap-platform.
+ */
+
++#if defined(CONFIG_SERIAL_OMAP_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
++#define SUPPORT_SYSRQ
++#endif
++
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/console.h>
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/omap3-touchbook/defconfig b/extras/recipes-kernel/linux/linux-omap/omap3-touchbook/defconfig
new file mode 120000
index 00000000..44e34a71
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/omap3-touchbook/defconfig
@@ -0,0 +1 @@
+../beagleboard/defconfig \ No newline at end of file
diff --git a/extras/recipes-kernel/linux/linux-omap/omap3evm/defconfig b/extras/recipes-kernel/linux/linux-omap/omap3evm/defconfig
new file mode 120000
index 00000000..44e34a71
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/omap3evm/defconfig
@@ -0,0 +1 @@
+../beagleboard/defconfig \ No newline at end of file
diff --git a/extras/recipes-kernel/linux/linux-omap/overo/defconfig b/extras/recipes-kernel/linux/linux-omap/overo/defconfig
new file mode 120000
index 00000000..44e34a71
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/overo/defconfig
@@ -0,0 +1 @@
+../beagleboard/defconfig \ No newline at end of file
diff --git a/extras/recipes-kernel/linux/linux-omap/usrp-e1xx/defconfig b/extras/recipes-kernel/linux/linux-omap/usrp-e1xx/defconfig
new file mode 120000
index 00000000..44e34a71
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/usrp-e1xx/defconfig
@@ -0,0 +1 @@
+../beagleboard/defconfig \ No newline at end of file
diff --git a/extras/recipes-kernel/linux/linux-omap/usrp/0001-Add-defines-to-set-config-options-in-GPMC-per-CS-con.patch b/extras/recipes-kernel/linux/linux-omap/usrp/0001-Add-defines-to-set-config-options-in-GPMC-per-CS-con.patch
new file mode 100644
index 00000000..9f73f00d
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/usrp/0001-Add-defines-to-set-config-options-in-GPMC-per-CS-con.patch
@@ -0,0 +1,80 @@
+From cba7c162c77d225afbf53148273019946a73b2c2 Mon Sep 17 00:00:00 2001
+From: Philip Balister <balister@nomad.(none)>
+Date: Wed, 17 Feb 2010 14:51:39 -0800
+Subject: [PATCH 1/3] Add defines to set config options in GPMC per CS control registers.
+
+---
+ arch/arm/plat-omap/include/plat/gpmc.h | 36 ++++++++++++++++++++++++++++++++
+ 1 files changed, 36 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
+index 85ded59..1a6c748 100644
+--- a/arch/arm/plat-omap/include/plat/gpmc.h
++++ b/arch/arm/plat-omap/include/plat/gpmc.h
+@@ -46,6 +46,11 @@
+ #define GPMC_ECC_WRITE 1 /* Reset Hardware ECC for write */
+ #define GPMC_ECC_READSYN 2 /* Reset before syndrom is read back */
+
++#define GPMC_CONFIG 0x50
++#define GPMC_STATUS 0x54
++#define GPMC_CS0_BASE 0x60
++#define GPMC_CS_SIZE 0x30
++
+ #define GPMC_CONFIG1_WRAPBURST_SUPP (1 << 31)
+ #define GPMC_CONFIG1_READMULTIPLE_SUPP (1 << 30)
+ #define GPMC_CONFIG1_READTYPE_ASYNC (0 << 29)
+@@ -63,6 +68,7 @@
+ #define GPMC_CONFIG1_DEVICESIZE_16 GPMC_CONFIG1_DEVICESIZE(1)
+ #define GPMC_CONFIG1_DEVICETYPE(val) ((val & 3) << 10)
+ #define GPMC_CONFIG1_DEVICETYPE_NOR GPMC_CONFIG1_DEVICETYPE(0)
++#define GPMC_CONFIG1_DEVICETYPE_NAND GPMC_CONFIG1_DEVICETYPE(2)
+ #define GPMC_CONFIG1_MUXADDDATA (1 << 9)
+ #define GPMC_CONFIG1_TIME_PARA_GRAN (1 << 4)
+ #define GPMC_CONFIG1_FCLK_DIV(val) (val & 3)
+@@ -79,6 +85,35 @@
+ #define GPMC_PREFETCH_STATUS_FIFO_CNT(val) ((val >> 24) & 0x7F)
+ #define GPMC_PREFETCH_STATUS_COUNT(val) (val & 0x00003fff)
+
++#define GPMC_CONFIG2_CSWROFFTIME(val) ((val & 31) << 16)
++#define GPMC_CONFIG2_CSRDOFFTIME(val) ((val & 31) << 8)
++#define GPMC_CONFIG2_CSEXTRADELAY (1 << 7)
++#define GPMC_CONFIG2_CSONTIME(val) (val & 15)
++
++#define GPMC_CONFIG3_ADVWROFFTIME(val) ((val & 31) << 16)
++#define GPMC_CONFIG3_ADVRDOFFTIME(val) ((val & 31) << 8)
++#define GPMC_CONFIG3_ADVEXTRADELAY (1 << 7)
++#define GPMC_CONFIG3_ADVONTIME(val) (val & 15)
++
++#define GPMC_CONFIG4_WEOFFTIME(val) ((val & 31) << 24)
++#define GPMC_CONFIG4_WEEXTRADELAY (1 << 23)
++#define GPMC_CONFIG4_WEONTIME(val) ((val & 15) << 16)
++#define GPMC_CONFIG4_OEOFFTIME(val) ((val & 31) << 8)
++#define GPMC_CONFIG4_OEEXTRADELAY (1 << 7)
++#define GPMC_CONFIG4_OEONTIME(val) (val & 15)
++
++#define GPMC_CONFIG5_PAGEBURSTACCESSTIME(val) ((val & 15) << 24)
++#define GPMC_CONFIG5_RDACCESSTIME(val) ((val & 31) << 16)
++#define GPMC_CONFIG5_WRCYCLETIME(val) ((val & 31) << 8)
++#define GPMC_CONFIG5_RDCYCLETIME(val) (val & 31)
++
++#define GPMC_CONFIG6_WRACCESSTIME(val) ((val & 31) << 24)
++#define GPMC_CONFIG6_WRDATAONADMUXBUS(val) ((val & 15) << 16)
++#define GPMC_CONFIG6_CYCLE2CYCLEDELAY(val) ((val & 15) << 8)
++#define GPMC_CONFIG6_CYCLE2CYCLESAMECSEN (1 << 7)
++#define GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN (1 << 6)
++#define GPMC_CONFIG6_BUSTURNAROUND(val) (val & 15)
++
+ /*
+ * Note that all values in this struct are in nanoseconds except sync_clk
+ * (which is in picoseconds), while the register values are in gpmc_fck cycles.
+@@ -133,6 +168,7 @@ extern int gpmc_cs_reserved(int cs);
+ extern int gpmc_prefetch_enable(int cs, int dma_mode,
+ unsigned int u32_count, int is_write);
+ extern int gpmc_prefetch_reset(int cs);
++extern int gpmc_prefetch_status(void);
+ extern void omap3_gpmc_save_context(void);
+ extern void omap3_gpmc_restore_context(void);
+ extern void gpmc_init(void);
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/usrp/0002-Add-functions-to-dma.c-to-set-address-and-length-for.patch b/extras/recipes-kernel/linux/linux-omap/usrp/0002-Add-functions-to-dma.c-to-set-address-and-length-for.patch
new file mode 100644
index 00000000..a7415ff0
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/usrp/0002-Add-functions-to-dma.c-to-set-address-and-length-for.patch
@@ -0,0 +1,83 @@
+From fa589f1ad83e8795ba0509e7899dd1a6926c5fbd Mon Sep 17 00:00:00 2001
+From: Philip Balister <philip@opensdr.com>
+Date: Thu, 22 Apr 2010 19:41:58 -0700
+Subject: [PATCH 2/3] Add functions to dma.c to set address and length for src and dest.
+
+---
+ arch/arm/plat-omap/dma.c | 30 ++++++++++++++++++++++++++++++
+ arch/arm/plat-omap/include/plat/dma.h | 4 ++++
+ 2 files changed, 34 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
+index c4b2b47..f28f756 100644
+--- a/arch/arm/plat-omap/dma.c
++++ b/arch/arm/plat-omap/dma.c
+@@ -471,6 +471,21 @@ void omap_set_dma_src_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
+ }
+ EXPORT_SYMBOL(omap_set_dma_src_burst_mode);
+
++void omap_set_dma_src_addr_size(int lch, unsigned int addr, int elem_count)
++{
++
++ if (cpu_class_is_omap1()) {
++ p->dma_write(addr >> 16, CSSA, lch);
++ //p->dma_write((u16)addr, CSSA_L, lch);
++ }
++
++ if (cpu_class_is_omap2())
++ p->dma_write(addr, CSSA, lch);
++
++ p->dma_write(elem_count, CEN, lch);
++}
++EXPORT_SYMBOL_GPL(omap_set_dma_src_addr_size);
++
+ /* Note that dest_port is only for OMAP1 */
+ void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode,
+ unsigned long dest_start,
+@@ -561,6 +576,21 @@ void omap_set_dma_dest_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
+ }
+ EXPORT_SYMBOL(omap_set_dma_dest_burst_mode);
+
++void omap_set_dma_dest_addr_size(int lch, unsigned int addr, int elem_count)
++{
++
++ if (cpu_class_is_omap1()) {
++ p->dma_write(addr >> 16, CDSA, lch);
++ //p->dma_write((u16)addr, CDSA_L, lch);
++ }
++
++ if (cpu_class_is_omap2())
++ p->dma_write(addr, CDSA, lch);
++
++ p->dma_write(elem_count, CEN, lch);
++}
++EXPORT_SYMBOL_GPL(omap_set_dma_dest_addr_size);
++
+ static inline void omap_enable_channel_irq(int lch)
+ {
+ u32 status;
+diff --git a/arch/arm/plat-omap/include/plat/dma.h b/arch/arm/plat-omap/include/plat/dma.h
+index d1c916f..1e7243e 100644
+--- a/arch/arm/plat-omap/include/plat/dma.h
++++ b/arch/arm/plat-omap/include/plat/dma.h
+@@ -462,6 +462,8 @@ extern void omap_set_dma_src_index(int lch, int eidx, int fidx);
+ extern void omap_set_dma_src_data_pack(int lch, int enable);
+ extern void omap_set_dma_src_burst_mode(int lch,
+ enum omap_dma_burst_mode burst_mode);
++extern void omap_set_dma_src_addr_size(int lch, unsigned int addr,
++ int elem_count);
+
+ extern void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode,
+ unsigned long dest_start,
+@@ -470,6 +472,8 @@ extern void omap_set_dma_dest_index(int lch, int eidx, int fidx);
+ extern void omap_set_dma_dest_data_pack(int lch, int enable);
+ extern void omap_set_dma_dest_burst_mode(int lch,
+ enum omap_dma_burst_mode burst_mode);
++extern void omap_set_dma_dest_addr_size(int lch, unsigned int addr,
++ int elem_count);
+
+ extern void omap_set_dma_params(int lch,
+ struct omap_dma_channel_params *params);
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/usrp/0003-usrp-embedded-Add-driver-for-USRP-Embedded-FPGA-inte.patch b/extras/recipes-kernel/linux/linux-omap/usrp/0003-usrp-embedded-Add-driver-for-USRP-Embedded-FPGA-inte.patch
new file mode 100644
index 00000000..400807d1
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/usrp/0003-usrp-embedded-Add-driver-for-USRP-Embedded-FPGA-inte.patch
@@ -0,0 +1,1889 @@
+From 56a2e5e0ace395e94f176a90a12d3cfcd8b7f68f Mon Sep 17 00:00:00 2001
+From: Philip Balister <balister@moose.(none)>
+Date: Wed, 13 Jan 2010 14:35:39 -0500
+Subject: [PATCH 3/3] usrp-embedded : Add driver for USRP Embedded FPGA interface.
+
+---
+ arch/arm/mach-omap2/board-overo.c | 176 +++++-
+ drivers/misc/Kconfig | 9 +
+ drivers/misc/Makefile | 1 +
+ drivers/misc/usrp_e.c | 1481 +++++++++++++++++++++++++++++++++++++
+ include/linux/usrp_e.h | 87 +++
+ 5 files changed, 1750 insertions(+), 4 deletions(-)
+ create mode 100644 drivers/misc/usrp_e.c
+ create mode 100644 include/linux/usrp_e.h
+
+diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
+index 8a44c17..8686015 100644
+--- a/arch/arm/mach-omap2/board-overo.c
++++ b/arch/arm/mach-omap2/board-overo.c
+@@ -35,6 +35,8 @@
+ #include <linux/mtd/partitions.h>
+ #include <linux/mmc/host.h>
+
++#include <linux/spi/spi.h>
++
+ #include <asm/mach-types.h>
+ #include <asm/mach/arch.h>
+ #include <asm/mach/flash.h>
+@@ -63,6 +65,8 @@
+ #define OVERO_GPIO_USBH_NRESET 183
+
+ #define NAND_BLOCK_SIZE SZ_128K
++#define GPMC_CS0_BASE 0x60
++#define GPMC_CS_SIZE 0x30
+
+ #define OVERO_SMSC911X_CS 5
+ #define OVERO_SMSC911X_GPIO 176
+@@ -164,7 +168,9 @@ static struct platform_device overo_smsc911x2_device = {
+
+ static struct platform_device *smsc911x_devices[] = {
+ &overo_smsc911x_device,
++#if 0
+ &overo_smsc911x2_device,
++#endif
+ };
+
+ static inline void __init overo_init_smsc911x(void)
+@@ -194,6 +200,7 @@ static inline void __init overo_init_smsc911x(void)
+
+ /* set up second smsc911x chip */
+
++#if 0
+ if (gpmc_cs_request(OVERO_SMSC911X2_CS, SZ_16M, &cs_mem_base2) < 0) {
+ printk(KERN_ERR "Failed request for GPMC mem for smsc911x2\n");
+ return;
+@@ -213,6 +220,7 @@ static inline void __init overo_init_smsc911x(void)
+ overo_smsc911x2_resources[1].start = OMAP_GPIO_IRQ(OVERO_SMSC911X2_GPIO);
+ overo_smsc911x2_resources[1].end = 0;
+
++#endif
+ platform_add_devices(smsc911x_devices, ARRAY_SIZE(smsc911x_devices));
+ }
+
+@@ -353,6 +361,16 @@ static struct regulator_consumer_supply overo_vdda_dac_supply =
+ static struct regulator_consumer_supply overo_vdds_dsi_supply =
+ REGULATOR_SUPPLY("vdds_dsi", "omapdss");
+
++static struct spi_board_info overo_mcspi_board_info[] = {
++ {
++ .modalias = "spidev",
++ .max_speed_hz = 12000000, // 12 MHz
++ .bus_num = 1,
++ .chip_select = 0,
++ .mode = SPI_MODE_1,
++ },
++};
++
+ static struct mtd_partition overo_nand_partitions[] = {
+ {
+ .name = "xloader",
+@@ -432,8 +450,8 @@ static struct omap2_hsmmc_info mmc[] = {
+ .mmc = 2,
+ .caps = MMC_CAP_4_BIT_DATA,
+ .gpio_cd = -EINVAL,
+- .gpio_wp = -EINVAL,
+- .transceiver = true,
++ .transceiver = true,
++ .gpio_wp = 150,
+ .ocr_mask = 0x00100000, /* 3.3V */
+ },
+ {} /* Terminator */
+@@ -612,6 +630,8 @@ static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+ static struct omap_board_mux board_mux[] __initdata = {
+ { .reg_offset = OMAP_MUX_TERMINATOR },
+ };
++#else
++#define board_mux NULL
+ #endif
+
+ static struct omap_musb_board_data musb_board_data = {
+@@ -626,6 +646,148 @@ static struct omap_musb_board_data musb_board_data = {
+ .power = 100,
+ };
+
++static void __init usrp1_e_init(void)
++{
++ unsigned int tmp;
++
++ printk("Setup up gpmc timing.\n");
++
++// Set up CS4, data read/write
++
++#if 1
++ // Signal control parameters per chip select
++ tmp = gpmc_cs_read_reg(4, GPMC_CS_CONFIG1);
++// tmp |= (GPMC_CONFIG1_MUXADDDATA);
++// tmp |= (GPMC_CONFIG1_WRITETYPE_SYNC);
++// tmp |= (GPMC_CONFIG1_READTYPE_SYNC);
++ tmp |= (GPMC_CONFIG1_FCLK_DIV(0));
++ gpmc_cs_write_reg(4, GPMC_CS_CONFIG1, tmp);
++ printk("GPMC_CONFIG1 reg: %x\n", tmp);
++#endif
++
++#if 1
++ // CS signal timing parameter configuration
++ tmp = 0;
++ tmp |= GPMC_CONFIG2_CSONTIME(1); /* 1 */
++ tmp |= GPMC_CONFIG2_CSWROFFTIME(16); /* 16 */
++ tmp |= GPMC_CONFIG2_CSRDOFFTIME(16); /* 16 */
++ printk("GPMC_CONFIG2 reg: %x\n", tmp);
++ gpmc_cs_write_reg(4, GPMC_CS_CONFIG2, tmp);
++#endif
++
++#if 0
++ // nADV signal timing parameter configuration
++ tmp = 0;
++ tmp |= GPMC_CONFIG3_ADVONTIME(1);
++ tmp |= GPMC_CONFIG3_ADVRDOFFTIME(2);
++ tmp |= GPMC_CONFIG3_ADVWROFFTIME(2);
++ printk("GPMC_CONFIG3 reg: %x\n", tmp);
++ gpmc_cs_write_reg(4, GPMC_CS_CONFIG3, tmp);
++#endif
++
++#if 1
++ // nWE and nOE signals timing parameter configuration
++ tmp = 0;
++ tmp |= GPMC_CONFIG4_WEONTIME(3); /* 3 */
++ tmp |= GPMC_CONFIG4_WEOFFTIME(16); /* 16 */
++ tmp |= GPMC_CONFIG4_OEONTIME(3); /* 3 */
++ tmp |= GPMC_CONFIG4_OEOFFTIME(16); /* 16 */
++ printk("GPMC_CONFIG4 reg: %x\n", tmp);
++ gpmc_cs_write_reg(4, GPMC_CS_CONFIG4, tmp);
++#endif
++
++#if 1
++ // RdAccess time and Cycle time timing parameters configuration
++ tmp = 0;
++ tmp |= GPMC_CONFIG5_PAGEBURSTACCESSTIME(1);
++ tmp |= GPMC_CONFIG5_RDACCESSTIME(15); /* 15 */
++ tmp |= GPMC_CONFIG5_WRCYCLETIME(17); /* 17 */
++ tmp |= GPMC_CONFIG5_RDCYCLETIME(17); /* 17 */
++ printk("GPMC_CONFIG5 reg: %x\n", tmp);
++
++ gpmc_cs_write_reg(4, GPMC_CS_CONFIG5, tmp);
++#endif
++
++#if 1
++ // WrAccessTime WrDataOnADmuxBus, Cycle2Cycle, and BusTurnAround params
++ tmp = (1<<31);
++ tmp |= GPMC_CONFIG6_WRACCESSTIME(15); /* 15 */
++ tmp |= GPMC_CONFIG6_WRDATAONADMUXBUS(3);
++ tmp |= GPMC_CONFIG6_CYCLE2CYCLEDELAY(0);
++ tmp |= GPMC_CONFIG6_BUSTURNAROUND(0);
++ printk("GPMC_CONFIG6 reg: %x\n", tmp);
++ gpmc_cs_write_reg(4, GPMC_CS_CONFIG6, tmp);
++#endif
++
++// Configure timing for CS6, wishbone access
++
++#if 1
++ // Signal control parameters per chip select
++ tmp = gpmc_cs_read_reg(6, GPMC_CS_CONFIG1);
++// tmp |= (GPMC_CONFIG1_MUXADDDATA);
++ tmp |= (GPMC_CONFIG1_WRITETYPE_SYNC);
++ tmp |= (GPMC_CONFIG1_READTYPE_SYNC);
++ tmp |= (GPMC_CONFIG1_FCLK_DIV(0));
++ gpmc_cs_write_reg(6, GPMC_CS_CONFIG1, tmp);
++ printk("GPMC_CONFIG1 reg: %x\n", tmp);
++#endif
++
++#if 1
++ // CS signal timing parameter configuration
++ tmp = 0;
++ tmp |= GPMC_CONFIG2_CSONTIME(1);
++ tmp |= GPMC_CONFIG2_CSWROFFTIME(17);
++ tmp |= GPMC_CONFIG2_CSRDOFFTIME(17);
++ printk("GPMC_CONFIG2 reg: %x\n", tmp);
++ gpmc_cs_write_reg(6, GPMC_CS_CONFIG2, tmp);
++#endif
++
++#if 0
++ // nADV signal timing parameter configuration
++ tmp = 0;
++ tmp |= GPMC_CONFIG3_ADVONTIME(1);
++ tmp |= GPMC_CONFIG3_ADVRDOFFTIME(2);
++ tmp |= GPMC_CONFIG3_ADVWROFFTIME(2);
++ printk("GPMC_CONFIG3 reg: %x\n", tmp);
++ gpmc_cs_write_reg(6, GPMC_CS_CONFIG3, tmp);
++#endif
++
++#if 0
++ // nWE and nOE signals timing parameter configuration
++ tmp = 0;
++ tmp |= GPMC_CONFIG4_WEONTIME(3);
++ tmp |= GPMC_CONFIG4_WEOFFTIME(4);
++ tmp |= GPMC_CONFIG4_OEONTIME(3);
++ tmp |= GPMC_CONFIG4_OEOFFTIME(4);
++ printk("GPMC_CONFIG4 reg: %x\n", tmp);
++ gpmc_cs_write_reg(6, GPMC_CS_CONFIG4, tmp);
++#endif
++
++#if 0
++ // RdAccess time and Cycle time timing paraters configuration
++ tmp = 0;
++ tmp |= GPMC_CONFIG5_PAGEBURSTACCESSTIME(1);
++ tmp |= GPMC_CONFIG5_RDACCESSTIME(4);
++ tmp |= GPMC_CONFIG5_WRCYCLETIME(5);
++ tmp |= GPMC_CONFIG5_RDCYCLETIME(5);
++ printk("GPMC_CONFIG5 reg: %x\n", tmp);
++ gpmc_cs_write_reg(6, GPMC_CS_CONFIG5, tmp);
++#endif
++
++#if 1
++ // WrAccessTime WrDataOnADmuxBus, Cycle2Cycle, and BusTurnAround params
++ tmp = 0;
++ tmp |= GPMC_CONFIG6_WRACCESSTIME(15);
++ tmp |= GPMC_CONFIG6_WRDATAONADMUXBUS(3);
++ tmp |= GPMC_CONFIG6_CYCLE2CYCLEDELAY(3);
++ tmp |= GPMC_CONFIG6_CYCLE2CYCLESAMECSEN;
++ tmp |= GPMC_CONFIG6_BUSTURNAROUND(0);
++ printk("GPMC_CONFIG6 reg: %x\n", tmp);
++ gpmc_cs_write_reg(6, GPMC_CS_CONFIG6, tmp);
++#endif
++
++}
++
+ static void __init overo_init(void)
+ {
+ omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+@@ -637,8 +799,14 @@ static void __init overo_init(void)
+ usb_ehci_init(&ehci_pdata);
+ overo_spi_init();
+ overo_init_smsc911x();
++#if 0
+ overo_display_init();
+-
++#endif
++ usrp1_e_init();
++#if 1
++ spi_register_board_info(overo_mcspi_board_info,
++ ARRAY_SIZE(overo_mcspi_board_info));
++#endif
+ /* Ensure SDRC pins are mux'd for self-refresh */
+ omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
+ omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
+@@ -680,7 +848,7 @@ static void __init overo_init(void)
+ "OVERO_GPIO_USBH_CPEN\n");
+ }
+
+-MACHINE_START(OVERO, "Gumstsix Overo")
++MACHINE_START(OVERO, "Gumstix Overo")
+ .boot_params = 0x80000100,
+ .map_io = omap3_map_io,
+ .reserve = omap_reserve,
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index 4d073f1..8bd6dfb 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -452,6 +452,15 @@ config PCH_PHUB
+ To compile this driver as a module, choose M here: the module will
+ be called pch_phub.
+
++config USRP_E
++ tristate "USRP-E FPGA interface driver"
++ default n
++ help
++ This driver is for the Ettus Research USRP Embedded Software
++ Defined Radio platform.
++
++ If you do not plan to run this kernel on that hardware choose N.
++
+ source "drivers/misc/c2port/Kconfig"
+ source "drivers/misc/eeprom/Kconfig"
+ source "drivers/misc/cb710/Kconfig"
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index 98009cc..f43483e 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -35,6 +35,7 @@ obj-$(CONFIG_TI_DAC7512) += ti_dac7512.o
+ obj-$(CONFIG_C2PORT) += c2port/
+ obj-$(CONFIG_IWMC3200TOP) += iwmc3200top/
+ obj-$(CONFIG_HMC6352) += hmc6352.o
++obj-$(CONFIG_USRP_E) += usrp_e.o
+ obj-y += eeprom/
+ obj-y += cb710/
+ obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o
+diff --git a/drivers/misc/usrp_e.c b/drivers/misc/usrp_e.c
+new file mode 100644
+index 0000000..2923b14
+--- /dev/null
++++ b/drivers/misc/usrp_e.c
+@@ -0,0 +1,1481 @@
++/*
++ * -*- linux-c -*-
++ * Interface for USRP Embedded from Ettus Research, LLC.
++ * This driver uses the GPMC interface on the OMAP3 to pass data
++ * to/from a Spartan 3 FPGA.
++ *
++ * Copyright (C) Ettus Research, LLC
++ *
++ * Written by Philip Balister <philip@opensdr.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "linux/fs.h"
++#include "linux/module.h"
++#include "linux/cdev.h"
++#include "linux/device.h"
++#include "linux/spinlock.h"
++#include "linux/errno.h"
++#include "linux/irq.h"
++#include "linux/interrupt.h"
++#include "linux/wait.h"
++#include "linux/sched.h"
++#include "linux/dma-mapping.h"
++#include "linux/semaphore.h"
++#include "linux/kthread.h"
++#include "linux/poll.h"
++#include "linux/slab.h"
++
++#include "plat/gpmc.h"
++#include "plat/gpio.h"
++#include "plat/dma.h"
++
++#include "asm/uaccess.h"
++#include "asm/io.h"
++#include "asm/atomic.h"
++
++#include "linux/usrp_e.h"
++
++#define TX_SPACE_AVAILABLE_GPIO 144
++#define RX_DATA_READY_GPIO 146
++
++static atomic_t use_count = ATOMIC_INIT(0);
++static atomic_t mapped = ATOMIC_INIT(0);
++static int shutting_down;
++
++struct spi_regs_wb;
++struct i2c_regs_wb;
++
++struct usrp_e_dev {
++ struct cdev cdev;
++ unsigned long mem_base;
++ unsigned long control_mem_base;
++ u32 *ioaddr;
++ u8 *ctl_addr;
++ struct spi_regs_wb *ctl_spi;
++ struct i2c_regs_wb *ctl_i2c;
++ spinlock_t fpga_lock;
++
++ atomic_t n_overruns;
++ atomic_t n_underruns;
++
++} *usrp_e_devp;
++
++struct dma_data {
++ int ch;
++ struct omap_dma_channel_params params;
++
++ unsigned long virt_from;
++ unsigned long virt_to;
++ unsigned long phys_from;
++ unsigned long phys_to;
++};
++
++#define MISC_REGS_BASE 0x0
++
++#define UE_REG_MISC_LED (MISC_REGS_BASE + 0)
++
++#define UE_REG_MISC_RX_LEN (MISC_REGS_BASE + 10)
++#define UE_REG_MISC_TX_LEN (MISC_REGS_BASE + 12)
++
++#define UE_REG_SLAVE(n) ((n)<<7)
++#define UE_REG_SR_ADDR(n) ((UE_REG_SLAVE(5)) + (4*(n)))
++
++#define UE_REG_CTRL_TX_CLEAR_UNDERRUN UE_REG_SR_ADDR(25)
++#define UE_SR_CLEAR_FIFO UE_REG_SR_ADDR(6)
++
++#define CTL_SPI_BASE 0x100
++
++struct spi_regs_wb {
++ u32 txrx0;
++ u32 txrx1;
++ u32 txrx2;
++ u32 txrx3;
++ u32 ctrl;
++ u32 div;
++ u32 ss;
++};
++
++/* Defines for spi ctrl register */
++#define UE_SPI_CTRL_ASS (BIT(13))
++#define UE_SPI_CTRL_IE (BIT(12))
++#define UE_SPI_CTRL_LSB (BIT(11))
++/* defines for TXNEG and RXNEG in usrp_e.h so user can pass them to driver. */
++#define UE_SPI_CTRL_GO_BSY (BIT(8))
++#define UE_SPI_CTRL_CHAR_LEN_MASK 0x7f
++
++
++#define CTL_I2C_BASE 0x180
++#if 1
++struct i2c_regs_wb {
++ u8 prescalar_lo;
++ u8 dummy;
++ u8 dummy1;
++ u8 dummy2;
++ u8 prescalar_hi;
++ u8 dummy3;
++ u8 dummy4;
++ u8 dummy5;
++ u8 ctrl;
++ u8 dummy6;
++ u8 dummy7;
++ u8 dummy8;
++ u8 data;
++ u8 dummy9;
++ u8 dummy10;
++ u8 dummy11;
++ u8 cmd_status;
++};
++#else
++struct i2c_regs_wb {
++ u16 prescalar_lo;
++ u16 dummy2;
++ u16 prescalar_hi;
++ u16 dummy3;
++ u16 ctrl;
++ u16 dummy6;
++ u16 data;
++ u16 dummy9;
++ u16 cmd_status;
++};
++#endif
++
++#define I2C_CTRL_EN (BIT(7)) /* core enable */
++#define I2C_CTRL_IE (BIT(6)) /* interrupt enable */
++
++/* STA, STO, RD, WR, and IACK bits are cleared automatically */
++
++#define I2C_CMD_START (BIT(7))
++#define I2C_CMD_STOP (BIT(6))
++#define I2C_CMD_RD (BIT(5))
++#define I2C_CMD_WR (BIT(4))
++#define I2C_CMD_NACK (BIT(3))
++#define I2C_CMD_RSVD_2 (BIT(2))
++#define I2C_CMD_RSVD_1 (BIT(1))
++#define I2C_CMD_IACK (BIT(0))
++
++#define I2C_ST_RXACK (BIT(7))
++#define I2C_ST_BUSY (BIT(6))
++#define I2C_ST_AL (BIT(5))
++#define I2C_RSVD_4 (BIT(4))
++#define I2C_RSVD_3 (BIT(3))
++#define I2C_RSVD_2 (BIT(2))
++#define I2C_ST_TIP (BIT(1))
++#define I2C_ST_IP (BIT(0))
++
++#define MAX_WB_DIV 4
++#define MASTER_CLK_RATE 64000000
++#define PRESCALAR(wb_div) (((MASTER_CLK_RATE/(wb_div)) / (5 * 100000)) - 1)
++
++static __u16 prescalar_values[MAX_WB_DIV+1] = {
++ 0xffff,
++ PRESCALAR(1),
++ PRESCALAR(2),
++ PRESCALAR(3),
++ PRESCALAR(4),
++};
++
++static struct dma_data *rx_dma;
++static struct dma_data *tx_dma;
++
++struct ring_buffer_entry {
++ unsigned long dma_addr;
++ __u8 *frame_addr;
++};
++
++struct ring_buffer {
++ struct ring_buffer_info (*rbi)[];
++ struct ring_buffer_entry (*rbe)[];
++ int num_pages;
++ unsigned long (*pages)[];
++};
++
++static struct ring_buffer tx_rb;
++static struct ring_buffer rx_rb;
++
++static struct usrp_e_ring_buffer_size_t rb_size;
++
++#define NUM_PAGES_RX_FLAGS 1
++#define NUM_RX_FRAMES 100
++#define NUM_PAGES_TX_FLAGS 1
++#define NUM_TX_FRAMES 100
++
++static int tx_rb_write;
++static int tx_rb_read;
++static int rx_rb_write;
++static int rx_rb_read;
++
++static int alloc_ring_buffer(struct ring_buffer *rb,
++ unsigned int num_bufs, enum dma_data_direction direction);
++static void delete_ring_buffer(struct ring_buffer *rb,
++ unsigned int num_bufs, enum dma_data_direction direction);
++static int alloc_ring_buffers(void);
++static void init_ring_buffer(struct ring_buffer *rb, int num_bufs,
++ int init_flags, enum dma_data_direction direction);
++
++static dev_t usrp_e_dev_number;
++static struct class *usrp_e_class;
++
++#define DEVICE_NAME "usrp_e"
++
++static const struct file_operations usrp_e_fops;
++
++static irqreturn_t space_available_irqhandler(int irq, void *dev_id);
++static irqreturn_t data_ready_irqhandler(int irq, void *dev_id);
++static void usrp_rx_dma_irq(int ch, u16 stat, void *data);
++static void usrp_tx_dma_irq(int ch, u16 stat, void *data);
++
++static DECLARE_WAIT_QUEUE_HEAD(data_received_queue);
++static DECLARE_WAIT_QUEUE_HEAD(space_available_queue);
++static DECLARE_WAIT_QUEUE_HEAD(received_data_from_user);
++static DECLARE_WAIT_QUEUE_HEAD(tx_rb_space_available);
++
++static int tx_dma_waiting_for_data;
++static int waiting_for_space_in_tx_rb;
++
++#define DEBUG_RX 1
++
++static DEFINE_SEMAPHORE(dma_lock);
++
++static void usrp_e_spi_init(void);
++static void usrp_e_i2c_init(void);
++
++static int init_dma_controller(void);
++static void release_dma_controller(void);
++static int get_frame_from_fpga_start(void);
++static int get_frame_from_fpga_finish(void);
++static int send_frame_to_fpga_start(void);
++static int send_frame_to_fpga_finish(void);
++
++static int rx_dma_active;
++static int tx_dma_active;
++
++static int __init
++usrp_e_init(void)
++{
++ int ret;
++ struct usrp_e_dev *p;
++
++ printk(KERN_DEBUG "usrp_e entering driver initialization\n");
++
++ if (alloc_chrdev_region(&usrp_e_dev_number, 0, 1, DEVICE_NAME) < 0) {
++ printk(KERN_DEBUG "Can't register device\n");
++ return -1;
++ }
++
++ usrp_e_class = class_create(THIS_MODULE, DEVICE_NAME);
++
++ usrp_e_devp = kzalloc(sizeof(struct usrp_e_dev), GFP_KERNEL);
++ if (!usrp_e_devp) {
++ printk(KERN_ERR "Bad kmalloc\n");
++ return -ENOMEM;
++ }
++
++ p = usrp_e_devp; /* Shorten var name so I stay sane. */
++
++ printk(KERN_DEBUG "usrp_e data struct malloc'd.\n");
++
++ atomic_set(&p->n_underruns, 0);
++ atomic_set(&p->n_overruns, 0);
++
++ printk(KERN_DEBUG "usrp_e Data initialized..\n");
++
++ cdev_init(&p->cdev, &usrp_e_fops);
++ p->cdev.owner = THIS_MODULE;
++
++ ret = cdev_add(&p->cdev, MKDEV(MAJOR(usrp_e_dev_number), 0), 1);
++ if (ret) {
++ printk(KERN_ERR "Bad cdev\n");
++ return ret;
++ }
++
++ printk(KERN_DEBUG "usrp_e major number : %d\n",
++ MAJOR(usrp_e_dev_number));
++ device_create(usrp_e_class, NULL, MKDEV(MAJOR(usrp_e_dev_number), 0),
++ NULL, "usrp_e%d", 0);
++
++ printk(KERN_DEBUG "Getting Chip Select\n");
++
++ if (gpmc_cs_request(4, SZ_2K, &p->mem_base) < 0) {
++ printk(KERN_ERR "Failed request for GPMC mem for usrp_e\n");
++ return -1;
++ }
++ printk(KERN_DEBUG "Got CS4, address = %lx\n", p->mem_base);
++
++ if (!request_mem_region(p->mem_base, SZ_2K, "usrp_e")) {
++ printk(KERN_ERR "Request_mem_region failed.\n");
++ gpmc_cs_free(4);
++ return -1;
++ }
++
++ p->ioaddr = ioremap(p->mem_base, SZ_2K);
++ spin_lock_init(&p->fpga_lock);
++
++ if (gpmc_cs_request(6, SZ_2K, &p->control_mem_base) < 0) {
++ printk(KERN_ERR "Failed request for GPMC control mem for usrp_e\n");
++ return -1;
++ }
++ printk(KERN_DEBUG "Got CS6, address = %lx\n", p->control_mem_base);
++
++ if (!request_mem_region(p->control_mem_base, SZ_2K, "usrp_e_c")) {
++ printk(KERN_ERR "Request_mem_region failed.\n");
++ gpmc_cs_free(6);
++ return -1;
++ }
++
++ p->ctl_addr = ioremap_nocache(p->control_mem_base, SZ_2K);
++
++ /* Initialize wishbone SPI and I2C interfaces */
++
++ usrp_e_spi_init();
++ usrp_e_i2c_init();
++
++ /* Configure GPIO's */
++
++ if (!(((gpio_request(TX_SPACE_AVAILABLE_GPIO,
++ "TX_SPACE_AVAILABLE_GPIO") == 0) &&
++ (gpio_direction_input(TX_SPACE_AVAILABLE_GPIO) == 0)))) {
++ printk(KERN_ERR "Could not claim GPIO for TX_SPACE_AVAILABLE_GPIO\n");
++ return -1;
++ }
++
++ if (!(((gpio_request(RX_DATA_READY_GPIO, "RX_DATA_READY_GPIO") == 0) &&
++ (gpio_direction_input(RX_DATA_READY_GPIO) == 0)))) {
++ printk(KERN_ERR "Could not claim GPIO for RX_DATA_READY_GPIO\n");
++ return -1;
++ }
++
++ /* Debug gpios */
++ if (!(((gpio_request(14, "Debug0") == 0) &&
++ (gpio_direction_output(14, 0) == 0)))) {
++ printk(KERN_ERR "Could not claim GPIO for Debug0\n");
++ return -1;
++ }
++
++ if (!(((gpio_request(21, "Debug1") == 0) &&
++ (gpio_direction_output(21, 0) == 0)))) {
++ printk(KERN_ERR "Could not claim GPIO for Debug1\n");
++ return -1;
++ }
++
++ if (!(((gpio_request(22, "Debug2") == 0) &&
++ (gpio_direction_output(22, 0) == 0)))) {
++ printk(KERN_ERR "Could not claim GPIO for Debug2\n");
++ return -1;
++ }
++
++ if (!(((gpio_request(23, "Debug3") == 0) &&
++ (gpio_direction_output(23, 0) == 0)))) {
++ printk(KERN_ERR "Could not claim GPIO for Debug3\n");
++ return -1;
++ }
++
++
++ rb_size.num_pages_rx_flags = NUM_PAGES_RX_FLAGS;
++ rb_size.num_rx_frames = NUM_RX_FRAMES;
++ rb_size.num_pages_tx_flags = NUM_PAGES_TX_FLAGS;
++ rb_size.num_tx_frames = NUM_TX_FRAMES;
++
++ ret = alloc_ring_buffers();
++ if (ret < 0)
++ return ret;
++
++ /* Initialize various DMA related flags */
++ rx_dma_active = 0;
++ tx_dma_active = 0;
++ shutting_down = 0;
++
++ printk(KERN_DEBUG "usrp_e Driver Initialized.\n");
++
++ return 0;
++}
++
++static void __exit
++usrp_e_cleanup(void)
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++
++ unregister_chrdev_region(usrp_e_dev_number, 1);
++
++ release_mem_region(p->mem_base, SZ_2K);
++ release_mem_region(p->control_mem_base, SZ_2K);
++
++ device_destroy(usrp_e_class, MKDEV(MAJOR(usrp_e_dev_number), 0));
++ cdev_del(&p->cdev);
++
++ class_destroy(usrp_e_class);
++
++ iounmap(p->ioaddr);
++ iounmap(p->ctl_addr);
++
++ gpmc_cs_free(4);
++ gpmc_cs_free(6);
++
++ printk(KERN_DEBUG "Freeing gpios\n");
++
++ gpio_free(TX_SPACE_AVAILABLE_GPIO);
++ gpio_free(RX_DATA_READY_GPIO);
++
++ /* debug */
++ gpio_free(14);
++ gpio_free(21);
++ gpio_free(22);
++ gpio_free(23);
++
++ delete_ring_buffer(&tx_rb, rb_size.num_tx_frames, DMA_TO_DEVICE);
++ delete_ring_buffer(&rx_rb, rb_size.num_rx_frames, DMA_FROM_DEVICE);
++
++ kfree(p);
++
++ printk(KERN_DEBUG "Leaving cleanup\n");
++}
++
++static int
++usrp_e_open(struct inode *inode, struct file *file)
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++ int ret;
++
++ printk(KERN_DEBUG "usrp_e open called, use_count = %d\n",
++ atomic_read(&use_count));
++ if (atomic_add_return(1, &use_count) != 1) {
++ printk(KERN_ERR "use_count = %d\n", atomic_read(&use_count));
++ atomic_dec(&use_count);
++ return -EBUSY;
++ }
++
++ /* Clear rx and tx fifos in the fpga */
++ writel(1, p->ctl_addr + UE_SR_CLEAR_FIFO);
++ writel(2, p->ctl_addr + UE_SR_CLEAR_FIFO);
++
++#if 0
++ usrp_e_devp = container_of(inode->i_cdev, struct usrp_e_dev, cdev);
++
++ file->private_data = usrp_e_devp;
++#endif
++
++ ret = init_dma_controller();
++ if (ret < 0)
++ return ret;
++
++ tx_rb_write = 0;
++ tx_rb_read = 0;
++
++ rx_rb_write = 0;
++ rx_rb_read = 0;
++
++ tx_dma_active = 0;
++ rx_dma_active = 0;
++ shutting_down = 0;
++
++ init_ring_buffer(&rx_rb, rb_size.num_rx_frames, RB_KERNEL, DMA_FROM_DEVICE);
++ init_ring_buffer(&tx_rb, rb_size.num_tx_frames, RB_KERNEL, DMA_TO_DEVICE);
++
++ /* Configure interrupts for GPIO pins */
++
++ ret = request_irq(gpio_to_irq(TX_SPACE_AVAILABLE_GPIO),
++ space_available_irqhandler,
++ IRQF_TRIGGER_RISING, "usrp_e_space_available", NULL);
++
++ ret = request_irq(gpio_to_irq(RX_DATA_READY_GPIO),
++ data_ready_irqhandler,
++ IRQF_TRIGGER_RISING, "usrp_e_data_ready", NULL);
++
++ printk(KERN_DEBUG "usrp: leaving open\n");
++ return 0;
++}
++
++static int
++usrp_e_release(struct inode *inode, struct file *file)
++{
++ struct usrp_e_dev *usrp_e_devp = file->private_data;
++
++ printk(KERN_DEBUG "usrp_e release called\n");
++
++ if (atomic_read(&use_count) != 1) {
++ printk(KERN_ERR "Attempt to close usrp_e driver that is not open");
++ return -ENOENT;
++ }
++
++ printk(KERN_DEBUG "Waiting for DMA to become inactive\n");
++ shutting_down = 0;
++ while (tx_dma_active || rx_dma_active)
++ cpu_relax();
++
++ /* Freeing gpio irq's */
++ printk(KERN_DEBUG "Freeing gpio irq's\n");
++
++ free_irq(gpio_to_irq(TX_SPACE_AVAILABLE_GPIO), NULL);
++ free_irq(gpio_to_irq(RX_DATA_READY_GPIO), NULL);
++
++ printk(KERN_DEBUG "Freeing DMA channels\n");
++
++ release_dma_controller();
++
++ usrp_e_devp = 0;
++
++ atomic_dec(&use_count);
++
++ return 0;
++}
++
++static ssize_t
++usrp_e_read(struct file *file, char *buf, size_t count, loff_t *ppos)
++{
++ size_t ret;
++ int rx_pkt_len;
++
++ if (count > SZ_2K)
++ return -EMSGSIZE;
++
++ if (!((*rx_rb.rbi)[rx_rb_read].flags & RB_USER)) {
++ if (wait_event_interruptible(data_received_queue,
++ (((*rx_rb.rbi)[rx_rb_read].flags & RB_USER))))
++ return -EINTR;
++ }
++
++ rx_pkt_len = (*rx_rb.rbi)[rx_rb_read].len;
++ ret = copy_to_user(buf, (*rx_rb.rbe)[rx_rb_read].frame_addr, rx_pkt_len);
++
++ (*rx_rb.rbi)[rx_rb_read].flags = RB_KERNEL;
++
++ rx_rb_read++;
++ if (rx_rb_read == rb_size.num_rx_frames)
++ rx_rb_read = 0;
++
++ get_frame_from_fpga_start();
++
++ return ((ret == 0) ? rx_pkt_len : -ret);
++}
++
++static ssize_t
++usrp_e_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
++{
++ size_t ret;
++
++#if 0
++// printk("In write.\n");
++
++ /* Trigger a DMA transfer. Used to start transmit after writing */
++ /* data into the transmit ring buffer from user space */
++ if (count < 0) {
++ send_frame_to_fpga_start();
++ return 0;
++ }
++
++ if (count > SZ_2K)
++ return -EMSGSIZE;
++
++// printk("Write flags: %d\n", (*tx_rb.rbe)[tx_rb_write].flags);
++ if (!((*tx_rb.rbi)[tx_rb_write].flags & RB_KERNEL)) {
++ waiting_for_space_in_tx_rb = 1;
++// printk("Sleeping\n");
++ if (wait_event_interruptible(tx_rb_space_available,
++ ((*tx_rb.rbi)[tx_rb_write].flags & RB_KERNEL)))
++ return -EINTR;
++// printk("Waking\n");
++ }
++
++ ret = copy_from_user((*tx_rb.rbe)[tx_rb_write].frame_addr, buf, count);
++ if (ret)
++ return -ret;
++
++ (*tx_rb.rbi)[tx_rb_write].len = count;
++ (*tx_rb.rbi)[tx_rb_write].flags = RB_USER;
++
++ tx_rb_write++;
++ if (tx_rb_write == rb_size.num_tx_frames)
++ tx_rb_write = 0;
++
++// printk("Calling send_to_fpga_start from write\n");
++#endif
++ send_frame_to_fpga_start();
++
++ return count;
++}
++
++static loff_t
++usrp_e_llseek(struct file *file, loff_t offest, int orig)
++{
++ printk(KERN_DEBUG "usrp_e llseek called\n");
++
++ return 0;
++}
++
++static int usrp_e_ctl16(unsigned long arg, int direction)
++{
++ struct usrp_e_ctl16 __user *argp = (struct usrp_e_ctl16 __user *) arg;
++ int i;
++ struct usrp_e_ctl16 ctl;
++
++ if (copy_from_user(&ctl, argp, sizeof(struct usrp_e_ctl16)))
++ return -EFAULT;
++
++ if (ctl.count > 10)
++ return -EINVAL;
++
++ if (direction == 0) {
++ for (i = 0; i < ctl.count; i++)
++ writew(ctl.buf[i], &usrp_e_devp->ctl_addr \
++ [i + ctl.offset]);
++ } else if (direction == 1) {
++ for (i = 0; i < ctl.count; i++)
++ ctl.buf[i] = readw(&usrp_e_devp->ctl_addr \
++ [i + ctl.offset]);
++
++ if (copy_to_user(argp, &ctl, sizeof(struct usrp_e_ctl16)))
++ return -EFAULT;
++ } else
++ return -EFAULT;
++
++ return 0;
++}
++
++static int usrp_e_ctl32(unsigned long arg, int direction)
++{
++ struct usrp_e_ctl32 __user *argp = (struct usrp_e_ctl32 __user *) arg;
++ int i;
++ struct usrp_e_ctl32 ctl;
++
++ if (copy_from_user(&ctl, argp, sizeof(struct usrp_e_ctl32)))
++ return -EFAULT;
++
++ if (ctl.count > 20)
++ return -EINVAL;
++
++ if (direction == 0) {
++ for (i = 0; i < ctl.count; i++)
++ writel(ctl.buf[i], &usrp_e_devp->ctl_addr \
++ [i + ctl.offset]);
++ } else if (direction == 1) {
++ for (i = 0; i < ctl.count; i++)
++ ctl.buf[i] = readl(&usrp_e_devp->ctl_addr \
++ [i + ctl.offset]);
++
++ if (copy_to_user(argp, &ctl, sizeof(struct usrp_e_ctl16)))
++ return -EFAULT;
++
++ } else
++ return -EFAULT;
++
++ return 0;
++}
++
++static int usrp_e_get_rb_info(unsigned long arg)
++{
++ struct usrp_e_ring_buffer_size_t __user *argp = (struct usrp_e_ring_buffer_size_t __user *) arg;
++ int i;
++
++ if (copy_to_user(argp, &rb_size, sizeof(rb_size)))
++ return -EFAULT;
++
++ return 0;
++}
++
++static void usrp_e_spi_init()
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++
++ p->ctl_spi = (struct spi_regs_wb *)(p->ctl_addr + CTL_SPI_BASE);
++ p->ctl_spi->div = 64; /* 1 = Div by 4 (12.5 MHz) */
++}
++
++static int usrp_e_spi_wait(void)
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++
++ while (p->ctl_spi->ctrl & UE_SPI_CTRL_GO_BSY) {
++ if (signal_pending(current)) {
++ printk(KERN_DEBUG "Signal received.\n");
++ set_current_state(TASK_RUNNING);
++ return -EINTR;
++ }
++ schedule();
++ }
++
++ return 0;
++}
++
++static int usrp_e_spi(unsigned long __user arg)
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++ struct usrp_e_spi __user *argp = (struct usrp_e_spi __user *) arg;
++ struct usrp_e_spi spi_cmd;
++ int ctrl, ret;
++
++ if (copy_from_user(&spi_cmd, argp, sizeof(struct usrp_e_spi)))
++ return -EFAULT;
++
++ spi_cmd.flags &= (UE_SPI_CTRL_TXNEG | UE_SPI_CTRL_RXNEG);
++ ctrl = UE_SPI_CTRL_ASS | (UE_SPI_CTRL_CHAR_LEN_MASK & spi_cmd.length) \
++ | spi_cmd.flags;
++
++ ret = usrp_e_spi_wait();
++ if (ret < 0)
++ return ret;
++
++ p->ctl_spi->ss = spi_cmd.slave & 0xff;
++
++ p->ctl_spi->txrx0 = spi_cmd.data;
++
++ p->ctl_spi->ctrl = ctrl;
++ p->ctl_spi->ctrl = ctrl | UE_SPI_CTRL_GO_BSY;
++
++ if (spi_cmd.readback) {
++ usrp_e_spi_wait();
++ if (copy_to_user(&argp->data, &p->ctl_spi->txrx0,
++ sizeof(__u32)))
++ return -EFAULT;
++ else
++ return 0;
++ } else
++ return 0;
++
++}
++
++static void usrp_e_i2c_init()
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++ int wb_div;
++
++ p->ctl_i2c = (struct i2c_regs_wb *)(p->ctl_addr + CTL_I2C_BASE);
++
++ writeb(0, &p->ctl_i2c->ctrl); /* disable core */
++
++ /* Assume wb_div is 4, deal with this later */
++ wb_div = 4;
++ if (wb_div > MAX_WB_DIV)
++ wb_div = MAX_WB_DIV;
++
++ writeb((prescalar_values[wb_div] & 0xff), &p->ctl_i2c->prescalar_lo);
++ writeb(((prescalar_values[wb_div] >> 8) & 0xff),
++ &p->ctl_i2c->prescalar_hi);
++ writeb(I2C_CTRL_EN, &p->ctl_i2c->ctrl); /* enable core */
++}
++
++static int usrp_e_i2c_wait(__u32 mask, int chk_ack)
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++
++ while (readb(&p->ctl_i2c->cmd_status) & mask) {
++ if (signal_pending(current)) {
++ printk(KERN_DEBUG "Signal received.\n");
++ set_current_state(TASK_RUNNING);
++ return -EINTR;
++ }
++ schedule();
++ }
++
++ if (chk_ack) {
++ if ((readb(&p->ctl_i2c->cmd_status) & I2C_ST_RXACK) == 0)
++ return 1;
++ else
++ return 0;
++ }
++
++ return 0;
++}
++
++static int usrp_e_i2c(unsigned long arg, int direction)
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++ struct usrp_e_i2c __user *argp = (struct usrp_e_i2c __user *) arg;
++ struct usrp_e_i2c tmp;
++ struct usrp_e_i2c *i2c_msg;
++ int ret, len, i;
++
++ if (copy_from_user(&tmp, argp, sizeof(struct usrp_e_i2c)))
++ return -EFAULT;
++
++ i2c_msg = kmalloc(sizeof(struct usrp_e_i2c) + tmp.len, GFP_KERNEL);
++ if (!i2c_msg)
++ return -ENOMEM;
++
++ if (copy_from_user(i2c_msg, argp,
++ (sizeof(struct usrp_e_i2c) + tmp.len)))
++ return -EFAULT;
++
++ if (direction) {
++ /* read */
++ if (i2c_msg->len == 0)
++ return 1;
++
++ usrp_e_i2c_wait(I2C_ST_BUSY, 0);
++
++ writeb(((i2c_msg->addr << 1) | 1), &p->ctl_i2c->data);
++ writeb((I2C_CMD_WR | I2C_CMD_START), &p->ctl_i2c->cmd_status);
++ ret = usrp_e_i2c_wait(I2C_ST_TIP, 1);
++ if (ret < 0) {
++ return ret;
++ } else if (ret == 0) {
++ writeb(I2C_CMD_STOP, &p->ctl_i2c->cmd_status);
++ return 2;
++ }
++
++ for (len = i2c_msg->len, i = 0; len > 0; i++, len--) {
++ writeb((I2C_CMD_RD | ((len == 1) ?
++ (I2C_CMD_NACK | I2C_CMD_STOP) : 0)),
++ &p->ctl_i2c->cmd_status);
++ usrp_e_i2c_wait(I2C_ST_TIP, 0);
++ i2c_msg->data[i] = readb(&p->ctl_i2c->data);
++ }
++ if (copy_to_user(argp, i2c_msg, (sizeof(struct usrp_e_i2c) +
++ tmp.len)))
++ return -EFAULT;
++ } else {
++ /* write */
++ usrp_e_i2c_wait(I2C_ST_BUSY, 0);
++ writeb(((i2c_msg->addr << 1) | 0), &p->ctl_i2c->data);
++ writeb((I2C_CMD_WR | I2C_CMD_START |
++ (i2c_msg->len == 0 ? I2C_CMD_STOP : 0)),
++ &p->ctl_i2c->cmd_status);
++ ret = usrp_e_i2c_wait(I2C_ST_TIP, 1);
++ if (ret < 0) {
++ return ret;
++ } else if (ret == 0) {
++ writeb(I2C_CMD_STOP, &p->ctl_i2c->cmd_status);
++ return 2;
++ }
++ for (len = i2c_msg->len, i = 0; len > 0; i++, len--) {
++ writeb(i2c_msg->data[i], &p->ctl_i2c->data);
++ writeb((I2C_CMD_WR | (len == 1 ? I2C_CMD_STOP : 0)),
++ &p->ctl_i2c->cmd_status);
++ ret = usrp_e_i2c_wait(I2C_ST_TIP, 1);
++ if (ret < 0) {
++ return ret;
++ } else if (ret == 0) {
++ writeb(I2C_CMD_STOP, &p->ctl_i2c->cmd_status);
++ return 2;
++ }
++ }
++
++ }
++
++
++ return 1;
++}
++
++static int usrp_e_ioctl(struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++
++ switch (cmd) {
++ case USRP_E_WRITE_CTL16:
++ return usrp_e_ctl16(arg, 0);
++
++ case USRP_E_READ_CTL16:
++ return usrp_e_ctl16(arg, 1);
++
++ case USRP_E_WRITE_CTL32:
++ return usrp_e_ctl32(arg, 0);
++
++ case USRP_E_READ_CTL32:
++ return usrp_e_ctl32(arg, 1);
++
++ case USRP_E_SPI:
++ return usrp_e_spi(arg);
++
++ case USRP_E_I2C_WRITE:
++ return usrp_e_i2c(arg, 0);
++
++ case USRP_E_I2C_READ:
++ return usrp_e_i2c(arg, 1);
++
++ case USRP_E_GET_RB_INFO:
++ return usrp_e_get_rb_info(arg);
++
++ default:
++ return -ENOTTY;
++ }
++
++ return 0;
++}
++
++static unsigned int usrp_e_poll(struct file *filp, poll_table *wait)
++{
++ unsigned int mask = 0;
++
++ poll_wait(filp, &data_received_queue, wait);
++ poll_wait(filp, &tx_rb_space_available, wait);
++
++ // Make sure write is active before sleeping
++ send_frame_to_fpga_start();
++
++ /* Make sure to read in case the rx ring buffer is full */
++ get_frame_from_fpga_start();
++
++ // This likely needs some locking. The pointer is incremented
++ // before the flag state is updated.
++
++ if (rx_rb_write == 0) {
++ if ((*rx_rb.rbi)[rb_size.num_rx_frames - 1].flags & RB_USER)
++ mask |= POLLIN | POLLRDNORM;
++ } else {
++ if ((*rx_rb.rbi)[rx_rb_write - 1].flags & RB_USER)
++ mask |= POLLIN | POLLRDNORM;
++ }
++
++ if (tx_rb_read == 0) {
++ if ((*tx_rb.rbi)[rb_size.num_tx_frames - 1].flags & RB_KERNEL)
++ mask |= POLLOUT | POLLWRNORM;
++ } else {
++ if ((*tx_rb.rbi)[tx_rb_read - 1].flags & RB_KERNEL)
++ mask |= POLLOUT | POLLWRNORM;
++ }
++
++ return mask;
++
++}
++
++/* The mmap code is based on code in af_packet.c */
++
++static void usrp_e_mm_open(struct vm_area_struct *vma)
++{
++
++ atomic_inc(&mapped);
++}
++
++static void usrp_e_mm_close(struct vm_area_struct *vma)
++{
++
++ atomic_dec(&mapped);
++}
++
++static const struct vm_operations_struct usrp_e_mmap_ops = {
++ .open = usrp_e_mm_open,
++ .close = usrp_e_mm_close,
++};
++
++static int usrp_e_mmap(struct file *filp, struct vm_area_struct *vma)
++{
++ unsigned long size, expected_size;
++ unsigned int i;
++ unsigned long start;
++ int err;
++ struct page *page;
++
++ printk("In mmap\n");
++
++ if (vma->vm_pgoff)
++ return -EINVAL;
++
++ /* Verify the user will map the entire tx and rx ring buffer space */
++ expected_size = (rb_size.num_rx_frames + rb_size.num_tx_frames) * (PAGE_SIZE >> 1)
++ + (rb_size.num_pages_rx_flags + rb_size.num_pages_tx_flags) * PAGE_SIZE;
++
++ size = vma->vm_end - vma->vm_start;
++ printk(KERN_DEBUG "Size = %d, expected sixe = %d\n", size, expected_size);
++
++ if (size != expected_size)
++ return -EINVAL;
++
++ start = vma->vm_start;
++
++ page = virt_to_page(rx_rb.rbi);
++ err = vm_insert_page(vma, start, page);
++ if (err)
++ return -EINVAL;
++
++ start += PAGE_SIZE;
++
++ for (i = 0; i < rx_rb.num_pages; ++i) {
++ struct page *page = virt_to_page((*rx_rb.pages)[i]);
++ err = vm_insert_page(vma, start, page);
++ if (err)
++ return -EINVAL;
++
++ start += PAGE_SIZE;
++ }
++
++ page = virt_to_page(tx_rb.rbi);
++ err = vm_insert_page(vma, start, page);
++ if (err)
++ return -EINVAL;
++
++ start += PAGE_SIZE;
++
++ for (i = 0; i < tx_rb.num_pages; ++i) {
++ struct page *page = virt_to_page((*tx_rb.pages)[i]);
++
++ err = vm_insert_page(vma, start, page);
++ if (err)
++ return err;
++
++ start += PAGE_SIZE;
++ }
++
++ vma->vm_ops = &usrp_e_mmap_ops;
++
++ return 0;
++}
++
++static const struct file_operations usrp_e_fops = {
++ .owner = THIS_MODULE,
++ .open = usrp_e_open,
++ .release = usrp_e_release,
++ .read = usrp_e_read,
++ .write = usrp_e_write,
++ .llseek = usrp_e_llseek,
++ .unlocked_ioctl = usrp_e_ioctl,
++ .poll = usrp_e_poll,
++ .mmap = usrp_e_mmap,
++};
++
++MODULE_VERSION("0.1");
++MODULE_ALIAS(DEVICE_NAME);
++MODULE_DESCRIPTION(DEVICE_NAME);
++MODULE_AUTHOR("Philip Balister <philip@opensdr.com>");
++MODULE_LICENSE("GPL v2");
++
++module_init(usrp_e_init);
++module_exit(usrp_e_cleanup);
++
++static irqreturn_t space_available_irqhandler(int irq, void *dev_id)
++{
++ int serviced = IRQ_NONE;
++
++#ifdef DEBUG_TX
++ gpio_set_value(22, 1);
++#endif
++
++// printk("Calling send_to_fpga_start from space_available irq\n");
++ send_frame_to_fpga_start();
++
++ serviced = IRQ_HANDLED;
++
++#ifdef DEBUG_TX
++ gpio_set_value(22, 0);
++#endif
++
++ return serviced;
++}
++
++static void usrp_rx_dma_irq(int ch, u16 stat, void *data)
++{
++
++#ifdef DEBUG_RX
++ gpio_set_value(23, 1);
++#endif
++
++ rx_dma_active = 0;
++
++ get_frame_from_fpga_finish();
++
++#ifdef DEBUG_RX
++ gpio_set_value(23, 0);
++#endif
++}
++
++static void usrp_tx_dma_irq(int ch, u16 stat, void *data)
++{
++
++#ifdef DEBUG_TX
++ gpio_set_value(23, 1);
++#endif
++ tx_dma_active = 0;
++
++ send_frame_to_fpga_finish();
++
++#ifdef DEBUG_TX
++ gpio_set_value(23, 0);
++#endif
++
++/* Save
++ gpio_set_value(21, 1);
++ gpio_set_value(21, 0);
++*/
++
++}
++
++static irqreturn_t data_ready_irqhandler(int irq, void *dev_id)
++{
++ int serviced = IRQ_NONE;
++
++#ifdef DEBUG_RX
++ gpio_set_value(22, 1);
++#endif
++
++ get_frame_from_fpga_start();
++
++ serviced = IRQ_HANDLED;
++
++#ifdef DEBUG_RX
++ gpio_set_value(22, 0);
++#endif
++ return serviced;
++}
++
++static int init_dma_controller()
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++
++ rx_dma = kzalloc(sizeof(struct dma_data), GFP_KERNEL);
++ if (!rx_dma) {
++ printk(KERN_ERR "Failed to allocate memory for rx_dma struct.");
++ return -ENOMEM;
++ }
++
++ if (omap_request_dma(OMAP_DMA_NO_DEVICE, "usrp-e-rx",
++ usrp_rx_dma_irq, (void *) rx_dma, &rx_dma->ch)) {
++ printk(KERN_ERR "Could not get rx DMA channel for usrp_e\n");
++ return -ENOMEM;
++ }
++ printk(KERN_DEBUG "rx_dma->ch %d\n", rx_dma->ch);
++
++ rx_dma->phys_from = p->mem_base;
++
++ memset(&rx_dma->params, 0, sizeof(rx_dma->params));
++ rx_dma->params.data_type = OMAP_DMA_DATA_TYPE_S16;
++
++ rx_dma->params.src_amode = OMAP_DMA_AMODE_CONSTANT;
++ rx_dma->params.dst_amode = OMAP_DMA_AMODE_POST_INC;
++
++ rx_dma->params.src_start = p->mem_base;
++ rx_dma->params.dst_start = rx_dma->phys_to;
++
++ rx_dma->params.src_ei = 1;
++ rx_dma->params.src_fi = 1;
++ rx_dma->params.dst_ei = 1;
++ rx_dma->params.dst_fi = 1;
++
++ rx_dma->params.elem_count = 1024;
++ rx_dma->params.frame_count = 1;
++
++ rx_dma->params.read_prio = DMA_CH_PRIO_HIGH;
++ rx_dma->params.write_prio = DMA_CH_PRIO_LOW;
++
++ omap_set_dma_params(rx_dma->ch, &rx_dma->params);
++
++// Play with these with a real application
++//G omap_set_dma_src_burst_mode(rx_dma->ch, OMAP_DMA_DATA_BURST_16);
++// omap_set_dma_dest_burst_mode(rx_dma->ch, OMAP_DMA_DATA_BURST_16);
++
++#if 0 // Need to find implentations of the endian calls
++ omap_set_dma_src_endian_type(rx_dma->ch, OMAP_DMA_BIG_ENDIAN);
++ omap_set_dma_dst_endian_type(rx_dma->ch, OMAP_DMA_LITTLE_ENDIAN);
++#endif
++
++ tx_dma = kzalloc(sizeof(struct dma_data), GFP_KERNEL);
++ if (!tx_dma) {
++ printk(KERN_ERR "Failed to allocate memory for tx_dma struct.");
++ return -ENOMEM;
++ }
++
++ if (omap_request_dma(OMAP_DMA_NO_DEVICE, "usrp-e-tx",
++ usrp_tx_dma_irq, (void *) tx_dma, &tx_dma->ch)) {
++ printk(KERN_ERR "Could not get tx DMA channel for usrp_e\n");
++ return -ENOMEM;
++ }
++
++ printk(KERN_DEBUG "tx_dma->ch %d\n", tx_dma->ch);
++
++ tx_dma->phys_from = p->mem_base;
++
++ memset(&tx_dma->params, 0, sizeof(tx_dma->params));
++ tx_dma->params.data_type = OMAP_DMA_DATA_TYPE_S16;
++
++ tx_dma->params.src_amode = OMAP_DMA_AMODE_POST_INC;
++ tx_dma->params.dst_amode = OMAP_DMA_AMODE_CONSTANT;
++
++ tx_dma->params.src_start = tx_dma->phys_from;
++ tx_dma->params.dst_start = p->mem_base;
++
++ tx_dma->params.src_ei = 1;
++ tx_dma->params.src_fi = 1;
++ tx_dma->params.dst_ei = 1;
++ tx_dma->params.dst_fi = 1;
++
++ tx_dma->params.elem_count = 1024;
++ tx_dma->params.frame_count = 1;
++
++ tx_dma->params.read_prio = DMA_CH_PRIO_LOW;
++ tx_dma->params.write_prio = DMA_CH_PRIO_HIGH;
++
++ omap_set_dma_params(tx_dma->ch, &tx_dma->params);
++
++// Play with these with a real application
++//G omap_set_dma_src_burst_mode(tx_dma->ch, OMAP_DMA_DATA_BURST_16);
++// omap_set_dma_dest_burst_mode(tx_dma->ch, OMAP_DMA_DATA_BURST_16);
++
++ return 0;
++}
++
++static void release_dma_controller()
++{
++
++ omap_free_dma(rx_dma->ch);
++ omap_free_dma(tx_dma->ch);
++
++ kfree(rx_dma);
++ kfree(tx_dma);
++}
++
++static int get_frame_from_fpga_start()
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++ struct ring_buffer_info *rbi = &(*rx_rb.rbi)[rx_rb_write];
++ struct ring_buffer_entry *rbe = &(*rx_rb.rbe)[rx_rb_write];
++ u16 elements_to_read;
++
++ /* Check for space available in the ring buffer */
++ /* If no space, drop data. A read call will restart dma transfers. */
++ if (((*rx_rb.rbi)[rx_rb_write].flags & RB_KERNEL) && (gpio_get_value(RX_DATA_READY_GPIO)) && !rx_dma_active && !shutting_down) {
++
++ rx_dma_active = 1;
++#ifdef DEBUG_RX
++ gpio_set_value(14, 1);
++#endif
++
++ elements_to_read = readw(p->ctl_addr + UE_REG_MISC_RX_LEN);
++
++ rbi->flags = RB_DMA_ACTIVE;
++
++ rbi->len = elements_to_read << 1;
++
++ omap_set_dma_dest_addr_size(rx_dma->ch, rbe->dma_addr,
++ elements_to_read);
++
++ dma_sync_single_for_device(NULL, rbe->dma_addr, SZ_2K, DMA_FROM_DEVICE);
++
++ omap_start_dma(rx_dma->ch);
++ }
++
++ return 0;
++}
++
++
++static int get_frame_from_fpga_finish()
++{
++ dma_sync_single_for_cpu(NULL, (*rx_rb.rbe)[rx_rb_write].dma_addr, SZ_2K, DMA_FROM_DEVICE);
++
++ (*rx_rb.rbi)[rx_rb_write].flags = RB_USER;
++ rx_rb_write++;
++ if (rx_rb_write == rb_size.num_rx_frames)
++ rx_rb_write = 0;
++
++ wake_up_interruptible(&data_received_queue);
++
++ rx_dma_active = 0;
++
++ get_frame_from_fpga_start();
++
++#ifdef DEBUG_RX
++ gpio_set_value(14, 0);
++#endif
++
++ return 0;
++}
++
++static int send_frame_to_fpga_start()
++{
++ struct usrp_e_dev *p = usrp_e_devp;
++ struct ring_buffer_info *rbi = &(*tx_rb.rbi)[tx_rb_read];
++ struct ring_buffer_entry *rbe = &(*tx_rb.rbe)[tx_rb_read];
++ u16 elements_to_write;
++
++// printk("In send_frame_to_fpga_start.\n");
++
++ /* Check if there is data to write to the FPGA, if so send it */
++ /* Otherwise, do nothing. Process is restarted by calls to write */
++ if (((*tx_rb.rbi)[tx_rb_read].flags & RB_USER) && !tx_dma_active && (gpio_get_value(TX_SPACE_AVAILABLE_GPIO)) && !shutting_down) {
++// printk("In send_frame_to_fpga_start, past if.\n");
++ tx_dma_active = 1;
++#ifdef DEBUG_TX
++ gpio_set_value(14, 1);
++#endif
++
++ elements_to_write = ((rbi->len) >> 1);
++
++ writew(elements_to_write, p->ctl_addr + UE_REG_MISC_TX_LEN);
++
++ rbi->flags = RB_DMA_ACTIVE;
++
++ omap_set_dma_src_addr_size(tx_dma->ch, rbe->dma_addr,
++ elements_to_write);
++
++ dma_sync_single_for_device(NULL, rbe->dma_addr, SZ_2K, DMA_TO_DEVICE);
++
++ omap_start_dma(tx_dma->ch);
++ }
++
++ return 0;
++}
++
++static int send_frame_to_fpga_finish()
++{
++
++ dma_sync_single_for_cpu(NULL, (*tx_rb.rbe)[tx_rb_read].dma_addr, SZ_2K, DMA_TO_DEVICE);
++
++ (*tx_rb.rbi)[tx_rb_read].flags = RB_KERNEL;
++
++ tx_rb_read++;
++ if (tx_rb_read == rb_size.num_tx_frames)
++ tx_rb_read = 0;
++
++ wake_up_interruptible(&tx_rb_space_available);
++
++ tx_dma_active = 0;
++
++ send_frame_to_fpga_start();
++
++#ifdef DEBUG_TX
++ gpio_set_value(14, 0);
++#endif
++
++ return 0;
++}
++
++static int alloc_ring_buffer(struct ring_buffer *rb,
++ unsigned int num_bufs, enum dma_data_direction direction)
++{
++ int i;
++
++ rb->rbi = __get_free_page(GFP_KERNEL | __GFP_COMP | __GFP_ZERO | __GFP_NOWARN);
++
++ rb->rbe = kzalloc(sizeof(struct ring_buffer_entry) * num_bufs, GFP_KERNEL);
++ if (!rb) {
++ printk(KERN_ERR "Failed to allocate memory for rb entries\n");
++ return -ENOMEM;
++ }
++
++ rb->num_pages = (num_bufs & 1) ? ((num_bufs + 1) / 2) : (num_bufs / 2);
++
++ rb->pages = kzalloc(sizeof(unsigned long) * rb->num_pages, GFP_KERNEL);
++ if (!(rb->pages)) {
++ printk(KERN_ERR "Failed to allocate memory for rb page entries\n");
++ return -ENOMEM;
++ }
++
++ for (i = 0; i < rb->num_pages; i++) {
++ (*rb->pages)[i] = __get_free_page(GFP_KERNEL | __GFP_DMA | __GFP_COMP | __GFP_ZERO | __GFP_NOWARN);
++
++ (*(rb->rbe))[i*2].frame_addr =
++ (*(rb->pages))[i];
++ (*(rb->rbe))[i*2 + 1].frame_addr =
++ ((*(rb->pages))[i] + SZ_2K);
++ if (!(*(rb->rbe))[i*2].frame_addr || !(*(rb->rbe))[i*2 + 1].frame_addr) {
++ printk(KERN_ERR "Failed to allocate memory dma buf\n");
++ return -ENOMEM;
++ }
++
++ (*(rb->rbe))[i*2].dma_addr = dma_map_single(NULL, (*(rb->rbe))[i*2].frame_addr, SZ_2K, direction);
++ (*(rb->rbe))[i*2 + 1].dma_addr = dma_map_single(NULL, (*(rb->rbe))[i*2 + 1].frame_addr, SZ_2K, direction);
++ if (!(*(rb->rbe))[i*2].dma_addr || !(*(rb->rbe))[i*2 + 1].dma_addr) {
++ printk(KERN_ERR "Failed to get physical address for dma buf\n");
++ return -ENOMEM;
++ }
++ }
++
++ return 0;
++}
++
++static void delete_ring_buffer(struct ring_buffer *rb,
++ unsigned int num_bufs, enum dma_data_direction direction)
++{
++ unsigned int i;
++ unsigned int num_pages;
++
++ printk(KERN_DEBUG "Entering delete_ring_buffer\n");
++
++ num_pages = (num_bufs & 1) ? ((num_bufs + 1) / 2) : (num_bufs / 2);
++
++ for (i = 0; i < num_pages; i++) {
++ dma_unmap_single(NULL, (*rb->rbe)[i*2].dma_addr, SZ_2K, direction);
++ dma_unmap_single(NULL, (*rb->rbe)[i*2 + 1].dma_addr, SZ_2K, direction);
++ free_page((*rb->pages)[i]);
++ }
++
++ free_page(rb->rbi);
++
++ kfree(rb->pages);
++ kfree(rb->rbe);
++
++ printk(KERN_DEBUG "Leaving delete_ring_buffer\n");
++}
++
++static int alloc_ring_buffers()
++{
++
++ if (alloc_ring_buffer(&tx_rb, rb_size.num_rx_frames, DMA_TO_DEVICE) < 0)
++ return -ENOMEM;
++ if (alloc_ring_buffer(&rx_rb, rb_size.num_tx_frames, DMA_FROM_DEVICE) < 0)
++ return -ENOMEM;
++
++ return 0;
++}
++
++static void init_ring_buffer(struct ring_buffer *rb, int num_bufs,
++ int initial_flags, enum dma_data_direction direction)
++{
++ int i;
++
++ for (i = 0; i < num_bufs; i++) {
++ dma_sync_single_for_device(NULL, (*rb->rbe)[i].dma_addr,
++ SZ_2K, direction);
++ dma_sync_single_for_cpu(NULL, (*rb->rbe)[i].dma_addr,
++ SZ_2K, direction);
++ (*rb->rbi)[i].flags = initial_flags;
++ }
++
++}
++
++#if 0
++static int tx_dma_func(void *data)
++{
++ int ret;
++ struct sched_param s = { .sched_priority = 1};
++
++ printk(KERN_DEBUG "In tx_dma_func\n");
++
++ allow_signal(SIGSTOP);
++
++ sched_setscheduler(current, SCHED_FIFO, &s);
++
++ while (!kthread_should_stop() && !closing_driver) {
++
++ if (!((*tx_rb.rbe)[tx_rb_read].flags & RB_USER)) {
++ tx_dma_waiting_for_data = 1;
++ ret = wait_event_interruptible(received_data_from_user,
++ (*tx_rb.rbe)[tx_rb_read].flags & RB_USER);
++ if (ret) {
++ printk(KERN_DEBUG
++ "tx_dma_func received signal %d\n",
++ ret);
++ if (closing_driver)
++ break;
++
++ }
++ tx_dma_waiting_for_data = 0;
++ }
++
++ if (wait_event_interruptible(space_available_queue,
++ gpio_get_value(TX_SPACE_AVAILABLE_GPIO))) {
++ printk(KERN_DEBUG "tx_dma received signal waiting for space.\n");
++ if (closing_driver)
++ break;
++ }
++
++ if (send_frame_to_fpga(&(*tx_rb.rbe)[tx_rb_read]) != 0) {
++ printk(KERN_DEBUG "send_frame received signal.\n");
++ if (closing_driver)
++ break;
++ }
++
++ (*tx_rb.rbe)[tx_rb_read].flags = RB_KERNEL;
++
++ tx_rb_read++;
++ if (tx_rb_read == RB_SIZE)
++ tx_rb_read = 0;
++
++#if 0
++ if (waiting_for_space_in_tx_rb)
++#endif
++ wake_up_interruptible(&tx_rb_space_queue);
++
++ }
++ return 0;
++}
++#endif
+diff --git a/include/linux/usrp_e.h b/include/linux/usrp_e.h
+new file mode 100644
+index 0000000..e52f709
+--- /dev/null
++++ b/include/linux/usrp_e.h
+@@ -0,0 +1,87 @@
++
++/*
++ * Copyright (C) 2010 Ettus Research, LLC
++ *
++ * Written by Philip Balister <philip@opensdr.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#ifndef __USRP_E_H
++#define __USRP_E_H
++
++#include <linux/types.h>
++#include <linux/ioctl.h>
++
++struct usrp_e_ctl16 {
++ __u32 offset;
++ __u32 count;
++ __u16 buf[20];
++};
++
++struct usrp_e_ctl32 {
++ __u32 offset;
++ __u32 count;
++ __u32 buf[10];
++};
++
++/* SPI interface */
++
++#define UE_SPI_TXONLY 0
++#define UE_SPI_TXRX 1
++
++/* Defines for spi ctrl register */
++#define UE_SPI_CTRL_TXNEG (BIT(10))
++#define UE_SPI_CTRL_RXNEG (BIT(9))
++
++#define UE_SPI_PUSH_RISE 0
++#define UE_SPI_PUSH_FALL UE_SPI_CTRL_TXNEG
++#define UE_SPI_LATCH_RISE 0
++#define UE_SPI_LATCH_FALL UE_SPI_CTRL_RXNEG
++
++struct usrp_e_spi {
++ __u8 readback;
++ __u32 slave;
++ __u32 data;
++ __u32 length;
++ __u32 flags;
++};
++
++struct usrp_e_i2c {
++ __u8 addr;
++ __u32 len;
++ __u8 data[];
++};
++
++#define USRP_E_IOC_MAGIC 'u'
++#define USRP_E_WRITE_CTL16 _IOW(USRP_E_IOC_MAGIC, 0x20, struct usrp_e_ctl16)
++#define USRP_E_READ_CTL16 _IOWR(USRP_E_IOC_MAGIC, 0x21, struct usrp_e_ctl16)
++#define USRP_E_WRITE_CTL32 _IOW(USRP_E_IOC_MAGIC, 0x22, struct usrp_e_ctl32)
++#define USRP_E_READ_CTL32 _IOWR(USRP_E_IOC_MAGIC, 0x23, struct usrp_e_ctl32)
++#define USRP_E_SPI _IOWR(USRP_E_IOC_MAGIC, 0x24, struct usrp_e_spi)
++#define USRP_E_I2C_READ _IOWR(USRP_E_IOC_MAGIC, 0x25, struct usrp_e_i2c)
++#define USRP_E_I2C_WRITE _IOW(USRP_E_IOC_MAGIC, 0x26, struct usrp_e_i2c)
++#define USRP_E_GET_RB_INFO _IOR(USRP_E_IOC_MAGIC, 0x27, struct usrp_e_ring_buffer_size_t)
++
++/* Flag defines */
++#define RB_USER (BIT(0))
++#define RB_KERNEL (BIT(1))
++#define RB_OVERRUN (BIT(2))
++#define RB_DMA_ACTIVE (BIT(3))
++
++struct ring_buffer_info {
++ int flags;
++ int len;
++};
++
++struct usrp_e_ring_buffer_size_t {
++ int num_pages_rx_flags;
++ int num_rx_frames;
++ int num_pages_tx_flags;
++ int num_tx_frames;
++};
++
++#endif
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/wl1271/0001-wl12xx-Read-MAC-address-from-NVS-file-on-HW-startup.patch b/extras/recipes-kernel/linux/linux-omap/wl1271/0001-wl12xx-Read-MAC-address-from-NVS-file-on-HW-startup.patch
new file mode 100644
index 00000000..a4f08736
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/wl1271/0001-wl12xx-Read-MAC-address-from-NVS-file-on-HW-startup.patch
@@ -0,0 +1,41 @@
+From 5d302917bbdb377538f6c848243a6265878abcee Mon Sep 17 00:00:00 2001
+From: Arik Nemtsov <arik@wizery.com>
+Date: Sat, 16 Oct 2010 21:49:52 +0200
+Subject: [PATCH 01/15] wl12xx: Read MAC address from NVS file on HW startup
+
+Try to read the MAC address from the on-disk NVS file.
+A non-zero MAC address is required to add an AP interface.
+
+Signed-off-by: Arik Nemtsov <arik@wizery.com>
+Reviewed-by: Luciano Coelho <coelho@ti.com>
+Signed-off-by: Luciano Coelho <coelho@ti.com>
+---
+ drivers/net/wireless/wl12xx/wl1271_main.c | 12 ++++++++++++
+ 1 files changed, 12 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
+index 48a4b99..591de0e 100644
+--- a/drivers/net/wireless/wl12xx/wl1271_main.c
++++ b/drivers/net/wireless/wl12xx/wl1271_main.c
+@@ -2391,6 +2391,18 @@ int wl1271_register_hw(struct wl1271 *wl)
+ if (wl->mac80211_registered)
+ return 0;
+
++ ret = wl1271_fetch_nvs(wl);
++ if (ret == 0) {
++ u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
++
++ wl->mac_addr[0] = nvs_ptr[11];
++ wl->mac_addr[1] = nvs_ptr[10];
++ wl->mac_addr[2] = nvs_ptr[6];
++ wl->mac_addr[3] = nvs_ptr[5];
++ wl->mac_addr[4] = nvs_ptr[4];
++ wl->mac_addr[5] = nvs_ptr[3];
++ }
++
+ SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
+
+ ret = ieee80211_register_hw(wl->hw);
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/wl1271/0002-wl1271-11n-Support-Add-Definitions.patch b/extras/recipes-kernel/linux/linux-omap/wl1271/0002-wl1271-11n-Support-Add-Definitions.patch
new file mode 100644
index 00000000..1da7be6c
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/wl1271/0002-wl1271-11n-Support-Add-Definitions.patch
@@ -0,0 +1,165 @@
+From 99d1c6c23faa446ec0ebdf056d8aa8f4d983d518 Mon Sep 17 00:00:00 2001
+From: Shahar Levi <shahar_levi@ti.com>
+Date: Wed, 13 Oct 2010 16:09:39 +0200
+Subject: [PATCH 02/15] wl1271: 11n Support, Add Definitions
+
+Two acx commands: ht_capabilities & ht_information, 11n sta capabilities
+macro.
+
+Signed-off-by: Shahar Levi <shahar_levi@ti.com>
+Reviewed-by: Luciano Coelho <luciano.coelho@nokia.com>
+Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
+---
+ drivers/net/wireless/wl12xx/wl1271.h | 11 ++++-
+ drivers/net/wireless/wl12xx/wl1271_acx.h | 81 +++++++++++++++++++++++++++++
+ drivers/net/wireless/wl12xx/wl1271_main.c | 15 +++++
+ 3 files changed, 106 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h
+index 8a4cd76..45a2583 100644
+--- a/drivers/net/wireless/wl12xx/wl1271.h
++++ b/drivers/net/wireless/wl12xx/wl1271.h
+@@ -432,7 +432,12 @@ struct wl1271 {
+ /* Our association ID */
+ u16 aid;
+
+- /* currently configured rate set */
++ /*
++ * currently configured rate set:
++ * bits 0-15 - 802.11abg rates
++ * bits 16-23 - 802.11n MCS index mask
++ * support only 1 stream, thus only 8 bits for the MCS rates (0-7).
++ */
+ u32 sta_rate_set;
+ u32 basic_rate_set;
+ u32 basic_rate;
+@@ -509,4 +514,8 @@ int wl1271_plt_stop(struct wl1271 *wl);
+ #define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */
+ #define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */
+
++/* Macros to handle wl1271.sta_rate_set */
++#define HW_BG_RATES_MASK 0xffff
++#define HW_HT_RATES_OFFSET 16
++
+ #endif
+diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h
+index ebb341d..f090a04 100644
+--- a/drivers/net/wireless/wl12xx/wl1271_acx.h
++++ b/drivers/net/wireless/wl12xx/wl1271_acx.h
+@@ -964,6 +964,87 @@ struct wl1271_acx_rssi_snr_avg_weights {
+ u8 snr_data;
+ };
+
++/*
++ * ACX_PEER_HT_CAP
++ * Configure HT capabilities - declare the capabilities of the peer
++ * we are connected to.
++ */
++struct wl1271_acx_ht_capabilities {
++ struct acx_header header;
++
++ /*
++ * bit 0 - Allow HT Operation
++ * bit 1 - Allow Greenfield format in TX
++ * bit 2 - Allow Short GI in TX
++ * bit 3 - Allow L-SIG TXOP Protection in TX
++ * bit 4 - Allow HT Control fields in TX.
++ * Note, driver will still leave space for HT control in packets
++ * regardless of the value of this field. FW will be responsible
++ * to drop the HT field from any frame when this Bit set to 0.
++ * bit 5 - Allow RD initiation in TXOP. FW is allowed to initate RD.
++ * Exact policy setting for this feature is TBD.
++ * Note, this bit can only be set to 1 if bit 3 is set to 1.
++ */
++ __le32 ht_capabilites;
++
++ /*
++ * Indicates to which peer these capabilities apply.
++ * For infrastructure use ff:ff:ff:ff:ff:ff that indicates relevance
++ * for all peers.
++ * Only valid for IBSS/DLS operation.
++ */
++ u8 mac_address[ETH_ALEN];
++
++ /*
++ * This the maximum A-MPDU length supported by the AP. The FW may not
++ * exceed this length when sending A-MPDUs
++ */
++ u8 ampdu_max_length;
++
++ /* This is the minimal spacing required when sending A-MPDUs to the AP*/
++ u8 ampdu_min_spacing;
++} __packed;
++
++/* HT Capabilites Fw Bit Mask Mapping */
++#define WL1271_ACX_FW_CAP_HT_OPERATION BIT(0)
++#define WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT BIT(1)
++#define WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS BIT(2)
++#define WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION BIT(3)
++#define WL1271_ACX_FW_CAP_HT_CONTROL_FIELDS BIT(4)
++#define WL1271_ACX_FW_CAP_RD_INITIATION BIT(5)
++
++
++/*
++ * ACX_HT_BSS_OPERATION
++ * Configure HT capabilities - AP rules for behavior in the BSS.
++ */
++struct wl1271_acx_ht_information {
++ struct acx_header header;
++
++ /* Values: 0 - RIFS not allowed, 1 - RIFS allowed */
++ u8 rifs_mode;
++
++ /* Values: 0 - 3 like in spec */
++ u8 ht_protection;
++
++ /* Values: 0 - GF protection not required, 1 - GF protection required */
++ u8 gf_protection;
++
++ /*Values: 0 - TX Burst limit not required, 1 - TX Burst Limit required*/
++ u8 ht_tx_burst_limit;
++
++ /*
++ * Values: 0 - Dual CTS protection not required,
++ * 1 - Dual CTS Protection required
++ * Note: When this value is set to 1 FW will protect all TXOP with RTS
++ * frame and will not use CTS-to-self regardless of the value of the
++ * ACX_CTS_PROTECTION information element
++ */
++ u8 dual_cts_protection;
++
++ u8 padding[3];
++} __packed;
++
+ struct wl1271_acx_fw_tsf_information {
+ struct acx_header header;
+
+diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
+index 591de0e..785b73c 100644
+--- a/drivers/net/wireless/wl12xx/wl1271_main.c
++++ b/drivers/net/wireless/wl12xx/wl1271_main.c
+@@ -2134,6 +2134,21 @@ static const u8 wl1271_rate_to_idx_2ghz[] = {
+ 0 /* CONF_HW_RXTX_RATE_1 */
+ };
+
++/* 11n STA capabilities */
++#define HW_RX_HIGHEST_RATE 72
++
++#define WL1271_HT_CAP { \
++ .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
++ .ht_supported = true, \
++ .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
++ .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
++ .mcs = { \
++ .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
++ .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
++ .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
++ }, \
++}
++
+ /* can't be const, mac80211 writes to this */
+ static struct ieee80211_supported_band wl1271_band_2ghz = {
+ .channels = wl1271_channels,
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/wl1271/0003-wl1271-11n-Support-ACX-Commands.patch b/extras/recipes-kernel/linux/linux-omap/wl1271/0003-wl1271-11n-Support-ACX-Commands.patch
new file mode 100644
index 00000000..8d2412b1
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/wl1271/0003-wl1271-11n-Support-ACX-Commands.patch
@@ -0,0 +1,128 @@
+From 160169e1e717020b8456278950c30d2b1f15c314 Mon Sep 17 00:00:00 2001
+From: Shahar Levi <shahar_levi@ti.com>
+Date: Wed, 13 Oct 2010 16:09:40 +0200
+Subject: [PATCH 03/15] wl1271: 11n Support, ACX Commands
+
+Added ACX command to the FW for 11n support.
+
+Signed-off-by: Shahar Levi <shahar_levi@ti.com>
+Reviewed-by: Luciano Coelho <luciano.coelho@nokia.com>
+Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
+---
+ drivers/net/wireless/wl12xx/wl1271_acx.c | 83 ++++++++++++++++++++++++++++++
+ drivers/net/wireless/wl12xx/wl1271_acx.h | 5 ++
+ 2 files changed, 88 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c
+index 6189934..bd7f95f 100644
+--- a/drivers/net/wireless/wl12xx/wl1271_acx.c
++++ b/drivers/net/wireless/wl12xx/wl1271_acx.c
+@@ -1226,6 +1226,89 @@ out:
+ return ret;
+ }
+
++int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
++ struct ieee80211_sta_ht_cap *ht_cap,
++ bool allow_ht_operation)
++{
++ struct wl1271_acx_ht_capabilities *acx;
++ u8 mac_address[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
++ int ret = 0;
++
++ wl1271_debug(DEBUG_ACX, "acx ht capabilities setting");
++
++ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
++ if (!acx) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ /* Allow HT Operation ? */
++ if (allow_ht_operation) {
++ acx->ht_capabilites =
++ WL1271_ACX_FW_CAP_HT_OPERATION;
++ if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD)
++ acx->ht_capabilites |=
++ WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT;
++ if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
++ acx->ht_capabilites |=
++ WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS;
++ if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT)
++ acx->ht_capabilites |=
++ WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION;
++
++ /* get data from A-MPDU parameters field */
++ acx->ampdu_max_length = ht_cap->ampdu_factor;
++ acx->ampdu_min_spacing = ht_cap->ampdu_density;
++
++ memcpy(acx->mac_address, mac_address, ETH_ALEN);
++ } else { /* HT operations are not allowed */
++ acx->ht_capabilites = 0;
++ }
++
++ ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx));
++ if (ret < 0) {
++ wl1271_warning("acx ht capabilities setting failed: %d", ret);
++ goto out;
++ }
++
++out:
++ kfree(acx);
++ return ret;
++}
++
++int wl1271_acx_set_ht_information(struct wl1271 *wl,
++ u16 ht_operation_mode)
++{
++ struct wl1271_acx_ht_information *acx;
++ int ret = 0;
++
++ wl1271_debug(DEBUG_ACX, "acx ht information setting");
++
++ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
++ if (!acx) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ acx->ht_protection =
++ (u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION);
++ acx->rifs_mode = 0;
++ acx->gf_protection = 0;
++ acx->ht_tx_burst_limit = 0;
++ acx->dual_cts_protection = 0;
++
++ ret = wl1271_cmd_configure(wl, ACX_HT_BSS_OPERATION, acx, sizeof(*acx));
++
++ if (ret < 0) {
++ wl1271_warning("acx ht information setting failed: %d", ret);
++ goto out;
++ }
++
++out:
++ kfree(acx);
++ return ret;
++}
++
+ int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime)
+ {
+ struct wl1271_acx_fw_tsf_information *tsf_info;
+diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h
+index f090a04..7589167 100644
+--- a/drivers/net/wireless/wl12xx/wl1271_acx.h
++++ b/drivers/net/wireless/wl12xx/wl1271_acx.h
+@@ -1174,6 +1174,11 @@ int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid);
+ int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
+ s16 thold, u8 hyst);
+ int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl);
++int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
++ struct ieee80211_sta_ht_cap *ht_cap,
++ bool allow_ht_operation);
++int wl1271_acx_set_ht_information(struct wl1271 *wl,
++ u16 ht_operation_mode);
+ int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
+
+ #endif /* __WL1271_ACX_H__ */
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/wl1271/0004-wl1271-11n-Support-functionality-and-configuration-a.patch b/extras/recipes-kernel/linux/linux-omap/wl1271/0004-wl1271-11n-Support-functionality-and-configuration-a.patch
new file mode 100644
index 00000000..17ed6e63
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/wl1271/0004-wl1271-11n-Support-functionality-and-configuration-a.patch
@@ -0,0 +1,249 @@
+From 9685ab91494ae35d2cb7e0033c5ee1bf3cdf0c64 Mon Sep 17 00:00:00 2001
+From: Shahar Levi <shahar_levi@ti.com>
+Date: Wed, 13 Oct 2010 16:09:41 +0200
+Subject: [PATCH 04/15] wl1271: 11n Support, functionality and configuration ability
+
+Add 11n ability in scan, connection and using MCS rates.
+The configuration is temporary due to the code incomplete and
+still in testing process. That plans to be remove in the future.
+
+Signed-off-by: Shahar Levi <shahar_levi@ti.com>
+Reviewed-by: Luciano Coelho <luciano.coelho@nokia.com>
+Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
+---
+ drivers/net/wireless/wl12xx/Kconfig | 10 +++
+ drivers/net/wireless/wl12xx/wl1271_main.c | 96 +++++++++++++++++++++++------
+ drivers/net/wireless/wl12xx/wl1271_rx.c | 6 ++
+ drivers/net/wireless/wl12xx/wl1271_tx.c | 11 +++
+ 4 files changed, 105 insertions(+), 18 deletions(-)
+
+diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
+index b447559..1b3b7bd 100644
+--- a/drivers/net/wireless/wl12xx/Kconfig
++++ b/drivers/net/wireless/wl12xx/Kconfig
+@@ -18,6 +18,16 @@ config WL1271
+ If you choose to build a module, it'll be called wl1271. Say N if
+ unsure.
+
++config WL1271_HT
++ bool "TI wl1271 802.11 HT support (EXPERIMENTAL)"
++ depends on WL1271 && EXPERIMENTAL
++ default n
++ ---help---
++ This will enable 802.11 HT support for TI wl1271 chipset.
++
++ That configuration is temporary due to the code incomplete and
++ still in testing process.
++
+ config WL1271_SPI
+ tristate "TI wl1271 SPI support"
+ depends on WL1271 && SPI_MASTER
+diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
+index 785b73c..49ec0ef 100644
+--- a/drivers/net/wireless/wl12xx/wl1271_main.c
++++ b/drivers/net/wireless/wl12xx/wl1271_main.c
+@@ -851,12 +851,32 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+ struct ieee80211_sta *sta = txinfo->control.sta;
+ unsigned long flags;
+
+- /* peek into the rates configured in the STA entry */
++ /*
++ * peek into the rates configured in the STA entry.
++ * The rates set after connection stage, The first block only BG sets:
++ * the compare is for bit 0-16 of sta_rate_set. The second block add
++ * HT rates in case of HT supported.
++ */
+ spin_lock_irqsave(&wl->wl_lock, flags);
+- if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
++ if (sta &&
++ (sta->supp_rates[conf->channel->band] !=
++ (wl->sta_rate_set & HW_BG_RATES_MASK))) {
+ wl->sta_rate_set = sta->supp_rates[conf->channel->band];
+ set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
+ }
++
++#ifdef CONFIG_WL1271_HT
++ if (sta &&
++ sta->ht_cap.ht_supported &&
++ ((wl->sta_rate_set >> HW_HT_RATES_OFFSET) !=
++ sta->ht_cap.mcs.rx_mask[0])) {
++ /* Clean MCS bits before setting them */
++ wl->sta_rate_set &= HW_BG_RATES_MASK;
++ wl->sta_rate_set |=
++ (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
++ set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
++ }
++#endif
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+ /* queue the packet */
+@@ -1709,6 +1729,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
+ {
+ enum wl1271_cmd_ps_mode mode;
+ struct wl1271 *wl = hw->priv;
++ struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid);
+ bool do_join = false;
+ bool set_assoc = false;
+ int ret;
+@@ -1927,6 +1948,37 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
+ }
+ }
+
++ /*
++ * Takes care of: New association with HT enable,
++ * HT information change in beacon.
++ */
++ if (sta &&
++ (changed & BSS_CHANGED_HT) &&
++ (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
++ ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true);
++ if (ret < 0) {
++ wl1271_warning("Set ht cap true failed %d", ret);
++ goto out_sleep;
++ }
++ ret = wl1271_acx_set_ht_information(wl,
++ bss_conf->ht_operation_mode);
++ if (ret < 0) {
++ wl1271_warning("Set ht information failed %d", ret);
++ goto out_sleep;
++ }
++ }
++ /*
++ * Takes care of: New association without HT,
++ * Disassociation.
++ */
++ else if (sta && (changed & BSS_CHANGED_ASSOC)) {
++ ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false);
++ if (ret < 0) {
++ wl1271_warning("Set ht cap false failed %d", ret);
++ goto out_sleep;
++ }
++ }
++
+ if (changed & BSS_CHANGED_ARP_FILTER) {
+ __be32 addr = bss_conf->arp_addr_list[0];
+ WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
+@@ -2107,14 +2159,14 @@ static struct ieee80211_channel wl1271_channels[] = {
+ /* mapping to indexes for wl1271_rates */
+ static const u8 wl1271_rate_to_idx_2ghz[] = {
+ /* MCS rates are used only with 11n */
+- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
+- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
+- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
+- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
+- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
+- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
+- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
+- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
++ 7, /* CONF_HW_RXTX_RATE_MCS7 */
++ 6, /* CONF_HW_RXTX_RATE_MCS6 */
++ 5, /* CONF_HW_RXTX_RATE_MCS5 */
++ 4, /* CONF_HW_RXTX_RATE_MCS4 */
++ 3, /* CONF_HW_RXTX_RATE_MCS3 */
++ 2, /* CONF_HW_RXTX_RATE_MCS2 */
++ 1, /* CONF_HW_RXTX_RATE_MCS1 */
++ 0, /* CONF_HW_RXTX_RATE_MCS0 */
+
+ 11, /* CONF_HW_RXTX_RATE_54 */
+ 10, /* CONF_HW_RXTX_RATE_48 */
+@@ -2137,6 +2189,7 @@ static const u8 wl1271_rate_to_idx_2ghz[] = {
+ /* 11n STA capabilities */
+ #define HW_RX_HIGHEST_RATE 72
+
++#ifdef CONFIG_WL1271_HT
+ #define WL1271_HT_CAP { \
+ .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
+ .ht_supported = true, \
+@@ -2148,6 +2201,11 @@ static const u8 wl1271_rate_to_idx_2ghz[] = {
+ .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
+ }, \
+ }
++#else
++#define WL1271_HT_CAP { \
++ .ht_supported = false, \
++}
++#endif
+
+ /* can't be const, mac80211 writes to this */
+ static struct ieee80211_supported_band wl1271_band_2ghz = {
+@@ -2155,6 +2213,7 @@ static struct ieee80211_supported_band wl1271_band_2ghz = {
+ .n_channels = ARRAY_SIZE(wl1271_channels),
+ .bitrates = wl1271_rates,
+ .n_bitrates = ARRAY_SIZE(wl1271_rates),
++ .ht_cap = WL1271_HT_CAP,
+ };
+
+ /* 5 GHz data rates for WL1273 */
+@@ -2237,14 +2296,14 @@ static struct ieee80211_channel wl1271_channels_5ghz[] = {
+ /* mapping to indexes for wl1271_rates_5ghz */
+ static const u8 wl1271_rate_to_idx_5ghz[] = {
+ /* MCS rates are used only with 11n */
+- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
+- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
+- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
+- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
+- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
+- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
+- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
+- CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
++ 7, /* CONF_HW_RXTX_RATE_MCS7 */
++ 6, /* CONF_HW_RXTX_RATE_MCS6 */
++ 5, /* CONF_HW_RXTX_RATE_MCS5 */
++ 4, /* CONF_HW_RXTX_RATE_MCS4 */
++ 3, /* CONF_HW_RXTX_RATE_MCS3 */
++ 2, /* CONF_HW_RXTX_RATE_MCS2 */
++ 1, /* CONF_HW_RXTX_RATE_MCS1 */
++ 0, /* CONF_HW_RXTX_RATE_MCS0 */
+
+ 7, /* CONF_HW_RXTX_RATE_54 */
+ 6, /* CONF_HW_RXTX_RATE_48 */
+@@ -2269,6 +2328,7 @@ static struct ieee80211_supported_band wl1271_band_5ghz = {
+ .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
+ .bitrates = wl1271_rates_5ghz,
+ .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
++ .ht_cap = WL1271_HT_CAP,
+ };
+
+ static const u8 *wl1271_band_rate_to_idx[] = {
+diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c
+index bea133b..ac13f7d 100644
+--- a/drivers/net/wireless/wl12xx/wl1271_rx.c
++++ b/drivers/net/wireless/wl12xx/wl1271_rx.c
+@@ -53,6 +53,12 @@ static void wl1271_rx_status(struct wl1271 *wl,
+ status->band = wl->band;
+ status->rate_idx = wl1271_rate_to_idx(wl, desc->rate);
+
++#ifdef CONFIG_WL1271_HT
++ /* 11n support */
++ if (desc->rate <= CONF_HW_RXTX_RATE_MCS0)
++ status->flag |= RX_FLAG_HT;
++#endif
++
+ status->signal = desc->rssi;
+
+ /*
+diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c
+index e3dc13c..6a87633 100644
+--- a/drivers/net/wireless/wl12xx/wl1271_tx.c
++++ b/drivers/net/wireless/wl12xx/wl1271_tx.c
+@@ -201,6 +201,17 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
+ rate_set >>= 1;
+ }
+
++#ifdef CONFIG_WL1271_HT
++ /* MCS rates indication are on bits 16 - 23 */
++ rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates;
++
++ for (bit = 0; bit < 8; bit++) {
++ if (rate_set & 0x1)
++ enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit);
++ rate_set >>= 1;
++ }
++#endif
++
+ return enabled_rates;
+ }
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/wl1271/0005-wl1271-set-wl-vif-only-if-add_interface-succeeded.patch b/extras/recipes-kernel/linux/linux-omap/wl1271/0005-wl1271-set-wl-vif-only-if-add_interface-succeeded.patch
new file mode 100644
index 00000000..3707b7c3
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/wl1271/0005-wl1271-set-wl-vif-only-if-add_interface-succeeded.patch
@@ -0,0 +1,86 @@
+From dd812452fb91de492a8fd8d838d16cfc67cbfcf4 Mon Sep 17 00:00:00 2001
+From: Eliad Peller <eliad@wizery.com>
+Date: Thu, 28 Oct 2010 21:46:43 +0200
+Subject: [PATCH 05/15] wl1271: set wl->vif only if add_interface succeeded.
+
+set wl->vif to the newly created interface only after the firmware booted
+successfully. on the way - make the function flow more clear.
+
+Signed-off-by: Eliad Peller <eliad@wizery.com>
+Reviewed-by: Luciano Coelho <luciano.coelho@nokia.com>
+Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
+---
+ drivers/net/wireless/wl12xx/wl1271_main.c | 33 +++++++++++++++++-----------
+ 1 files changed, 20 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
+index 49ec0ef..78273c9 100644
+--- a/drivers/net/wireless/wl12xx/wl1271_main.c
++++ b/drivers/net/wireless/wl12xx/wl1271_main.c
+@@ -939,18 +939,19 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
+ struct wiphy *wiphy = hw->wiphy;
+ int retries = WL1271_BOOT_RETRIES;
+ int ret = 0;
++ bool booted = false;
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
+ vif->type, vif->addr);
+
+ mutex_lock(&wl->mutex);
+ if (wl->vif) {
++ wl1271_debug(DEBUG_MAC80211,
++ "multiple vifs are not supported yet");
+ ret = -EBUSY;
+ goto out;
+ }
+
+- wl->vif = vif;
+-
+ switch (vif->type) {
+ case NL80211_IFTYPE_STATION:
+ wl->bss_type = BSS_TYPE_STA_BSS;
+@@ -988,15 +989,8 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
+ if (ret < 0)
+ goto irq_disable;
+
+- wl->state = WL1271_STATE_ON;
+- wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
+-
+- /* update hw/fw version info in wiphy struct */
+- wiphy->hw_version = wl->chip.id;
+- strncpy(wiphy->fw_version, wl->chip.fw_ver,
+- sizeof(wiphy->fw_version));
+-
+- goto out;
++ booted = true;
++ break;
+
+ irq_disable:
+ wl1271_disable_interrupts(wl);
+@@ -1014,8 +1008,21 @@ power_off:
+ wl1271_power_off(wl);
+ }
+
+- wl1271_error("firmware boot failed despite %d retries",
+- WL1271_BOOT_RETRIES);
++ if (!booted) {
++ wl1271_error("firmware boot failed despite %d retries",
++ WL1271_BOOT_RETRIES);
++ goto out;
++ }
++
++ wl->vif = vif;
++ wl->state = WL1271_STATE_ON;
++ wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
++
++ /* update hw/fw version info in wiphy struct */
++ wiphy->hw_version = wl->chip.id;
++ strncpy(wiphy->fw_version, wl->chip.fw_ver,
++ sizeof(wiphy->fw_version));
++
+ out:
+ mutex_unlock(&wl->mutex);
+
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/wl1271/0006-wl12xx-Unset-bssid-filter-ssid-and-bssid-from-firmwa.patch b/extras/recipes-kernel/linux/linux-omap/wl1271/0006-wl12xx-Unset-bssid-filter-ssid-and-bssid-from-firmwa.patch
new file mode 100644
index 00000000..5b83bc96
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/wl1271/0006-wl12xx-Unset-bssid-filter-ssid-and-bssid-from-firmwa.patch
@@ -0,0 +1,44 @@
+From 54b32b60bed66ac4ecf00279466496d9d4e80afa Mon Sep 17 00:00:00 2001
+From: Juuso Oikarinen <juuso.oikarinen@nokia.com>
+Date: Mon, 22 Nov 2010 12:59:08 +0200
+Subject: [PATCH 06/15] wl12xx: Unset bssid filter, ssid and bssid from firmware on disassoc
+
+On the disassociation event from the mac80211, the wl12xx driver does not
+clear the chipset configuration related to the AP - i.e. it does not perform
+a DISCONNECT and then a JOIN with zero SSID and dummy BSSID. Also, it does not
+unset the BSSID filter.
+
+Often this is not a problem, as the above is performed upon entering idle
+state. But if a scenario arises where a new association is attempted without
+cycling through idle state, the new association will fail.
+
+Fix this by resetting the firmware state on disassociation.
+
+Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
+Reviewed-by: Luciano Coelho <luciano.coelho@nokia.com>
+Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
+---
+ drivers/net/wireless/wl12xx/wl1271_main.c | 5 ++++-
+ 1 files changed, 4 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
+index 78273c9..db97648 100644
+--- a/drivers/net/wireless/wl12xx/wl1271_main.c
++++ b/drivers/net/wireless/wl12xx/wl1271_main.c
+@@ -1919,9 +1919,12 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
+
+ /* Disable the keep-alive feature */
+ ret = wl1271_acx_keep_alive_mode(wl, false);
+-
+ if (ret < 0)
+ goto out_sleep;
++
++ /* restore the bssid filter and go to dummy bssid */
++ wl1271_unjoin(wl);
++ wl1271_dummy_join(wl);
+ }
+
+ }
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/wl1271/0007-drivers-media-radio-wl128x-FM-Driver-common-header-f.patch b/extras/recipes-kernel/linux/linux-omap/wl1271/0007-drivers-media-radio-wl128x-FM-Driver-common-header-f.patch
new file mode 100644
index 00000000..d104a727
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/wl1271/0007-drivers-media-radio-wl128x-FM-Driver-common-header-f.patch
@@ -0,0 +1,268 @@
+From f568ec9bb6ccd1e17278dcab3fbc810cf2e071ac Mon Sep 17 00:00:00 2001
+From: Manjunatha Halli <manjunatha_halli@ti.com>
+Date: Tue, 11 Jan 2011 11:31:21 +0000
+Subject: [PATCH 07/15] drivers:media:radio: wl128x: FM Driver common header file
+
+These are common headers used in FM submodules (FM V4L2,
+FM common, FM Rx,and FM TX).
+
+Signed-off-by: Manjunatha Halli <manjunatha_halli@ti.com>
+Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
+---
+ drivers/media/radio/wl128x/fmdrv.h | 244 ++++++++++++++++++++++++++++++++++++
+ 1 files changed, 244 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/media/radio/wl128x/fmdrv.h
+
+diff --git a/drivers/media/radio/wl128x/fmdrv.h b/drivers/media/radio/wl128x/fmdrv.h
+new file mode 100644
+index 0000000..392b62d
+--- /dev/null
++++ b/drivers/media/radio/wl128x/fmdrv.h
+@@ -0,0 +1,244 @@
++/*
++ * FM Driver for Connectivity chip of Texas Instruments.
++ *
++ * Common header for all FM driver sub-modules.
++ *
++ * Copyright (C) 2011 Texas Instruments
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#ifndef _FM_DRV_H
++#define _FM_DRV_H
++
++#include <linux/skbuff.h>
++#include <linux/interrupt.h>
++#include <sound/core.h>
++#include <sound/initval.h>
++#include <linux/timer.h>
++#include <linux/version.h>
++#include <media/v4l2-ioctl.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-ctrls.h>
++
++#define FM_DRV_VERSION "0.09"
++/* Should match with FM_DRV_VERSION */
++#define FM_DRV_RADIO_VERSION KERNEL_VERSION(0, 0, 1)
++#define FM_DRV_NAME "ti_fmdrv"
++#define FM_DRV_CARD_SHORT_NAME "TI FM Radio"
++#define FM_DRV_CARD_LONG_NAME "Texas Instruments FM Radio"
++
++/* Flag info */
++#define FM_INTTASK_RUNNING 0
++#define FM_INTTASK_SCHEDULE_PENDING 1
++#define FM_FW_DW_INPROGRESS 2
++#define FM_CORE_READY 3
++#define FM_CORE_TRANSPORT_READY 4
++#define FM_AF_SWITCH_INPROGRESS 5
++#define FM_CORE_TX_XMITING 6
++
++#define FM_TUNE_COMPLETE 0x1
++#define FM_BAND_LIMIT 0x2
++
++#define FM_DRV_TX_TIMEOUT (5*HZ) /* 5 seconds */
++#define FM_DRV_RX_SEEK_TIMEOUT (20*HZ) /* 20 seconds */
++
++#define NO_OF_ENTRIES_IN_ARRAY(array) (sizeof(array) / sizeof(array[0]))
++
++#define fmerr(format, ...) \
++ printk(KERN_ERR "fmdrv: " format, ## __VA_ARGS__)
++#define fmwarn(format, ...) \
++ printk(KERN_WARNING "fmdrv: " format, ##__VA_ARGS__)
++#ifdef DEBUG
++#define fmdbg(format, ...) \
++ printk(KERN_DEBUG "fmdrv: " format, ## __VA_ARGS__)
++#else /* DEBUG */
++#define fmdbg(format, ...)
++#endif
++enum {
++ FM_MODE_OFF,
++ FM_MODE_TX,
++ FM_MODE_RX,
++ FM_MODE_ENTRY_MAX
++};
++
++#define FM_RX_RDS_INFO_FIELD_MAX 8 /* 4 Group * 2 Bytes */
++
++/* RX RDS data format */
++struct fm_rdsdata_format {
++ union {
++ struct {
++ u8 buff[FM_RX_RDS_INFO_FIELD_MAX];
++ } groupdatabuff;
++ struct {
++ u16 pidata;
++ u8 blk_b[2];
++ u8 blk_c[2];
++ u8 blk_d[2];
++ } groupgeneral;
++ struct {
++ u16 pidata;
++ u8 blk_b[2];
++ u8 af[2];
++ u8 ps[2];
++ } group0A;
++ struct {
++ u16 pi[2];
++ u8 blk_b[2];
++ u8 ps[2];
++ } group0B;
++ } data;
++};
++
++/* FM region (Europe/US, Japan) info */
++struct region_info {
++ u32 chanl_space;
++ u32 bot_freq;
++ u32 top_freq;
++ u8 fm_band;
++};
++struct fmdev;
++typedef void (*int_handler_prototype) (struct fmdev *);
++
++/* FM Interrupt processing related info */
++struct fm_irq {
++ u8 stage;
++ u16 flag; /* FM interrupt flag */
++ u16 mask; /* FM interrupt mask */
++ /* Interrupt process timeout handler */
++ struct timer_list timer;
++ u8 retry;
++ int_handler_prototype *handlers;
++};
++
++/* RDS info */
++struct fm_rds {
++ u8 flag; /* RX RDS on/off status */
++ u8 last_blk_idx; /* Last received RDS block */
++
++ /* RDS buffer */
++ wait_queue_head_t read_queue;
++ u32 buf_size; /* Size is always multiple of 3 */
++ u32 wr_idx;
++ u32 rd_idx;
++ u8 *buff;
++};
++
++#define FM_RDS_MAX_AF_LIST 25
++
++/*
++ * Current RX channel Alternate Frequency cache.
++ * This info is used to switch to other freq (AF)
++ * when current channel signal strengh is below RSSI threshold.
++ */
++struct tuned_station_info {
++ u16 picode;
++ u32 af_cache[FM_RDS_MAX_AF_LIST];
++ u8 afcache_size;
++ u8 af_list_max;
++};
++
++/* FM RX mode info */
++struct fm_rx {
++ struct region_info region; /* Current selected band */
++ u32 freq; /* Current RX frquency */
++ u8 mute_mode; /* Current mute mode */
++ u8 deemphasis_mode; /* Current deemphasis mode */
++ /* RF dependent soft mute mode */
++ u8 rf_depend_mute;
++ u16 volume; /* Current volume level */
++ u16 rssi_threshold; /* Current RSSI threshold level */
++ /* Holds the index of the current AF jump */
++ u8 afjump_idx;
++ /* Will hold the frequency before the jump */
++ u32 freq_before_jump;
++ u8 rds_mode; /* RDS operation mode (RDS/RDBS) */
++ u8 af_mode; /* Alternate frequency on/off */
++ struct tuned_station_info stat_info;
++ struct fm_rds rds;
++};
++
++#define FMTX_RDS_TXT_STR_SIZE 25
++/*
++ * FM TX RDS data
++ *
++ * @ text_type: is the text following PS or RT
++ * @ text: radio text string which could either be PS or RT
++ * @ af_freq: alternate frequency for Tx
++ * TODO: to be declared in application
++ */
++struct tx_rds {
++ u8 text_type;
++ u8 text[FMTX_RDS_TXT_STR_SIZE];
++ u8 flag;
++ u32 af_freq;
++};
++/*
++ * FM TX global data
++ *
++ * @ pwr_lvl: Power Level of the Transmission from mixer control
++ * @ xmit_state: Transmission state = Updated locally upon Start/Stop
++ * @ audio_io: i2S/Analog
++ * @ tx_frq: Transmission frequency
++ */
++struct fmtx_data {
++ u8 pwr_lvl;
++ u8 xmit_state;
++ u8 audio_io;
++ u8 region;
++ u16 aud_mode;
++ u32 preemph;
++ u32 tx_frq;
++ struct tx_rds rds;
++};
++
++/* FM driver operation structure */
++struct fmdev {
++ struct video_device *radio_dev; /* V4L2 video device pointer */
++ struct snd_card *card; /* Card which holds FM mixer controls */
++ u16 asci_id;
++ spinlock_t rds_buff_lock; /* To protect access to RDS buffer */
++ spinlock_t resp_skb_lock; /* To protect access to received SKB */
++
++ long flag; /* FM driver state machine info */
++ u8 streg_cbdata; /* status of ST registration */
++
++ struct sk_buff_head rx_q; /* RX queue */
++ struct tasklet_struct rx_task; /* RX Tasklet */
++
++ struct sk_buff_head tx_q; /* TX queue */
++ struct tasklet_struct tx_task; /* TX Tasklet */
++ unsigned long last_tx_jiffies; /* Timestamp of last pkt sent */
++ atomic_t tx_cnt; /* Number of packets can send at a time */
++
++ struct sk_buff *resp_skb; /* Response from the chip */
++ /* Main task completion handler */
++ struct completion maintask_comp;
++ /* Opcode of last command sent to the chip */
++ u8 pre_op;
++ /* Handler used for wakeup when response packet is received */
++ struct completion *resp_comp;
++ struct fm_irq irq_info;
++ u8 curr_fmmode; /* Current FM chip mode (TX, RX, OFF) */
++ struct fm_rx rx; /* FM receiver info */
++ struct fmtx_data tx_data;
++
++ /* V4L2 ctrl framwork handler*/
++ struct v4l2_ctrl_handler ctrl_handler;
++
++ /* For core assisted locking */
++ struct mutex mutex;
++};
++#endif
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/wl1271/0008-drivers-media-radio-wl128x-FM-Driver-V4L2-sources.patch b/extras/recipes-kernel/linux/linux-omap/wl1271/0008-drivers-media-radio-wl128x-FM-Driver-V4L2-sources.patch
new file mode 100644
index 00000000..c3eae97f
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/wl1271/0008-drivers-media-radio-wl128x-FM-Driver-V4L2-sources.patch
@@ -0,0 +1,645 @@
+From d532e33a286ec2275b441c05675de52cd5b069d2 Mon Sep 17 00:00:00 2001
+From: Manjunatha Halli <manjunatha_halli@ti.com>
+Date: Tue, 11 Jan 2011 11:31:22 +0000
+Subject: [PATCH 08/15] drivers:media:radio: wl128x: FM Driver V4L2 sources
+
+This module interfaces V4L2 subsystem and FM common module.
+It registers itself with V4L2 as Radio module.
+
+Signed-off-by: Manjunatha Halli <manjunatha_halli@ti.com>
+Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
+---
+ drivers/media/radio/wl128x/fmdrv_v4l2.c | 580 +++++++++++++++++++++++++++++++
+ drivers/media/radio/wl128x/fmdrv_v4l2.h | 33 ++
+ 2 files changed, 613 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/media/radio/wl128x/fmdrv_v4l2.c
+ create mode 100644 drivers/media/radio/wl128x/fmdrv_v4l2.h
+
+diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c
+new file mode 100644
+index 0000000..d50e5ac
+--- /dev/null
++++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c
+@@ -0,0 +1,580 @@
++/*
++ * FM Driver for Connectivity chip of Texas Instruments.
++ * This file provides interfaces to V4L2 subsystem.
++ *
++ * This module registers with V4L2 subsystem as Radio
++ * data system interface (/dev/radio). During the registration,
++ * it will expose two set of function pointers.
++ *
++ * 1) File operation related API (open, close, read, write, poll...etc).
++ * 2) Set of V4L2 IOCTL complaint API.
++ *
++ * Copyright (C) 2011 Texas Instruments
++ * Author: Raja Mani <raja_mani@ti.com>
++ * Author: Manjunatha Halli <manjunatha_halli@ti.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#include "fmdrv.h"
++#include "fmdrv_v4l2.h"
++#include "fmdrv_common.h"
++#include "fmdrv_rx.h"
++#include "fmdrv_tx.h"
++
++static struct video_device *gradio_dev;
++static u8 radio_disconnected;
++
++/* -- V4L2 RADIO (/dev/radioX) device file operation interfaces --- */
++
++/* Read RX RDS data */
++static ssize_t fm_v4l2_fops_read(struct file *file, char __user * buf,
++ size_t count, loff_t *ppos)
++{
++ u8 rds_mode;
++ int ret;
++ struct fmdev *fmdev;
++
++ fmdev = video_drvdata(file);
++
++ if (!radio_disconnected) {
++ fmerr("FM device is already disconnected\n");
++ return -EIO;
++ }
++
++ /* Turn on RDS mode , if it is disabled */
++ ret = fm_rx_get_rds_mode(fmdev, &rds_mode);
++ if (ret < 0) {
++ fmerr("Unable to read current rds mode\n");
++ return ret;
++ }
++
++ if (rds_mode == FM_RDS_DISABLE) {
++ ret = fmc_set_rds_mode(fmdev, FM_RDS_ENABLE);
++ if (ret < 0) {
++ fmerr("Failed to enable rds mode\n");
++ return ret;
++ }
++ }
++
++ /* Copy RDS data from internal buffer to user buffer */
++ return fmc_transfer_rds_from_internal_buff(fmdev, file, buf, count);
++}
++
++/* Write TX RDS data */
++static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf,
++ size_t count, loff_t *ppos)
++{
++ struct tx_rds rds;
++ int ret;
++ struct fmdev *fmdev;
++
++ ret = copy_from_user(&rds, buf, sizeof(rds));
++ fmdbg("(%d)type: %d, text %s, af %d\n",
++ ret, rds.text_type, rds.text, rds.af_freq);
++
++ fmdev = video_drvdata(file);
++ fm_tx_set_radio_text(fmdev, rds.text, rds.text_type);
++ fm_tx_set_af(fmdev, rds.af_freq);
++
++ return 0;
++}
++
++static u32 fm_v4l2_fops_poll(struct file *file, struct poll_table_struct *pts)
++{
++ int ret;
++ struct fmdev *fmdev;
++
++ fmdev = video_drvdata(file);
++ ret = fmc_is_rds_data_available(fmdev, file, pts);
++ if (ret < 0)
++ return POLLIN | POLLRDNORM;
++
++ return 0;
++}
++
++/*
++ * Handle open request for "/dev/radioX" device.
++ * Start with FM RX mode as default.
++ */
++static int fm_v4l2_fops_open(struct file *file)
++{
++ int ret;
++ struct fmdev *fmdev = NULL;
++
++ /* Don't allow multiple open */
++ if (radio_disconnected) {
++ fmerr("FM device is already opened\n");
++ return -EBUSY;
++ }
++
++ fmdev = video_drvdata(file);
++
++ ret = fmc_prepare(fmdev);
++ if (ret < 0) {
++ fmerr("Unable to prepare FM CORE\n");
++ return ret;
++ }
++
++ fmdbg("Load FM RX firmware..\n");
++
++ ret = fmc_set_mode(fmdev, FM_MODE_RX);
++ if (ret < 0) {
++ fmerr("Unable to load FM RX firmware\n");
++ return ret;
++ }
++ radio_disconnected = 1;
++
++ return ret;
++}
++
++static int fm_v4l2_fops_release(struct file *file)
++{
++ int ret;
++ struct fmdev *fmdev;
++
++ fmdev = video_drvdata(file);
++ if (!radio_disconnected) {
++ fmdbg("FM device is already closed\n");
++ return 0;
++ }
++
++ ret = fmc_set_mode(fmdev, FM_MODE_OFF);
++ if (ret < 0) {
++ fmerr("Unable to turn off the chip\n");
++ return ret;
++ }
++
++ ret = fmc_release(fmdev);
++ if (ret < 0) {
++ fmerr("FM CORE release failed\n");
++ return ret;
++ }
++ radio_disconnected = 0;
++
++ return ret;
++}
++
++/* V4L2 RADIO (/dev/radioX) device IOCTL interfaces */
++static int fm_v4l2_vidioc_querycap(struct file *file, void *priv,
++ struct v4l2_capability *capability)
++{
++ strlcpy(capability->driver, FM_DRV_NAME, sizeof(capability->driver));
++ strlcpy(capability->card, FM_DRV_CARD_SHORT_NAME,
++ sizeof(capability->card));
++ sprintf(capability->bus_info, "UART");
++ capability->version = FM_DRV_RADIO_VERSION;
++ capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER |
++ V4L2_CAP_RADIO | V4L2_CAP_MODULATOR |
++ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE |
++ V4L2_CAP_RDS_CAPTURE;
++
++ return 0;
++}
++
++static int fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct fmdev *fmdev = container_of(ctrl->handler,
++ struct fmdev, ctrl_handler);
++
++ switch (ctrl->id) {
++ case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
++ ctrl->val = fm_tx_get_tune_cap_val(fmdev);
++ break;
++ default:
++ fmwarn("%s: Unknown IOCTL: %d\n", __func__, ctrl->id);
++ break;
++ }
++
++ return 0;
++}
++
++static int fm_v4l2_s_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct fmdev *fmdev = container_of(ctrl->handler,
++ struct fmdev, ctrl_handler);
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_VOLUME: /* set volume */
++ return fm_rx_set_volume(fmdev, (u16)ctrl->val);
++
++ case V4L2_CID_AUDIO_MUTE: /* set mute */
++ return fmc_set_mute_mode(fmdev, (u8)ctrl->val);
++
++ case V4L2_CID_TUNE_POWER_LEVEL:
++ /* set TX power level - ext control */
++ return fm_tx_set_pwr_lvl(fmdev, (u8)ctrl->val);
++
++ case V4L2_CID_TUNE_PREEMPHASIS:
++ return fm_tx_set_preemph_filter(fmdev, (u8) ctrl->val);
++
++ default:
++ return -EINVAL;
++ }
++}
++
++static int fm_v4l2_vidioc_g_audio(struct file *file, void *priv,
++ struct v4l2_audio *audio)
++{
++ memset(audio, 0, sizeof(*audio));
++ strcpy(audio->name, "Radio");
++ audio->capability = V4L2_AUDCAP_STEREO;
++
++ return 0;
++}
++
++static int fm_v4l2_vidioc_s_audio(struct file *file, void *priv,
++ struct v4l2_audio *audio)
++{
++ if (audio->index != 0)
++ return -EINVAL;
++
++ return 0;
++}
++
++/* Get tuner attributes. If current mode is NOT RX, return error */
++static int fm_v4l2_vidioc_g_tuner(struct file *file, void *priv,
++ struct v4l2_tuner *tuner)
++{
++ struct fmdev *fmdev = video_drvdata(file);
++ u32 bottom_freq;
++ u32 top_freq;
++ u16 stereo_mono_mode;
++ u16 rssilvl;
++ int ret;
++
++ if (tuner->index != 0)
++ return -EINVAL;
++
++ if (fmdev->curr_fmmode != FM_MODE_RX)
++ return -EPERM;
++
++ ret = fm_rx_get_band_freq_range(fmdev, &bottom_freq, &top_freq);
++ if (ret != 0)
++ return ret;
++
++ ret = fm_rx_get_stereo_mono(fmdev, &stereo_mono_mode);
++ if (ret != 0)
++ return ret;
++
++ ret = fm_rx_get_rssi_level(fmdev, &rssilvl);
++ if (ret != 0)
++ return ret;
++
++ strcpy(tuner->name, "FM");
++ tuner->type = V4L2_TUNER_RADIO;
++ /* Store rangelow and rangehigh freq in unit of 62.5 Hz */
++ tuner->rangelow = bottom_freq * 16;
++ tuner->rangehigh = top_freq * 16;
++ tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO |
++ ((fmdev->rx.rds.flag == FM_RDS_ENABLE) ? V4L2_TUNER_SUB_RDS : 0);
++ tuner->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS |
++ V4L2_TUNER_CAP_LOW;
++ tuner->audmode = (stereo_mono_mode ?
++ V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO);
++
++ /*
++ * Actual rssi value lies in between -128 to +127.
++ * Convert this range from 0 to 255 by adding +128
++ */
++ rssilvl += 128;
++
++ /*
++ * Return signal strength value should be within 0 to 65535.
++ * Find out correct signal radio by multiplying (65535/255) = 257
++ */
++ tuner->signal = rssilvl * 257;
++ tuner->afc = 0;
++
++ return ret;
++}
++
++/*
++ * Set tuner attributes. If current mode is NOT RX, set to RX.
++ * Currently, we set only audio mode (mono/stereo) and RDS state (on/off).
++ * Should we set other tuner attributes, too?
++ */
++static int fm_v4l2_vidioc_s_tuner(struct file *file, void *priv,
++ struct v4l2_tuner *tuner)
++{
++ struct fmdev *fmdev = video_drvdata(file);
++ u16 aud_mode;
++ u8 rds_mode;
++ int ret;
++
++ if (tuner->index != 0)
++ return -EINVAL;
++
++ aud_mode = (tuner->audmode == V4L2_TUNER_MODE_STEREO) ?
++ FM_STEREO_MODE : FM_MONO_MODE;
++ rds_mode = (tuner->rxsubchans & V4L2_TUNER_SUB_RDS) ?
++ FM_RDS_ENABLE : FM_RDS_DISABLE;
++
++ if (fmdev->curr_fmmode != FM_MODE_RX) {
++ ret = fmc_set_mode(fmdev, FM_MODE_RX);
++ if (ret < 0) {
++ fmerr("Failed to set RX mode\n");
++ return ret;
++ }
++ }
++
++ ret = fmc_set_stereo_mono(fmdev, aud_mode);
++ if (ret < 0) {
++ fmerr("Failed to set RX stereo/mono mode\n");
++ return ret;
++ }
++
++ ret = fmc_set_rds_mode(fmdev, rds_mode);
++ if (ret < 0)
++ fmerr("Failed to set RX RDS mode\n");
++
++ return ret;
++}
++
++/* Get tuner or modulator radio frequency */
++static int fm_v4l2_vidioc_g_freq(struct file *file, void *priv,
++ struct v4l2_frequency *freq)
++{
++ struct fmdev *fmdev = video_drvdata(file);
++ int ret;
++
++ ret = fmc_get_freq(fmdev, &freq->frequency);
++ if (ret < 0) {
++ fmerr("Failed to get frequency\n");
++ return ret;
++ }
++
++ /* Frequency unit of 62.5 Hz*/
++ freq->frequency = (u32) freq->frequency * 16;
++
++ return 0;
++}
++
++/* Set tuner or modulator radio frequency */
++static int fm_v4l2_vidioc_s_freq(struct file *file, void *priv,
++ struct v4l2_frequency *freq)
++{
++ struct fmdev *fmdev = video_drvdata(file);
++
++ /*
++ * As V4L2_TUNER_CAP_LOW is set 1 user sends the frequency
++ * in units of 62.5 Hz.
++ */
++ freq->frequency = (u32)(freq->frequency / 16);
++
++ return fmc_set_freq(fmdev, freq->frequency);
++}
++
++/* Set hardware frequency seek. If current mode is NOT RX, set it RX. */
++static int fm_v4l2_vidioc_s_hw_freq_seek(struct file *file, void *priv,
++ struct v4l2_hw_freq_seek *seek)
++{
++ struct fmdev *fmdev = video_drvdata(file);
++ int ret;
++
++ if (fmdev->curr_fmmode != FM_MODE_RX) {
++ ret = fmc_set_mode(fmdev, FM_MODE_RX);
++ if (ret != 0) {
++ fmerr("Failed to set RX mode\n");
++ return ret;
++ }
++ }
++
++ ret = fm_rx_seek(fmdev, seek->seek_upward, seek->wrap_around,
++ seek->spacing);
++ if (ret < 0)
++ fmerr("RX seek failed - %d\n", ret);
++
++ return ret;
++}
++/* Get modulator attributes. If mode is not TX, return no attributes. */
++static int fm_v4l2_vidioc_g_modulator(struct file *file, void *priv,
++ struct v4l2_modulator *mod)
++{
++ struct fmdev *fmdev = video_drvdata(file);;
++
++ if (mod->index != 0)
++ return -EINVAL;
++
++ if (fmdev->curr_fmmode != FM_MODE_TX)
++ return -EPERM;
++
++ mod->txsubchans = ((fmdev->tx_data.aud_mode == FM_STEREO_MODE) ?
++ V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO) |
++ ((fmdev->tx_data.rds.flag == FM_RDS_ENABLE) ?
++ V4L2_TUNER_SUB_RDS : 0);
++
++ mod->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS |
++ V4L2_TUNER_CAP_LOW;
++
++ return 0;
++}
++
++/* Set modulator attributes. If mode is not TX, set to TX. */
++static int fm_v4l2_vidioc_s_modulator(struct file *file, void *priv,
++ struct v4l2_modulator *mod)
++{
++ struct fmdev *fmdev = video_drvdata(file);
++ u8 rds_mode;
++ u16 aud_mode;
++ int ret;
++
++ if (mod->index != 0)
++ return -EINVAL;
++
++ if (fmdev->curr_fmmode != FM_MODE_TX) {
++ ret = fmc_set_mode(fmdev, FM_MODE_TX);
++ if (ret != 0) {
++ fmerr("Failed to set TX mode\n");
++ return ret;
++ }
++ }
++
++ aud_mode = (mod->txsubchans & V4L2_TUNER_SUB_STEREO) ?
++ FM_STEREO_MODE : FM_MONO_MODE;
++ rds_mode = (mod->txsubchans & V4L2_TUNER_SUB_RDS) ?
++ FM_RDS_ENABLE : FM_RDS_DISABLE;
++ ret = fm_tx_set_stereo_mono(fmdev, aud_mode);
++ if (ret < 0) {
++ fmerr("Failed to set mono/stereo mode for TX\n");
++ return ret;
++ }
++ ret = fm_tx_set_rds_mode(fmdev, rds_mode);
++ if (ret < 0)
++ fmerr("Failed to set rds mode for TX\n");
++
++ return ret;
++}
++
++static const struct v4l2_file_operations fm_drv_fops = {
++ .owner = THIS_MODULE,
++ .read = fm_v4l2_fops_read,
++ .write = fm_v4l2_fops_write,
++ .poll = fm_v4l2_fops_poll,
++ .unlocked_ioctl = video_ioctl2,
++ .open = fm_v4l2_fops_open,
++ .release = fm_v4l2_fops_release,
++};
++
++static const struct v4l2_ctrl_ops fm_ctrl_ops = {
++ .s_ctrl = fm_v4l2_s_ctrl,
++ .g_volatile_ctrl = fm_g_volatile_ctrl,
++};
++static const struct v4l2_ioctl_ops fm_drv_ioctl_ops = {
++ .vidioc_querycap = fm_v4l2_vidioc_querycap,
++ .vidioc_g_audio = fm_v4l2_vidioc_g_audio,
++ .vidioc_s_audio = fm_v4l2_vidioc_s_audio,
++ .vidioc_g_tuner = fm_v4l2_vidioc_g_tuner,
++ .vidioc_s_tuner = fm_v4l2_vidioc_s_tuner,
++ .vidioc_g_frequency = fm_v4l2_vidioc_g_freq,
++ .vidioc_s_frequency = fm_v4l2_vidioc_s_freq,
++ .vidioc_s_hw_freq_seek = fm_v4l2_vidioc_s_hw_freq_seek,
++ .vidioc_g_modulator = fm_v4l2_vidioc_g_modulator,
++ .vidioc_s_modulator = fm_v4l2_vidioc_s_modulator
++};
++
++/* V4L2 RADIO device parent structure */
++static struct video_device fm_viddev_template = {
++ .fops = &fm_drv_fops,
++ .ioctl_ops = &fm_drv_ioctl_ops,
++ .name = FM_DRV_NAME,
++ .release = video_device_release,
++};
++
++int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr)
++{
++ struct v4l2_ctrl *ctrl;
++ int ret;
++
++ /* Init mutex for core locking */
++ mutex_init(&fmdev->mutex);
++
++ /* Allocate new video device */
++ gradio_dev = video_device_alloc();
++ if (NULL == gradio_dev) {
++ fmerr("Can't allocate video device\n");
++ return -ENOMEM;
++ }
++
++ /* Setup FM driver's V4L2 properties */
++ memcpy(gradio_dev, &fm_viddev_template, sizeof(fm_viddev_template));
++
++ video_set_drvdata(gradio_dev, fmdev);
++
++ gradio_dev->lock = &fmdev->mutex;
++
++ /* Register with V4L2 subsystem as RADIO device */
++ if (video_register_device(gradio_dev, VFL_TYPE_RADIO, radio_nr)) {
++ video_device_release(gradio_dev);
++ fmerr("Could not register video device\n");
++ return -ENOMEM;
++ }
++
++ fmdev->radio_dev = gradio_dev;
++
++ /* Register to v4l2 ctrl handler framework */
++ fmdev->radio_dev->ctrl_handler = &fmdev->ctrl_handler;
++
++ ret = v4l2_ctrl_handler_init(&fmdev->ctrl_handler, 5);
++ if (ret < 0) {
++ fmerr("(fmdev): Can't init ctrl handler\n");
++ v4l2_ctrl_handler_free(&fmdev->ctrl_handler);
++ return -EBUSY;
++ }
++
++ /*
++ * Following controls are handled by V4L2 control framework.
++ * Added in ascending ID order.
++ */
++ v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops,
++ V4L2_CID_AUDIO_VOLUME, FM_RX_VOLUME_MIN,
++ FM_RX_VOLUME_MAX, 1, FM_RX_VOLUME_MAX);
++
++ v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops,
++ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
++
++ v4l2_ctrl_new_std_menu(&fmdev->ctrl_handler, &fm_ctrl_ops,
++ V4L2_CID_TUNE_PREEMPHASIS, V4L2_PREEMPHASIS_75_uS,
++ 0, V4L2_PREEMPHASIS_75_uS);
++
++ v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops,
++ V4L2_CID_TUNE_POWER_LEVEL, FM_PWR_LVL_LOW,
++ FM_PWR_LVL_HIGH, 1, FM_PWR_LVL_HIGH);
++
++ ctrl = v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops,
++ V4L2_CID_TUNE_ANTENNA_CAPACITOR, 0,
++ 255, 1, 255);
++
++ if (ctrl)
++ ctrl->is_volatile = 1;
++
++ return 0;
++}
++
++void *fm_v4l2_deinit_video_device(void)
++{
++ struct fmdev *fmdev;
++
++
++ fmdev = video_get_drvdata(gradio_dev);
++
++ /* Unregister to v4l2 ctrl handler framework*/
++ v4l2_ctrl_handler_free(&fmdev->ctrl_handler);
++
++ /* Unregister RADIO device from V4L2 subsystem */
++ video_unregister_device(gradio_dev);
++
++ return fmdev;
++}
+diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.h b/drivers/media/radio/wl128x/fmdrv_v4l2.h
+new file mode 100644
+index 0000000..0ba79d7
+--- /dev/null
++++ b/drivers/media/radio/wl128x/fmdrv_v4l2.h
+@@ -0,0 +1,33 @@
++/*
++ * FM Driver for Connectivity chip of Texas Instruments.
++ *
++ * FM V4L2 module header.
++ *
++ * Copyright (C) 2011 Texas Instruments
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#ifndef _FMDRV_V4L2_H
++#define _FMDRV_V4L2_H
++
++#include <media/v4l2-ioctl.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-ctrls.h>
++
++int fm_v4l2_init_video_device(struct fmdev *, int);
++void *fm_v4l2_deinit_video_device(void);
++
++#endif
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/wl1271/0009-drivers-media-radio-wl128x-FM-Driver-Common-sources.patch b/extras/recipes-kernel/linux/linux-omap/wl1271/0009-drivers-media-radio-wl128x-FM-Driver-Common-sources.patch
new file mode 100644
index 00000000..61dc164b
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/wl1271/0009-drivers-media-radio-wl128x-FM-Driver-Common-sources.patch
@@ -0,0 +1,2114 @@
+From 1c32040233847f9c7998e7c557fa80dfd953e236 Mon Sep 17 00:00:00 2001
+From: Manjunatha Halli <manjunatha_halli@ti.com>
+Date: Tue, 11 Jan 2011 11:31:23 +0000
+Subject: [PATCH 09/15] drivers:media:radio: wl128x: FM Driver Common sources
+
+These are the sources for the common interfaces required by the
+FM V4L2 driver for TI WL127x and WL128x chips.
+
+These implement the FM channel-8 protocol communication with the
+chip. This makes use of the Shared Transport as its transport.
+
+Signed-off-by: Manjunatha Halli <manjunatha_halli@ti.com>
+Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
+---
+ drivers/media/radio/wl128x/fmdrv_common.c | 1677 +++++++++++++++++++++++++++++
+ drivers/media/radio/wl128x/fmdrv_common.h | 402 +++++++
+ 2 files changed, 2079 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/media/radio/wl128x/fmdrv_common.c
+ create mode 100644 drivers/media/radio/wl128x/fmdrv_common.h
+
+diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c
+new file mode 100644
+index 0000000..12f4c65
+--- /dev/null
++++ b/drivers/media/radio/wl128x/fmdrv_common.c
+@@ -0,0 +1,1677 @@
++/*
++ * FM Driver for Connectivity chip of Texas Instruments.
++ *
++ * This sub-module of FM driver is common for FM RX and TX
++ * functionality. This module is responsible for:
++ * 1) Forming group of Channel-8 commands to perform particular
++ * functionality (eg., frequency set require more than
++ * one Channel-8 command to be sent to the chip).
++ * 2) Sending each Channel-8 command to the chip and reading
++ * response back over Shared Transport.
++ * 3) Managing TX and RX Queues and Tasklets.
++ * 4) Handling FM Interrupt packet and taking appropriate action.
++ * 5) Loading FM firmware to the chip (common, FM TX, and FM RX
++ * firmware files based on mode selection)
++ *
++ * Copyright (C) 2011 Texas Instruments
++ * Author: Raja Mani <raja_mani@ti.com>
++ * Author: Manjunatha Halli <manjunatha_halli@ti.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/firmware.h>
++#include <linux/delay.h>
++#include "fmdrv.h"
++#include "fmdrv_v4l2.h"
++#include "fmdrv_common.h"
++#include <linux/ti_wilink_st.h>
++#include "fmdrv_rx.h"
++#include "fmdrv_tx.h"
++
++/* Region info */
++static struct region_info region_configs[] = {
++ /* Europe/US */
++ {
++ .chanl_space = FM_CHANNEL_SPACING_200KHZ * FM_FREQ_MUL,
++ .bot_freq = 87500, /* 87.5 MHz */
++ .top_freq = 108000, /* 108 MHz */
++ .fm_band = 0,
++ },
++ /* Japan */
++ {
++ .chanl_space = FM_CHANNEL_SPACING_200KHZ * FM_FREQ_MUL,
++ .bot_freq = 76000, /* 76 MHz */
++ .top_freq = 90000, /* 90 MHz */
++ .fm_band = 1,
++ },
++};
++
++/* Band selection */
++static u8 default_radio_region; /* Europe/US */
++module_param(default_radio_region, byte, 0);
++MODULE_PARM_DESC(default_radio_region, "Region: 0=Europe/US, 1=Japan");
++
++/* RDS buffer blocks */
++static u32 default_rds_buf = 300;
++module_param(default_rds_buf, uint, 0444);
++MODULE_PARM_DESC(rds_buf, "RDS buffer entries");
++
++/* Radio Nr */
++static u32 radio_nr = -1;
++module_param(radio_nr, int, 0444);
++MODULE_PARM_DESC(radio_nr, "Radio Nr");
++
++/* FM irq handlers forward declaration */
++static void fm_irq_send_flag_getcmd(struct fmdev *);
++static void fm_irq_handle_flag_getcmd_resp(struct fmdev *);
++static void fm_irq_handle_hw_malfunction(struct fmdev *);
++static void fm_irq_handle_rds_start(struct fmdev *);
++static void fm_irq_send_rdsdata_getcmd(struct fmdev *);
++static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *);
++static void fm_irq_handle_rds_finish(struct fmdev *);
++static void fm_irq_handle_tune_op_ended(struct fmdev *);
++static void fm_irq_handle_power_enb(struct fmdev *);
++static void fm_irq_handle_low_rssi_start(struct fmdev *);
++static void fm_irq_afjump_set_pi(struct fmdev *);
++static void fm_irq_handle_set_pi_resp(struct fmdev *);
++static void fm_irq_afjump_set_pimask(struct fmdev *);
++static void fm_irq_handle_set_pimask_resp(struct fmdev *);
++static void fm_irq_afjump_setfreq(struct fmdev *);
++static void fm_irq_handle_setfreq_resp(struct fmdev *);
++static void fm_irq_afjump_enableint(struct fmdev *);
++static void fm_irq_afjump_enableint_resp(struct fmdev *);
++static void fm_irq_start_afjump(struct fmdev *);
++static void fm_irq_handle_start_afjump_resp(struct fmdev *);
++static void fm_irq_afjump_rd_freq(struct fmdev *);
++static void fm_irq_afjump_rd_freq_resp(struct fmdev *);
++static void fm_irq_handle_low_rssi_finish(struct fmdev *);
++static void fm_irq_send_intmsk_cmd(struct fmdev *);
++static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *);
++
++/*
++ * When FM common module receives interrupt packet, following handlers
++ * will be executed one after another to service the interrupt(s)
++ */
++enum fmc_irq_handler_index {
++ FM_SEND_FLAG_GETCMD_IDX,
++ FM_HANDLE_FLAG_GETCMD_RESP_IDX,
++
++ /* HW malfunction irq handler */
++ FM_HW_MAL_FUNC_IDX,
++
++ /* RDS threshold reached irq handler */
++ FM_RDS_START_IDX,
++ FM_RDS_SEND_RDS_GETCMD_IDX,
++ FM_RDS_HANDLE_RDS_GETCMD_RESP_IDX,
++ FM_RDS_FINISH_IDX,
++
++ /* Tune operation ended irq handler */
++ FM_HW_TUNE_OP_ENDED_IDX,
++
++ /* TX power enable irq handler */
++ FM_HW_POWER_ENB_IDX,
++
++ /* Low RSSI irq handler */
++ FM_LOW_RSSI_START_IDX,
++ FM_AF_JUMP_SETPI_IDX,
++ FM_AF_JUMP_HANDLE_SETPI_RESP_IDX,
++ FM_AF_JUMP_SETPI_MASK_IDX,
++ FM_AF_JUMP_HANDLE_SETPI_MASK_RESP_IDX,
++ FM_AF_JUMP_SET_AF_FREQ_IDX,
++ FM_AF_JUMP_HANDLE_SET_AFFREQ_RESP_IDX,
++ FM_AF_JUMP_ENABLE_INT_IDX,
++ FM_AF_JUMP_ENABLE_INT_RESP_IDX,
++ FM_AF_JUMP_START_AFJUMP_IDX,
++ FM_AF_JUMP_HANDLE_START_AFJUMP_RESP_IDX,
++ FM_AF_JUMP_RD_FREQ_IDX,
++ FM_AF_JUMP_RD_FREQ_RESP_IDX,
++ FM_LOW_RSSI_FINISH_IDX,
++
++ /* Interrupt process post action */
++ FM_SEND_INTMSK_CMD_IDX,
++ FM_HANDLE_INTMSK_CMD_RESP_IDX,
++};
++
++/* FM interrupt handler table */
++static int_handler_prototype int_handler_table[] = {
++ fm_irq_send_flag_getcmd,
++ fm_irq_handle_flag_getcmd_resp,
++ fm_irq_handle_hw_malfunction,
++ fm_irq_handle_rds_start, /* RDS threshold reached irq handler */
++ fm_irq_send_rdsdata_getcmd,
++ fm_irq_handle_rdsdata_getcmd_resp,
++ fm_irq_handle_rds_finish,
++ fm_irq_handle_tune_op_ended,
++ fm_irq_handle_power_enb, /* TX power enable irq handler */
++ fm_irq_handle_low_rssi_start,
++ fm_irq_afjump_set_pi,
++ fm_irq_handle_set_pi_resp,
++ fm_irq_afjump_set_pimask,
++ fm_irq_handle_set_pimask_resp,
++ fm_irq_afjump_setfreq,
++ fm_irq_handle_setfreq_resp,
++ fm_irq_afjump_enableint,
++ fm_irq_afjump_enableint_resp,
++ fm_irq_start_afjump,
++ fm_irq_handle_start_afjump_resp,
++ fm_irq_afjump_rd_freq,
++ fm_irq_afjump_rd_freq_resp,
++ fm_irq_handle_low_rssi_finish,
++ fm_irq_send_intmsk_cmd, /* Interrupt process post action */
++ fm_irq_handle_intmsk_cmd_resp
++};
++
++long (*g_st_write) (struct sk_buff *skb);
++static struct completion wait_for_fmdrv_reg_comp;
++
++static inline void fm_irq_call(struct fmdev *fmdev)
++{
++ fmdev->irq_info.handlers[fmdev->irq_info.stage](fmdev);
++}
++
++/* Continue next function in interrupt handler table */
++static inline void fm_irq_call_stage(struct fmdev *fmdev, u8 stage)
++{
++ fmdev->irq_info.stage = stage;
++ fm_irq_call(fmdev);
++}
++
++static inline void fm_irq_timeout_stage(struct fmdev *fmdev, u8 stage)
++{
++ fmdev->irq_info.stage = stage;
++ mod_timer(&fmdev->irq_info.timer, jiffies + FM_DRV_TX_TIMEOUT);
++}
++
++#ifdef FM_DUMP_TXRX_PKT
++ /* To dump outgoing FM Channel-8 packets */
++inline void dump_tx_skb_data(struct sk_buff *skb)
++{
++ int len, len_org;
++ u8 index;
++ struct fm_cmd_msg_hdr *cmd_hdr;
++
++ cmd_hdr = (struct fm_cmd_msg_hdr *)skb->data;
++ printk(KERN_INFO "<<%shdr:%02x len:%02x opcode:%02x type:%s dlen:%02x",
++ fm_cb(skb)->completion ? " " : "*", cmd_hdr->hdr,
++ cmd_hdr->len, cmd_hdr->op,
++ cmd_hdr->rd_wr ? "RD" : "WR", cmd_hdr->dlen);
++
++ len_org = skb->len - FM_CMD_MSG_HDR_SIZE;
++ if (len_org > 0) {
++ printk("\n data(%d): ", cmd_hdr->dlen);
++ len = min(len_org, 14);
++ for (index = 0; index < len; index++)
++ printk("%x ",
++ skb->data[FM_CMD_MSG_HDR_SIZE + index]);
++ printk("%s", (len_org > 14) ? ".." : "");
++ }
++ printk("\n");
++}
++
++ /* To dump incoming FM Channel-8 packets */
++inline void dump_rx_skb_data(struct sk_buff *skb)
++{
++ int len, len_org;
++ u8 index;
++ struct fm_event_msg_hdr *evt_hdr;
++
++ evt_hdr = (struct fm_event_msg_hdr *)skb->data;
++ printk(KERN_INFO ">> hdr:%02x len:%02x sts:%02x numhci:%02x "
++ "opcode:%02x type:%s dlen:%02x", evt_hdr->hdr, evt_hdr->len,
++ evt_hdr->status, evt_hdr->num_fm_hci_cmds, evt_hdr->op,
++ (evt_hdr->rd_wr) ? "RD" : "WR", evt_hdr->dlen);
++
++ len_org = skb->len - FM_EVT_MSG_HDR_SIZE;
++ if (len_org > 0) {
++ printk("\n data(%d): ", evt_hdr->dlen);
++ len = min(len_org, 14);
++ for (index = 0; index < len; index++)
++ printk("%x ",
++ skb->data[FM_EVT_MSG_HDR_SIZE + index]);
++ printk("%s", (len_org > 14) ? ".." : "");
++ }
++ printk("\n");
++}
++#endif
++
++void fmc_update_region_info(struct fmdev *fmdev, u8 region_to_set)
++{
++ fmdev->rx.region = region_configs[region_to_set];
++}
++
++/*
++ * FM common sub-module will schedule this tasklet whenever it receives
++ * FM packet from ST driver.
++ */
++static void recv_tasklet(unsigned long arg)
++{
++ struct fmdev *fmdev;
++ struct fm_irq *irq_info;
++ struct fm_event_msg_hdr *evt_hdr;
++ struct sk_buff *skb;
++ u8 num_fm_hci_cmds;
++ unsigned long flags;
++
++ fmdev = (struct fmdev *)arg;
++ irq_info = &fmdev->irq_info;
++ /* Process all packets in the RX queue */
++ while ((skb = skb_dequeue(&fmdev->rx_q))) {
++ if (skb->len < sizeof(struct fm_event_msg_hdr)) {
++ fmerr("skb(%p) has only %d bytes"
++ "atleast need %d bytes to decode\n", skb,
++ skb->len, sizeof(struct fm_event_msg_hdr));
++ kfree_skb(skb);
++ continue;
++ }
++
++ evt_hdr = (void *)skb->data;
++ num_fm_hci_cmds = evt_hdr->num_fm_hci_cmds;
++
++ /* FM interrupt packet? */
++ if (evt_hdr->op == FM_INTERRUPT) {
++ /* FM interrupt handler started already? */
++ if (!test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) {
++ set_bit(FM_INTTASK_RUNNING, &fmdev->flag);
++ if (irq_info->stage != 0) {
++ fmerr("Inval stage resetting to zero\n");
++ irq_info->stage = 0;
++ }
++
++ /*
++ * Execute first function in interrupt handler
++ * table.
++ */
++ irq_info->handlers[irq_info->stage](fmdev);
++ } else {
++ set_bit(FM_INTTASK_SCHEDULE_PENDING, &fmdev->flag);
++ }
++ kfree_skb(skb);
++ }
++ /* Anyone waiting for this with completion handler? */
++ else if (evt_hdr->op == fmdev->pre_op && fmdev->resp_comp != NULL) {
++
++ spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
++ fmdev->resp_skb = skb;
++ spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
++ complete(fmdev->resp_comp);
++
++ fmdev->resp_comp = NULL;
++ atomic_set(&fmdev->tx_cnt, 1);
++ }
++ /* Is this for interrupt handler? */
++ else if (evt_hdr->op == fmdev->pre_op && fmdev->resp_comp == NULL) {
++ if (fmdev->resp_skb != NULL)
++ fmerr("Response SKB ptr not NULL\n");
++
++ spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
++ fmdev->resp_skb = skb;
++ spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
++
++ /* Execute interrupt handler where state index points */
++ irq_info->handlers[irq_info->stage](fmdev);
++
++ kfree_skb(skb);
++ atomic_set(&fmdev->tx_cnt, 1);
++ } else {
++ fmerr("Nobody claimed SKB(%p),purging\n", skb);
++ }
++
++ /*
++ * Check flow control field. If Num_FM_HCI_Commands field is
++ * not zero, schedule FM TX tasklet.
++ */
++ if (num_fm_hci_cmds && atomic_read(&fmdev->tx_cnt))
++ if (!skb_queue_empty(&fmdev->tx_q))
++ tasklet_schedule(&fmdev->tx_task);
++ }
++}
++
++/* FM send tasklet: is scheduled when FM packet has to be sent to chip */
++static void send_tasklet(unsigned long arg)
++{
++ struct fmdev *fmdev;
++ struct sk_buff *skb;
++ int len;
++
++ fmdev = (struct fmdev *)arg;
++
++ if (!atomic_read(&fmdev->tx_cnt))
++ return;
++
++ /* Check, is there any timeout happenned to last transmitted packet */
++ if ((jiffies - fmdev->last_tx_jiffies) > FM_DRV_TX_TIMEOUT) {
++ fmerr("TX timeout occurred\n");
++ atomic_set(&fmdev->tx_cnt, 1);
++ }
++
++ /* Send queued FM TX packets */
++ skb = skb_dequeue(&fmdev->tx_q);
++ if (!skb)
++ return;
++
++ atomic_dec(&fmdev->tx_cnt);
++ fmdev->pre_op = fm_cb(skb)->fm_op;
++
++ if (fmdev->resp_comp != NULL)
++ fmerr("Response completion handler is not NULL\n");
++
++ fmdev->resp_comp = fm_cb(skb)->completion;
++
++ /* Write FM packet to ST driver */
++ len = g_st_write(skb);
++ if (len < 0) {
++ kfree_skb(skb);
++ fmdev->resp_comp = NULL;
++ fmerr("TX tasklet failed to send skb(%p)\n", skb);
++ atomic_set(&fmdev->tx_cnt, 1);
++ } else {
++ fmdev->last_tx_jiffies = jiffies;
++ }
++}
++
++/*
++ * Queues FM Channel-8 packet to FM TX queue and schedules FM TX tasklet for
++ * transmission
++ */
++static u32 fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
++ int payload_len, struct completion *wait_completion)
++{
++ struct sk_buff *skb;
++ struct fm_cmd_msg_hdr *hdr;
++ int size;
++
++ if (fm_op >= FM_INTERRUPT) {
++ fmerr("Invalid fm opcode - %d\n", fm_op);
++ return -EINVAL;
++ }
++ if (test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag) && payload == NULL) {
++ fmerr("Payload data is NULL during fw download\n");
++ return -EINVAL;
++ }
++ if (!test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag))
++ size =
++ FM_CMD_MSG_HDR_SIZE + ((payload == NULL) ? 0 : payload_len);
++ else
++ size = payload_len;
++
++ skb = alloc_skb(size, GFP_ATOMIC);
++ if (!skb) {
++ fmerr("No memory to create new SKB\n");
++ return -ENOMEM;
++ }
++ /*
++ * Don't fill FM header info for the commands which come from
++ * FM firmware file.
++ */
++ if (!test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag) ||
++ test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) {
++ /* Fill command header info */
++ hdr = (struct fm_cmd_msg_hdr *)skb_put(skb, FM_CMD_MSG_HDR_SIZE);
++ hdr->hdr = FM_PKT_LOGICAL_CHAN_NUMBER; /* 0x08 */
++
++ /* 3 (fm_opcode,rd_wr,dlen) + payload len) */
++ hdr->len = ((payload == NULL) ? 0 : payload_len) + 3;
++
++ /* FM opcode */
++ hdr->op = fm_op;
++
++ /* read/write type */
++ hdr->rd_wr = type;
++ hdr->dlen = payload_len;
++ fm_cb(skb)->fm_op = fm_op;
++
++ /*
++ * If firmware download has finished and the command is
++ * not a read command then payload is != NULL - a write
++ * command with u16 payload - convert to be16
++ */
++ if (payload != NULL)
++ *(u16 *)payload = cpu_to_be16(*(u16 *)payload);
++
++ } else if (payload != NULL) {
++ fm_cb(skb)->fm_op = *((u8 *)payload + 2);
++ }
++ if (payload != NULL)
++ memcpy(skb_put(skb, payload_len), payload, payload_len);
++
++ fm_cb(skb)->completion = wait_completion;
++ skb_queue_tail(&fmdev->tx_q, skb);
++ tasklet_schedule(&fmdev->tx_task);
++
++ return 0;
++}
++
++/* Sends FM Channel-8 command to the chip and waits for the response */
++u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
++ unsigned int payload_len, void *response, int *response_len)
++{
++ struct sk_buff *skb;
++ struct fm_event_msg_hdr *evt_hdr;
++ unsigned long flags;
++ u32 ret;
++
++ init_completion(&fmdev->maintask_comp);
++ ret = fm_send_cmd(fmdev, fm_op, type, payload, payload_len,
++ &fmdev->maintask_comp);
++ if (ret)
++ return ret;
++
++ ret = wait_for_completion_timeout(&fmdev->maintask_comp, FM_DRV_TX_TIMEOUT);
++ if (!ret) {
++ fmerr("Timeout(%d sec),didn't get reg"
++ "completion signal from RX tasklet\n",
++ jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
++ return -ETIMEDOUT;
++ }
++ if (!fmdev->resp_skb) {
++ fmerr("Reponse SKB is missing\n");
++ return -EFAULT;
++ }
++ spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
++ skb = fmdev->resp_skb;
++ fmdev->resp_skb = NULL;
++ spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
++
++ evt_hdr = (void *)skb->data;
++ if (evt_hdr->status != 0) {
++ fmerr("Received event pkt status(%d) is not zero\n",
++ evt_hdr->status);
++ kfree_skb(skb);
++ return -EIO;
++ }
++ /* Send response data to caller */
++ if (response != NULL && response_len != NULL && evt_hdr->dlen) {
++ /* Skip header info and copy only response data */
++ skb_pull(skb, sizeof(struct fm_event_msg_hdr));
++ memcpy(response, skb->data, evt_hdr->dlen);
++ *response_len = evt_hdr->dlen;
++ } else if (response_len != NULL && evt_hdr->dlen == 0) {
++ *response_len = 0;
++ }
++ kfree_skb(skb);
++
++ return 0;
++}
++
++/* --- Helper functions used in FM interrupt handlers ---*/
++static inline u32 check_cmdresp_status(struct fmdev *fmdev,
++ struct sk_buff **skb)
++{
++ struct fm_event_msg_hdr *fm_evt_hdr;
++ unsigned long flags;
++
++ del_timer(&fmdev->irq_info.timer);
++
++ spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
++ *skb = fmdev->resp_skb;
++ fmdev->resp_skb = NULL;
++ spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
++
++ fm_evt_hdr = (void *)(*skb)->data;
++ if (fm_evt_hdr->status != 0) {
++ fmerr("irq: opcode %x response status is not zero "
++ "Initiating irq recovery process\n",
++ fm_evt_hdr->op);
++
++ mod_timer(&fmdev->irq_info.timer, jiffies + FM_DRV_TX_TIMEOUT);
++ return -1;
++ }
++
++ return 0;
++}
++
++static inline void fm_irq_common_cmd_resp_helper(struct fmdev *fmdev, u8 stage)
++{
++ struct sk_buff *skb;
++
++ if (!check_cmdresp_status(fmdev, &skb))
++ fm_irq_call_stage(fmdev, stage);
++}
++
++/*
++ * Interrupt process timeout handler.
++ * One of the irq handler did not get proper response from the chip. So take
++ * recovery action here. FM interrupts are disabled in the beginning of
++ * interrupt process. Therefore reset stage index to re-enable default
++ * interrupts. So that next interrupt will be processed as usual.
++ */
++static void int_timeout_handler(unsigned long data)
++{
++ struct fmdev *fmdev;
++ struct fm_irq *fmirq;
++
++ fmdbg("irq: timeout,trying to re-enable fm interrupts\n");
++ fmdev = (struct fmdev *)data;
++ fmirq = &fmdev->irq_info;
++ fmirq->retry++;
++
++ if (fmirq->retry > FM_IRQ_TIMEOUT_RETRY_MAX) {
++ /* Stop recovery action (interrupt reenable process) and
++ * reset stage index & retry count values */
++ fmirq->stage = 0;
++ fmirq->retry = 0;
++ fmerr("Recovery action failed during"
++ "irq processing, max retry reached\n");
++ return;
++ }
++ fm_irq_call_stage(fmdev, FM_SEND_INTMSK_CMD_IDX);
++}
++
++/* --------- FM interrupt handlers ------------*/
++static void fm_irq_send_flag_getcmd(struct fmdev *fmdev)
++{
++ u16 flag;
++
++ /* Send FLAG_GET command , to know the source of interrupt */
++ if (!fm_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, sizeof(flag), NULL))
++ fm_irq_timeout_stage(fmdev, FM_HANDLE_FLAG_GETCMD_RESP_IDX);
++}
++
++static void fm_irq_handle_flag_getcmd_resp(struct fmdev *fmdev)
++{
++ struct sk_buff *skb;
++ struct fm_event_msg_hdr *fm_evt_hdr;
++
++ if (check_cmdresp_status(fmdev, &skb))
++ return;
++
++ fm_evt_hdr = (void *)skb->data;
++
++ /* Skip header info and copy only response data */
++ skb_pull(skb, sizeof(struct fm_event_msg_hdr));
++ memcpy(&fmdev->irq_info.flag, skb->data, fm_evt_hdr->dlen);
++
++ fmdev->irq_info.flag = be16_to_cpu(fmdev->irq_info.flag);
++ fmdbg("irq: flag register(0x%x)\n", fmdev->irq_info.flag);
++
++ /* Continue next function in interrupt handler table */
++ fm_irq_call_stage(fmdev, FM_HW_MAL_FUNC_IDX);
++}
++
++static void fm_irq_handle_hw_malfunction(struct fmdev *fmdev)
++{
++ if (fmdev->irq_info.flag & FM_MAL_EVENT & fmdev->irq_info.mask)
++ fmerr("irq: HW MAL int received - do nothing\n");
++
++ /* Continue next function in interrupt handler table */
++ fm_irq_call_stage(fmdev, FM_RDS_START_IDX);
++}
++
++static void fm_irq_handle_rds_start(struct fmdev *fmdev)
++{
++ if (fmdev->irq_info.flag & FM_RDS_EVENT & fmdev->irq_info.mask) {
++ fmdbg("irq: rds threshold reached\n");
++ fmdev->irq_info.stage = FM_RDS_SEND_RDS_GETCMD_IDX;
++ } else {
++ /* Continue next function in interrupt handler table */
++ fmdev->irq_info.stage = FM_HW_TUNE_OP_ENDED_IDX;
++ }
++
++ fm_irq_call(fmdev);
++}
++
++static void fm_irq_send_rdsdata_getcmd(struct fmdev *fmdev)
++{
++ /* Send the command to read RDS data from the chip */
++ if (!fm_send_cmd(fmdev, RDS_DATA_GET, REG_RD, NULL,
++ (FM_RX_RDS_FIFO_THRESHOLD * 3), NULL))
++ fm_irq_timeout_stage(fmdev, FM_RDS_HANDLE_RDS_GETCMD_RESP_IDX);
++}
++
++/* Keeps track of current RX channel AF (Alternate Frequency) */
++static void fm_rx_update_af_cache(struct fmdev *fmdev, u8 af)
++{
++ struct tuned_station_info *stat_info = &fmdev->rx.stat_info;
++ u8 reg_idx = fmdev->rx.region.fm_band;
++ u8 index;
++ u32 freq;
++
++ /* First AF indicates the number of AF follows. Reset the list */
++ if ((af >= FM_RDS_1_AF_FOLLOWS) && (af <= FM_RDS_25_AF_FOLLOWS)) {
++ fmdev->rx.stat_info.af_list_max = (af - FM_RDS_1_AF_FOLLOWS + 1);
++ fmdev->rx.stat_info.afcache_size = 0;
++ fmdbg("No of expected AF : %d\n", fmdev->rx.stat_info.af_list_max);
++ return;
++ }
++
++ if (af < FM_RDS_MIN_AF)
++ return;
++ if (reg_idx == FM_BAND_EUROPE_US && af > FM_RDS_MAX_AF)
++ return;
++ if (reg_idx == FM_BAND_JAPAN && af > FM_RDS_MAX_AF_JAPAN)
++ return;
++
++ freq = fmdev->rx.region.bot_freq + (af * 100);
++ if (freq == fmdev->rx.freq) {
++ fmdbg("Current freq(%d) is matching with received AF(%d)\n",
++ fmdev->rx.freq, freq);
++ return;
++ }
++ /* Do check in AF cache */
++ for (index = 0; index < stat_info->afcache_size; index++) {
++ if (stat_info->af_cache[index] == freq)
++ break;
++ }
++ /* Reached the limit of the list - ignore the next AF */
++ if (index == stat_info->af_list_max) {
++ fmdbg("AF cache is full\n");
++ return;
++ }
++ /*
++ * If we reached the end of the list then this AF is not
++ * in the list - add it.
++ */
++ if (index == stat_info->afcache_size) {
++ fmdbg("Storing AF %d to cache index %d\n", freq, index);
++ stat_info->af_cache[index] = freq;
++ stat_info->afcache_size++;
++ }
++}
++
++/*
++ * Converts RDS buffer data from big endian format
++ * to little endian format.
++ */
++static void fm_rdsparse_swapbytes(struct fmdev *fmdev,
++ struct fm_rdsdata_format *rds_format)
++{
++ u8 byte1;
++ u8 index = 0;
++ u8 *rds_buff;
++
++ /*
++ * Since in Orca the 2 RDS Data bytes are in little endian and
++ * in Dolphin they are in big endian, the parsing of the RDS data
++ * is chip dependent
++ */
++ if (fmdev->asci_id != 0x6350) {
++ rds_buff = &rds_format->data.groupdatabuff.buff[0];
++ while (index + 1 < FM_RX_RDS_INFO_FIELD_MAX) {
++ byte1 = rds_buff[index];
++ rds_buff[index] = rds_buff[index + 1];
++ rds_buff[index + 1] = byte1;
++ index += 2;
++ }
++ }
++}
++
++static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *fmdev)
++{
++ struct sk_buff *skb;
++ struct fm_rdsdata_format rds_fmt;
++ struct fm_rds *rds = &fmdev->rx.rds;
++ unsigned long group_idx, flags;
++ u8 *rds_data, meta_data, tmpbuf[3];
++ u8 type, blk_idx;
++ u16 cur_picode;
++ u32 rds_len;
++
++ if (check_cmdresp_status(fmdev, &skb))
++ return;
++
++ /* Skip header info */
++ skb_pull(skb, sizeof(struct fm_event_msg_hdr));
++ rds_data = skb->data;
++ rds_len = skb->len;
++
++ /* Parse the RDS data */
++ while (rds_len >= FM_RDS_BLK_SIZE) {
++ meta_data = rds_data[2];
++ /* Get the type: 0=A, 1=B, 2=C, 3=C', 4=D, 5=E */
++ type = (meta_data & 0x07);
++
++ /* Transform the blk type into index sequence (0, 1, 2, 3, 4) */
++ blk_idx = (type <= FM_RDS_BLOCK_C ? type : (type - 1));
++ fmdbg("Block index:%d(%s)\n", blk_idx,
++ (meta_data & FM_RDS_STATUS_ERR_MASK) ? "Bad" : "Ok");
++
++ if ((meta_data & FM_RDS_STATUS_ERR_MASK) != 0)
++ break;
++
++ if (blk_idx < FM_RDS_BLK_IDX_A || blk_idx > FM_RDS_BLK_IDX_D) {
++ fmdbg("Block sequence mismatch\n");
++ rds->last_blk_idx = -1;
++ break;
++ }
++
++ /* Skip checkword (control) byte and copy only data byte */
++ memcpy(&rds_fmt.data.groupdatabuff.
++ buff[blk_idx * (FM_RDS_BLK_SIZE - 1)],
++ rds_data, (FM_RDS_BLK_SIZE - 1));
++
++ rds->last_blk_idx = blk_idx;
++
++ /* If completed a whole group then handle it */
++ if (blk_idx == FM_RDS_BLK_IDX_D) {
++ fmdbg("Good block received\n");
++ fm_rdsparse_swapbytes(fmdev, &rds_fmt);
++
++ /*
++ * Extract PI code and store in local cache.
++ * We need this during AF switch processing.
++ */
++ cur_picode = be16_to_cpu(rds_fmt.data.groupgeneral.pidata);
++ if (fmdev->rx.stat_info.picode != cur_picode)
++ fmdev->rx.stat_info.picode = cur_picode;
++
++ fmdbg("picode:%d\n", cur_picode);
++
++ group_idx = (rds_fmt.data.groupgeneral.blk_b[0] >> 3);
++ fmdbg("(fmdrv):Group:%ld%s\n", group_idx/2,
++ (group_idx % 2) ? "B" : "A");
++
++ group_idx = 1 << (rds_fmt.data.groupgeneral.blk_b[0] >> 3);
++ if (group_idx == FM_RDS_GROUP_TYPE_MASK_0A) {
++ fm_rx_update_af_cache(fmdev, rds_fmt.data.group0A.af[0]);
++ fm_rx_update_af_cache(fmdev, rds_fmt.data.group0A.af[1]);
++ }
++ }
++ rds_len -= FM_RDS_BLK_SIZE;
++ rds_data += FM_RDS_BLK_SIZE;
++ }
++
++ /* Copy raw rds data to internal rds buffer */
++ rds_data = skb->data;
++ rds_len = skb->len;
++
++ spin_lock_irqsave(&fmdev->rds_buff_lock, flags);
++ while (rds_len > 0) {
++ /*
++ * Fill RDS buffer as per V4L2 specification.
++ * Store control byte
++ */
++ type = (rds_data[2] & 0x07);
++ blk_idx = (type <= FM_RDS_BLOCK_C ? type : (type - 1));
++ tmpbuf[2] = blk_idx; /* Offset name */
++ tmpbuf[2] |= blk_idx << 3; /* Received offset */
++
++ /* Store data byte */
++ tmpbuf[0] = rds_data[0];
++ tmpbuf[1] = rds_data[1];
++
++ memcpy(&rds->buff[rds->wr_idx], &tmpbuf, FM_RDS_BLK_SIZE);
++ rds->wr_idx = (rds->wr_idx + FM_RDS_BLK_SIZE) % rds->buf_size;
++
++ /* Check for overflow & start over */
++ if (rds->wr_idx == rds->rd_idx) {
++ fmdbg("RDS buffer overflow\n");
++ rds->wr_idx = 0;
++ rds->rd_idx = 0;
++ break;
++ }
++ rds_len -= FM_RDS_BLK_SIZE;
++ rds_data += FM_RDS_BLK_SIZE;
++ }
++ spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags);
++
++ /* Wakeup read queue */
++ if (rds->wr_idx != rds->rd_idx)
++ wake_up_interruptible(&rds->read_queue);
++
++ fm_irq_call_stage(fmdev, FM_RDS_FINISH_IDX);
++}
++
++static void fm_irq_handle_rds_finish(struct fmdev *fmdev)
++{
++ fm_irq_call_stage(fmdev, FM_HW_TUNE_OP_ENDED_IDX);
++}
++
++static void fm_irq_handle_tune_op_ended(struct fmdev *fmdev)
++{
++ if (fmdev->irq_info.flag & (FM_FR_EVENT | FM_BL_EVENT) & fmdev->
++ irq_info.mask) {
++ fmdbg("irq: tune ended/bandlimit reached\n");
++ if (test_and_clear_bit(FM_AF_SWITCH_INPROGRESS, &fmdev->flag)) {
++ fmdev->irq_info.stage = FM_AF_JUMP_RD_FREQ_IDX;
++ } else {
++ complete(&fmdev->maintask_comp);
++ fmdev->irq_info.stage = FM_HW_POWER_ENB_IDX;
++ }
++ } else
++ fmdev->irq_info.stage = FM_HW_POWER_ENB_IDX;
++
++ fm_irq_call(fmdev);
++}
++
++static void fm_irq_handle_power_enb(struct fmdev *fmdev)
++{
++ if (fmdev->irq_info.flag & FM_POW_ENB_EVENT) {
++ fmdbg("irq: Power Enabled/Disabled\n");
++ complete(&fmdev->maintask_comp);
++ }
++
++ fm_irq_call_stage(fmdev, FM_LOW_RSSI_START_IDX);
++}
++
++static void fm_irq_handle_low_rssi_start(struct fmdev *fmdev)
++{
++ if ((fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) &&
++ (fmdev->irq_info.flag & FM_LEV_EVENT & fmdev->irq_info.mask) &&
++ (fmdev->rx.freq != FM_UNDEFINED_FREQ) &&
++ (fmdev->rx.stat_info.afcache_size != 0)) {
++ fmdbg("irq: rssi level has fallen below threshold level\n");
++
++ /* Disable further low RSSI interrupts */
++ fmdev->irq_info.mask &= ~FM_LEV_EVENT;
++
++ fmdev->rx.afjump_idx = 0;
++ fmdev->rx.freq_before_jump = fmdev->rx.freq;
++ fmdev->irq_info.stage = FM_AF_JUMP_SETPI_IDX;
++ } else {
++ /* Continue next function in interrupt handler table */
++ fmdev->irq_info.stage = FM_SEND_INTMSK_CMD_IDX;
++ }
++
++ fm_irq_call(fmdev);
++}
++
++static void fm_irq_afjump_set_pi(struct fmdev *fmdev)
++{
++ u16 payload;
++
++ /* Set PI code - must be updated if the AF list is not empty */
++ payload = fmdev->rx.stat_info.picode;
++ if (!fm_send_cmd(fmdev, RDS_PI_SET, REG_WR, &payload, sizeof(payload), NULL))
++ fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SETPI_RESP_IDX);
++}
++
++static void fm_irq_handle_set_pi_resp(struct fmdev *fmdev)
++{
++ fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_SETPI_MASK_IDX);
++}
++
++/*
++ * Set PI mask.
++ * 0xFFFF = Enable PI code matching
++ * 0x0000 = Disable PI code matching
++ */
++static void fm_irq_afjump_set_pimask(struct fmdev *fmdev)
++{
++ u16 payload;
++
++ payload = 0x0000;
++ if (!fm_send_cmd(fmdev, RDS_PI_MASK_SET, REG_WR, &payload, sizeof(payload), NULL))
++ fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SETPI_MASK_RESP_IDX);
++}
++
++static void fm_irq_handle_set_pimask_resp(struct fmdev *fmdev)
++{
++ fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_SET_AF_FREQ_IDX);
++}
++
++static void fm_irq_afjump_setfreq(struct fmdev *fmdev)
++{
++ u16 frq_index;
++ u16 payload;
++
++ fmdbg("Swtich to %d KHz\n", fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx]);
++ frq_index = (fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx] -
++ fmdev->rx.region.bot_freq) / FM_FREQ_MUL;
++
++ payload = frq_index;
++ if (!fm_send_cmd(fmdev, AF_FREQ_SET, REG_WR, &payload, sizeof(payload), NULL))
++ fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SET_AFFREQ_RESP_IDX);
++}
++
++static void fm_irq_handle_setfreq_resp(struct fmdev *fmdev)
++{
++ fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_ENABLE_INT_IDX);
++}
++
++static void fm_irq_afjump_enableint(struct fmdev *fmdev)
++{
++ u16 payload;
++
++ /* Enable FR (tuning operation ended) interrupt */
++ payload = FM_FR_EVENT;
++ if (!fm_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, sizeof(payload), NULL))
++ fm_irq_timeout_stage(fmdev, FM_AF_JUMP_ENABLE_INT_RESP_IDX);
++}
++
++static void fm_irq_afjump_enableint_resp(struct fmdev *fmdev)
++{
++ fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_START_AFJUMP_IDX);
++}
++
++static void fm_irq_start_afjump(struct fmdev *fmdev)
++{
++ u16 payload;
++
++ payload = FM_TUNER_AF_JUMP_MODE;
++ if (!fm_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload,
++ sizeof(payload), NULL))
++ fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_START_AFJUMP_RESP_IDX);
++}
++
++static void fm_irq_handle_start_afjump_resp(struct fmdev *fmdev)
++{
++ struct sk_buff *skb;
++
++ if (check_cmdresp_status(fmdev, &skb))
++ return;
++
++ fmdev->irq_info.stage = FM_SEND_FLAG_GETCMD_IDX;
++ set_bit(FM_AF_SWITCH_INPROGRESS, &fmdev->flag);
++ clear_bit(FM_INTTASK_RUNNING, &fmdev->flag);
++}
++
++static void fm_irq_afjump_rd_freq(struct fmdev *fmdev)
++{
++ u16 payload;
++
++ if (!fm_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, sizeof(payload), NULL))
++ fm_irq_timeout_stage(fmdev, FM_AF_JUMP_RD_FREQ_RESP_IDX);
++}
++
++static void fm_irq_afjump_rd_freq_resp(struct fmdev *fmdev)
++{
++ struct sk_buff *skb;
++ u16 read_freq;
++ u32 curr_freq, jumped_freq;
++
++ if (check_cmdresp_status(fmdev, &skb))
++ return;
++
++ /* Skip header info and copy only response data */
++ skb_pull(skb, sizeof(struct fm_event_msg_hdr));
++ memcpy(&read_freq, skb->data, sizeof(read_freq));
++ read_freq = be16_to_cpu(read_freq);
++ curr_freq = fmdev->rx.region.bot_freq + ((u32)read_freq * FM_FREQ_MUL);
++
++ jumped_freq = fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx];
++
++ /* If the frequency was changed the jump succeeded */
++ if ((curr_freq != fmdev->rx.freq_before_jump) && (curr_freq == jumped_freq)) {
++ fmdbg("Successfully switched to alternate freq %d\n", curr_freq);
++ fmdev->rx.freq = curr_freq;
++ fm_rx_reset_rds_cache(fmdev);
++
++ /* AF feature is on, enable low level RSSI interrupt */
++ if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON)
++ fmdev->irq_info.mask |= FM_LEV_EVENT;
++
++ fmdev->irq_info.stage = FM_LOW_RSSI_FINISH_IDX;
++ } else { /* jump to the next freq in the AF list */
++ fmdev->rx.afjump_idx++;
++
++ /* If we reached the end of the list - stop searching */
++ if (fmdev->rx.afjump_idx >= fmdev->rx.stat_info.afcache_size) {
++ fmdbg("AF switch processing failed\n");
++ fmdev->irq_info.stage = FM_LOW_RSSI_FINISH_IDX;
++ } else { /* AF List is not over - try next one */
++
++ fmdbg("Trying next freq in AF cache\n");
++ fmdev->irq_info.stage = FM_AF_JUMP_SETPI_IDX;
++ }
++ }
++ fm_irq_call(fmdev);
++}
++
++static void fm_irq_handle_low_rssi_finish(struct fmdev *fmdev)
++{
++ fm_irq_call_stage(fmdev, FM_SEND_INTMSK_CMD_IDX);
++}
++
++static void fm_irq_send_intmsk_cmd(struct fmdev *fmdev)
++{
++ u16 payload;
++
++ /* Re-enable FM interrupts */
++ payload = fmdev->irq_info.mask;
++
++ if (!fm_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
++ sizeof(payload), NULL))
++ fm_irq_timeout_stage(fmdev, FM_HANDLE_INTMSK_CMD_RESP_IDX);
++}
++
++static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *fmdev)
++{
++ struct sk_buff *skb;
++
++ if (check_cmdresp_status(fmdev, &skb))
++ return;
++ /*
++ * This is last function in interrupt table to be executed.
++ * So, reset stage index to 0.
++ */
++ fmdev->irq_info.stage = FM_SEND_FLAG_GETCMD_IDX;
++
++ /* Start processing any pending interrupt */
++ if (test_and_clear_bit(FM_INTTASK_SCHEDULE_PENDING, &fmdev->flag))
++ fmdev->irq_info.handlers[fmdev->irq_info.stage](fmdev);
++ else
++ clear_bit(FM_INTTASK_RUNNING, &fmdev->flag);
++}
++
++/* Returns availability of RDS data in internel buffer */
++u32 fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file,
++ struct poll_table_struct *pts)
++{
++ poll_wait(file, &fmdev->rx.rds.read_queue, pts);
++ if (fmdev->rx.rds.rd_idx != fmdev->rx.rds.wr_idx)
++ return 0;
++
++ return -EAGAIN;
++}
++
++/* Copies RDS data from internal buffer to user buffer */
++u32 fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file,
++ u8 __user *buf, size_t count)
++{
++ u32 block_count;
++ unsigned long flags;
++ int ret;
++
++ if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx) {
++ if (file->f_flags & O_NONBLOCK)
++ return -EWOULDBLOCK;
++
++ ret = wait_event_interruptible(fmdev->rx.rds.read_queue,
++ (fmdev->rx.rds.wr_idx != fmdev->rx.rds.rd_idx));
++ if (ret)
++ return -EINTR;
++ }
++
++ /* Calculate block count from byte count */
++ count /= 3;
++ block_count = 0;
++ ret = 0;
++
++ spin_lock_irqsave(&fmdev->rds_buff_lock, flags);
++
++ while (block_count < count) {
++ if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx)
++ break;
++
++ if (copy_to_user(buf, &fmdev->rx.rds.buff[fmdev->rx.rds.rd_idx],
++ FM_RDS_BLK_SIZE))
++ break;
++
++ fmdev->rx.rds.rd_idx += FM_RDS_BLK_SIZE;
++ if (fmdev->rx.rds.rd_idx >= fmdev->rx.rds.buf_size)
++ fmdev->rx.rds.rd_idx = 0;
++
++ block_count++;
++ buf += FM_RDS_BLK_SIZE;
++ ret += FM_RDS_BLK_SIZE;
++ }
++ spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags);
++ return ret;
++}
++
++u32 fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set)
++{
++ switch (fmdev->curr_fmmode) {
++ case FM_MODE_RX:
++ return fm_rx_set_freq(fmdev, freq_to_set);
++
++ case FM_MODE_TX:
++ return fm_tx_set_freq(fmdev, freq_to_set);
++
++ default:
++ return -EINVAL;
++ }
++}
++
++u32 fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq)
++{
++ if (fmdev->rx.freq == FM_UNDEFINED_FREQ) {
++ fmerr("RX frequency is not set\n");
++ return -EPERM;
++ }
++ if (cur_tuned_frq == NULL) {
++ fmerr("Invalid memory\n");
++ return -ENOMEM;
++ }
++
++ switch (fmdev->curr_fmmode) {
++ case FM_MODE_RX:
++ *cur_tuned_frq = fmdev->rx.freq;
++ return 0;
++
++ case FM_MODE_TX:
++ *cur_tuned_frq = 0; /* TODO : Change this later */
++ return 0;
++
++ default:
++ return -EINVAL;
++ }
++
++}
++
++u32 fmc_set_region(struct fmdev *fmdev, u8 region_to_set)
++{
++ switch (fmdev->curr_fmmode) {
++ case FM_MODE_RX:
++ return fm_rx_set_region(fmdev, region_to_set);
++
++ case FM_MODE_TX:
++ return fm_tx_set_region(fmdev, region_to_set);
++
++ default:
++ return -EINVAL;
++ }
++}
++
++u32 fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
++{
++ switch (fmdev->curr_fmmode) {
++ case FM_MODE_RX:
++ return fm_rx_set_mute_mode(fmdev, mute_mode_toset);
++
++ case FM_MODE_TX:
++ return fm_tx_set_mute_mode(fmdev, mute_mode_toset);
++
++ default:
++ return -EINVAL;
++ }
++}
++
++u32 fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode)
++{
++ switch (fmdev->curr_fmmode) {
++ case FM_MODE_RX:
++ return fm_rx_set_stereo_mono(fmdev, mode);
++
++ case FM_MODE_TX:
++ return fm_tx_set_stereo_mono(fmdev, mode);
++
++ default:
++ return -EINVAL;
++ }
++}
++
++u32 fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
++{
++ switch (fmdev->curr_fmmode) {
++ case FM_MODE_RX:
++ return fm_rx_set_rds_mode(fmdev, rds_en_dis);
++
++ case FM_MODE_TX:
++ return fm_tx_set_rds_mode(fmdev, rds_en_dis);
++
++ default:
++ return -EINVAL;
++ }
++}
++
++/* Sends power off command to the chip */
++static u32 fm_power_down(struct fmdev *fmdev)
++{
++ u16 payload;
++ u32 ret;
++
++ if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
++ fmerr("FM core is not ready\n");
++ return -EPERM;
++ }
++ if (fmdev->curr_fmmode == FM_MODE_OFF) {
++ fmdbg("FM chip is already in OFF state\n");
++ return 0;
++ }
++
++ payload = 0x0;
++ ret = fmc_send_cmd(fmdev, FM_POWER_MODE, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ return fmc_release(fmdev);
++}
++
++/* Reads init command from FM firmware file and loads to the chip */
++static u32 fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name)
++{
++ const struct firmware *fw_entry;
++ struct bts_header *fw_header;
++ struct bts_action *action;
++ struct bts_action_delay *delay;
++ u8 *fw_data;
++ int ret, fw_len, cmd_cnt;
++
++ cmd_cnt = 0;
++ set_bit(FM_FW_DW_INPROGRESS, &fmdev->flag);
++
++ ret = request_firmware(&fw_entry, fw_name,
++ &fmdev->radio_dev->dev);
++ if (ret < 0) {
++ fmerr("Unable to read firmware(%s) content\n", fw_name);
++ return ret;
++ }
++ fmdbg("Firmware(%s) length : %d bytes\n", fw_name, fw_entry->size);
++
++ fw_data = (void *)fw_entry->data;
++ fw_len = fw_entry->size;
++
++ fw_header = (struct bts_header *)fw_data;
++ if (fw_header->magic != FM_FW_FILE_HEADER_MAGIC) {
++ fmerr("%s not a legal TI firmware file\n", fw_name);
++ ret = -EINVAL;
++ goto rel_fw;
++ }
++ fmdbg("FW(%s) magic number : 0x%x\n", fw_name, fw_header->magic);
++
++ /* Skip file header info , we already verified it */
++ fw_data += sizeof(struct bts_header);
++ fw_len -= sizeof(struct bts_header);
++
++ while (fw_data && fw_len > 0) {
++ action = (struct bts_action *)fw_data;
++
++ switch (action->type) {
++ case ACTION_SEND_COMMAND: /* Send */
++ if (fmc_send_cmd(fmdev, 0, 0, action->data,
++ action->size, NULL, NULL))
++ goto rel_fw;
++
++ cmd_cnt++;
++ break;
++
++ case ACTION_DELAY: /* Delay */
++ delay = (struct bts_action_delay *)action->data;
++ mdelay(delay->msec);
++ break;
++ }
++
++ fw_data += (sizeof(struct bts_action) + (action->size));
++ fw_len -= (sizeof(struct bts_action) + (action->size));
++ }
++ fmdbg("Firmware commands(%d) loaded to chip\n", cmd_cnt);
++rel_fw:
++ release_firmware(fw_entry);
++ clear_bit(FM_FW_DW_INPROGRESS, &fmdev->flag);
++
++ return ret;
++}
++
++/* Loads default RX configuration to the chip */
++static u32 load_default_rx_configuration(struct fmdev *fmdev)
++{
++ int ret;
++
++ ret = fm_rx_set_volume(fmdev, FM_DEFAULT_RX_VOLUME);
++ if (ret < 0)
++ return ret;
++
++ return fm_rx_set_rssi_threshold(fmdev, FM_DEFAULT_RSSI_THRESHOLD);
++}
++
++/* Does FM power on sequence */
++static u32 fm_power_up(struct fmdev *fmdev, u8 mode)
++{
++ u16 payload, asic_id, asic_ver;
++ int resp_len, ret;
++ u8 fw_name[50];
++
++ if (mode >= FM_MODE_ENTRY_MAX) {
++ fmerr("Invalid firmware download option\n");
++ return -EINVAL;
++ }
++
++ /*
++ * Initialize FM common module. FM GPIO toggling is
++ * taken care in Shared Transport driver.
++ */
++ ret = fmc_prepare(fmdev);
++ if (ret < 0) {
++ fmerr("Unable to prepare FM Common\n");
++ return ret;
++ }
++
++ payload = FM_ENABLE;
++ if (fmc_send_cmd(fmdev, FM_POWER_MODE, REG_WR, &payload,
++ sizeof(payload), NULL, NULL))
++ goto rel;
++
++ /* Allow the chip to settle down in Channel-8 mode */
++ msleep(20);
++
++ if (fmc_send_cmd(fmdev, ASIC_ID_GET, REG_RD, NULL,
++ sizeof(asic_id), &asic_id, &resp_len))
++ goto rel;
++
++ if (fmc_send_cmd(fmdev, ASIC_VER_GET, REG_RD, NULL,
++ sizeof(asic_ver), &asic_ver, &resp_len))
++ goto rel;
++
++ fmdbg("ASIC ID: 0x%x , ASIC Version: %d\n",
++ be16_to_cpu(asic_id), be16_to_cpu(asic_ver));
++
++ sprintf(fw_name, "%s_%x.%d.bts", FM_FMC_FW_FILE_START,
++ be16_to_cpu(asic_id), be16_to_cpu(asic_ver));
++
++ ret = fm_download_firmware(fmdev, fw_name);
++ if (ret < 0) {
++ fmdbg("Failed to download firmware file %s\n", fw_name);
++ goto rel;
++ }
++ sprintf(fw_name, "%s_%x.%d.bts", (mode == FM_MODE_RX) ?
++ FM_RX_FW_FILE_START : FM_TX_FW_FILE_START,
++ be16_to_cpu(asic_id), be16_to_cpu(asic_ver));
++
++ ret = fm_download_firmware(fmdev, fw_name);
++ if (ret < 0) {
++ fmdbg("Failed to download firmware file %s\n", fw_name);
++ goto rel;
++ } else
++ return ret;
++rel:
++ return fmc_release(fmdev);
++}
++
++/* Set FM Modes(TX, RX, OFF) */
++u32 fmc_set_mode(struct fmdev *fmdev, u8 fm_mode)
++{
++ int ret = 0;
++
++ if (fm_mode >= FM_MODE_ENTRY_MAX) {
++ fmerr("Invalid FM mode\n");
++ return -EINVAL;
++ }
++ if (fmdev->curr_fmmode == fm_mode) {
++ fmdbg("Already fm is in mode(%d)\n", fm_mode);
++ return ret;
++ }
++
++ switch (fm_mode) {
++ case FM_MODE_OFF: /* OFF Mode */
++ ret = fm_power_down(fmdev);
++ if (ret < 0) {
++ fmerr("Failed to set OFF mode\n");
++ return ret;
++ }
++ break;
++
++ case FM_MODE_TX: /* TX Mode */
++ case FM_MODE_RX: /* RX Mode */
++ /* Power down before switching to TX or RX mode */
++ if (fmdev->curr_fmmode != FM_MODE_OFF) {
++ ret = fm_power_down(fmdev);
++ if (ret < 0) {
++ fmerr("Failed to set OFF mode\n");
++ return ret;
++ }
++ msleep(30);
++ }
++ ret = fm_power_up(fmdev, fm_mode);
++ if (ret < 0) {
++ fmerr("Failed to load firmware\n");
++ return ret;
++ }
++ }
++ fmdev->curr_fmmode = fm_mode;
++
++ /* Set default configuration */
++ if (fmdev->curr_fmmode == FM_MODE_RX) {
++ fmdbg("Loading default rx configuration..\n");
++ ret = load_default_rx_configuration(fmdev);
++ if (ret < 0)
++ fmerr("Failed to load default values\n");
++ }
++
++ return ret;
++}
++
++/* Returns current FM mode (TX, RX, OFF) */
++u32 fmc_get_mode(struct fmdev *fmdev, u8 *fmmode)
++{
++ if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
++ fmerr("FM core is not ready\n");
++ return -EPERM;
++ }
++ if (fmmode == NULL) {
++ fmerr("Invalid memory\n");
++ return -ENOMEM;
++ }
++
++ *fmmode = fmdev->curr_fmmode;
++ return 0;
++}
++
++/* Called by ST layer when FM packet is available */
++static long fm_st_receive(void *arg, struct sk_buff *skb)
++{
++ struct fmdev *fmdev;
++
++ fmdev = (struct fmdev *)arg;
++
++ if (skb == NULL) {
++ fmerr("Invalid SKB received from ST\n");
++ return -EFAULT;
++ }
++
++ if (skb->cb[0] != FM_PKT_LOGICAL_CHAN_NUMBER) {
++ fmerr("Received SKB (%p) is not FM Channel 8 pkt\n", skb);
++ return -EINVAL;
++ }
++
++ memcpy(skb_push(skb, 1), &skb->cb[0], 1);
++ skb_queue_tail(&fmdev->rx_q, skb);
++ tasklet_schedule(&fmdev->rx_task);
++
++ return 0;
++}
++
++/*
++ * Called by ST layer to indicate protocol registration completion
++ * status.
++ */
++static void fm_st_reg_comp_cb(void *arg, char data)
++{
++ struct fmdev *fmdev;
++
++ fmdev = (struct fmdev *)arg;
++ fmdev->streg_cbdata = data;
++ complete(&wait_for_fmdrv_reg_comp);
++}
++
++/*
++ * This function will be called from FM V4L2 open function.
++ * Register with ST driver and initialize driver data.
++ */
++u32 fmc_prepare(struct fmdev *fmdev)
++{
++ static struct st_proto_s fm_st_proto;
++ u32 ret;
++
++ if (test_bit(FM_CORE_READY, &fmdev->flag)) {
++ fmdbg("FM Core is already up\n");
++ return 0;
++ }
++
++ memset(&fm_st_proto, 0, sizeof(fm_st_proto));
++ fm_st_proto.type = ST_FM;
++ fm_st_proto.recv = fm_st_receive;
++ fm_st_proto.match_packet = NULL;
++ fm_st_proto.reg_complete_cb = fm_st_reg_comp_cb;
++ fm_st_proto.write = NULL; /* TI ST driver will fill write pointer */
++ fm_st_proto.priv_data = fmdev;
++
++ ret = st_register(&fm_st_proto);
++ if (ret == -EINPROGRESS) {
++ init_completion(&wait_for_fmdrv_reg_comp);
++ fmdev->streg_cbdata = -EINPROGRESS;
++ fmdbg("%s waiting for ST reg completion signal\n", __func__);
++
++ ret = wait_for_completion_timeout(&wait_for_fmdrv_reg_comp,
++ FM_ST_REG_TIMEOUT);
++
++ if (!ret) {
++ fmerr("Timeout(%d sec), didn't get reg "
++ "completion signal from ST\n",
++ jiffies_to_msecs(FM_ST_REG_TIMEOUT) / 1000);
++ return -ETIMEDOUT;
++ }
++ if (fmdev->streg_cbdata != 0) {
++ fmerr("ST reg comp CB called with error "
++ "status %d\n", fmdev->streg_cbdata);
++ return -EAGAIN;
++ }
++
++ ret = 0;
++ } else if (ret == -1) {
++ fmerr("st_register failed %d\n", ret);
++ return -EAGAIN;
++ }
++
++ if (fm_st_proto.write != NULL) {
++ g_st_write = fm_st_proto.write;
++ } else {
++ fmerr("Failed to get ST write func pointer\n");
++ ret = st_unregister(ST_FM);
++ if (ret < 0)
++ fmerr("st_unregister failed %d\n", ret);
++ return -EAGAIN;
++ }
++
++ spin_lock_init(&fmdev->rds_buff_lock);
++ spin_lock_init(&fmdev->resp_skb_lock);
++
++ /* Initialize TX queue and TX tasklet */
++ skb_queue_head_init(&fmdev->tx_q);
++ tasklet_init(&fmdev->tx_task, send_tasklet, (unsigned long)fmdev);
++
++ /* Initialize RX Queue and RX tasklet */
++ skb_queue_head_init(&fmdev->rx_q);
++ tasklet_init(&fmdev->rx_task, recv_tasklet, (unsigned long)fmdev);
++
++ fmdev->irq_info.stage = 0;
++ atomic_set(&fmdev->tx_cnt, 1);
++ fmdev->resp_comp = NULL;
++
++ init_timer(&fmdev->irq_info.timer);
++ fmdev->irq_info.timer.function = &int_timeout_handler;
++ fmdev->irq_info.timer.data = (unsigned long)fmdev;
++ /*TODO: add FM_STIC_EVENT later */
++ fmdev->irq_info.mask = FM_MAL_EVENT;
++
++ /* Region info */
++ memcpy(&fmdev->rx.region, &region_configs[default_radio_region],
++ sizeof(struct region_info));
++
++ fmdev->rx.mute_mode = FM_MUTE_OFF;
++ fmdev->rx.rf_depend_mute = FM_RX_RF_DEPENDENT_MUTE_OFF;
++ fmdev->rx.rds.flag = FM_RDS_DISABLE;
++ fmdev->rx.freq = FM_UNDEFINED_FREQ;
++ fmdev->rx.rds_mode = FM_RDS_SYSTEM_RDS;
++ fmdev->rx.af_mode = FM_RX_RDS_AF_SWITCH_MODE_OFF;
++ fmdev->irq_info.retry = 0;
++
++ fm_rx_reset_rds_cache(fmdev);
++ init_waitqueue_head(&fmdev->rx.rds.read_queue);
++
++ fm_rx_reset_station_info(fmdev);
++ set_bit(FM_CORE_READY, &fmdev->flag);
++
++ return ret;
++}
++
++/*
++ * This function will be called from FM V4L2 release function.
++ * Unregister from ST driver.
++ */
++u32 fmc_release(struct fmdev *fmdev)
++{
++ u32 ret;
++
++ if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
++ fmdbg("FM Core is already down\n");
++ return 0;
++ }
++ /* Sevice pending read */
++ wake_up_interruptible(&fmdev->rx.rds.read_queue);
++
++ tasklet_kill(&fmdev->tx_task);
++ tasklet_kill(&fmdev->rx_task);
++
++ skb_queue_purge(&fmdev->tx_q);
++ skb_queue_purge(&fmdev->rx_q);
++
++ fmdev->resp_comp = NULL;
++ fmdev->rx.freq = 0;
++
++ ret = st_unregister(ST_FM);
++ if (ret < 0)
++ fmerr("Failed to de-register FM from ST %d\n", ret);
++ else
++ fmdbg("Successfully unregistered from ST\n");
++
++ clear_bit(FM_CORE_READY, &fmdev->flag);
++ return ret;
++}
++
++/*
++ * Module init function. Ask FM V4L module to register video device.
++ * Allocate memory for FM driver context and RX RDS buffer.
++ */
++static int __init fm_drv_init(void)
++{
++ struct fmdev *fmdev = NULL;
++ u32 ret = -ENOMEM;
++
++ fmdbg("FM driver version %s\n", FM_DRV_VERSION);
++
++ fmdev = kzalloc(sizeof(struct fmdev), GFP_KERNEL);
++ if (NULL == fmdev) {
++ fmerr("Can't allocate operation structure memory\n");
++ return ret;
++ }
++ fmdev->rx.rds.buf_size = default_rds_buf * FM_RDS_BLK_SIZE;
++ fmdev->rx.rds.buff = kzalloc(fmdev->rx.rds.buf_size, GFP_KERNEL);
++ if (NULL == fmdev->rx.rds.buff) {
++ fmerr("Can't allocate rds ring buffer\n");
++ goto rel_dev;
++ }
++
++ ret = fm_v4l2_init_video_device(fmdev, radio_nr);
++ if (ret < 0)
++ goto rel_rdsbuf;
++
++ fmdev->irq_info.handlers = int_handler_table;
++ fmdev->curr_fmmode = FM_MODE_OFF;
++ fmdev->tx_data.pwr_lvl = FM_PWR_LVL_DEF;
++ fmdev->tx_data.preemph = FM_TX_PREEMPH_50US;
++ return ret;
++
++rel_rdsbuf:
++ kfree(fmdev->rx.rds.buff);
++rel_dev:
++ kfree(fmdev);
++
++ return ret;
++}
++
++/* Module exit function. Ask FM V4L module to unregister video device */
++static void __exit fm_drv_exit(void)
++{
++ struct fmdev *fmdev = NULL;
++
++ fmdev = fm_v4l2_deinit_video_device();
++ if (fmdev != NULL) {
++ kfree(fmdev->rx.rds.buff);
++ kfree(fmdev);
++ }
++}
++
++module_init(fm_drv_init);
++module_exit(fm_drv_exit);
++
++/* ------------- Module Info ------------- */
++MODULE_AUTHOR("Manjunatha Halli <manjunatha_halli@ti.com>");
++MODULE_DESCRIPTION("FM Driver for TI's Connectivity chip. " FM_DRV_VERSION);
++MODULE_VERSION(FM_DRV_VERSION);
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/radio/wl128x/fmdrv_common.h b/drivers/media/radio/wl128x/fmdrv_common.h
+new file mode 100644
+index 0000000..e5091f4
+--- /dev/null
++++ b/drivers/media/radio/wl128x/fmdrv_common.h
+@@ -0,0 +1,402 @@
++/*
++ * FM Driver for Connectivity chip of Texas Instruments.
++ * FM Common module header file
++ *
++ * Copyright (C) 2011 Texas Instruments
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#ifndef _FMDRV_COMMON_H
++#define _FMDRV_COMMON_H
++
++#define FM_ST_REG_TIMEOUT msecs_to_jiffies(6000) /* 6 sec */
++#define FM_PKT_LOGICAL_CHAN_NUMBER 0x08 /* Logical channel 8 */
++
++#define REG_RD 0x1
++#define REG_WR 0x0
++
++struct fm_reg_table {
++ u8 opcode;
++ u8 type;
++ u8 *name;
++};
++
++#define STEREO_GET 0
++#define RSSI_LVL_GET 1
++#define IF_COUNT_GET 2
++#define FLAG_GET 3
++#define RDS_SYNC_GET 4
++#define RDS_DATA_GET 5
++#define FREQ_SET 10
++#define AF_FREQ_SET 11
++#define MOST_MODE_SET 12
++#define MOST_BLEND_SET 13
++#define DEMPH_MODE_SET 14
++#define SEARCH_LVL_SET 15
++#define BAND_SET 16
++#define MUTE_STATUS_SET 17
++#define RDS_PAUSE_LVL_SET 18
++#define RDS_PAUSE_DUR_SET 19
++#define RDS_MEM_SET 20
++#define RDS_BLK_B_SET 21
++#define RDS_MSK_B_SET 22
++#define RDS_PI_MASK_SET 23
++#define RDS_PI_SET 24
++#define RDS_SYSTEM_SET 25
++#define INT_MASK_SET 26
++#define SEARCH_DIR_SET 27
++#define VOLUME_SET 28
++#define AUDIO_ENABLE_SET 29
++#define PCM_MODE_SET 30
++#define I2S_MODE_CONFIG_SET 31
++#define POWER_SET 32
++#define INTX_CONFIG_SET 33
++#define PULL_EN_SET 34
++#define HILO_SET 35
++#define SWITCH2FREF 36
++#define FREQ_DRIFT_REPORT 37
++
++#define PCE_GET 40
++#define FIRM_VER_GET 41
++#define ASIC_VER_GET 42
++#define ASIC_ID_GET 43
++#define MAN_ID_GET 44
++#define TUNER_MODE_SET 45
++#define STOP_SEARCH 46
++#define RDS_CNTRL_SET 47
++
++#define WRITE_HARDWARE_REG 100
++#define CODE_DOWNLOAD 101
++#define RESET 102
++
++#define FM_POWER_MODE 254
++#define FM_INTERRUPT 255
++
++/* Transmitter API */
++
++#define CHANL_SET 55
++#define CHANL_BW_SET 56
++#define REF_SET 57
++#define POWER_ENB_SET 90
++#define POWER_ATT_SET 58
++#define POWER_LEV_SET 59
++#define AUDIO_DEV_SET 60
++#define PILOT_DEV_SET 61
++#define RDS_DEV_SET 62
++#define TX_BAND_SET 65
++#define PUPD_SET 91
++#define AUDIO_IO_SET 63
++#define PREMPH_SET 64
++#define MONO_SET 66
++#define MUTE 92
++#define MPX_LMT_ENABLE 67
++#define PI_SET 93
++#define ECC_SET 69
++#define PTY 70
++#define AF 71
++#define DISPLAY_MODE 74
++#define RDS_REP_SET 77
++#define RDS_CONFIG_DATA_SET 98
++#define RDS_DATA_SET 99
++#define RDS_DATA_ENB 94
++#define TA_SET 78
++#define TP_SET 79
++#define DI_SET 80
++#define MS_SET 81
++#define PS_SCROLL_SPEED 82
++#define TX_AUDIO_LEVEL_TEST 96
++#define TX_AUDIO_LEVEL_TEST_THRESHOLD 73
++#define TX_AUDIO_INPUT_LEVEL_RANGE_SET 54
++#define RX_ANTENNA_SELECT 87
++#define I2C_DEV_ADDR_SET 86
++#define REF_ERR_CALIB_PARAM_SET 88
++#define REF_ERR_CALIB_PERIODICITY_SET 89
++#define SOC_INT_TRIGGER 52
++#define SOC_AUDIO_PATH_SET 83
++#define SOC_PCMI_OVERRIDE 84
++#define SOC_I2S_OVERRIDE 85
++#define RSSI_BLOCK_SCAN_FREQ_SET 95
++#define RSSI_BLOCK_SCAN_START 97
++#define RSSI_BLOCK_SCAN_DATA_GET 5
++#define READ_FMANT_TUNE_VALUE 104
++
++/* SKB helpers */
++struct fm_skb_cb {
++ __u8 fm_op;
++ struct completion *completion;
++};
++
++#define fm_cb(skb) ((struct fm_skb_cb *)(skb->cb))
++
++/* FM Channel-8 command message format */
++struct fm_cmd_msg_hdr {
++ __u8 hdr; /* Logical Channel-8 */
++ __u8 len; /* Number of bytes follows */
++ __u8 op; /* FM Opcode */
++ __u8 rd_wr; /* Read/Write command */
++ __u8 dlen; /* Length of payload */
++} __attribute__ ((packed));
++
++#define FM_CMD_MSG_HDR_SIZE 5 /* sizeof(struct fm_cmd_msg_hdr) */
++
++/* FM Channel-8 event messgage format */
++struct fm_event_msg_hdr {
++ __u8 header; /* Logical Channel-8 */
++ __u8 len; /* Number of bytes follows */
++ __u8 status; /* Event status */
++ __u8 num_fm_hci_cmds; /* Number of pkts the host allowed to send */
++ __u8 op; /* FM Opcode */
++ __u8 rd_wr; /* Read/Write command */
++ __u8 dlen; /* Length of payload */
++} __attribute__ ((packed));
++
++#define FM_EVT_MSG_HDR_SIZE 7 /* sizeof(struct fm_event_msg_hdr) */
++
++/* TI's magic number in firmware file */
++#define FM_FW_FILE_HEADER_MAGIC 0x42535442
++
++#define FM_ENABLE 1
++#define FM_DISABLE 0
++
++/* FLAG_GET register bits */
++#define FM_FR_EVENT (1 << 0)
++#define FM_BL_EVENT (1 << 1)
++#define FM_RDS_EVENT (1 << 2)
++#define FM_BBLK_EVENT (1 << 3)
++#define FM_LSYNC_EVENT (1 << 4)
++#define FM_LEV_EVENT (1 << 5)
++#define FM_IFFR_EVENT (1 << 6)
++#define FM_PI_EVENT (1 << 7)
++#define FM_PD_EVENT (1 << 8)
++#define FM_STIC_EVENT (1 << 9)
++#define FM_MAL_EVENT (1 << 10)
++#define FM_POW_ENB_EVENT (1 << 11)
++
++/*
++ * Firmware files of FM. ASIC ID and ASIC version will be appened to this,
++ * later.
++ */
++#define FM_FMC_FW_FILE_START ("fmc_ch8")
++#define FM_RX_FW_FILE_START ("fm_rx_ch8")
++#define FM_TX_FW_FILE_START ("fm_tx_ch8")
++
++#define FM_UNDEFINED_FREQ 0xFFFFFFFF
++
++/* Band types */
++#define FM_BAND_EUROPE_US 0
++#define FM_BAND_JAPAN 1
++
++/* Seek directions */
++#define FM_SEARCH_DIRECTION_DOWN 0
++#define FM_SEARCH_DIRECTION_UP 1
++
++/* Tunner modes */
++#define FM_TUNER_STOP_SEARCH_MODE 0
++#define FM_TUNER_PRESET_MODE 1
++#define FM_TUNER_AUTONOMOUS_SEARCH_MODE 2
++#define FM_TUNER_AF_JUMP_MODE 3
++
++/* Min and Max volume */
++#define FM_RX_VOLUME_MIN 0
++#define FM_RX_VOLUME_MAX 70
++
++/* Volume gain step */
++#define FM_RX_VOLUME_GAIN_STEP 0x370
++
++/* Mute modes */
++#define FM_MUTE_OFF 0
++#define FM_MUTE_ON 1
++#define FM_MUTE_ATTENUATE 2
++
++#define FM_RX_UNMUTE_MODE 0x00
++#define FM_RX_RF_DEP_MODE 0x01
++#define FM_RX_AC_MUTE_MODE 0x02
++#define FM_RX_HARD_MUTE_LEFT_MODE 0x04
++#define FM_RX_HARD_MUTE_RIGHT_MODE 0x08
++#define FM_RX_SOFT_MUTE_FORCE_MODE 0x10
++
++/* RF dependent mute mode */
++#define FM_RX_RF_DEPENDENT_MUTE_ON 1
++#define FM_RX_RF_DEPENDENT_MUTE_OFF 0
++
++/* RSSI threshold min and max */
++#define FM_RX_RSSI_THRESHOLD_MIN -128
++#define FM_RX_RSSI_THRESHOLD_MAX 127
++
++/* Stereo/Mono mode */
++#define FM_STEREO_MODE 0
++#define FM_MONO_MODE 1
++#define FM_STEREO_SOFT_BLEND 1
++
++/* FM RX De-emphasis filter modes */
++#define FM_RX_EMPHASIS_FILTER_50_USEC 0
++#define FM_RX_EMPHASIS_FILTER_75_USEC 1
++
++/* FM RDS modes */
++#define FM_RDS_DISABLE 0
++#define FM_RDS_ENABLE 1
++
++#define FM_NO_PI_CODE 0
++
++/* FM and RX RDS block enable/disable */
++#define FM_RX_PWR_SET_FM_ON_RDS_OFF 0x1
++#define FM_RX_PWR_SET_FM_AND_RDS_BLK_ON 0x3
++#define FM_RX_PWR_SET_FM_AND_RDS_BLK_OFF 0x0
++
++/* RX RDS */
++#define FM_RX_RDS_FLUSH_FIFO 0x1
++#define FM_RX_RDS_FIFO_THRESHOLD 64 /* tuples */
++#define FM_RDS_BLK_SIZE 3 /* 3 bytes */
++
++/* RDS block types */
++#define FM_RDS_BLOCK_A 0
++#define FM_RDS_BLOCK_B 1
++#define FM_RDS_BLOCK_C 2
++#define FM_RDS_BLOCK_Ctag 3
++#define FM_RDS_BLOCK_D 4
++#define FM_RDS_BLOCK_E 5
++
++#define FM_RDS_BLK_IDX_A 0
++#define FM_RDS_BLK_IDX_B 1
++#define FM_RDS_BLK_IDX_C 2
++#define FM_RDS_BLK_IDX_D 3
++#define FM_RDS_BLK_IDX_UNKNOWN 0xF0
++
++#define FM_RDS_STATUS_ERR_MASK 0x18
++
++/*
++ * Represents an RDS group type & version.
++ * There are 15 groups, each group has 2 versions: A and B.
++ */
++#define FM_RDS_GROUP_TYPE_MASK_0A ((unsigned long)1<<0)
++#define FM_RDS_GROUP_TYPE_MASK_0B ((unsigned long)1<<1)
++#define FM_RDS_GROUP_TYPE_MASK_1A ((unsigned long)1<<2)
++#define FM_RDS_GROUP_TYPE_MASK_1B ((unsigned long)1<<3)
++#define FM_RDS_GROUP_TYPE_MASK_2A ((unsigned long)1<<4)
++#define FM_RDS_GROUP_TYPE_MASK_2B ((unsigned long)1<<5)
++#define FM_RDS_GROUP_TYPE_MASK_3A ((unsigned long)1<<6)
++#define FM_RDS_GROUP_TYPE_MASK_3B ((unsigned long)1<<7)
++#define FM_RDS_GROUP_TYPE_MASK_4A ((unsigned long)1<<8)
++#define FM_RDS_GROUP_TYPE_MASK_4B ((unsigned long)1<<9)
++#define FM_RDS_GROUP_TYPE_MASK_5A ((unsigned long)1<<10)
++#define FM_RDS_GROUP_TYPE_MASK_5B ((unsigned long)1<<11)
++#define FM_RDS_GROUP_TYPE_MASK_6A ((unsigned long)1<<12)
++#define FM_RDS_GROUP_TYPE_MASK_6B ((unsigned long)1<<13)
++#define FM_RDS_GROUP_TYPE_MASK_7A ((unsigned long)1<<14)
++#define FM_RDS_GROUP_TYPE_MASK_7B ((unsigned long)1<<15)
++#define FM_RDS_GROUP_TYPE_MASK_8A ((unsigned long)1<<16)
++#define FM_RDS_GROUP_TYPE_MASK_8B ((unsigned long)1<<17)
++#define FM_RDS_GROUP_TYPE_MASK_9A ((unsigned long)1<<18)
++#define FM_RDS_GROUP_TYPE_MASK_9B ((unsigned long)1<<19)
++#define FM_RDS_GROUP_TYPE_MASK_10A ((unsigned long)1<<20)
++#define FM_RDS_GROUP_TYPE_MASK_10B ((unsigned long)1<<21)
++#define FM_RDS_GROUP_TYPE_MASK_11A ((unsigned long)1<<22)
++#define FM_RDS_GROUP_TYPE_MASK_11B ((unsigned long)1<<23)
++#define FM_RDS_GROUP_TYPE_MASK_12A ((unsigned long)1<<24)
++#define FM_RDS_GROUP_TYPE_MASK_12B ((unsigned long)1<<25)
++#define FM_RDS_GROUP_TYPE_MASK_13A ((unsigned long)1<<26)
++#define FM_RDS_GROUP_TYPE_MASK_13B ((unsigned long)1<<27)
++#define FM_RDS_GROUP_TYPE_MASK_14A ((unsigned long)1<<28)
++#define FM_RDS_GROUP_TYPE_MASK_14B ((unsigned long)1<<29)
++#define FM_RDS_GROUP_TYPE_MASK_15A ((unsigned long)1<<30)
++#define FM_RDS_GROUP_TYPE_MASK_15B ((unsigned long)1<<31)
++
++/* RX Alternate Frequency info */
++#define FM_RDS_MIN_AF 1
++#define FM_RDS_MAX_AF 204
++#define FM_RDS_MAX_AF_JAPAN 140
++#define FM_RDS_1_AF_FOLLOWS 225
++#define FM_RDS_25_AF_FOLLOWS 249
++
++/* RDS system type (RDS/RBDS) */
++#define FM_RDS_SYSTEM_RDS 0
++#define FM_RDS_SYSTEM_RBDS 1
++
++/* AF on/off */
++#define FM_RX_RDS_AF_SWITCH_MODE_ON 1
++#define FM_RX_RDS_AF_SWITCH_MODE_OFF 0
++
++/* Retry count when interrupt process goes wrong */
++#define FM_IRQ_TIMEOUT_RETRY_MAX 5 /* 5 times */
++
++/* Audio IO set values */
++#define FM_RX_AUDIO_ENABLE_I2S 0x01
++#define FM_RX_AUDIO_ENABLE_ANALOG 0x02
++#define FM_RX_AUDIO_ENABLE_I2S_AND_ANALOG 0x03
++#define FM_RX_AUDIO_ENABLE_DISABLE 0x00
++
++/* HI/LO set values */
++#define FM_RX_IFFREQ_TO_HI_SIDE 0x0
++#define FM_RX_IFFREQ_TO_LO_SIDE 0x1
++#define FM_RX_IFFREQ_HILO_AUTOMATIC 0x2
++
++/*
++ * Default RX mode configuration. Chip will be configured
++ * with this default values after loading RX firmware.
++ */
++#define FM_DEFAULT_RX_VOLUME 10
++#define FM_DEFAULT_RSSI_THRESHOLD 3
++
++/* Range for TX power level in units for dB/uV */
++#define FM_PWR_LVL_LOW 91
++#define FM_PWR_LVL_HIGH 122
++
++/* Chip specific default TX power level value */
++#define FM_PWR_LVL_DEF 4
++
++/* FM TX Pre-emphasis filter values */
++#define FM_TX_PREEMPH_OFF 1
++#define FM_TX_PREEMPH_50US 0
++#define FM_TX_PREEMPH_75US 2
++
++/* FM TX antenna impedence values */
++#define FM_TX_ANT_IMP_50 0
++#define FM_TX_ANT_IMP_200 1
++#define FM_TX_ANT_IMP_500 2
++
++/* Functions exported by FM common sub-module */
++u32 fmc_prepare(struct fmdev *);
++u32 fmc_release(struct fmdev *);
++
++void fmc_update_region_info(struct fmdev *, u8);
++u32 fmc_send_cmd(struct fmdev *, u8, u16,
++ void *, unsigned int, void *, int *);
++u32 fmc_is_rds_data_available(struct fmdev *, struct file *,
++ struct poll_table_struct *);
++u32 fmc_transfer_rds_from_internal_buff(struct fmdev *, struct file *,
++ u8 __user *, size_t);
++
++u32 fmc_set_freq(struct fmdev *, u32);
++u32 fmc_set_mode(struct fmdev *, u8);
++u32 fmc_set_region(struct fmdev *, u8);
++u32 fmc_set_mute_mode(struct fmdev *, u8);
++u32 fmc_set_stereo_mono(struct fmdev *, u16);
++u32 fmc_set_rds_mode(struct fmdev *, u8);
++
++u32 fmc_get_freq(struct fmdev *, u32 *);
++u32 fmc_get_region(struct fmdev *, u8 *);
++u32 fmc_get_mode(struct fmdev *, u8 *);
++
++/*
++ * channel spacing
++ */
++#define FM_CHANNEL_SPACING_50KHZ 1
++#define FM_CHANNEL_SPACING_100KHZ 2
++#define FM_CHANNEL_SPACING_200KHZ 4
++#define FM_FREQ_MUL 50
++
++#endif
++
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/wl1271/0010-drivers-media-radio-wl128x-FM-driver-RX-sources.patch b/extras/recipes-kernel/linux/linux-omap/wl1271/0010-drivers-media-radio-wl128x-FM-driver-RX-sources.patch
new file mode 100644
index 00000000..8899a318
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/wl1271/0010-drivers-media-radio-wl128x-FM-driver-RX-sources.patch
@@ -0,0 +1,938 @@
+From ba32e1ae2a43f33dcfd459c1456d4e612da885db Mon Sep 17 00:00:00 2001
+From: Manjunatha Halli <manjunatha_halli@ti.com>
+Date: Tue, 11 Jan 2011 11:31:24 +0000
+Subject: [PATCH 10/15] drivers:media:radio: wl128x: FM driver RX sources
+
+This has implementation for FM RX functionality.
+It communicates with FM V4l2 module and FM common module
+
+Signed-off-by: Manjunatha Halli <manjunatha_halli@ti.com>
+Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
+---
+ drivers/media/radio/wl128x/fmdrv_rx.c | 847 +++++++++++++++++++++++++++++++++
+ drivers/media/radio/wl128x/fmdrv_rx.h | 59 +++
+ 2 files changed, 906 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/media/radio/wl128x/fmdrv_rx.c
+ create mode 100644 drivers/media/radio/wl128x/fmdrv_rx.h
+
+diff --git a/drivers/media/radio/wl128x/fmdrv_rx.c b/drivers/media/radio/wl128x/fmdrv_rx.c
+new file mode 100644
+index 0000000..ec529b5
+--- /dev/null
++++ b/drivers/media/radio/wl128x/fmdrv_rx.c
+@@ -0,0 +1,847 @@
++/*
++ * FM Driver for Connectivity chip of Texas Instruments.
++ * This sub-module of FM driver implements FM RX functionality.
++ *
++ * Copyright (C) 2011 Texas Instruments
++ * Author: Raja Mani <raja_mani@ti.com>
++ * Author: Manjunatha Halli <manjunatha_halli@ti.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#include "fmdrv.h"
++#include "fmdrv_common.h"
++#include "fmdrv_rx.h"
++
++void fm_rx_reset_rds_cache(struct fmdev *fmdev)
++{
++ fmdev->rx.rds.flag = FM_RDS_DISABLE;
++ fmdev->rx.rds.last_blk_idx = 0;
++ fmdev->rx.rds.wr_idx = 0;
++ fmdev->rx.rds.rd_idx = 0;
++
++ if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON)
++ fmdev->irq_info.mask |= FM_LEV_EVENT;
++}
++
++void fm_rx_reset_station_info(struct fmdev *fmdev)
++{
++ fmdev->rx.stat_info.picode = FM_NO_PI_CODE;
++ fmdev->rx.stat_info.afcache_size = 0;
++ fmdev->rx.stat_info.af_list_max = 0;
++}
++
++u32 fm_rx_set_freq(struct fmdev *fmdev, u32 freq)
++{
++ unsigned long timeleft;
++ u16 payload, curr_frq, intr_flag;
++ u32 curr_frq_in_khz;
++ u32 ret, resp_len;
++
++ if (freq < fmdev->rx.region.bot_freq || freq > fmdev->rx.region.top_freq) {
++ fmerr("Invalid frequency %d\n", freq);
++ return -EINVAL;
++ }
++
++ /* Set audio enable */
++ payload = FM_RX_AUDIO_ENABLE_I2S_AND_ANALOG;
++
++ ret = fmc_send_cmd(fmdev, AUDIO_ENABLE_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* Set hilo to automatic selection */
++ payload = FM_RX_IFFREQ_HILO_AUTOMATIC;
++ ret = fmc_send_cmd(fmdev, HILO_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* Calculate frequency index and set*/
++ payload = (freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL;
++
++ ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* Read flags - just to clear any pending interrupts if we had */
++ ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* Enable FR, BL interrupts */
++ intr_flag = fmdev->irq_info.mask;
++ fmdev->irq_info.mask = (FM_FR_EVENT | FM_BL_EVENT);
++ payload = fmdev->irq_info.mask;
++ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* Start tune */
++ payload = FM_TUNER_PRESET_MODE;
++ ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ goto exit;
++
++ /* Wait for tune ended interrupt */
++ init_completion(&fmdev->maintask_comp);
++ timeleft = wait_for_completion_timeout(&fmdev->maintask_comp,
++ FM_DRV_TX_TIMEOUT);
++ if (!timeleft) {
++ fmerr("Timeout(%d sec),didn't get tune ended int\n",
++ jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
++ ret = -ETIMEDOUT;
++ goto exit;
++ }
++
++ /* Read freq back to confirm */
++ ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2, &curr_frq, &resp_len);
++ if (ret < 0)
++ goto exit;
++
++ curr_frq = be16_to_cpu(curr_frq);
++ curr_frq_in_khz = (fmdev->rx.region.bot_freq + ((u32)curr_frq * FM_FREQ_MUL));
++
++ if (curr_frq_in_khz != freq) {
++ pr_info("Frequency is set to (%d) but "
++ "requested freq is (%d)\n", curr_frq_in_khz, freq);
++ }
++
++ /* Update local cache */
++ fmdev->rx.freq = curr_frq_in_khz;
++exit:
++ /* Re-enable default FM interrupts */
++ fmdev->irq_info.mask = intr_flag;
++ payload = fmdev->irq_info.mask;
++ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* Reset RDS cache and current station pointers */
++ fm_rx_reset_rds_cache(fmdev);
++ fm_rx_reset_station_info(fmdev);
++
++ return ret;
++}
++
++static u32 fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing)
++{
++ u16 payload;
++ u32 ret;
++
++ if (spacing > 0 && spacing <= 50000)
++ spacing = FM_CHANNEL_SPACING_50KHZ;
++ else if (spacing > 50000 && spacing <= 100000)
++ spacing = FM_CHANNEL_SPACING_100KHZ;
++ else
++ spacing = FM_CHANNEL_SPACING_200KHZ;
++
++ /* set channel spacing */
++ payload = spacing;
++ ret = fmc_send_cmd(fmdev, CHANL_BW_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ fmdev->rx.region.chanl_space = spacing * FM_FREQ_MUL;
++
++ return ret;
++}
++
++u32 fm_rx_seek(struct fmdev *fmdev, u32 seek_upward,
++ u32 wrap_around, u32 spacing)
++{
++ u32 resp_len;
++ u16 curr_frq, next_frq, last_frq;
++ u16 payload, int_reason, intr_flag;
++ u16 offset, space_idx;
++ unsigned long timeleft;
++ u32 ret;
++
++ /* Set channel spacing */
++ ret = fm_rx_set_channel_spacing(fmdev, spacing);
++ if (ret < 0) {
++ fmerr("Failed to set channel spacing\n");
++ return ret;
++ }
++
++ /* Read the current frequency from chip */
++ ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL,
++ sizeof(curr_frq), &curr_frq, &resp_len);
++ if (ret < 0)
++ return ret;
++
++ curr_frq = be16_to_cpu(curr_frq);
++ last_frq = (fmdev->rx.region.top_freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL;
++
++ /* Check the offset in order to be aligned to the channel spacing*/
++ space_idx = fmdev->rx.region.chanl_space / FM_FREQ_MUL;
++ offset = curr_frq % space_idx;
++
++ next_frq = seek_upward ? curr_frq + space_idx /* Seek Up */ :
++ curr_frq - space_idx /* Seek Down */ ;
++
++ /*
++ * Add or subtract offset in order to stay aligned to the channel
++ * spacing.
++ */
++ if ((short)next_frq < 0)
++ next_frq = last_frq - offset;
++ else if (next_frq > last_frq)
++ next_frq = 0 + offset;
++
++again:
++ /* Set calculated next frequency to perform seek */
++ payload = next_frq;
++ ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* Set search direction (0:Seek Down, 1:Seek Up) */
++ payload = (seek_upward ? FM_SEARCH_DIRECTION_UP : FM_SEARCH_DIRECTION_DOWN);
++ ret = fmc_send_cmd(fmdev, SEARCH_DIR_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* Read flags - just to clear any pending interrupts if we had */
++ ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* Enable FR, BL interrupts */
++ intr_flag = fmdev->irq_info.mask;
++ fmdev->irq_info.mask = (FM_FR_EVENT | FM_BL_EVENT);
++ payload = fmdev->irq_info.mask;
++ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* Start seek */
++ payload = FM_TUNER_AUTONOMOUS_SEARCH_MODE;
++ ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* Wait for tune ended/band limit reached interrupt */
++ init_completion(&fmdev->maintask_comp);
++ timeleft = wait_for_completion_timeout(&fmdev->maintask_comp,
++ FM_DRV_RX_SEEK_TIMEOUT);
++ if (!timeleft) {
++ fmerr("Timeout(%d sec),didn't get tune ended int\n",
++ jiffies_to_msecs(FM_DRV_RX_SEEK_TIMEOUT) / 1000);
++ return -ETIMEDOUT;
++ }
++
++ int_reason = fmdev->irq_info.flag & (FM_TUNE_COMPLETE | FM_BAND_LIMIT);
++
++ /* Re-enable default FM interrupts */
++ fmdev->irq_info.mask = intr_flag;
++ payload = fmdev->irq_info.mask;
++ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ if (int_reason & FM_BL_EVENT) {
++ if (wrap_around == 0) {
++ fmdev->rx.freq = seek_upward ?
++ fmdev->rx.region.top_freq :
++ fmdev->rx.region.bot_freq;
++ } else {
++ fmdev->rx.freq = seek_upward ?
++ fmdev->rx.region.bot_freq :
++ fmdev->rx.region.top_freq;
++ /* Calculate frequency index to write */
++ next_frq = (fmdev->rx.freq -
++ fmdev->rx.region.bot_freq) / FM_FREQ_MUL;
++ goto again;
++ }
++ } else {
++ /* Read freq to know where operation tune operation stopped */
++ ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2,
++ &curr_frq, &resp_len);
++ if (ret < 0)
++ return ret;
++
++ curr_frq = be16_to_cpu(curr_frq);
++ fmdev->rx.freq = (fmdev->rx.region.bot_freq +
++ ((u32)curr_frq * FM_FREQ_MUL));
++
++ }
++ /* Reset RDS cache and current station pointers */
++ fm_rx_reset_rds_cache(fmdev);
++ fm_rx_reset_station_info(fmdev);
++
++ return ret;
++}
++
++u32 fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set)
++{
++ u16 payload;
++ u32 ret;
++
++ if (fmdev->curr_fmmode != FM_MODE_RX)
++ return -EPERM;
++
++ if (vol_to_set < FM_RX_VOLUME_MIN || vol_to_set > FM_RX_VOLUME_MAX) {
++ fmerr("Volume is not within(%d-%d) range\n",
++ FM_RX_VOLUME_MIN, FM_RX_VOLUME_MAX);
++ return -EINVAL;
++ }
++ vol_to_set *= FM_RX_VOLUME_GAIN_STEP;
++
++ payload = vol_to_set;
++ ret = fmc_send_cmd(fmdev, VOLUME_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ fmdev->rx.volume = vol_to_set;
++ return ret;
++}
++
++/* Get volume */
++u32 fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol)
++{
++ if (fmdev->curr_fmmode != FM_MODE_RX)
++ return -EPERM;
++
++ if (curr_vol == NULL) {
++ fmerr("Invalid memory\n");
++ return -ENOMEM;
++ }
++
++ *curr_vol = fmdev->rx.volume / FM_RX_VOLUME_GAIN_STEP;
++
++ return 0;
++}
++
++/* To get current band's bottom and top frequency */
++u32 fm_rx_get_band_freq_range(struct fmdev *fmdev, u32 *bot_freq, u32 *top_freq)
++{
++ if (bot_freq != NULL)
++ *bot_freq = fmdev->rx.region.bot_freq;
++
++ if (top_freq != NULL)
++ *top_freq = fmdev->rx.region.top_freq;
++
++ return 0;
++}
++
++/* Returns current band index (0-Europe/US; 1-Japan) */
++void fm_rx_get_region(struct fmdev *fmdev, u8 *region)
++{
++ *region = fmdev->rx.region.fm_band;
++}
++
++/* Sets band (0-Europe/US; 1-Japan) */
++u32 fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set)
++{
++ u16 payload;
++ u32 new_frq = 0;
++ u32 ret;
++
++ if (region_to_set != FM_BAND_EUROPE_US &&
++ region_to_set != FM_BAND_JAPAN) {
++ fmerr("Invalid band\n");
++ return -EINVAL;
++ }
++
++ if (fmdev->rx.region.fm_band == region_to_set) {
++ fmerr("Requested band is already configured\n");
++ return 0;
++ }
++
++ /* Send cmd to set the band */
++ payload = (u16)region_to_set;
++ ret = fmc_send_cmd(fmdev, BAND_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ fmc_update_region_info(fmdev, region_to_set);
++
++ /* Check whether current RX frequency is within band boundary */
++ if (fmdev->rx.freq < fmdev->rx.region.bot_freq)
++ new_frq = fmdev->rx.region.bot_freq;
++ else if (fmdev->rx.freq > fmdev->rx.region.top_freq)
++ new_frq = fmdev->rx.region.top_freq;
++
++ if (new_frq) {
++ fmdbg("Current freq is not within band limit boundary,"
++ "switching to %d KHz\n", new_frq);
++ /* Current RX frequency is not in range. So, update it */
++ ret = fm_rx_set_freq(fmdev, new_frq);
++ }
++
++ return ret;
++}
++
++/* Reads current mute mode (Mute Off/On/Attenuate)*/
++u32 fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode)
++{
++ if (fmdev->curr_fmmode != FM_MODE_RX)
++ return -EPERM;
++
++ if (curr_mute_mode == NULL) {
++ fmerr("Invalid memory\n");
++ return -ENOMEM;
++ }
++
++ *curr_mute_mode = fmdev->rx.mute_mode;
++
++ return 0;
++}
++
++static u32 fm_config_rx_mute_reg(struct fmdev *fmdev)
++{
++ u16 payload, muteval;
++ u32 ret;
++
++ muteval = 0;
++ switch (fmdev->rx.mute_mode) {
++ case FM_MUTE_ON:
++ muteval = FM_RX_AC_MUTE_MODE;
++ break;
++
++ case FM_MUTE_OFF:
++ muteval = FM_RX_UNMUTE_MODE;
++ break;
++
++ case FM_MUTE_ATTENUATE:
++ muteval = FM_RX_SOFT_MUTE_FORCE_MODE;
++ break;
++ }
++ if (fmdev->rx.rf_depend_mute == FM_RX_RF_DEPENDENT_MUTE_ON)
++ muteval |= FM_RX_RF_DEP_MODE;
++ else
++ muteval &= ~FM_RX_RF_DEP_MODE;
++
++ payload = muteval;
++ ret = fmc_send_cmd(fmdev, MUTE_STATUS_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++/* Configures mute mode (Mute Off/On/Attenuate) */
++u32 fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
++{
++ u8 org_state;
++ u32 ret;
++
++ if (fmdev->rx.mute_mode == mute_mode_toset)
++ return 0;
++
++ org_state = fmdev->rx.mute_mode;
++ fmdev->rx.mute_mode = mute_mode_toset;
++
++ ret = fm_config_rx_mute_reg(fmdev);
++ if (ret < 0) {
++ fmdev->rx.mute_mode = org_state;
++ return ret;
++ }
++
++ return 0;
++}
++
++/* Gets RF dependent soft mute mode enable/disable status */
++u32 fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode)
++{
++ if (fmdev->curr_fmmode != FM_MODE_RX)
++ return -EPERM;
++
++ if (curr_mute_mode == NULL) {
++ fmerr("Invalid memory\n");
++ return -ENOMEM;
++ }
++
++ *curr_mute_mode = fmdev->rx.rf_depend_mute;
++
++ return 0;
++}
++
++/* Sets RF dependent soft mute mode */
++u32 fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute)
++{
++ u8 org_state;
++ u32 ret;
++
++ if (fmdev->curr_fmmode != FM_MODE_RX)
++ return -EPERM;
++
++ if (rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_ON &&
++ rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_OFF) {
++ fmerr("Invalid RF dependent soft mute\n");
++ return -EINVAL;
++ }
++ if (fmdev->rx.rf_depend_mute == rfdepend_mute)
++ return 0;
++
++ org_state = fmdev->rx.rf_depend_mute;
++ fmdev->rx.rf_depend_mute = rfdepend_mute;
++
++ ret = fm_config_rx_mute_reg(fmdev);
++ if (ret < 0) {
++ fmdev->rx.rf_depend_mute = org_state;
++ return ret;
++ }
++
++ return 0;
++}
++
++/* Returns the signal strength level of current channel */
++u32 fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl)
++{
++ u16 curr_rssi_lel;
++ u32 resp_len;
++ u32 ret;
++
++ if (rssilvl == NULL) {
++ fmerr("Invalid memory\n");
++ return -ENOMEM;
++ }
++ /* Read current RSSI level */
++ ret = fmc_send_cmd(fmdev, RSSI_LVL_GET, REG_RD, NULL, 2,
++ &curr_rssi_lel, &resp_len);
++ if (ret < 0)
++ return ret;
++
++ *rssilvl = be16_to_cpu(curr_rssi_lel);
++
++ return 0;
++}
++
++/*
++ * Sets the signal strength level that once reached
++ * will stop the auto search process
++ */
++u32 fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset)
++{
++ u16 payload;
++ u32 ret;
++
++ if (rssi_lvl_toset < FM_RX_RSSI_THRESHOLD_MIN ||
++ rssi_lvl_toset > FM_RX_RSSI_THRESHOLD_MAX) {
++ fmerr("Invalid RSSI threshold level\n");
++ return -EINVAL;
++ }
++ payload = (u16)rssi_lvl_toset;
++ ret = fmc_send_cmd(fmdev, SEARCH_LVL_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ fmdev->rx.rssi_threshold = rssi_lvl_toset;
++
++ return 0;
++}
++
++/* Returns current RX RSSI threshold value */
++u32 fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl)
++{
++ if (fmdev->curr_fmmode != FM_MODE_RX)
++ return -EPERM;
++
++ if (curr_rssi_lvl == NULL) {
++ fmerr("Invalid memory\n");
++ return -ENOMEM;
++ }
++
++ *curr_rssi_lvl = fmdev->rx.rssi_threshold;
++
++ return 0;
++}
++
++/* Sets RX stereo/mono modes */
++u32 fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
++{
++ u16 payload;
++ u32 ret;
++
++ if (mode != FM_STEREO_MODE && mode != FM_MONO_MODE) {
++ fmerr("Invalid mode\n");
++ return -EINVAL;
++ }
++
++ /* Set stereo/mono mode */
++ payload = (u16)mode;
++ ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* Set stereo blending mode */
++ payload = FM_STEREO_SOFT_BLEND;
++ ret = fmc_send_cmd(fmdev, MOST_BLEND_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++/* Gets current RX stereo/mono mode */
++u32 fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode)
++{
++ u16 curr_mode;
++ u32 ret, resp_len;
++
++ if (mode == NULL) {
++ fmerr("Invalid memory\n");
++ return -ENOMEM;
++ }
++
++ ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_RD, NULL, 2,
++ &curr_mode, &resp_len);
++ if (ret < 0)
++ return ret;
++
++ *mode = be16_to_cpu(curr_mode);
++
++ return 0;
++}
++
++/* Choose RX de-emphasis filter mode (50us/75us) */
++u32 fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode)
++{
++ u16 payload;
++ u32 ret;
++
++ if (fmdev->curr_fmmode != FM_MODE_RX)
++ return -EPERM;
++
++ if (mode != FM_RX_EMPHASIS_FILTER_50_USEC &&
++ mode != FM_RX_EMPHASIS_FILTER_75_USEC) {
++ fmerr("Invalid rx de-emphasis mode (%d)\n", mode);
++ return -EINVAL;
++ }
++
++ payload = mode;
++ ret = fmc_send_cmd(fmdev, DEMPH_MODE_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ fmdev->rx.deemphasis_mode = mode;
++
++ return 0;
++}
++
++/* Gets current RX de-emphasis filter mode */
++u32 fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode)
++{
++ if (fmdev->curr_fmmode != FM_MODE_RX)
++ return -EPERM;
++
++ if (curr_deemphasis_mode == NULL) {
++ fmerr("Invalid memory\n");
++ return -ENOMEM;
++ }
++
++ *curr_deemphasis_mode = fmdev->rx.deemphasis_mode;
++
++ return 0;
++}
++
++/* Enable/Disable RX RDS */
++u32 fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
++{
++ u16 payload;
++ u32 ret;
++
++ if (rds_en_dis != FM_RDS_ENABLE && rds_en_dis != FM_RDS_DISABLE) {
++ fmerr("Invalid rds option\n");
++ return -EINVAL;
++ }
++
++ if (rds_en_dis == FM_RDS_ENABLE
++ && fmdev->rx.rds.flag == FM_RDS_DISABLE) {
++ /* Turn on RX RDS and RDS circuit */
++ payload = FM_RX_PWR_SET_FM_AND_RDS_BLK_ON;
++ ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* Clear and reset RDS FIFO */
++ payload = FM_RX_RDS_FLUSH_FIFO;
++ ret = fmc_send_cmd(fmdev, RDS_CNTRL_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* Read flags - just to clear any pending interrupts. */
++ ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2,
++ NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* Set RDS FIFO threshold value */
++ payload = FM_RX_RDS_FIFO_THRESHOLD;
++ ret = fmc_send_cmd(fmdev, RDS_MEM_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* Enable RDS interrupt */
++ fmdev->irq_info.mask |= FM_RDS_EVENT;
++ payload = fmdev->irq_info.mask;
++ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0) {
++ fmdev->irq_info.mask &= ~FM_RDS_EVENT;
++ return ret;
++ }
++
++ /* Update our local flag */
++ fmdev->rx.rds.flag = FM_RDS_ENABLE;
++ } else if (rds_en_dis == FM_RDS_DISABLE
++ && fmdev->rx.rds.flag == FM_RDS_ENABLE) {
++ /* Turn off RX RDS */
++ payload = FM_RX_PWR_SET_FM_ON_RDS_OFF;
++ ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* Reset RDS pointers */
++ fmdev->rx.rds.last_blk_idx = 0;
++ fmdev->rx.rds.wr_idx = 0;
++ fmdev->rx.rds.rd_idx = 0;
++ fm_rx_reset_station_info(fmdev);
++
++ /* Update RDS local cache */
++ fmdev->irq_info.mask &= ~(FM_RDS_EVENT);
++ fmdev->rx.rds.flag = FM_RDS_DISABLE;
++ }
++
++ return 0;
++}
++
++/* Returns current RX RDS enable/disable status */
++u32 fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis)
++{
++ if (fmdev->curr_fmmode != FM_MODE_RX)
++ return -EPERM;
++
++ if (curr_rds_en_dis == NULL) {
++ fmerr("Invalid memory\n");
++ return -ENOMEM;
++ }
++
++ *curr_rds_en_dis = fmdev->rx.rds.flag;
++
++ return 0;
++}
++
++/* Sets RDS operation mode (RDS/RDBS) */
++u32 fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode)
++{
++ u16 payload;
++ u32 ret;
++
++ if (fmdev->curr_fmmode != FM_MODE_RX)
++ return -EPERM;
++
++ if (rds_mode != FM_RDS_SYSTEM_RDS && rds_mode != FM_RDS_SYSTEM_RBDS) {
++ fmerr("Invalid rds mode\n");
++ return -EINVAL;
++ }
++ /* Set RDS operation mode */
++ payload = (u16)rds_mode;
++ ret = fmc_send_cmd(fmdev, RDS_SYSTEM_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ fmdev->rx.rds_mode = rds_mode;
++
++ return 0;
++}
++
++/* Returns current RDS operation mode */
++u32 fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode)
++{
++ if (fmdev->curr_fmmode != FM_MODE_RX)
++ return -EPERM;
++
++ if (rds_mode == NULL) {
++ fmerr("Invalid memory\n");
++ return -ENOMEM;
++ }
++
++ *rds_mode = fmdev->rx.rds_mode;
++
++ return 0;
++}
++
++/* Configures Alternate Frequency switch mode */
++u32 fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode)
++{
++ u16 payload;
++ u32 ret;
++
++ if (fmdev->curr_fmmode != FM_MODE_RX)
++ return -EPERM;
++
++ if (af_mode != FM_RX_RDS_AF_SWITCH_MODE_ON &&
++ af_mode != FM_RX_RDS_AF_SWITCH_MODE_OFF) {
++ fmerr("Invalid af mode\n");
++ return -EINVAL;
++ }
++ /* Enable/disable low RSSI interrupt based on af_mode */
++ if (af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON)
++ fmdev->irq_info.mask |= FM_LEV_EVENT;
++ else
++ fmdev->irq_info.mask &= ~FM_LEV_EVENT;
++
++ payload = fmdev->irq_info.mask;
++ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ fmdev->rx.af_mode = af_mode;
++
++ return 0;
++}
++
++/* Returns Alternate Frequency switch status */
++u32 fm_rx_get_af_switch(struct fmdev *fmdev, u8 *af_mode)
++{
++ if (fmdev->curr_fmmode != FM_MODE_RX)
++ return -EPERM;
++
++ if (af_mode == NULL) {
++ fmerr("Invalid memory\n");
++ return -ENOMEM;
++ }
++
++ *af_mode = fmdev->rx.af_mode;
++
++ return 0;
++}
+diff --git a/drivers/media/radio/wl128x/fmdrv_rx.h b/drivers/media/radio/wl128x/fmdrv_rx.h
+new file mode 100644
+index 0000000..329e62f
+--- /dev/null
++++ b/drivers/media/radio/wl128x/fmdrv_rx.h
+@@ -0,0 +1,59 @@
++/*
++ * FM Driver for Connectivity chip of Texas Instruments.
++ * FM RX module header.
++ *
++ * Copyright (C) 2011 Texas Instruments
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#ifndef _FMDRV_RX_H
++#define _FMDRV_RX_H
++
++u32 fm_rx_set_freq(struct fmdev *, u32);
++u32 fm_rx_set_mute_mode(struct fmdev *, u8);
++u32 fm_rx_set_stereo_mono(struct fmdev *, u16);
++u32 fm_rx_set_rds_mode(struct fmdev *, u8);
++u32 fm_rx_set_rds_system(struct fmdev *, u8);
++u32 fm_rx_set_volume(struct fmdev *, u16);
++u32 fm_rx_set_rssi_threshold(struct fmdev *, short);
++u32 fm_rx_set_region(struct fmdev *, u8);
++u32 fm_rx_set_rfdepend_softmute(struct fmdev *, u8);
++u32 fm_rx_set_deemphasis_mode(struct fmdev *, u16);
++u32 fm_rx_set_af_switch(struct fmdev *, u8);
++
++void fm_rx_reset_rds_cache(struct fmdev *);
++void fm_rx_reset_station_info(struct fmdev *);
++
++u32 fm_rx_seek(struct fmdev *, u32, u32, u32);
++
++u32 fm_rx_get_rds_mode(struct fmdev *, u8 *);
++u32 fm_rx_get_rds_system(struct fmdev *, u8 *);
++u32 fm_rx_get_mute_mode(struct fmdev *, u8 *);
++u32 fm_rx_get_volume(struct fmdev *, u16 *);
++u32 fm_rx_get_band_freq_range(struct fmdev *,
++ u32 *, u32 *);
++u32 fm_rx_get_stereo_mono(struct fmdev *, u16 *);
++u32 fm_rx_get_rssi_level(struct fmdev *, u16 *);
++u32 fm_rx_get_rssi_threshold(struct fmdev *, short *);
++u32 fm_rx_get_rfdepend_softmute(struct fmdev *, u8 *);
++u32 fm_rx_get_deemph_mode(struct fmdev *, u16 *);
++u32 fm_rx_get_af_switch(struct fmdev *, u8 *);
++void fm_rx_get_region(struct fmdev *, u8 *);
++
++u32 fm_rx_set_chanl_spacing(struct fmdev *, u8);
++u32 fm_rx_get_chanl_spacing(struct fmdev *, u8 *);
++#endif
++
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/wl1271/0011-drivers-media-radio-wl128x-FM-driver-TX-sources.patch b/extras/recipes-kernel/linux/linux-omap/wl1271/0011-drivers-media-radio-wl128x-FM-driver-TX-sources.patch
new file mode 100644
index 00000000..52b409f8
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/wl1271/0011-drivers-media-radio-wl128x-FM-driver-TX-sources.patch
@@ -0,0 +1,494 @@
+From 87d399bad67bdff67c1601fbb8e54deb5e0cf7e0 Mon Sep 17 00:00:00 2001
+From: Manjunatha Halli <manjunatha_halli@ti.com>
+Date: Tue, 11 Jan 2011 11:31:25 +0000
+Subject: [PATCH 11/15] drivers:media:radio: wl128x: FM driver TX sources
+
+This has implementation for FM TX functionality.
+It communicates with FM V4l2 module and FM common module.
+
+Signed-off-by: Manjunatha Halli <manjunatha_halli@ti.com>
+Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
+---
+ drivers/media/radio/wl128x/fmdrv_tx.c | 425 +++++++++++++++++++++++++++++++++
+ drivers/media/radio/wl128x/fmdrv_tx.h | 37 +++
+ 2 files changed, 462 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/media/radio/wl128x/fmdrv_tx.c
+ create mode 100644 drivers/media/radio/wl128x/fmdrv_tx.h
+
+diff --git a/drivers/media/radio/wl128x/fmdrv_tx.c b/drivers/media/radio/wl128x/fmdrv_tx.c
+new file mode 100644
+index 0000000..be54068
+--- /dev/null
++++ b/drivers/media/radio/wl128x/fmdrv_tx.c
+@@ -0,0 +1,425 @@
++/*
++ * FM Driver for Connectivity chip of Texas Instruments.
++ * This sub-module of FM driver implements FM TX functionality.
++ *
++ * Copyright (C) 2011 Texas Instruments
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#include <linux/delay.h>
++#include "fmdrv.h"
++#include "fmdrv_common.h"
++#include "fmdrv_tx.h"
++
++u32 fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
++{
++ u16 payload;
++ u32 ret;
++
++ if (fmdev->tx_data.aud_mode == mode)
++ return 0;
++
++ fmdbg("stereo mode: %d\n", mode);
++
++ /* Set Stereo/Mono mode */
++ payload = (1 - mode);
++ ret = fmc_send_cmd(fmdev, MONO_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ fmdev->tx_data.aud_mode = mode;
++
++ return ret;
++}
++
++static u32 set_rds_text(struct fmdev *fmdev, u8 *rds_text)
++{
++ u16 payload;
++ u32 ret;
++
++ ret = fmc_send_cmd(fmdev, RDS_DATA_SET, REG_WR, rds_text,
++ strlen(rds_text), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* Scroll mode */
++ payload = (u16)0x1;
++ ret = fmc_send_cmd(fmdev, DISPLAY_MODE, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++static u32 set_rds_data_mode(struct fmdev *fmdev, u8 mode)
++{
++ u16 payload;
++ u32 ret;
++
++ /* Setting unique PI TODO: how unique? */
++ payload = (u16)0xcafe;
++ ret = fmc_send_cmd(fmdev, PI_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* Set decoder id */
++ payload = (u16)0xa;
++ ret = fmc_send_cmd(fmdev, DI_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* TODO: RDS_MODE_GET? */
++ return 0;
++}
++
++static u32 set_rds_len(struct fmdev *fmdev, u8 type, u16 len)
++{
++ u16 payload;
++ u32 ret;
++
++ len |= type << 8;
++ payload = len;
++ ret = fmc_send_cmd(fmdev, RDS_CONFIG_DATA_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* TODO: LENGTH_GET? */
++ return 0;
++}
++
++u32 fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
++{
++ u16 payload;
++ u32 ret;
++ u8 rds_text[] = "Zoom2\n";
++
++ fmdbg("rds_en_dis:%d(E:%d, D:%d)\n", rds_en_dis,
++ FM_RDS_ENABLE, FM_RDS_DISABLE);
++
++ if (rds_en_dis == FM_RDS_ENABLE) {
++ /* Set RDS length */
++ set_rds_len(fmdev, 0, strlen(rds_text));
++
++ /* Set RDS text */
++ set_rds_text(fmdev, rds_text);
++
++ /* Set RDS mode */
++ set_rds_data_mode(fmdev, 0x0);
++ }
++
++ /* Send command to enable RDS */
++ if (rds_en_dis == FM_RDS_ENABLE)
++ payload = 0x01;
++ else
++ payload = 0x00;
++
++ ret = fmc_send_cmd(fmdev, RDS_DATA_ENB, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ if (rds_en_dis == FM_RDS_ENABLE) {
++ /* Set RDS length */
++ set_rds_len(fmdev, 0, strlen(rds_text));
++
++ /* Set RDS text */
++ set_rds_text(fmdev, rds_text);
++ }
++ fmdev->tx_data.rds.flag = rds_en_dis;
++
++ return 0;
++}
++
++u32 fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type)
++{
++ u16 payload;
++ u32 ret;
++
++ if (fmdev->curr_fmmode != FM_MODE_TX)
++ return -EPERM;
++
++ fm_tx_set_rds_mode(fmdev, 0);
++
++ /* Set RDS length */
++ set_rds_len(fmdev, rds_type, strlen(rds_text));
++
++ /* Set RDS text */
++ set_rds_text(fmdev, rds_text);
++
++ /* Set RDS mode */
++ set_rds_data_mode(fmdev, 0x0);
++
++ payload = 1;
++ ret = fmc_send_cmd(fmdev, RDS_DATA_ENB, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++u32 fm_tx_set_af(struct fmdev *fmdev, u32 af)
++{
++ u16 payload;
++ u32 ret;
++
++ if (fmdev->curr_fmmode != FM_MODE_TX)
++ return -EPERM;
++
++ fmdbg("AF: %d\n", af);
++
++ af = (af - 87500) / 100;
++ payload = (u16)af;
++ ret = fmc_send_cmd(fmdev, TA_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++u32 fm_tx_set_region(struct fmdev *fmdev, u8 region)
++{
++ u16 payload;
++ u32 ret;
++
++ if (region != FM_BAND_EUROPE_US && region != FM_BAND_JAPAN) {
++ fmerr("Invalid band\n");
++ return -EINVAL;
++ }
++
++ /* Send command to set the band */
++ payload = (u16)region;
++ ret = fmc_send_cmd(fmdev, TX_BAND_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++u32 fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
++{
++ u16 payload;
++ u32 ret;
++
++ fmdbg("tx: mute mode %d\n", mute_mode_toset);
++
++ payload = mute_mode_toset;
++ ret = fmc_send_cmd(fmdev, MUTE, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++/* Set TX Audio I/O */
++static u32 set_audio_io(struct fmdev *fmdev)
++{
++ struct fmtx_data *tx = &fmdev->tx_data;
++ u16 payload;
++ u32 ret;
++
++ /* Set Audio I/O Enable */
++ payload = tx->audio_io;
++ ret = fmc_send_cmd(fmdev, AUDIO_IO_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* TODO: is audio set? */
++ return 0;
++}
++
++/* Start TX Transmission */
++static u32 enable_xmit(struct fmdev *fmdev, u8 new_xmit_state)
++{
++ struct fmtx_data *tx = &fmdev->tx_data;
++ unsigned long timeleft;
++ u16 payload;
++ u32 ret;
++
++ /* Enable POWER_ENB interrupts */
++ payload = FM_POW_ENB_EVENT;
++ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* Set Power Enable */
++ payload = new_xmit_state;
++ ret = fmc_send_cmd(fmdev, POWER_ENB_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* Wait for Power Enabled */
++ init_completion(&fmdev->maintask_comp);
++ timeleft = wait_for_completion_timeout(&fmdev->maintask_comp,
++ FM_DRV_TX_TIMEOUT);
++ if (!timeleft) {
++ fmerr("Timeout(%d sec),didn't get tune ended interrupt\n",
++ jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
++ return -ETIMEDOUT;
++ }
++
++ set_bit(FM_CORE_TX_XMITING, &fmdev->flag);
++ tx->xmit_state = new_xmit_state;
++
++ return 0;
++}
++
++/* Set TX power level */
++u32 fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl)
++{
++ u16 payload;
++ struct fmtx_data *tx = &fmdev->tx_data;
++ u32 ret;
++
++ if (fmdev->curr_fmmode != FM_MODE_TX)
++ return -EPERM;
++ fmdbg("tx: pwr_level_to_set %ld\n", (long int)new_pwr_lvl);
++
++ /* If the core isn't ready update global variable */
++ if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
++ tx->pwr_lvl = new_pwr_lvl;
++ return 0;
++ }
++
++ /* Set power level: Application will specify power level value in
++ * units of dB/uV, whereas range and step are specific to FM chip.
++ * For TI's WL chips, convert application specified power level value
++ * to chip specific value by subtracting 122 from it. Refer to TI FM
++ * data sheet for details.
++ * */
++
++ payload = (FM_PWR_LVL_HIGH - new_pwr_lvl);
++ ret = fmc_send_cmd(fmdev, POWER_LEV_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ /* TODO: is the power level set? */
++ tx->pwr_lvl = new_pwr_lvl;
++
++ return 0;
++}
++
++/*
++ * Sets FM TX pre-emphasis filter value (OFF, 50us, or 75us)
++ * Convert V4L2 specified filter values to chip specific filter values.
++ */
++u32 fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis)
++{
++ struct fmtx_data *tx = &fmdev->tx_data;
++ u16 payload;
++ u32 ret;
++
++ if (fmdev->curr_fmmode != FM_MODE_TX)
++ return -EPERM;
++
++ switch (preemphasis) {
++ case V4L2_PREEMPHASIS_DISABLED:
++ payload = FM_TX_PREEMPH_OFF;
++ break;
++ case V4L2_PREEMPHASIS_50_uS:
++ payload = FM_TX_PREEMPH_50US;
++ break;
++ case V4L2_PREEMPHASIS_75_uS:
++ payload = FM_TX_PREEMPH_75US;
++ break;
++ }
++
++ ret = fmc_send_cmd(fmdev, PREMPH_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ tx->preemph = payload;
++
++ return ret;
++}
++
++/* Get the TX tuning capacitor value.*/
++u32 fm_tx_get_tune_cap_val(struct fmdev *fmdev)
++{
++ u16 curr_val;
++ u32 ret, resp_len;
++
++ if (fmdev->curr_fmmode != FM_MODE_TX)
++ return -EPERM;
++
++ ret = fmc_send_cmd(fmdev, READ_FMANT_TUNE_VALUE, REG_RD,
++ NULL, sizeof(curr_val), &curr_val, &resp_len);
++ if (ret < 0)
++ return ret;
++
++ curr_val = be16_to_cpu(curr_val);
++
++ return curr_val;
++}
++
++/* Set TX Frequency */
++u32 fm_tx_set_freq(struct fmdev *fmdev, u32 freq_to_set)
++{
++ struct fmtx_data *tx = &fmdev->tx_data;
++ u16 payload, chanl_index;
++ u32 ret;
++
++ if (test_bit(FM_CORE_TX_XMITING, &fmdev->flag)) {
++ enable_xmit(fmdev, 0);
++ clear_bit(FM_CORE_TX_XMITING, &fmdev->flag);
++ }
++
++ /* Enable FR, BL interrupts */
++ payload = (FM_FR_EVENT | FM_BL_EVENT);
++ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ tx->tx_frq = (unsigned long)freq_to_set;
++ fmdbg("tx: freq_to_set %ld\n", (long int)tx->tx_frq);
++
++ chanl_index = freq_to_set / 10;
++
++ /* Set current tuner channel */
++ payload = chanl_index;
++ ret = fmc_send_cmd(fmdev, CHANL_SET, REG_WR, &payload,
++ sizeof(payload), NULL, NULL);
++ if (ret < 0)
++ return ret;
++
++ fm_tx_set_pwr_lvl(fmdev, tx->pwr_lvl);
++ fm_tx_set_preemph_filter(fmdev, tx->preemph);
++
++ tx->audio_io = 0x01; /* I2S */
++ set_audio_io(fmdev);
++
++ enable_xmit(fmdev, 0x01); /* Enable transmission */
++
++ tx->aud_mode = FM_STEREO_MODE;
++ tx->rds.flag = FM_RDS_DISABLE;
++
++ return 0;
++}
++
+diff --git a/drivers/media/radio/wl128x/fmdrv_tx.h b/drivers/media/radio/wl128x/fmdrv_tx.h
+new file mode 100644
+index 0000000..e393a2b
+--- /dev/null
++++ b/drivers/media/radio/wl128x/fmdrv_tx.h
+@@ -0,0 +1,37 @@
++/*
++ * FM Driver for Connectivity chip of Texas Instruments.
++ * FM TX module header.
++ *
++ * Copyright (C) 2011 Texas Instruments
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#ifndef _FMDRV_TX_H
++#define _FMDRV_TX_H
++
++u32 fm_tx_set_freq(struct fmdev *, u32);
++u32 fm_tx_set_pwr_lvl(struct fmdev *, u8);
++u32 fm_tx_set_region(struct fmdev *, u8);
++u32 fm_tx_set_mute_mode(struct fmdev *, u8);
++u32 fm_tx_set_stereo_mono(struct fmdev *, u16);
++u32 fm_tx_set_rds_mode(struct fmdev *, u8);
++u32 fm_tx_set_radio_text(struct fmdev *, u8 *, u8);
++u32 fm_tx_set_af(struct fmdev *, u32);
++u32 fm_tx_set_preemph_filter(struct fmdev *, u32);
++u32 fm_tx_get_tune_cap_val(struct fmdev *);
++
++#endif
++
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/wl1271/0012-drivers-media-radio-wl128x-Kconfig-Makefile-for-wl12.patch b/extras/recipes-kernel/linux/linux-omap/wl1271/0012-drivers-media-radio-wl128x-Kconfig-Makefile-for-wl12.patch
new file mode 100644
index 00000000..2e5fda86
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/wl1271/0012-drivers-media-radio-wl128x-Kconfig-Makefile-for-wl12.patch
@@ -0,0 +1,52 @@
+From 949d2c98bb76cc321e5ef5a96a632d831e5953bf Mon Sep 17 00:00:00 2001
+From: Manjunatha Halli <manjunatha_halli@ti.com>
+Date: Tue, 11 Jan 2011 11:31:26 +0000
+Subject: [PATCH 12/15] drivers:media:radio: wl128x: Kconfig & Makefile for wl128x driver
+
+Signed-off-by: Manjunatha Halli <manjunatha_halli@ti.com>
+Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
+---
+ drivers/media/radio/wl128x/Kconfig | 17 +++++++++++++++++
+ drivers/media/radio/wl128x/Makefile | 6 ++++++
+ 2 files changed, 23 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/media/radio/wl128x/Kconfig
+ create mode 100644 drivers/media/radio/wl128x/Makefile
+
+diff --git a/drivers/media/radio/wl128x/Kconfig b/drivers/media/radio/wl128x/Kconfig
+new file mode 100644
+index 0000000..749f67b
+--- /dev/null
++++ b/drivers/media/radio/wl128x/Kconfig
+@@ -0,0 +1,17 @@
++#
++# TI's wl128x FM driver based on TI's ST driver.
++#
++menu "Texas Instruments WL128x FM driver (ST based)"
++config RADIO_WL128X
++ tristate "Texas Instruments WL128x FM Radio"
++ depends on VIDEO_V4L2 && RFKILL
++ select TI_ST
++ help
++ Choose Y here if you have this FM radio chip.
++
++ In order to control your radio card, you will need to use programs
++ that are compatible with the Video For Linux 2 API. Information on
++ this API and pointers to "v4l2" programs may be found at
++ <file:Documentation/video4linux/API.html>.
++
++endmenu
+diff --git a/drivers/media/radio/wl128x/Makefile b/drivers/media/radio/wl128x/Makefile
+new file mode 100644
+index 0000000..32a0ead
+--- /dev/null
++++ b/drivers/media/radio/wl128x/Makefile
+@@ -0,0 +1,6 @@
++#
++# Makefile for TI's shared transport driver based wl128x
++# FM radio.
++#
++obj-$(CONFIG_RADIO_WL128X) += fm_drv.o
++fm_drv-objs := fmdrv_common.o fmdrv_rx.o fmdrv_tx.o fmdrv_v4l2.o
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/wl1271/0013-drivers-media-radio-Update-Kconfig-and-Makefile-for-.patch b/extras/recipes-kernel/linux/linux-omap/wl1271/0013-drivers-media-radio-Update-Kconfig-and-Makefile-for-.patch
new file mode 100644
index 00000000..ea257a43
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/wl1271/0013-drivers-media-radio-Update-Kconfig-and-Makefile-for-.patch
@@ -0,0 +1,38 @@
+From 340d2fa4ff21c43309e70cc6b4a88f9ee6c23d95 Mon Sep 17 00:00:00 2001
+From: Manjunatha Halli <manjunatha_halli@ti.com>
+Date: Tue, 11 Jan 2011 11:31:27 +0000
+Subject: [PATCH 13/15] drivers:media:radio: Update Kconfig and Makefile for wl128x FM driver.
+
+Signed-off-by: Manjunatha Halli <manjunatha_halli@ti.com>
+Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
+---
+ drivers/media/radio/Kconfig | 3 +++
+ drivers/media/radio/Makefile | 1 +
+ 2 files changed, 4 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
+index 83567b8..4529bc7 100644
+--- a/drivers/media/radio/Kconfig
++++ b/drivers/media/radio/Kconfig
+@@ -452,4 +452,7 @@ config RADIO_TIMBERDALE
+ found behind the Timberdale FPGA on the Russellville board.
+ Enabling this driver will automatically select the DSP and tuner.
+
++# TI's ST based wl128x FM radio
++source "drivers/media/radio/wl128x/Kconfig"
++
+ endif # RADIO_ADAPTERS
+diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
+index f615583..b71f448 100644
+--- a/drivers/media/radio/Makefile
++++ b/drivers/media/radio/Makefile
+@@ -26,5 +26,6 @@ obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o
+ obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o
+ obj-$(CONFIG_RADIO_TEF6862) += tef6862.o
+ obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o
++obj-$(CONFIG_RADIO_WL128X) += wl128x/
+
+ EXTRA_CFLAGS += -Isound
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/wl1271/0014-drivers-misc-ti-st-change-protocol-parse-logic.patch b/extras/recipes-kernel/linux/linux-omap/wl1271/0014-drivers-misc-ti-st-change-protocol-parse-logic.patch
new file mode 100644
index 00000000..c16dc453
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/wl1271/0014-drivers-misc-ti-st-change-protocol-parse-logic.patch
@@ -0,0 +1,900 @@
+From 46b2c4077bedb96a38cdceff88f2c9b0a9923a8c Mon Sep 17 00:00:00 2001
+From: Pavan Savoy <pavan_savoy@ti.com>
+Date: Tue, 4 Jan 2011 10:59:47 +0000
+Subject: [PATCH 14/15] drivers:misc:ti-st: change protocol parse logic
+
+TI shared transport driver had to specifically know the
+protocol headers for each type of data it can receive to
+properly re-assemble data if its fragmented during UART
+transaction or fragment if the data is an assembly of
+
+different protocol data.
+
+Now the individual protocol drivers provide enough header
+information for shared transport driver to do this in a
+generic way applicable for all protocols.
+
+Signed-off-by: Pavan Savoy <pavan_savoy@ti.com>
+---
+ drivers/misc/ti-st/st_core.c | 355 +++++++++++++-----------------------------
+ drivers/misc/ti-st/st_kim.c | 56 ++++----
+ include/linux/ti_wilink_st.h | 40 ++++--
+ 3 files changed, 167 insertions(+), 284 deletions(-)
+
+diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
+index f9aad06..84d73c5 100644
+--- a/drivers/misc/ti-st/st_core.c
++++ b/drivers/misc/ti-st/st_core.c
+@@ -25,10 +25,9 @@
+ #include <linux/init.h>
+ #include <linux/tty.h>
+
+-/* understand BT, FM and GPS for now */
+-#include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/hci_core.h>
+-#include <net/bluetooth/hci.h>
++#include <linux/seq_file.h>
++#include <linux/skbuff.h>
++
+ #include <linux/ti_wilink_st.h>
+
+ /* function pointer pointing to either,
+@@ -38,21 +37,20 @@
+ void (*st_recv) (void*, const unsigned char*, long);
+
+ /********************************************************************/
+-#if 0
+-/* internal misc functions */
+-bool is_protocol_list_empty(void)
++static void add_channel_to_table(struct st_data_s *st_gdata,
++ struct st_proto_s *new_proto)
+ {
+- unsigned char i = 0;
+- pr_debug(" %s ", __func__);
+- for (i = 0; i < ST_MAX; i++) {
+- if (st_gdata->list[i] != NULL)
+- return ST_NOTEMPTY;
+- /* not empty */
+- }
+- /* list empty */
+- return ST_EMPTY;
++ pr_info("%s: id %d\n", __func__, new_proto->chnl_id);
++ /* list now has the channel id as index itself */
++ st_gdata->list[new_proto->chnl_id] = new_proto;
++}
++
++static void remove_channel_from_table(struct st_data_s *st_gdata,
++ struct st_proto_s *proto)
++{
++ pr_info("%s: id %d\n", __func__, proto->chnl_id);
++ st_gdata->list[proto->chnl_id] = NULL;
+ }
+-#endif
+
+ /* can be called in from
+ * -- KIM (during fw download)
+@@ -82,15 +80,15 @@ int st_int_write(struct st_data_s *st_gdata,
+ * push the skb received to relevant
+ * protocol stacks
+ */
+-void st_send_frame(enum proto_type protoid, struct st_data_s *st_gdata)
++void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata)
+ {
+- pr_info(" %s(prot:%d) ", __func__, protoid);
++ pr_info(" %s(prot:%d) ", __func__, chnl_id);
+
+ if (unlikely
+ (st_gdata == NULL || st_gdata->rx_skb == NULL
+- || st_gdata->list[protoid] == NULL)) {
+- pr_err("protocol %d not registered, no data to send?",
+- protoid);
++ || st_gdata->list[chnl_id] == NULL)) {
++ pr_err("chnl_id %d not registered, no data to send?",
++ chnl_id);
+ kfree_skb(st_gdata->rx_skb);
+ return;
+ }
+@@ -99,17 +97,17 @@ void st_send_frame(enum proto_type protoid, struct st_data_s *st_gdata)
+ * - should be just skb_queue_tail for the
+ * protocol stack driver
+ */
+- if (likely(st_gdata->list[protoid]->recv != NULL)) {
++ if (likely(st_gdata->list[chnl_id]->recv != NULL)) {
+ if (unlikely
+- (st_gdata->list[protoid]->recv
+- (st_gdata->list[protoid]->priv_data, st_gdata->rx_skb)
++ (st_gdata->list[chnl_id]->recv
++ (st_gdata->list[chnl_id]->priv_data, st_gdata->rx_skb)
+ != 0)) {
+- pr_err(" proto stack %d's ->recv failed", protoid);
++ pr_err(" proto stack %d's ->recv failed", chnl_id);
+ kfree_skb(st_gdata->rx_skb);
+ return;
+ }
+ } else {
+- pr_err(" proto stack %d's ->recv null", protoid);
++ pr_err(" proto stack %d's ->recv null", chnl_id);
+ kfree_skb(st_gdata->rx_skb);
+ }
+ return;
+@@ -124,7 +122,7 @@ void st_reg_complete(struct st_data_s *st_gdata, char err)
+ {
+ unsigned char i = 0;
+ pr_info(" %s ", __func__);
+- for (i = 0; i < ST_MAX; i++) {
++ for (i = 0; i < ST_MAX_CHANNELS; i++) {
+ if (likely(st_gdata != NULL && st_gdata->list[i] != NULL &&
+ st_gdata->list[i]->reg_complete_cb != NULL))
+ st_gdata->list[i]->reg_complete_cb
+@@ -133,7 +131,7 @@ void st_reg_complete(struct st_data_s *st_gdata, char err)
+ }
+
+ static inline int st_check_data_len(struct st_data_s *st_gdata,
+- int protoid, int len)
++ unsigned char chnl_id, int len)
+ {
+ int room = skb_tailroom(st_gdata->rx_skb);
+
+@@ -144,7 +142,7 @@ static inline int st_check_data_len(struct st_data_s *st_gdata,
+ * has zero length payload. So, ask ST CORE to
+ * forward the packet to protocol driver (BT/FM/GPS)
+ */
+- st_send_frame(protoid, st_gdata);
++ st_send_frame(chnl_id, st_gdata);
+
+ } else if (len > room) {
+ /* Received packet's payload length is larger.
+@@ -157,7 +155,7 @@ static inline int st_check_data_len(struct st_data_s *st_gdata,
+ /* Packet header has non-zero payload length and
+ * we have enough space in created skb. Lets read
+ * payload data */
+- st_gdata->rx_state = ST_BT_W4_DATA;
++ st_gdata->rx_state = ST_W4_DATA;
+ st_gdata->rx_count = len;
+ return len;
+ }
+@@ -167,6 +165,7 @@ static inline int st_check_data_len(struct st_data_s *st_gdata,
+ st_gdata->rx_state = ST_W4_PACKET_TYPE;
+ st_gdata->rx_skb = NULL;
+ st_gdata->rx_count = 0;
++ st_gdata->rx_chnl = 0;
+
+ return 0;
+ }
+@@ -208,13 +207,10 @@ void st_int_recv(void *disc_data,
+ const unsigned char *data, long count)
+ {
+ char *ptr;
+- struct hci_event_hdr *eh;
+- struct hci_acl_hdr *ah;
+- struct hci_sco_hdr *sh;
+- struct fm_event_hdr *fm;
+- struct gps_event_hdr *gps;
+- int len = 0, type = 0, dlen = 0;
+- static enum proto_type protoid = ST_MAX;
++ struct st_proto_s *proto;
++ unsigned short payload_len = 0;
++ int len = 0, type = 0;
++ unsigned char *plen;
+ struct st_data_s *st_gdata = (struct st_data_s *)disc_data;
+
+ ptr = (char *)data;
+@@ -242,64 +238,36 @@ void st_int_recv(void *disc_data,
+
+ /* Check ST RX state machine , where are we? */
+ switch (st_gdata->rx_state) {
+-
+- /* Waiting for complete packet ? */
+- case ST_BT_W4_DATA:
++ /* Waiting for complete packet ? */
++ case ST_W4_DATA:
+ pr_debug("Complete pkt received");
+-
+ /* Ask ST CORE to forward
+ * the packet to protocol driver */
+- st_send_frame(protoid, st_gdata);
++ st_send_frame(st_gdata->rx_chnl, st_gdata);
+
+ st_gdata->rx_state = ST_W4_PACKET_TYPE;
+ st_gdata->rx_skb = NULL;
+- protoid = ST_MAX; /* is this required ? */
+- continue;
+-
+- /* Waiting for Bluetooth event header ? */
+- case ST_BT_W4_EVENT_HDR:
+- eh = (struct hci_event_hdr *)st_gdata->rx_skb->
+- data;
+-
+- pr_debug("Event header: evt 0x%2.2x"
+- "plen %d", eh->evt, eh->plen);
+-
+- st_check_data_len(st_gdata, protoid, eh->plen);
+- continue;
+-
+- /* Waiting for Bluetooth acl header ? */
+- case ST_BT_W4_ACL_HDR:
+- ah = (struct hci_acl_hdr *)st_gdata->rx_skb->
+- data;
+- dlen = __le16_to_cpu(ah->dlen);
+-
+- pr_info("ACL header: dlen %d", dlen);
+-
+- st_check_data_len(st_gdata, protoid, dlen);
+- continue;
+-
+- /* Waiting for Bluetooth sco header ? */
+- case ST_BT_W4_SCO_HDR:
+- sh = (struct hci_sco_hdr *)st_gdata->rx_skb->
+- data;
+-
+- pr_info("SCO header: dlen %d", sh->dlen);
+-
+- st_check_data_len(st_gdata, protoid, sh->dlen);
+- continue;
+- case ST_FM_W4_EVENT_HDR:
+- fm = (struct fm_event_hdr *)st_gdata->rx_skb->
+- data;
+- pr_info("FM Header: ");
+- st_check_data_len(st_gdata, ST_FM, fm->plen);
+ continue;
+- /* TODO : Add GPS packet machine logic here */
+- case ST_GPS_W4_EVENT_HDR:
+- /* [0x09 pkt hdr][R/W byte][2 byte len] */
+- gps = (struct gps_event_hdr *)st_gdata->rx_skb->
+- data;
+- pr_info("GPS Header: ");
+- st_check_data_len(st_gdata, ST_GPS, gps->plen);
++ /* parse the header to know details */
++ case ST_W4_HEADER:
++ proto = st_gdata->list[st_gdata->rx_chnl];
++ plen =
++ &st_gdata->rx_skb->data
++ [proto->offset_len_in_hdr];
++ pr_info("plen pointing to %x\n", *plen);
++ if (proto->len_size == 1)/* 1 byte len field */
++ payload_len = *(unsigned char *)plen;
++ else if (proto->len_size == 2)
++ payload_len =
++ __le16_to_cpu(*(unsigned short *)plen);
++ else
++ pr_info("%s: invalid length "
++ "for id %d\n",
++ __func__, proto->chnl_id);
++ st_check_data_len(st_gdata, proto->chnl_id,
++ payload_len);
++ pr_info("off %d, pay len %d\n",
++ proto->offset_len_in_hdr, payload_len);
+ continue;
+ } /* end of switch rx_state */
+ }
+@@ -308,51 +276,6 @@ void st_int_recv(void *disc_data,
+ /* Check first byte of packet and identify module
+ * owner (BT/FM/GPS) */
+ switch (*ptr) {
+-
+- /* Bluetooth event packet? */
+- case HCI_EVENT_PKT:
+- pr_info("Event packet");
+- st_gdata->rx_state = ST_BT_W4_EVENT_HDR;
+- st_gdata->rx_count = HCI_EVENT_HDR_SIZE;
+- type = HCI_EVENT_PKT;
+- protoid = ST_BT;
+- break;
+-
+- /* Bluetooth acl packet? */
+- case HCI_ACLDATA_PKT:
+- pr_info("ACL packet");
+- st_gdata->rx_state = ST_BT_W4_ACL_HDR;
+- st_gdata->rx_count = HCI_ACL_HDR_SIZE;
+- type = HCI_ACLDATA_PKT;
+- protoid = ST_BT;
+- break;
+-
+- /* Bluetooth sco packet? */
+- case HCI_SCODATA_PKT:
+- pr_info("SCO packet");
+- st_gdata->rx_state = ST_BT_W4_SCO_HDR;
+- st_gdata->rx_count = HCI_SCO_HDR_SIZE;
+- type = HCI_SCODATA_PKT;
+- protoid = ST_BT;
+- break;
+-
+- /* Channel 8(FM) packet? */
+- case ST_FM_CH8_PKT:
+- pr_info("FM CH8 packet");
+- type = ST_FM_CH8_PKT;
+- st_gdata->rx_state = ST_FM_W4_EVENT_HDR;
+- st_gdata->rx_count = FM_EVENT_HDR_SIZE;
+- protoid = ST_FM;
+- break;
+-
+- /* Channel 9(GPS) packet? */
+- case 0x9: /*ST_LL_GPS_CH9_PKT */
+- pr_info("GPS CH9 packet");
+- type = 0x9; /* ST_LL_GPS_CH9_PKT; */
+- protoid = ST_GPS;
+- st_gdata->rx_state = ST_GPS_W4_EVENT_HDR;
+- st_gdata->rx_count = 3; /* GPS_EVENT_HDR_SIZE -1*/
+- break;
+ case LL_SLEEP_IND:
+ case LL_SLEEP_ACK:
+ case LL_WAKE_UP_IND:
+@@ -373,57 +296,22 @@ void st_int_recv(void *disc_data,
+ continue;
+ /* Unknow packet? */
+ default:
+- pr_err("Unknown packet type %2.2x", (__u8) *ptr);
+- ptr++;
+- count--;
+- continue;
++ type = *ptr;
++ st_gdata->rx_skb = alloc_skb(
++ st_gdata->list[type]->max_frame_size,
++ GFP_ATOMIC);
++ skb_reserve(st_gdata->rx_skb,
++ st_gdata->list[type]->reserve);
++ /* next 2 required for BT only */
++ st_gdata->rx_skb->cb[0] = type; /*pkt_type*/
++ st_gdata->rx_skb->cb[1] = 0; /*incoming*/
++ st_gdata->rx_chnl = *ptr;
++ st_gdata->rx_state = ST_W4_HEADER;
++ st_gdata->rx_count = st_gdata->list[type]->hdr_len;
++ pr_info("rx_count %ld\n", st_gdata->rx_count);
+ };
+ ptr++;
+ count--;
+-
+- switch (protoid) {
+- case ST_BT:
+- /* Allocate new packet to hold received data */
+- st_gdata->rx_skb =
+- bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+- if (!st_gdata->rx_skb) {
+- pr_err("Can't allocate mem for new packet");
+- st_gdata->rx_state = ST_W4_PACKET_TYPE;
+- st_gdata->rx_count = 0;
+- return;
+- }
+- bt_cb(st_gdata->rx_skb)->pkt_type = type;
+- break;
+- case ST_FM: /* for FM */
+- st_gdata->rx_skb =
+- alloc_skb(FM_MAX_FRAME_SIZE, GFP_ATOMIC);
+- if (!st_gdata->rx_skb) {
+- pr_err("Can't allocate mem for new packet");
+- st_gdata->rx_state = ST_W4_PACKET_TYPE;
+- st_gdata->rx_count = 0;
+- return;
+- }
+- /* place holder 0x08 */
+- skb_reserve(st_gdata->rx_skb, 1);
+- st_gdata->rx_skb->cb[0] = ST_FM_CH8_PKT;
+- break;
+- case ST_GPS:
+- /* for GPS */
+- st_gdata->rx_skb =
+- alloc_skb(100 /*GPS_MAX_FRAME_SIZE */ , GFP_ATOMIC);
+- if (!st_gdata->rx_skb) {
+- pr_err("Can't allocate mem for new packet");
+- st_gdata->rx_state = ST_W4_PACKET_TYPE;
+- st_gdata->rx_count = 0;
+- return;
+- }
+- /* place holder 0x09 */
+- skb_reserve(st_gdata->rx_skb, 1);
+- st_gdata->rx_skb->cb[0] = 0x09; /*ST_GPS_CH9_PKT; */
+- break;
+- case ST_MAX:
+- break;
+- }
+ }
+ pr_debug("done %s", __func__);
+ return;
+@@ -565,20 +453,28 @@ long st_register(struct st_proto_s *new_proto)
+ unsigned long flags = 0;
+
+ st_kim_ref(&st_gdata, 0);
+- pr_info("%s(%d) ", __func__, new_proto->type);
++ pr_info("%s(%d) ", __func__, new_proto->chnl_id);
+ if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL
+ || new_proto->reg_complete_cb == NULL) {
+ pr_err("gdata/new_proto/recv or reg_complete_cb not ready");
++ if (st_gdata == NULL)
++ pr_err("error 1\n");
++ if (new_proto == NULL)
++ pr_err("error 2\n");
++ if (new_proto->recv == NULL)
++ pr_err("error 3\n");
++ if (new_proto->reg_complete_cb == NULL)
++ pr_err("erro 4\n");
+ return -1;
+ }
+
+- if (new_proto->type < ST_BT || new_proto->type >= ST_MAX) {
+- pr_err("protocol %d not supported", new_proto->type);
++ if (new_proto->chnl_id >= ST_MAX_CHANNELS) {
++ pr_err("chnl_id %d not supported", new_proto->chnl_id);
+ return -EPROTONOSUPPORT;
+ }
+
+- if (st_gdata->list[new_proto->type] != NULL) {
+- pr_err("protocol %d already registered", new_proto->type);
++ if (st_gdata->list[new_proto->chnl_id] != NULL) {
++ pr_err("chnl_id %d already registered", new_proto->chnl_id);
+ return -EALREADY;
+ }
+
+@@ -586,11 +482,11 @@ long st_register(struct st_proto_s *new_proto)
+ spin_lock_irqsave(&st_gdata->lock, flags);
+
+ if (test_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state)) {
+- pr_info(" ST_REG_IN_PROGRESS:%d ", new_proto->type);
++ pr_info(" ST_REG_IN_PROGRESS:%d ", new_proto->chnl_id);
+ /* fw download in progress */
+- st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
++ st_kim_chip_toggle(new_proto->chnl_id, KIM_GPIO_ACTIVE);
+
+- st_gdata->list[new_proto->type] = new_proto;
++ add_channel_to_table(st_gdata, new_proto);
+ st_gdata->protos_registered++;
+ new_proto->write = st_write;
+
+@@ -598,7 +494,7 @@ long st_register(struct st_proto_s *new_proto)
+ spin_unlock_irqrestore(&st_gdata->lock, flags);
+ return -EINPROGRESS;
+ } else if (st_gdata->protos_registered == ST_EMPTY) {
+- pr_info(" protocol list empty :%d ", new_proto->type);
++ pr_info(" chnl_id list empty :%d ", new_proto->chnl_id);
+ set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
+ st_recv = st_kim_recv;
+
+@@ -622,9 +518,9 @@ long st_register(struct st_proto_s *new_proto)
+ return -1;
+ }
+
+- /* the protocol might require other gpios to be toggled
++ /* the chnl_id might require other gpios to be toggled
+ */
+- st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
++ st_kim_chip_toggle(new_proto->chnl_id, KIM_GPIO_ACTIVE);
+
+ clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
+ st_recv = st_int_recv;
+@@ -642,14 +538,14 @@ long st_register(struct st_proto_s *new_proto)
+ /* check for already registered once more,
+ * since the above check is old
+ */
+- if (st_gdata->list[new_proto->type] != NULL) {
++ if (st_gdata->list[new_proto->chnl_id] != NULL) {
+ pr_err(" proto %d already registered ",
+- new_proto->type);
++ new_proto->chnl_id);
+ return -EALREADY;
+ }
+
+ spin_lock_irqsave(&st_gdata->lock, flags);
+- st_gdata->list[new_proto->type] = new_proto;
++ add_channel_to_table(st_gdata, new_proto);
+ st_gdata->protos_registered++;
+ new_proto->write = st_write;
+ spin_unlock_irqrestore(&st_gdata->lock, flags);
+@@ -657,22 +553,7 @@ long st_register(struct st_proto_s *new_proto)
+ }
+ /* if fw is already downloaded & new stack registers protocol */
+ else {
+- switch (new_proto->type) {
+- case ST_BT:
+- /* do nothing */
+- break;
+- case ST_FM:
+- case ST_GPS:
+- st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
+- break;
+- case ST_MAX:
+- default:
+- pr_err("%d protocol not supported",
+- new_proto->type);
+- spin_unlock_irqrestore(&st_gdata->lock, flags);
+- return -EPROTONOSUPPORT;
+- }
+- st_gdata->list[new_proto->type] = new_proto;
++ add_channel_to_table(st_gdata, new_proto);
+ st_gdata->protos_registered++;
+ new_proto->write = st_write;
+
+@@ -680,48 +561,48 @@ long st_register(struct st_proto_s *new_proto)
+ spin_unlock_irqrestore(&st_gdata->lock, flags);
+ return err;
+ }
+- pr_debug("done %s(%d) ", __func__, new_proto->type);
++ pr_debug("done %s(%d) ", __func__, new_proto->chnl_id);
+ }
+ EXPORT_SYMBOL_GPL(st_register);
+
+ /* to unregister a protocol -
+ * to be called from protocol stack driver
+ */
+-long st_unregister(enum proto_type type)
++long st_unregister(struct st_proto_s *proto)
+ {
+ long err = 0;
+ unsigned long flags = 0;
+ struct st_data_s *st_gdata;
+
+- pr_debug("%s: %d ", __func__, type);
++ pr_debug("%s: %d ", __func__, proto->chnl_id);
+
+ st_kim_ref(&st_gdata, 0);
+- if (type < ST_BT || type >= ST_MAX) {
+- pr_err(" protocol %d not supported", type);
++ if (proto->chnl_id >= ST_MAX_CHANNELS) {
++ pr_err(" chnl_id %d not supported", proto->chnl_id);
+ return -EPROTONOSUPPORT;
+ }
+
+ spin_lock_irqsave(&st_gdata->lock, flags);
+
+- if (st_gdata->list[type] == NULL) {
+- pr_err(" protocol %d not registered", type);
++ if (st_gdata->list[proto->chnl_id] == NULL) {
++ pr_err(" chnl_id %d not registered", proto->chnl_id);
+ spin_unlock_irqrestore(&st_gdata->lock, flags);
+ return -EPROTONOSUPPORT;
+ }
+
+ st_gdata->protos_registered--;
+- st_gdata->list[type] = NULL;
++ remove_channel_from_table(st_gdata, proto);
+
+ /* kim ignores BT in the below function
+ * and handles the rest, BT is toggled
+ * only in kim_start and kim_stop
+ */
+- st_kim_chip_toggle(type, KIM_GPIO_INACTIVE);
++ st_kim_chip_toggle(proto->chnl_id, KIM_GPIO_INACTIVE);
+ spin_unlock_irqrestore(&st_gdata->lock, flags);
+
+ if ((st_gdata->protos_registered == ST_EMPTY) &&
+ (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
+- pr_info(" all protocols unregistered ");
++ pr_info(" all chnl_ids unregistered ");
+
+ /* stop traffic on tty */
+ if (st_gdata->tty) {
+@@ -729,7 +610,7 @@ long st_unregister(enum proto_type type)
+ stop_tty(st_gdata->tty);
+ }
+
+- /* all protocols now unregistered */
++ /* all chnl_ids now unregistered */
+ st_kim_stop(st_gdata->kim_data);
+ /* disable ST LL */
+ st_ll_disable(st_gdata);
+@@ -745,7 +626,7 @@ long st_write(struct sk_buff *skb)
+ {
+ struct st_data_s *st_gdata;
+ #ifdef DEBUG
+- enum proto_type protoid = ST_MAX;
++ unsigned char chnl_id = ST_MAX_CHANNELS;
+ #endif
+ long len;
+
+@@ -756,22 +637,10 @@ long st_write(struct sk_buff *skb)
+ return -1;
+ }
+ #ifdef DEBUG /* open-up skb to read the 1st byte */
+- switch (skb->data[0]) {
+- case HCI_COMMAND_PKT:
+- case HCI_ACLDATA_PKT:
+- case HCI_SCODATA_PKT:
+- protoid = ST_BT;
+- break;
+- case ST_FM_CH8_PKT:
+- protoid = ST_FM;
+- break;
+- case 0x09:
+- protoid = ST_GPS;
+- break;
+- }
+- if (unlikely(st_gdata->list[protoid] == NULL)) {
+- pr_err(" protocol %d not registered, and writing? ",
+- protoid);
++ chnl_id = skb->data[0];
++ if (unlikely(st_gdata->list[chnl_id] == NULL)) {
++ pr_err(" chnl_id %d not registered, and writing? ",
++ chnl_id);
+ return -1;
+ }
+ #endif
+@@ -824,7 +693,7 @@ static int st_tty_open(struct tty_struct *tty)
+
+ static void st_tty_close(struct tty_struct *tty)
+ {
+- unsigned char i = ST_MAX;
++ unsigned char i = ST_MAX_CHANNELS;
+ unsigned long flags = 0;
+ struct st_data_s *st_gdata = tty->disc_data;
+
+@@ -835,7 +704,7 @@ static void st_tty_close(struct tty_struct *tty)
+ * un-installed for some reason - what should be done ?
+ */
+ spin_lock_irqsave(&st_gdata->lock, flags);
+- for (i = ST_BT; i < ST_MAX; i++) {
++ for (i = ST_BT; i < ST_MAX_CHANNELS; i++) {
+ if (st_gdata->list[i] != NULL)
+ pr_err("%d not un-registered", i);
+ st_gdata->list[i] = NULL;
+@@ -869,7 +738,7 @@ static void st_tty_close(struct tty_struct *tty)
+ static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
+ char *tty_flags, int count)
+ {
+-
++#define VERBOSE
+ #ifdef VERBOSE
+ print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE,
+ 16, 1, data, count, 0);
+diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c
+index 73b6c8b..707c858 100644
+--- a/drivers/misc/ti-st/st_kim.c
++++ b/drivers/misc/ti-st/st_kim.c
+@@ -32,11 +32,7 @@
+ #include <linux/sched.h>
+ #include <linux/rfkill.h>
+
+-/* understand BT events for fw response */
+-#include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/hci_core.h>
+-#include <net/bluetooth/hci.h>
+-
++#include <linux/skbuff.h>
+ #include <linux/ti_wilink_st.h>
+
+
+@@ -134,7 +130,7 @@ static inline int kim_check_data_len(struct kim_data_s *kim_gdata, int len)
+ /* Packet header has non-zero payload length and
+ * we have enough space in created skb. Lets read
+ * payload data */
+- kim_gdata->rx_state = ST_BT_W4_DATA;
++ kim_gdata->rx_state = ST_W4_DATA;
+ kim_gdata->rx_count = len;
+ return len;
+ }
+@@ -158,8 +154,8 @@ void kim_int_recv(struct kim_data_s *kim_gdata,
+ const unsigned char *data, long count)
+ {
+ const unsigned char *ptr;
+- struct hci_event_hdr *eh;
+ int len = 0, type = 0;
++ unsigned char *plen;
+
+ pr_debug("%s", __func__);
+ /* Decode received bytes here */
+@@ -183,29 +179,27 @@ void kim_int_recv(struct kim_data_s *kim_gdata,
+ /* Check ST RX state machine , where are we? */
+ switch (kim_gdata->rx_state) {
+ /* Waiting for complete packet ? */
+- case ST_BT_W4_DATA:
++ case ST_W4_DATA:
+ pr_debug("Complete pkt received");
+ validate_firmware_response(kim_gdata);
+ kim_gdata->rx_state = ST_W4_PACKET_TYPE;
+ kim_gdata->rx_skb = NULL;
+ continue;
+ /* Waiting for Bluetooth event header ? */
+- case ST_BT_W4_EVENT_HDR:
+- eh = (struct hci_event_hdr *)kim_gdata->
+- rx_skb->data;
+- pr_debug("Event header: evt 0x%2.2x"
+- "plen %d", eh->evt, eh->plen);
+- kim_check_data_len(kim_gdata, eh->plen);
++ case ST_W4_HEADER:
++ plen =
++ (unsigned char *)&kim_gdata->rx_skb->data[1];
++ pr_debug("event hdr: plen 0x%02x\n", *plen);
++ kim_check_data_len(kim_gdata, *plen);
+ continue;
+ } /* end of switch */
+ } /* end of if rx_state */
+ switch (*ptr) {
+ /* Bluetooth event packet? */
+- case HCI_EVENT_PKT:
+- pr_info("Event packet");
+- kim_gdata->rx_state = ST_BT_W4_EVENT_HDR;
+- kim_gdata->rx_count = HCI_EVENT_HDR_SIZE;
+- type = HCI_EVENT_PKT;
++ case 0x04:
++ kim_gdata->rx_state = ST_W4_HEADER;
++ kim_gdata->rx_count = 2;
++ type = *ptr;
+ break;
+ default:
+ pr_info("unknown packet");
+@@ -216,16 +210,18 @@ void kim_int_recv(struct kim_data_s *kim_gdata,
+ ptr++;
+ count--;
+ kim_gdata->rx_skb =
+- bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
++ alloc_skb(1024+8, GFP_ATOMIC);
+ if (!kim_gdata->rx_skb) {
+ pr_err("can't allocate mem for new packet");
+ kim_gdata->rx_state = ST_W4_PACKET_TYPE;
+ kim_gdata->rx_count = 0;
+ return;
+ }
+- bt_cb(kim_gdata->rx_skb)->pkt_type = type;
++ skb_reserve(kim_gdata->rx_skb, 8);
++ kim_gdata->rx_skb->cb[0] = 4;
++ kim_gdata->rx_skb->cb[1] = 0;
++
+ }
+- pr_info("done %s", __func__);
+ return;
+ }
+
+@@ -398,7 +394,7 @@ void st_kim_chip_toggle(enum proto_type type, enum kim_gpio_state state)
+ gpio_set_value(kim_gdata->gpios[ST_GPS], GPIO_LOW);
+ break;
+
+- case ST_MAX:
++ case ST_MAX_CHANNELS:
+ default:
+ break;
+ }
+@@ -416,7 +412,6 @@ void st_kim_recv(void *disc_data, const unsigned char *data, long count)
+ struct st_data_s *st_gdata = (struct st_data_s *)disc_data;
+ struct kim_data_s *kim_gdata = st_gdata->kim_data;
+
+- pr_info(" %s ", __func__);
+ /* copy to local buffer */
+ if (unlikely(data[4] == 0x01 && data[5] == 0x10 && data[0] == 0x04)) {
+ /* must be the read_ver_cmd */
+@@ -578,7 +573,7 @@ static int kim_toggle_radio(void *data, bool blocked)
+ else
+ st_kim_chip_toggle(type, KIM_GPIO_ACTIVE);
+ break;
+- case ST_MAX:
++ case ST_MAX_CHANNELS:
+ pr_err(" wrong proto type ");
+ break;
+ }
+@@ -664,12 +659,13 @@ static int kim_probe(struct platform_device *pdev)
+ /* refer to itself */
+ kim_gdata->core_data->kim_data = kim_gdata;
+
+- for (proto = 0; proto < ST_MAX; proto++) {
++ for (proto = 0; proto < ST_MAX_CHANNELS; proto++) {
+ kim_gdata->gpios[proto] = gpios[proto];
+ pr_info(" %ld gpio to be requested", gpios[proto]);
+ }
+
+- for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) {
++ for (proto = 0; (proto < ST_MAX_CHANNELS)
++ && (gpios[proto] != -1); proto++) {
+ /* Claim the Bluetooth/FM/GPIO
+ * nShutdown gpio from the system
+ */
+@@ -704,7 +700,8 @@ static int kim_probe(struct platform_device *pdev)
+ init_completion(&kim_gdata->kim_rcvd);
+ init_completion(&kim_gdata->ldisc_installed);
+
+- for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) {
++ for (proto = 0; (proto < ST_MAX_CHANNELS)
++ && (gpios[proto] != -1); proto++) {
+ /* TODO: should all types be rfkill_type_bt ? */
+ kim_gdata->rf_protos[proto] = proto;
+ kim_gdata->rfkill[proto] = rfkill_alloc(protocol_names[proto],
+@@ -752,7 +749,8 @@ static int kim_remove(struct platform_device *pdev)
+
+ kim_gdata = dev_get_drvdata(&pdev->dev);
+
+- for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) {
++ for (proto = 0; (proto < ST_MAX_CHANNELS)
++ && (gpios[proto] != -1); proto++) {
+ /* Claim the Bluetooth/FM/GPIO
+ * nShutdown gpio from the system
+ */
+diff --git a/include/linux/ti_wilink_st.h b/include/linux/ti_wilink_st.h
+index 4c7be22..1674ca7 100644
+--- a/include/linux/ti_wilink_st.h
++++ b/include/linux/ti_wilink_st.h
+@@ -42,7 +42,7 @@ enum proto_type {
+ ST_BT,
+ ST_FM,
+ ST_GPS,
+- ST_MAX,
++ ST_MAX_CHANNELS = 16,
+ };
+
+ /**
+@@ -62,6 +62,17 @@ enum proto_type {
+ * @priv_data: privdate data holder for the protocol drivers, sent
+ * from the protocol drivers during registration, and sent back on
+ * reg_complete_cb and recv.
++ * @chnl_id: channel id the protocol driver is interested in, the channel
++ * id is nothing but the 1st byte of the packet in UART frame.
++ * @max_frame_size: size of the largest frame the protocol can receive.
++ * @hdr_len: length of the header structure of the protocol.
++ * @offset_len_in_hdr: this provides the offset of the length field in the
++ * header structure of the protocol header, to assist ST to know
++ * how much to receive, if the data is split across UART frames.
++ * @len_size: whether the length field inside the header is 2 bytes
++ * or 1 byte.
++ * @reserve: the number of bytes ST needs to reserve in the skb being
++ * prepared for the protocol driver.
+ */
+ struct st_proto_s {
+ enum proto_type type;
+@@ -70,10 +81,17 @@ struct st_proto_s {
+ void (*reg_complete_cb) (void *, char data);
+ long (*write) (struct sk_buff *skb);
+ void *priv_data;
++
++ unsigned char chnl_id;
++ unsigned short max_frame_size;
++ unsigned char hdr_len;
++ unsigned char offset_len_in_hdr;
++ unsigned char len_size;
++ unsigned char reserve;
+ };
+
+ extern long st_register(struct st_proto_s *);
+-extern long st_unregister(enum proto_type);
++extern long st_unregister(struct st_proto_s *);
+
+
+ /*
+@@ -114,6 +132,7 @@ extern long st_unregister(enum proto_type);
+ * @rx_skb: the skb where all data for a protocol gets accumulated,
+ * since tty might not call receive when a complete event packet
+ * is received, the states, count and the skb needs to be maintained.
++ * @rx_chnl: the channel ID for which the data is getting accumalated for.
+ * @txq: the list of skbs which needs to be sent onto the TTY.
+ * @tx_waitq: if the chip is not in AWAKE state, the skbs needs to be queued
+ * up in here, PM(WAKEUP_IND) data needs to be sent and then the skbs
+@@ -135,10 +154,11 @@ struct st_data_s {
+ #define ST_TX_SENDING 1
+ #define ST_TX_WAKEUP 2
+ unsigned long tx_state;
+- struct st_proto_s *list[ST_MAX];
++ struct st_proto_s *list[ST_MAX_CHANNELS];
+ unsigned long rx_state;
+ unsigned long rx_count;
+ struct sk_buff *rx_skb;
++ unsigned char rx_chnl;
+ struct sk_buff_head txq, tx_waitq;
+ spinlock_t lock;
+ unsigned char protos_registered;
+@@ -243,12 +263,12 @@ struct kim_data_s {
+ struct completion kim_rcvd, ldisc_installed;
+ char resp_buffer[30];
+ const struct firmware *fw_entry;
+- long gpios[ST_MAX];
++ long gpios[ST_MAX_CHANNELS];
+ unsigned long rx_state;
+ unsigned long rx_count;
+ struct sk_buff *rx_skb;
+- struct rfkill *rfkill[ST_MAX];
+- enum proto_type rf_protos[ST_MAX];
++ struct rfkill *rfkill[ST_MAX_CHANNELS];
++ enum proto_type rf_protos[ST_MAX_CHANNELS];
+ struct st_data_s *core_data;
+ struct chip_version version;
+ };
+@@ -338,12 +358,8 @@ struct hci_command {
+
+ /* ST LL receiver states */
+ #define ST_W4_PACKET_TYPE 0
+-#define ST_BT_W4_EVENT_HDR 1
+-#define ST_BT_W4_ACL_HDR 2
+-#define ST_BT_W4_SCO_HDR 3
+-#define ST_BT_W4_DATA 4
+-#define ST_FM_W4_EVENT_HDR 5
+-#define ST_GPS_W4_EVENT_HDR 6
++#define ST_W4_HEADER 1
++#define ST_W4_DATA 2
+
+ /* ST LL state machines */
+ #define ST_LL_ASLEEP 0
+--
+1.6.6.1
+
diff --git a/extras/recipes-kernel/linux/linux-omap/wl1271/0015-Bluetooth-btwilink-driver.patch b/extras/recipes-kernel/linux/linux-omap/wl1271/0015-Bluetooth-btwilink-driver.patch
new file mode 100644
index 00000000..f45149f3
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/wl1271/0015-Bluetooth-btwilink-driver.patch
@@ -0,0 +1,463 @@
+From e3948bda11a3a0d938500ffbc7ef43603909cc15 Mon Sep 17 00:00:00 2001
+From: Pavan Savoy <pavan_savoy@ti.com>
+Date: Tue, 4 Jan 2011 10:59:48 +0000
+Subject: [PATCH 15/15] Bluetooth: btwilink driver
+
+-- patch description --
+
+This is the bluetooth protocol driver for the TI WiLink7 chipsets.
+Texas Instrument's WiLink chipsets combine wireless technologies
+like BT, FM, GPS and WLAN onto a single chip.
+
+This Bluetooth driver works on top of the TI_ST shared transport
+line discipline driver which also allows other drivers like
+FM V4L2 and GPS character driver to make use of the same UART interface.
+
+Kconfig and Makefile modifications to enable the Bluetooth
+driver for Texas Instrument's WiLink 7 chipset.
+
+Signed-off-by: Pavan Savoy <pavan_savoy@ti.com>
+---
+ drivers/bluetooth/Kconfig | 10 +
+ drivers/bluetooth/Makefile | 1 +
+ drivers/bluetooth/btwilink.c | 397 ++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 408 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/bluetooth/btwilink.c
+
+diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
+index 02deef4..8e0de9a 100644
+--- a/drivers/bluetooth/Kconfig
++++ b/drivers/bluetooth/Kconfig
+@@ -219,4 +219,14 @@ config BT_ATH3K
+ Say Y here to compile support for "Atheros firmware download driver"
+ into the kernel or say M to compile it as module (ath3k).
+
++config BT_WILINK
++ tristate "Texas Instruments WiLink7 driver"
++ depends on TI_ST
++ help
++ This enables the Bluetooth driver for Texas Instrument's BT/FM/GPS
++ combo devices. This makes use of shared transport line discipline
++ core driver to communicate with the BT core of the combo chip.
++
++ Say Y here to compile support for Texas Instrument's WiLink7 driver
++ into the kernel or say M to compile it as module.
+ endmenu
+diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
+index 71bdf13..f4460f4 100644
+--- a/drivers/bluetooth/Makefile
++++ b/drivers/bluetooth/Makefile
+@@ -18,6 +18,7 @@ obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o
+ obj-$(CONFIG_BT_ATH3K) += ath3k.o
+ obj-$(CONFIG_BT_MRVL) += btmrvl.o
+ obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o
++obj-$(CONFIG_BT_WILINK) += btwilink.o
+
+ btmrvl-y := btmrvl_main.o
+ btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o
+diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c
+new file mode 100644
+index 0000000..0201aca
+--- /dev/null
++++ b/drivers/bluetooth/btwilink.c
+@@ -0,0 +1,397 @@
++/*
++ * Texas Instrument's Bluetooth Driver For Shared Transport.
++ *
++ * Bluetooth Driver acts as interface between HCI core and
++ * TI Shared Transport Layer.
++ *
++ * Copyright (C) 2009-2010 Texas Instruments
++ * Author: Raja Mani <raja_mani@ti.com>
++ * Pavan Savoy <pavan_savoy@ti.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ */
++
++#include <linux/platform_device.h>
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++
++#include <linux/ti_wilink_st.h>
++
++/* Bluetooth Driver Version */
++#define VERSION "1.0"
++
++/* Number of seconds to wait for registration completion
++ * when ST returns PENDING status.
++ */
++#define BT_REGISTER_TIMEOUT 6000 /* 6 sec */
++
++/**
++ * struct ti_st - driver operation structure
++ * @hdev: hci device pointer which binds to bt driver
++ * @reg_status: ST registration callback status
++ * @st_write: write function provided by the ST driver
++ * to be used by the driver during send_frame.
++ * @wait_reg_completion - completion sync between ti_st_open
++ * and ti_st_registration_completion_cb.
++ */
++struct ti_st {
++ struct hci_dev *hdev;
++ char reg_status;
++ long (*st_write) (struct sk_buff *);
++ struct completion wait_reg_completion;
++};
++
++/* Increments HCI counters based on pocket ID (cmd,acl,sco) */
++static inline void ti_st_tx_complete(struct ti_st *hst, int pkt_type)
++{
++ struct hci_dev *hdev = hst->hdev;
++
++ /* Update HCI stat counters */
++ switch (pkt_type) {
++ case HCI_COMMAND_PKT:
++ hdev->stat.cmd_tx++;
++ break;
++
++ case HCI_ACLDATA_PKT:
++ hdev->stat.acl_tx++;
++ break;
++
++ case HCI_SCODATA_PKT:
++ hdev->stat.sco_tx++;
++ break;
++ }
++}
++
++/* ------- Interfaces to Shared Transport ------ */
++
++/* Called by ST layer to indicate protocol registration completion
++ * status.ti_st_open() function will wait for signal from this
++ * API when st_register() function returns ST_PENDING.
++ */
++static void st_registration_completion_cb(void *priv_data, char data)
++{
++ struct ti_st *lhst = priv_data;
++
++ /* Save registration status for use in ti_st_open() */
++ lhst->reg_status = data;
++ /* complete the wait in ti_st_open() */
++ complete(&lhst->wait_reg_completion);
++}
++
++/* Called by Shared Transport layer when receive data is
++ * available */
++static long st_receive(void *priv_data, struct sk_buff *skb)
++{
++ struct ti_st *lhst = priv_data;
++ int err;
++
++ if (!skb)
++ return -EFAULT;
++
++ if (!lhst) {
++ kfree_skb(skb);
++ return -EFAULT;
++ }
++
++ skb->dev = (void *) lhst->hdev;
++
++ /* Forward skb to HCI core layer */
++ err = hci_recv_frame(skb);
++ if (err < 0) {
++ BT_ERR("Unable to push skb to HCI core(%d)", err);
++ return err;
++ }
++
++ lhst->hdev->stat.byte_rx += skb->len;
++
++ return 0;
++}
++
++/* ------- Interfaces to HCI layer ------ */
++/* protocol structure registered with shared transport */
++static struct st_proto_s ti_st_proto[3] = {
++ {
++ .chnl_id = 0x02, /* ACL */
++ .recv = st_receive,
++ .reg_complete_cb = st_registration_completion_cb,
++ .hdr_len = 4,
++ .offset_len_in_hdr = 2,
++ .len_size = 2,
++ .reserve = 8,
++ },
++ {
++ .chnl_id = 0x03, /* SCO */
++ .recv = st_receive,
++ .reg_complete_cb = st_registration_completion_cb,
++ .hdr_len = 3,
++ .offset_len_in_hdr = 2,
++ .len_size = 1,
++ .reserve = 8,
++ },
++ {
++ .chnl_id = 0x04, /* HCI Events */
++ .recv = st_receive,
++ .reg_complete_cb = st_registration_completion_cb,
++ .hdr_len = 2,
++ .offset_len_in_hdr = 1,
++ .len_size = 1,
++ .reserve = 8,
++ },
++};
++
++/* Called from HCI core to initialize the device */
++static int ti_st_open(struct hci_dev *hdev)
++{
++ unsigned long timeleft;
++ struct ti_st *hst;
++ int err, i;
++
++ BT_DBG("%s %p", hdev->name, hdev);
++ if (test_and_set_bit(HCI_RUNNING, &hdev->flags)) {
++ BT_ERR("btwilink already opened");
++ return -EBUSY;
++ }
++
++ /* provide contexts for callbacks from ST */
++ hst = hdev->driver_data;
++
++ for (i = 0; i < 3; i++) {
++ ti_st_proto[i].priv_data = hst;
++ ti_st_proto[i].max_frame_size = HCI_MAX_FRAME_SIZE;
++
++ err = st_register(&ti_st_proto[i]);
++ if (err == -EINPROGRESS) {
++ /* ST is busy with either protocol
++ * registration or firmware download.
++ */
++ /* Prepare wait-for-completion handler data structures.
++ */
++ init_completion(&hst->wait_reg_completion);
++
++ /* Reset ST registration callback status flag,
++ * this value will be updated in
++ * ti_st_registration_completion_cb()
++ * function whenever it called from ST driver.
++ */
++ hst->reg_status = -EINPROGRESS;
++
++ BT_DBG("waiting for registration "
++ "completion signal from ST");
++ timeleft = wait_for_completion_timeout
++ (&hst->wait_reg_completion,
++ msecs_to_jiffies(BT_REGISTER_TIMEOUT));
++ if (!timeleft) {
++ clear_bit(HCI_RUNNING, &hdev->flags);
++ BT_ERR("Timeout(%d sec),didn't get reg "
++ "completion signal from ST",
++ BT_REGISTER_TIMEOUT / 1000);
++ return -ETIMEDOUT;
++ }
++
++ /* Is ST registration callback
++ * called with ERROR status? */
++ if (hst->reg_status != 0) {
++ clear_bit(HCI_RUNNING, &hdev->flags);
++ BT_ERR("ST registration completed with invalid "
++ "status %d", hst->reg_status);
++ return -EAGAIN;
++ }
++ err = 0;
++ } else if (err != 0) {
++ clear_bit(HCI_RUNNING, &hdev->flags);
++ BT_ERR("st_register failed %d", err);
++ return err;
++ }
++ hst->st_write = ti_st_proto[i].write;
++ if (!hst->st_write) {
++ BT_ERR("undefined ST write function");
++ clear_bit(HCI_RUNNING, &hdev->flags);
++
++ /* Undo registration with ST */
++ err = st_unregister(&ti_st_proto[i]);
++ if (err)
++ BT_ERR("st_unregister() failed with "
++ "error %d", err);
++
++ hst->st_write = NULL;
++ /* ti_st_proto.write is filled up by the
++ * underlying shared transport driver
++ * upon registration
++ */
++ return err;
++ }
++ }
++
++ return err;
++}
++
++/* Close device */
++static int ti_st_close(struct hci_dev *hdev)
++{
++ int err, i;
++ struct ti_st *hst = hdev->driver_data;
++
++ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
++ return 0;
++
++ for (i = 0; i < 3; i++) {
++ /* continue to unregister from transport */
++ err = st_unregister(&ti_st_proto[i]);
++ if (err)
++ BT_ERR("st_unregister() failed with error %d", err);
++ }
++
++ hst->st_write = NULL;
++
++ return err;
++}
++
++static int ti_st_send_frame(struct sk_buff *skb)
++{
++ struct hci_dev *hdev;
++ struct ti_st *hst;
++ long len;
++
++ hdev = (struct hci_dev *)skb->dev;
++
++ if (!test_bit(HCI_RUNNING, &hdev->flags))
++ return -EBUSY;
++
++ hst = hdev->driver_data;
++
++ /* Prepend skb with frame type */
++ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
++
++ BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type,
++ skb->len);
++
++ /* Insert skb to shared transport layer's transmit queue.
++ * Freeing skb memory is taken care in shared transport layer,
++ * so don't free skb memory here.
++ */
++ len = hst->st_write(skb);
++ if (len < 0) {
++ kfree_skb(skb);
++ BT_ERR("ST write failed (%ld)", len);
++ /* Try Again, would only fail if UART has gone bad */
++ return -EAGAIN;
++ }
++
++ /* ST accepted our skb. So, Go ahead and do rest */
++ hdev->stat.byte_tx += len;
++ ti_st_tx_complete(hst, bt_cb(skb)->pkt_type);
++
++ return 0;
++}
++
++static void ti_st_destruct(struct hci_dev *hdev)
++{
++ BT_DBG("%s", hdev->name);
++ kfree(hdev->driver_data);
++}
++
++static int bt_ti_probe(struct platform_device *pdev)
++{
++ static struct ti_st *hst;
++ struct hci_dev *hdev;
++ int err;
++
++ hst = kzalloc(sizeof(struct ti_st), GFP_KERNEL);
++ if (!hst)
++ return -ENOMEM;
++
++ /* Expose "hciX" device to user space */
++ hdev = hci_alloc_dev();
++ if (!hdev) {
++ kfree(hst);
++ return -ENOMEM;
++ }
++
++ BT_DBG("hdev %p", hdev);
++
++ hst->hdev = hdev;
++ hdev->bus = HCI_UART;
++ hdev->driver_data = hst;
++ hdev->open = ti_st_open;
++ hdev->close = ti_st_close;
++ hdev->flush = NULL;
++ hdev->send = ti_st_send_frame;
++ hdev->destruct = ti_st_destruct;
++ hdev->owner = THIS_MODULE;
++
++ err = hci_register_dev(hdev);
++ if (err < 0) {
++ BT_ERR("Can't register HCI device error %d", err);
++ kfree(hst);
++ hci_free_dev(hdev);
++ return err;
++ }
++
++ BT_DBG("HCI device registered (hdev %p)", hdev);
++
++ dev_set_drvdata(&pdev->dev, hst);
++ return err;
++}
++
++static int bt_ti_remove(struct platform_device *pdev)
++{
++ struct hci_dev *hdev;
++ struct ti_st *hst = dev_get_drvdata(&pdev->dev);
++
++ if (!hst)
++ return -EFAULT;
++
++ hdev = hst->hdev;
++ ti_st_close(hdev);
++ hci_unregister_dev(hdev);
++
++ hci_free_dev(hdev);
++ kfree(hst);
++
++ dev_set_drvdata(&pdev->dev, NULL);
++ return 0;
++}
++
++static struct platform_driver btwilink_driver = {
++ .probe = bt_ti_probe,
++ .remove = bt_ti_remove,
++ .driver = {
++ .name = "btwilink",
++ .owner = THIS_MODULE,
++ },
++};
++
++/* ------- Module Init/Exit interfaces ------ */
++static int __init btwilink_init(void)
++{
++ BT_INFO("Bluetooth Driver for TI WiLink - Version %s", VERSION);
++
++ return platform_driver_register(&btwilink_driver);
++}
++
++static void __exit btwilink_exit(void)
++{
++ platform_driver_unregister(&btwilink_driver);
++}
++
++module_init(btwilink_init);
++module_exit(btwilink_exit);
++
++/* ------ Module Info ------ */
++
++MODULE_AUTHOR("Raja Mani <raja_mani@ti.com>");
++MODULE_DESCRIPTION("Bluetooth Driver for TI Shared Transport" VERSION);
++MODULE_VERSION(VERSION);
++MODULE_LICENSE("GPL");
+--
+1.6.6.1
+