summaryrefslogtreecommitdiff
path: root/multitech/recipes/linux
diff options
context:
space:
mode:
authorJesse Gilles <jgilles@multitech.com>2013-02-13 11:29:14 -0600
committerJesse Gilles <jgilles@multitech.com>2013-02-13 11:29:14 -0600
commitc6096a2290cec993d135e79676c259a8876065ec (patch)
treee5af4eaea110b4c389a97ebf4f4358dda22a208f /multitech/recipes/linux
parent345816b9381d2d0d9df8047596f0bc5c03d8a8d8 (diff)
linux-2.6.39.4: add support for mtocgd3
Uses the following patches from Atmel for AT91SAM9X5 support * 2.6.39-at91-exp.2 patches * SAM9X5 PMECC patches * SAM9X5 atmel_serial patches
Diffstat (limited to 'multitech/recipes/linux')
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0001-dmaengine-at_hdmac-modify-way-to-use-interrupts.patch75
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0002-dmaengine-at_hdmac-add-cyclic-DMA-operation-support.patch319
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0003-dmaengine-at_hdmac-debug-information-sg_len-for-prep.patch32
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0004-dmaengine-at_hdmac-remove-channel-status-testing-in-.patch41
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0005-dmaengine-at_hdmac-specialize-AHB-interfaces-to-opti.patch121
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0006-dmaengine-AT91SAM9X5-has-a-Atmel-AHB-DMA-engine.patch33
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0007-rtc-at91-workaround-for-5series-ES-chips.patch79
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0008-rtc-AT91SAM9X5-has-an-at91_rtc.patch41
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0009-ARM-at91-overall-definition-add-5series-support.patch356
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0010-ARM-at91-PMC-header-add-5series-support.patch121
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0011-ARM-at91-clock-add-5series-chip-family-support.patch215
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0012-ARM-at91-AT91SAM9x5-processors-and-EK-board-support.patch3216
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0013-ARM-at91-provide-defconfig-for-at91sam9x5ek.patch218
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0014-usb-AT91SAM9X5-has-EHCI.patch32
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0015-ARM-at91-pio-add-new-PIO3a-features.patch440
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0016-usb-AT91SAM9X5-has-a-atmel_usba_udc-device.patch39
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0017-clocksource-tcb-add-support-for-32-bit-mode.patch114
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0018-mmc-atmel-mci-add-support-for-ARCH_AT91SAM9X5.patch100
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0019-serial-atmel-convert-to-use-dma-engine.patch562
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0020-video-atmel_lcdfb-add-support-for-AT91SAM9x5.patch1803
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0021-video-atmel_lcdfb-The-output-bpp-should-not-change-a.patch66
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0022-input-atmel_tsadcc-add-support-for-ARCH_AT91SAM9X5.patch410
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0023-input-atmel_tsadcc-add-touch-screen-pressure-measure.patch109
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0024-input-atmel_tsadcc-enable-touchscreen-averaging-and-.patch81
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0025-input-atmel_tsadcc-add-ACR-register-and-change-trigg.patch97
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0026-MTD-atmel_nand-Add-PMECC-controller-support.patch1175
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0027-MTD-atmel_nand-optimize-read-write-buffer-functions.patch130
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0028-spi-atmel_spi-trivial-change-some-comments.patch40
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0029-spi-atmel_spi-add-physical-base-address.patch39
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0030-spi-atmel_spi-call-unmapping-on-transfers-buffers.patch43
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0031-spi-atmel_spi-status-information-passed-through-cont.patch80
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0032-spi-atmel_spi-add-flag-to-controller-data-for-lock-o.patch119
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0033-spi-atmel_spi-add-dmaengine-support.patch654
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0034-net-can-allow-CAN_AT91-on-AT91SAM9X5.patch33
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0035-Input-qt1070-Add-MODULE_DEVICE_TABLE.patch34
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0036-Input-qt1070-trivial-fix-CHANGE-line-typo.patch30
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0037-Input-qt1070-add-power-management-suspend-resume.patch166
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0038-dmaengine-at_hdmac-clear-channel-status-on-channel-r.patch30
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0039-dmaengine-at_hdmac-set-residue-as-total-len-in-atc_t.patch41
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0040-dmaengine-at_hdmac-implement-pause-and-resume-in-atc.patch170
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0041-dmaengine-at_hdmac-pause-no-need-to-wait-for-FIFO-em.patch60
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0042-dmaengine-at_hdmac-replace-spin_lock-with-irqsave-va.patch244
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0043-dmaengine-at_hdmac-improve-power-management-routines.patch182
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0044-sound-atmel-pcm-trivial-typo-in-debug-comment.patch30
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0045-sound-atmel-pcm-trivial-typo-in-atmel_pcm_dma_params.patch31
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0046-dmaengine-at_hdmac-add-slave-config-operation.patch58
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0047-SPI-m25p80-add-serial-flash-IDs.patch29
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0048-sound-wm8731-rework-power-management.patch44
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0049-atmel-ssc-add-phybase-in-device-structure.patch44
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0050-atmel-ssc-dmaengine-usage-switch-depending-on-cpu.patch36
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0051-sound-atmel_ssc_dai-fix-ssc-error-path.patch35
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0052-sound-atmel_ssc_dai-atmel-pmc-adapt-to-dmaengine-usa.patch706
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0053-sound-sam9x5_wm8731-machine-driver-for-at91sam9x5-wm.patch291
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0054-mtd-atmel_nand-do-not-scream-while-using-PIO-instead.patch33
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0055-MMC-PM-suspend-resume-in-atmel-mci.patch83
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0056-ASoc-wm8731-fix-wm8731_check_osc-connected-condition.patch37
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0057-ASoc-sam9g20_wm8731-use-the-proper-SYSCKL-value.patch34
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0058-sound-atmel_ssc_dai-PM-actually-stopping-clock-on-su.patch73
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0059-ARM-at91-sam9x5-increase-CONSISTENT_DMA_SIZE.patch29
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0060-SPI-atmel_spi-add-bit-in-mode-register-to-prevent-ov.patch130
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0061-media-at91sam9x5-video-new-driver-for-the-high-end-o.patch1530
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0062-can-at91_can-don-t-align-struct-definitions.patch81
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0063-can-at91_can-fix-comment-about-priv-tx_next.patch31
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0064-can-at91_can-don-t-copy-data-to-rx-ed-RTR-frames.patch42
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0065-can-at91_can-let-get_tx_-functions-return-unsigned-i.patch44
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0066-can-at91_can-directly-define-AT91_MB_RX_LAST.patch39
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0067-can-at91_can-rename-AT91_MB_RX_MASK-to-AT91_IRQ_MB_R.patch74
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0068-can-at91_can-convert-derived-mailbox-constants-into-.patch296
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0069-can-at91_can-add-id_table-and-convert-prime-mailbox-.patch337
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0070-can-at91_can-register-mb0-sysfs-entry-only-on-at91sa.patch45
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0071-can-at91_can-add-support-for-the-AT91SAM9X5-SOCs.patch139
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0072-media-V4L-videobuf2-memops-use-pr_debug-for-debug-me.patch51
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0073-video-atmelfb-initially-split-atmelfb-into-a-driver-.patch2622
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0074-video-atmelfb-refactor-core-setup.patch403
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0075-video-atmelfb-refactor-start-stop.patch196
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0076-video-atmelfb-refactor-isr.patch154
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0077-video-atmelfb-refactor-backlight-routines.patch256
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0078-video-atmelfb-refactor-dma_update.patch211
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0079-video-atmelfb-refactor-LUT.patch80
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0080-video-atmelfb-refactor-limit_screeninfo.patch92
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0081-arm-at91-refactor-lcdc-includes.patch2648
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0082-video-atmel_hlcdfb-add-new-driver.patch606
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0083-arm-at91-sam9x5-use-new-hlcdc-driver.patch30
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0084-arm-at91-sam9x5ek-use-16bpp-as-default-for-fb.patch34
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0085-create-platform-device-for-ovl1.patch97
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0086-WIP-add-clut-resource.patch167
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0087-video-atmel_lcdfb-add-error-msg-when-out-of-memory.patch33
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0088-Don-t-shortcut-vb2_reqbufs-in-case-the-format-change.patch42
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0089-at91-video-change-atmel-lcdfb-driver-selection-mode.patch95
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0090-sound-atmel_ssc_dai-add-a-missing-space-to-an-error-.patch35
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0091-at91-add-Atmel-Image-Sensor-Interface-ISI-support.patch1233
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0092-add-isi-support-in-board-files.patch238
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0093-media-at91-add-dumb-set_parm.patch40
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0094-AT91-5series-add-ISI-device-and-board-support.patch232
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0095-AT91-board-remove-not-needed-comments.patch47
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0096-AT91-5series-update-defconfig.patch266
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0097-AT91-input-atmel_tsadcc-rework-irq-infrastructure-an.patch191
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0098-5series-Update-LCD-timings-to-avoid-flickering.patch33
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0099-atmel_lcdfb-change-pixel-clock-ratio-calculation.patch31
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0100-MTD-atmel_nand_pmecc-fix-warning-about-uninitialized.patch27
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0101-MTD-atmel_nand-fix-wrong-use-of-0-as-NULL.patch29
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0102-ASoC-wm8731-active-bit-and-OSC-management.patch98
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0103-AT91-at91sam9x5-add-can-clocks-to-9x25-chip.patch27
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0104-AT91-LCD-include-remove-not-needed-comment.patch27
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0105-AT91-5series-fix-SPI0-MCI1-ISI-pins-conflicts-in-boa.patch102
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0106-PMECC-Fix-bug-incorrect-register-address-for-remaind.patch27
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0107-ARM-at91-add-smd-device-definition.patch112
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0001-Revert-MTD-atmel_nand-Add-PMECC-controller-support.patch1177
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0002-Revert-MTD-atmel_nand-optimize-read-write-buffer-fun.patch126
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0003-mtd-at91-extract-hw-ecc-initialization-to-one-functi.patch229
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0004-atmel_nand-add-PMECC-parameters-in-nand-structure.patch30
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0005-mtd-at91-atmel_nand-add-Programmable-Multibit-ECC-co.patch980
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0006-atmel_nand-port-to-2.6.39.-modify-function-definitio.patch65
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0007-atmel_nand-pass-the-pmecc-parameter-from-board-file-.patch86
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0008-atmel_nand-9x5ek-enable-PMECC-in-9x5ek-board.patch38
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0009-atmel_nand-enable-dma-for-9x5ek.patch28
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/linux-2.6.39.4-atmel_serial_disable_hwhs.patch32
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/linux-2.6.39.4-ledtrig-netdev.patch488
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/linux-2.6.39.4-option-telit.patch43
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/mtocgd3/defconfig2328
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-at91sam9_wdt-10second-timeout.patch14
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-at91sam9x5-extreset.patch16
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-atmel-mci-force-detect.patch30
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-macb-force-link.patch75
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-mach-at91-mtocgd3.patch403
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-wl12xx-sdio-irq.patch15
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0001-DMA-AT91-Get-residual-bytes-in-dma-buffer.patch327
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0002-Serial-Configure-DMAC-configuration-register-for-usa.patch73
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0003-Configure-peripheral-id-and-enable-basic-usart.patch153
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0004-Serial-Enable-Serial-cyclic-DMA-transfer.patch399
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0005-Serial-AT91-Refine-tx-dma.patch167
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0006-Serial-AT91-refine-error-handler-in-probe-stage.patch70
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0007-Serial-AT91-Add-dma-support-for-rs485-and-iso7816.patch71
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0008-Serial-AT91-remove-tx-dma-issue-pending.patch32
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0009-Serial-AT91-Fix-DBGU-peripheral_id-wrong.patch37
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0010-serial-at91-Make-DBGU-support-dma-and-pdc-transfer.patch183
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/Change-log.txt30
-rw-r--r--multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/how to apply.txt16
-rw-r--r--multitech/recipes/linux/linux_2.6.39.4.bb151
139 files changed, 34894 insertions, 1 deletions
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0001-dmaengine-at_hdmac-modify-way-to-use-interrupts.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0001-dmaengine-at_hdmac-modify-way-to-use-interrupts.patch
new file mode 100644
index 0000000..4967bd3
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0001-dmaengine-at_hdmac-modify-way-to-use-interrupts.patch
@@ -0,0 +1,75 @@
+From e22e7d2f67c4f8003215863361f19ac6acdb927e Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 1 Feb 2011 19:58:30 +0100
+Subject: [PATCH 001/107] dmaengine: at_hdmac: modify way to use interrupts
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Now we use Buffer Transfer Completed interrupts. If we
+want a chained buffer completed information, we setup the
+ATC_IEN bit in CTRLB register in the lli.
+This is done by set_desc_eol() function and used by
+memcpy/slave_sg functions.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/dma/at_hdmac.c | 4 ++--
+ drivers/dma/at_hdmac_regs.h | 11 ++++++++---
+ 2 files changed, 10 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
+index 235f53b..5124e09 100644
+--- a/drivers/dma/at_hdmac.c
++++ b/drivers/dma/at_hdmac.c
+@@ -464,7 +464,7 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id)
+
+ for (i = 0; i < atdma->dma_common.chancnt; i++) {
+ atchan = &atdma->chan[i];
+- if (pending & (AT_DMA_CBTC(i) | AT_DMA_ERR(i))) {
++ if (pending & (AT_DMA_BTC(i) | AT_DMA_ERR(i))) {
+ if (pending & AT_DMA_ERR(i)) {
+ /* Disable channel on AHB error */
+ dma_writel(atdma, CHDR, atchan->mask);
+@@ -549,7 +549,7 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
+ }
+
+ ctrla = ATC_DEFAULT_CTRLA;
+- ctrlb = ATC_DEFAULT_CTRLB
++ ctrlb = ATC_DEFAULT_CTRLB | ATC_IEN
+ | ATC_SRC_ADDR_MODE_INCR
+ | ATC_DST_ADDR_MODE_INCR
+ | ATC_FC_MEM2MEM;
+diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h
+index 495457e..8303306 100644
+--- a/drivers/dma/at_hdmac_regs.h
++++ b/drivers/dma/at_hdmac_regs.h
+@@ -309,8 +309,8 @@ static void atc_setup_irq(struct at_dma_chan *atchan, int on)
+ struct at_dma *atdma = to_at_dma(atchan->chan_common.device);
+ u32 ebci;
+
+- /* enable interrupts on buffer chain completion & error */
+- ebci = AT_DMA_CBTC(atchan->chan_common.chan_id)
++ /* enable interrupts on buffer transfer completion & error */
++ ebci = AT_DMA_BTC(atchan->chan_common.chan_id)
+ | AT_DMA_ERR(atchan->chan_common.chan_id);
+ if (on)
+ dma_writel(atdma, EBCIER, ebci);
+@@ -347,7 +347,12 @@ static inline int atc_chan_is_enabled(struct at_dma_chan *atchan)
+ */
+ static void set_desc_eol(struct at_desc *desc)
+ {
+- desc->lli.ctrlb |= ATC_SRC_DSCR_DIS | ATC_DST_DSCR_DIS;
++ u32 ctrlb = desc->lli.ctrlb;
++
++ ctrlb &= ~ATC_IEN;
++ ctrlb |= ATC_SRC_DSCR_DIS | ATC_DST_DSCR_DIS;
++
++ desc->lli.ctrlb = ctrlb;
+ desc->lli.dscr = 0;
+ }
+
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0002-dmaengine-at_hdmac-add-cyclic-DMA-operation-support.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0002-dmaengine-at_hdmac-add-cyclic-DMA-operation-support.patch
new file mode 100644
index 0000000..63d1757
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0002-dmaengine-at_hdmac-add-cyclic-DMA-operation-support.patch
@@ -0,0 +1,319 @@
+From 50730e4e5183b199232b7c0f93eadd8af1e439a6 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 1 Feb 2011 16:39:11 +0100
+Subject: [PATCH 002/107] dmaengine: at_hdmac: add cyclic DMA operation
+ support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/dma/at_hdmac.c | 187 +++++++++++++++++++++++++++++++++++++++---
+ drivers/dma/at_hdmac_regs.h | 14 +++-
+ 2 files changed, 185 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
+index 5124e09..a58ae65 100644
+--- a/drivers/dma/at_hdmac.c
++++ b/drivers/dma/at_hdmac.c
+@@ -237,16 +237,12 @@ static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first)
+ static void
+ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
+ {
+- dma_async_tx_callback callback;
+- void *param;
+ struct dma_async_tx_descriptor *txd = &desc->txd;
+
+ dev_vdbg(chan2dev(&atchan->chan_common),
+ "descriptor %u complete\n", txd->cookie);
+
+ atchan->completed_cookie = txd->cookie;
+- callback = txd->callback;
+- param = txd->callback_param;
+
+ /* move children to free_list */
+ list_splice_init(&desc->tx_list, &atchan->free_list);
+@@ -278,12 +274,19 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
+ }
+ }
+
+- /*
+- * The API requires that no submissions are done from a
+- * callback, so we don't need to drop the lock here
+- */
+- if (callback)
+- callback(param);
++ /* for cyclic transfers,
++ * no need to replay callback function while stopping */
++ if (!test_bit(ATC_IS_CYCLIC, &atchan->status)) {
++ dma_async_tx_callback callback = txd->callback;
++ void *param = txd->callback_param;
++
++ /*
++ * The API requires that no submissions are done from a
++ * callback, so we don't need to drop the lock here
++ */
++ if (callback)
++ callback(param);
++ }
+
+ dma_run_dependencies(txd);
+ }
+@@ -419,6 +422,26 @@ static void atc_handle_error(struct at_dma_chan *atchan)
+ atc_chain_complete(atchan, bad_desc);
+ }
+
++/**
++ * atc_handle_cyclic - at the end of a period, run callback function
++ * @atchan: channel used for cyclic operations
++ *
++ * Called with atchan->lock held and bh disabled
++ */
++static void atc_handle_cyclic(struct at_dma_chan *atchan)
++{
++ struct at_desc *first = atc_first_active(atchan);
++ struct dma_async_tx_descriptor *txd = &first->txd;
++ dma_async_tx_callback callback = txd->callback;
++ void *param = txd->callback_param;
++
++ dev_vdbg(chan2dev(&atchan->chan_common),
++ "new cyclic period llp 0x%08x\n",
++ channel_readl(atchan, DSCR));
++
++ if (callback)
++ callback(param);
++}
+
+ /*-- IRQ & Tasklet ---------------------------------------------------*/
+
+@@ -434,8 +457,10 @@ static void atc_tasklet(unsigned long data)
+ }
+
+ spin_lock(&atchan->lock);
+- if (test_and_clear_bit(0, &atchan->error_status))
++ if (test_and_clear_bit(ATC_IS_ERROR, &atchan->status))
+ atc_handle_error(atchan);
++ else if (test_bit(ATC_IS_CYCLIC, &atchan->status))
++ atc_handle_cyclic(atchan);
+ else
+ atc_advance_work(atchan);
+
+@@ -469,7 +494,7 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id)
+ /* Disable channel on AHB error */
+ dma_writel(atdma, CHDR, atchan->mask);
+ /* Give information to tasklet */
+- set_bit(0, &atchan->error_status);
++ set_bit(ATC_IS_ERROR, &atchan->status);
+ }
+ tasklet_schedule(&atchan->tasklet);
+ ret = IRQ_HANDLED;
+@@ -759,6 +784,127 @@ err_desc_get:
+ return NULL;
+ }
+
++/**
++ * atc_dma_cyclic_prep - prepare the cyclic DMA transfer
++ * @chan: the DMA channel to prepare
++ * @buf_addr: physical DMA address where the buffer starts
++ * @buf_len: total number of bytes for the entire buffer
++ * @period_len: number of bytes for each period
++ * @direction: transfer direction, to or from device
++ */
++static struct dma_async_tx_descriptor *
++atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
++ size_t period_len, enum dma_data_direction direction)
++{
++ struct at_dma_chan *atchan = to_at_dma_chan(chan);
++ struct at_dma_slave *atslave = chan->private;
++ struct at_desc *first = NULL;
++ struct at_desc *prev = NULL;
++ unsigned long was_cyclic;
++ unsigned int periods = buf_len / period_len;
++ unsigned int reg_width;
++ u32 ctrla;
++ u32 ctrlb;
++ unsigned int i;
++
++ dev_vdbg(chan2dev(chan), "prep_dma_cyclic: %s buf@0x%08x - %d (%d/%d)\n",
++ direction == DMA_TO_DEVICE ? "TO DEVICE" : "FROM DEVICE",
++ buf_addr,
++ periods, buf_len, period_len);
++
++ if (unlikely(!atslave || !buf_len || !period_len)) {
++ dev_dbg(chan2dev(chan), "prep_dma_cyclic: length is zero!\n");
++ return NULL;
++ }
++
++ was_cyclic = test_and_set_bit(ATC_IS_CYCLIC, &atchan->status);
++ if (was_cyclic) {
++ dev_dbg(chan2dev(chan), "prep_dma_cyclic: channel in use!\n");
++ return NULL;
++ }
++
++ reg_width = atslave->reg_width;
++
++ /* Check for too big/unaligned periods and unaligned DMA buffer */
++ if (period_len > (ATC_BTSIZE_MAX << reg_width))
++ goto err_out;
++ if (unlikely(period_len & ((1 << reg_width) - 1)))
++ goto err_out;
++ if (unlikely(buf_addr & ((1 << reg_width) - 1)))
++ goto err_out;
++ if (unlikely(!(direction & (DMA_TO_DEVICE | DMA_FROM_DEVICE))))
++ goto err_out;
++
++ /* prepare common CRTLA/CTRLB values */
++ ctrla = ATC_DEFAULT_CTRLA | atslave->ctrla
++ | ATC_DST_WIDTH(reg_width)
++ | ATC_SRC_WIDTH(reg_width)
++ | period_len >> reg_width;
++ ctrlb = ATC_DEFAULT_CTRLB;
++
++ /* build cyclic linked list */
++ for (i = 0; i < periods; i++) {
++ struct at_desc *desc;
++
++ desc = atc_desc_get(atchan);
++ if (!desc)
++ goto err_desc_get;
++
++ switch (direction) {
++ case DMA_TO_DEVICE:
++ desc->lli.saddr = buf_addr + (period_len * i);
++ desc->lli.daddr = atslave->tx_reg;
++ desc->lli.ctrla = ctrla;
++ desc->lli.ctrlb = ctrlb
++ | ATC_DST_ADDR_MODE_FIXED
++ | ATC_SRC_ADDR_MODE_INCR
++ | ATC_FC_MEM2PER;
++ break;
++
++ case DMA_FROM_DEVICE:
++ desc->lli.saddr = atslave->rx_reg;
++ desc->lli.daddr = buf_addr + (period_len * i);
++ desc->lli.ctrla = ctrla;
++ desc->lli.ctrlb = ctrlb
++ | ATC_DST_ADDR_MODE_INCR
++ | ATC_SRC_ADDR_MODE_FIXED
++ | ATC_FC_PER2MEM;
++ break;
++
++ default:
++ return NULL;
++ }
++
++ if (!first) {
++ first = desc;
++ } else {
++ /* inform the HW lli about chaining */
++ prev->lli.dscr = desc->txd.phys;
++ /* insert the link descriptor to the LD ring */
++ list_add_tail(&desc->desc_node,
++ &first->tx_list);
++ }
++ prev = desc;
++ }
++
++ /* lets make a cyclic list */
++ prev->lli.dscr = first->txd.phys;
++
++ /* First descriptor of the chain embedds additional information */
++ first->txd.cookie = -EBUSY;
++ first->len = buf_len;
++
++ return &first->txd;
++
++err_desc_get:
++ dev_err(chan2dev(chan), "not enough descriptors available\n");
++ atc_desc_put(atchan, first);
++err_out:
++ clear_bit(ATC_IS_CYCLIC, &atchan->status);
++ return NULL;
++}
++
++
+ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ unsigned long arg)
+ {
+@@ -795,6 +941,10 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+
+ spin_unlock_bh(&atchan->lock);
+
++ /* XXX/ukl: should this be done with bh disabled? */
++ /* if channel dedicated to cyclic operations, free it */
++ clear_bit(ATC_IS_CYCLIC, &atchan->status);
++
+ return 0;
+ }
+
+@@ -853,6 +1003,10 @@ static void atc_issue_pending(struct dma_chan *chan)
+
+ dev_vdbg(chan2dev(chan), "issue_pending\n");
+
++ /* Not needed for cyclic transfers */
++ if (test_bit(ATC_IS_CYCLIC, &atchan->status))
++ return;
++
+ spin_lock_bh(&atchan->lock);
+ if (!atc_chan_is_enabled(atchan)) {
+ atc_advance_work(atchan);
+@@ -1092,10 +1246,15 @@ static int __init at_dma_probe(struct platform_device *pdev)
+ if (dma_has_cap(DMA_MEMCPY, atdma->dma_common.cap_mask))
+ atdma->dma_common.device_prep_dma_memcpy = atc_prep_dma_memcpy;
+
+- if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask)) {
++ if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask))
+ atdma->dma_common.device_prep_slave_sg = atc_prep_slave_sg;
++
++ if (dma_has_cap(DMA_CYCLIC, atdma->dma_common.cap_mask))
++ atdma->dma_common.device_prep_dma_cyclic = atc_prep_dma_cyclic;
++
++ if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask) ||
++ dma_has_cap(DMA_CYCLIC, atdma->dma_common.cap_mask))
+ atdma->dma_common.device_control = atc_control;
+- }
+
+ dma_writel(atdma, EN, AT_DMA_ENABLE);
+
+diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h
+index 8303306..c79a9e0 100644
+--- a/drivers/dma/at_hdmac_regs.h
++++ b/drivers/dma/at_hdmac_regs.h
+@@ -181,12 +181,22 @@ txd_to_at_desc(struct dma_async_tx_descriptor *txd)
+ /*-- Channels --------------------------------------------------------*/
+
+ /**
++ * atc_status - information bits stored in channel status flag
++ *
++ * Manipulated with atomic operations.
++ */
++enum atc_status {
++ ATC_IS_ERROR = 0,
++ ATC_IS_CYCLIC = 24,
++};
++
++/**
+ * struct at_dma_chan - internal representation of an Atmel HDMAC channel
+ * @chan_common: common dmaengine channel object members
+ * @device: parent device
+ * @ch_regs: memory mapped register base
+ * @mask: channel index in a mask
+- * @error_status: transmit error status information from irq handler
++ * @status: transmit status information from irq/prep* functions
+ * to tasklet (use atomic operations)
+ * @tasklet: bottom half to finish transaction work
+ * @lock: serializes enqueue/dequeue operations to descriptors lists
+@@ -201,7 +211,7 @@ struct at_dma_chan {
+ struct at_dma *device;
+ void __iomem *ch_regs;
+ u8 mask;
+- unsigned long error_status;
++ unsigned long status;
+ struct tasklet_struct tasklet;
+
+ spinlock_t lock;
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0003-dmaengine-at_hdmac-debug-information-sg_len-for-prep.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0003-dmaengine-at_hdmac-debug-information-sg_len-for-prep.patch
new file mode 100644
index 0000000..d3770f0
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0003-dmaengine-at_hdmac-debug-information-sg_len-for-prep.patch
@@ -0,0 +1,32 @@
+From a4353fd9418ab145376c08ec57ffd2b7c231db30 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 7 Feb 2011 15:07:37 +0100
+Subject: [PATCH 003/107] dmaengine: at_hdmac: debug information sg_len for
+ prep_slave_sg
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/dma/at_hdmac.c | 3 ++-
+ 1 files changed, 2 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
+index a58ae65..1c1508e 100644
+--- a/drivers/dma/at_hdmac.c
++++ b/drivers/dma/at_hdmac.c
+@@ -664,7 +664,8 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
+ struct scatterlist *sg;
+ size_t total_len = 0;
+
+- dev_vdbg(chan2dev(chan), "prep_slave_sg: %s f0x%lx\n",
++ dev_vdbg(chan2dev(chan), "prep_slave_sg (%d): %s f0x%lx\n",
++ sg_len,
+ direction == DMA_TO_DEVICE ? "TO DEVICE" : "FROM DEVICE",
+ flags);
+
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0004-dmaengine-at_hdmac-remove-channel-status-testing-in-.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0004-dmaengine-at_hdmac-remove-channel-status-testing-in-.patch
new file mode 100644
index 0000000..60c4bfb
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0004-dmaengine-at_hdmac-remove-channel-status-testing-in-.patch
@@ -0,0 +1,41 @@
+From 1e96442285f67be04287e3f2cb536328f2cbae58 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 10 Feb 2011 12:33:54 +0100
+Subject: [PATCH 004/107] dmaengine: at_hdmac: remove channel status testing
+ in tasklet
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There is no need to test if channel is enabled in tasklet:
+- in error path, channel is disabled in interrupt routine
+- in normal path, this test is performed in sub functions to report
+a misuse of the engine.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/dma/at_hdmac.c | 7 -------
+ 1 files changed, 0 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
+index 1c1508e..858358a 100644
+--- a/drivers/dma/at_hdmac.c
++++ b/drivers/dma/at_hdmac.c
+@@ -449,13 +449,6 @@ static void atc_tasklet(unsigned long data)
+ {
+ struct at_dma_chan *atchan = (struct at_dma_chan *)data;
+
+- /* Channel cannot be enabled here */
+- if (atc_chan_is_enabled(atchan)) {
+- dev_err(chan2dev(&atchan->chan_common),
+- "BUG: channel enabled in tasklet\n");
+- return;
+- }
+-
+ spin_lock(&atchan->lock);
+ if (test_and_clear_bit(ATC_IS_ERROR, &atchan->status))
+ atc_handle_error(atchan);
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0005-dmaengine-at_hdmac-specialize-AHB-interfaces-to-opti.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0005-dmaengine-at_hdmac-specialize-AHB-interfaces-to-opti.patch
new file mode 100644
index 0000000..dd7d738
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0005-dmaengine-at_hdmac-specialize-AHB-interfaces-to-opti.patch
@@ -0,0 +1,121 @@
+From d319913ecdc643e960902b456069b7259e260a65 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 14 Feb 2011 19:27:46 +0100
+Subject: [PATCH 005/107] dmaengine: at_hdmac: specialize AHB interfaces to
+ optimize transfers
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+DMA controller has two AHB interfaces on the SOC internal
+matrix.
+It is more efficient to specialize each interface as the
+access to memory can introduce latencies that are not compatible
+with peripheral accesses requirements.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/dma/at_hdmac.c | 20 ++++++++++----------
+ drivers/dma/at_hdmac_regs.h | 2 ++
+ 2 files changed, 12 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
+index 858358a..db2c0bd 100644
+--- a/drivers/dma/at_hdmac.c
++++ b/drivers/dma/at_hdmac.c
+@@ -37,8 +37,7 @@
+
+ #define ATC_DEFAULT_CFG (ATC_FIFOCFG_HALFFIFO)
+ #define ATC_DEFAULT_CTRLA (0)
+-#define ATC_DEFAULT_CTRLB (ATC_SIF(0) \
+- |ATC_DIF(1))
++#define ATC_DEFAULT_CTRLB (ATC_SIF(MEM_IF) | ATC_DIF(MEM_IF))
+
+ /*
+ * Initial number of descriptors to allocate for each channel. This could
+@@ -670,14 +669,14 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
+ reg_width = atslave->reg_width;
+
+ ctrla = ATC_DEFAULT_CTRLA | atslave->ctrla;
+- ctrlb = ATC_DEFAULT_CTRLB | ATC_IEN;
++ ctrlb = ATC_IEN;
+
+ switch (direction) {
+ case DMA_TO_DEVICE:
+ ctrla |= ATC_DST_WIDTH(reg_width);
+ ctrlb |= ATC_DST_ADDR_MODE_FIXED
+ | ATC_SRC_ADDR_MODE_INCR
+- | ATC_FC_MEM2PER;
++ | ATC_FC_MEM2PER | ATC_SIF(MEM_IF) | ATC_DIF(PER_IF);
+ reg = atslave->tx_reg;
+ for_each_sg(sgl, sg, sg_len, i) {
+ struct at_desc *desc;
+@@ -718,7 +717,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
+ ctrla |= ATC_SRC_WIDTH(reg_width);
+ ctrlb |= ATC_DST_ADDR_MODE_INCR
+ | ATC_SRC_ADDR_MODE_FIXED
+- | ATC_FC_PER2MEM;
++ | ATC_FC_PER2MEM | ATC_SIF(PER_IF) | ATC_DIF(MEM_IF);
+
+ reg = atslave->rx_reg;
+ for_each_sg(sgl, sg, sg_len, i) {
+@@ -798,7 +797,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
+ unsigned int periods = buf_len / period_len;
+ unsigned int reg_width;
+ u32 ctrla;
+- u32 ctrlb;
++ u32 ctrlb = 0;
+ unsigned int i;
+
+ dev_vdbg(chan2dev(chan), "prep_dma_cyclic: %s buf@0x%08x - %d (%d/%d)\n",
+@@ -829,12 +828,11 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
+ if (unlikely(!(direction & (DMA_TO_DEVICE | DMA_FROM_DEVICE))))
+ goto err_out;
+
+- /* prepare common CRTLA/CTRLB values */
++ /* prepare common CRTLA value */
+ ctrla = ATC_DEFAULT_CTRLA | atslave->ctrla
+ | ATC_DST_WIDTH(reg_width)
+ | ATC_SRC_WIDTH(reg_width)
+ | period_len >> reg_width;
+- ctrlb = ATC_DEFAULT_CTRLB;
+
+ /* build cyclic linked list */
+ for (i = 0; i < periods; i++) {
+@@ -852,7 +850,8 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
+ desc->lli.ctrlb = ctrlb
+ | ATC_DST_ADDR_MODE_FIXED
+ | ATC_SRC_ADDR_MODE_INCR
+- | ATC_FC_MEM2PER;
++ | ATC_FC_MEM2PER
++ | ATC_SIF(MEM_IF) | ATC_DIF(PER_IF);
+ break;
+
+ case DMA_FROM_DEVICE:
+@@ -862,7 +861,8 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
+ desc->lli.ctrlb = ctrlb
+ | ATC_DST_ADDR_MODE_INCR
+ | ATC_SRC_ADDR_MODE_FIXED
+- | ATC_FC_PER2MEM;
++ | ATC_FC_PER2MEM
++ | ATC_SIF(PER_IF) | ATC_DIF(MEM_IF);
+ break;
+
+ default:
+diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h
+index c79a9e0..9afcb8d 100644
+--- a/drivers/dma/at_hdmac_regs.h
++++ b/drivers/dma/at_hdmac_regs.h
+@@ -103,6 +103,8 @@
+ /* Bitfields in CTRLB */
+ #define ATC_SIF(i) (0x3 & (i)) /* Src tx done via AHB-Lite Interface i */
+ #define ATC_DIF(i) ((0x3 & (i)) << 4) /* Dst tx done via AHB-Lite Interface i */
++#define MEM_IF 0 /* specify AHB interface 0 as memory interface */
++#define PER_IF 1 /* specify AHB interface 1 as peripheral interface */
+ #define ATC_SRC_PIP (0x1 << 8) /* Source Picture-in-Picture enabled */
+ #define ATC_DST_PIP (0x1 << 12) /* Destination Picture-in-Picture enabled */
+ #define ATC_SRC_DSCR_DIS (0x1 << 16) /* Src Descriptor fetch disable */
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0006-dmaengine-AT91SAM9X5-has-a-Atmel-AHB-DMA-engine.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0006-dmaengine-AT91SAM9X5-has-a-Atmel-AHB-DMA-engine.patch
new file mode 100644
index 0000000..b388baf
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0006-dmaengine-AT91SAM9X5-has-a-Atmel-AHB-DMA-engine.patch
@@ -0,0 +1,33 @@
+From b58656e215f783ca2099e29ee58396122a8220c7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
+Date: Mon, 18 Apr 2011 17:19:18 +0200
+Subject: [PATCH 006/107] dmaengine: AT91SAM9X5 has a Atmel AHB DMA engine
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This change was part of a patch provided (non-publically) by Atmel. I
+split it off because it was unrelated to the commit log and the other
+changes in that commit.
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/dma/Kconfig | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
+index a572600..354fcfa 100644
+--- a/drivers/dma/Kconfig
++++ b/drivers/dma/Kconfig
+@@ -91,7 +91,7 @@ config DW_DMAC
+
+ config AT_HDMAC
+ tristate "Atmel AHB DMA support"
+- depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
++ depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 || ARCH_AT91SAM9X5
+ select DMA_ENGINE
+ help
+ Support the Atmel AHB DMA controller. This can be integrated in
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0007-rtc-at91-workaround-for-5series-ES-chips.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0007-rtc-at91-workaround-for-5series-ES-chips.patch
new file mode 100644
index 0000000..7c802ca
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0007-rtc-at91-workaround-for-5series-ES-chips.patch
@@ -0,0 +1,79 @@
+From ef74ff3fcfc0072cbac374553e1a6b2f3bf099c4 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 19 Oct 2010 13:36:53 +0200
+Subject: [PATCH 007/107] rtc/at91: workaround for 5series ES chips
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The RTC IMR register is not working on 5series ES chips. Fake it with a static
+variable and some accessors functions.
+This workaround does not modify the original RTC code.
+
+XXX: reevaluate if the hardware-guys fixed it, if yes, drop this,
+ patch, if no send them some stinking fish and rework patch to make
+ the driver aware of the shortcoming.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ .../include/mach/at91sam9x5_rtc_workaround.h | 31 ++++++++++++++++++++
+ drivers/rtc/rtc-at91rm9200.c | 4 ++
+ 2 files changed, 35 insertions(+), 0 deletions(-)
+ create mode 100644 arch/arm/mach-at91/include/mach/at91sam9x5_rtc_workaround.h
+
+diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5_rtc_workaround.h b/arch/arm/mach-at91/include/mach/at91sam9x5_rtc_workaround.h
+new file mode 100644
+index 0000000..4b9f0d7
+--- /dev/null
++++ b/arch/arm/mach-at91/include/mach/at91sam9x5_rtc_workaround.h
+@@ -0,0 +1,31 @@
++/*
++ * Real Time Clock workaround header file
++ * apply to at91sam9x5 family Engineering Samples
++ *
++ * Copyright (C) 2010 Atmel, Nicolas Ferre <nicolas.ferre@atmel.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.
++ */
++
++static u32 sam9x5es_rtc_imr = 0;
++
++#define at91_sys_read(x) ( \
++ (x) == AT91_RTC_IMR? \
++ sam9x5es_rtc_imr: \
++ at91_sys_read(x) \
++ )
++
++#define at91_sys_write(y, x) do { \
++ if ((y) == AT91_RTC_IDR) { \
++ at91_sys_write(AT91_RTC_IDR, (x)); \
++ sam9x5es_rtc_imr &= ~(x); \
++ } else if ((y) == AT91_RTC_IER) { \
++ sam9x5es_rtc_imr |= (x); \
++ at91_sys_write(AT91_RTC_IER, (x)); \
++ } else { \
++ at91_sys_write((y), (x)); \
++ } \
++ } while (0)
+diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
+index e39b77a..b9038f4 100644
+--- a/drivers/rtc/rtc-at91rm9200.c
++++ b/drivers/rtc/rtc-at91rm9200.c
+@@ -32,6 +32,10 @@
+
+ #include <mach/at91_rtc.h>
+
++#if defined(CONFIG_ARCH_AT91SAM9X5)
++#include <mach/at91sam9x5_rtc_workaround.h>
++#endif
++
+
+ #define AT91_RTC_EPOCH 1900UL /* just like arch/arm/common/rtctime.c */
+
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0008-rtc-AT91SAM9X5-has-an-at91_rtc.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0008-rtc-AT91SAM9X5-has-an-at91_rtc.patch
new file mode 100644
index 0000000..1e4ad49
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0008-rtc-AT91SAM9X5-has-an-at91_rtc.patch
@@ -0,0 +1,41 @@
+From 25d339722fe977695b998ebb8b2ff2fab9faf7bb Mon Sep 17 00:00:00 2001
+From: Dan Liang <dan.liang@atmel.com>
+Date: Mon, 2 Aug 2010 16:01:39 +0800
+Subject: [PATCH 008/107] rtc: AT91SAM9X5 has an at91_rtc
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Dan Liang <dan.liang@atmel.com>
+[ukleinek: reword commit log]
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/rtc/Kconfig | 6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
+index e187887..fa5a072 100644
+--- a/drivers/rtc/Kconfig
++++ b/drivers/rtc/Kconfig
+@@ -789,15 +789,15 @@ config RTC_DRV_AT32AP700X
+
+ config RTC_DRV_AT91RM9200
+ tristate "AT91RM9200 or some AT91SAM9 RTC"
+- depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
++ depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 || ARCH_AT91SAM9X5
+ help
+ Driver for the internal RTC (Realtime Clock) module found on
+- Atmel AT91RM9200's and some AT91SAM9 chips. On AT91SAM9 chips
++ Atmel AT91RM9200's and some AT91SAM9 chips. On AT91SAM9 chips
+ this is powered by the backup power supply.
+
+ config RTC_DRV_AT91SAM9
+ tristate "AT91SAM9x/AT91CAP9 RTT as RTC"
+- depends on ARCH_AT91 && !(ARCH_AT91RM9200 || ARCH_AT91X40)
++ depends on ARCH_AT91 && !(ARCH_AT91RM9200 || ARCH_AT91X40 || ARCH_AT91SAM9X5)
+ help
+ RTC driver for the Atmel AT91SAM9x and AT91CAP9 internal RTT
+ (Real Time Timer). These timers are powered by the backup power
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0009-ARM-at91-overall-definition-add-5series-support.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0009-ARM-at91-overall-definition-add-5series-support.patch
new file mode 100644
index 0000000..133588d
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0009-ARM-at91-overall-definition-add-5series-support.patch
@@ -0,0 +1,356 @@
+From 4b93b1ba993ae9c9d60a86d0a55108a4d2ee2244 Mon Sep 17 00:00:00 2001
+From: Dan Liang <dan.liang@atmel.com>
+Date: Tue, 13 Jul 2010 15:56:23 +0800
+Subject: [PATCH 009/107] ARM: at91: overall definition: add 5series support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+[at91sam9x5.h]
+Add the definitions of peripheral and system registers for 5series chips family.
+
+[at91sam9x5_matrix.h]
+Add definitions of Matrix registers for 5series chips family.
+
+[cpu.h]
+Add ARCH_ID and basic cpu macros definition for 5series chips family.
+
+Signed-off-by: Dan Liang <dan.liang@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ arch/arm/mach-at91/include/mach/at91sam9x5.h | 179 ++++++++++++++++++++
+ .../arm/mach-at91/include/mach/at91sam9x5_matrix.h | 136 +++++++++++++++
+ 2 files changed, 315 insertions(+), 0 deletions(-)
+ create mode 100644 arch/arm/mach-at91/include/mach/at91sam9x5.h
+ create mode 100644 arch/arm/mach-at91/include/mach/at91sam9x5_matrix.h
+
+diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5.h b/arch/arm/mach-at91/include/mach/at91sam9x5.h
+new file mode 100644
+index 0000000..c263b46
+--- /dev/null
++++ b/arch/arm/mach-at91/include/mach/at91sam9x5.h
+@@ -0,0 +1,179 @@
++/*
++ * Chip-specific header file for the AT91SAM9x5 family
++ *
++ * Copyright (C) 2009-2010 Atmel Corporation.
++ *
++ * Common definitions.
++ * Based on AT91SAM9x5 preliminary datasheet.
++ *
++ * 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 AT91SAM9X5_H
++#define AT91SAM9X5_H
++
++/*
++ * Peripheral identifiers/interrupts.
++ */
++#define AT91_ID_FIQ 0 /* Advanced Interrupt Controller (FIQ) */
++#define AT91_ID_SYS 1 /* System Controller Interrupt */
++#define AT91SAM9X5_ID_PIOAB 2 /* Parallel I/O Controller A and B */
++#define AT91SAM9X5_ID_PIOCD 3 /* Parallel I/O Controller C and D */
++#define AT91SAM9X5_ID_SMD 4 /* SMD Soft Modem (SMD) */
++#define AT91SAM9X5_ID_USART0 5 /* USART 0 */
++#define AT91SAM9X5_ID_USART1 6 /* USART 1 */
++#define AT91SAM9X5_ID_USART2 7 /* USART 2 */
++#define AT91SAM9X5_ID_USART3 8 /* USART 3 */
++#define AT91SAM9X5_ID_TWI0 9 /* Two-Wire Interface 0 */
++#define AT91SAM9X5_ID_TWI1 10 /* Two-Wire Interface 1 */
++#define AT91SAM9X5_ID_TWI2 11 /* Two-Wire Interface 2 */
++#define AT91SAM9X5_ID_MCI0 12 /* High Speed Multimedia Card Interface 0 */
++#define AT91SAM9X5_ID_SPI0 13 /* Serial Peripheral Interface 0 */
++#define AT91SAM9X5_ID_SPI1 14 /* Serial Peripheral Interface 1 */
++#define AT91SAM9X5_ID_UART0 15 /* UART 0 */
++#define AT91SAM9X5_ID_UART1 16 /* UART 1 */
++#define AT91SAM9X5_ID_TCB 17 /* Timer Counter 0, 1, 2, 3, 4 and 5 */
++#define AT91SAM9X5_ID_PWM 18 /* Pulse Width Modulation Controller */
++#define AT91SAM9X5_ID_ADC 19 /* ADC Controller */
++#define AT91SAM9X5_ID_DMA0 20 /* DMA Controller 0 */
++#define AT91SAM9X5_ID_DMA1 21 /* DMA Controller 1 */
++#define AT91SAM9X5_ID_UHPHS 22 /* USB Host High Speed */
++#define AT91SAM9X5_ID_UDPHS 23 /* USB Device High Speed */
++#define AT91SAM9X5_ID_EMAC0 24 /* Ethernet MAC0 */
++#define AT91SAM9X5_ID_LCDC 25 /* LCD Controller */
++#define AT91SAM9X5_ID_ISI 25 /* Image Sensor Interface */
++#define AT91SAM9X5_ID_MCI1 26 /* High Speed Multimedia Card Interface 1 */
++#define AT91SAM9X5_ID_EMAC1 27 /* Ethernet MAC1 */
++#define AT91SAM9X5_ID_SSC 28 /* Synchronous Serial Controller */
++#define AT91SAM9X5_ID_CAN0 29 /* CAN Controller 0 */
++#define AT91SAM9X5_ID_CAN1 30 /* CAN Controller 1 */
++#define AT91SAM9X5_ID_IRQ0 31 /* Advanced Interrupt Controller */
++
++/*
++ * User Peripheral physical base addresses.
++ */
++#define AT91SAM9X5_BASE_SPI0 0xf0000000
++#define AT91SAM9X5_BASE_SPI1 0xf0004000
++#define AT91SAM9X5_BASE_MCI0 0xf0008000
++#define AT91SAM9X5_BASE_MCI1 0xf000c000
++#define AT91SAM9X5_BASE_SSC 0xf0010000
++#define AT91SAM9X5_BASE_CAN0 0xf8000000
++#define AT91SAM9X5_BASE_CAN1 0xf8004000
++#define AT91SAM9X5_BASE_TCB0 0xf8008000
++#define AT91SAM9X5_BASE_TC0 0xf8008000
++#define AT91SAM9X5_BASE_TC1 0xf8008040
++#define AT91SAM9X5_BASE_TC2 0xf8008080
++#define AT91SAM9X5_BASE_TCB1 0xf800c000
++#define AT91SAM9X5_BASE_TC3 0xf800c000
++#define AT91SAM9X5_BASE_TC4 0xf800c040
++#define AT91SAM9X5_BASE_TC5 0xf800c080
++#define AT91SAM9X5_BASE_TWI0 0xf8010000
++#define AT91SAM9X5_BASE_TWI1 0xf8014000
++#define AT91SAM9X5_BASE_TWI2 0xf8018000
++#define AT91SAM9X5_BASE_USART0 0xf801c000
++#define AT91SAM9X5_BASE_USART1 0xf8020000
++#define AT91SAM9X5_BASE_USART2 0xf8024000
++#define AT91SAM9X5_BASE_USART3 0xf8028000
++#define AT91SAM9X5_BASE_EMAC0 0xf802c000
++#define AT91SAM9X5_BASE_EMAC1 0xf8030000
++#define AT91SAM9X5_BASE_PWMC 0xf8034000
++#define AT91SAM9X5_BASE_LCDC 0xf8038000
++#define AT91SAM9X5_BASE_UDPHS 0xf803c000
++#define AT91SAM9X5_BASE_UART0 0xf8040000
++#define AT91SAM9X5_BASE_UART1 0xf8044000
++#define AT91SAM9X5_BASE_ISI 0xf8048000
++#define AT91SAM9X5_BASE_ADC 0xf804c000
++#define AT91_BASE_SYS 0xffffc000
++
++/*
++ * System Peripherals (offset from AT91_BASE_SYS)
++ */
++#define AT91_MATRIX (0xffffde00 - AT91_BASE_SYS)
++#define AT91_PMECC (0xffffe000 - AT91_BASE_SYS)
++#define AT91_PMERRLOC (0xffffe600 - AT91_BASE_SYS)
++#define AT91_DDRSDRC0 (0xffffe800 - AT91_BASE_SYS)
++#define AT91_SMC (0xffffea00 - AT91_BASE_SYS)
++#define AT91_DMA0 (0xffffec00 - AT91_BASE_SYS)
++#define AT91_DMA1 (0xffffee00 - AT91_BASE_SYS)
++#define AT91_AIC (0xfffff000 - AT91_BASE_SYS)
++#define AT91_DBGU (0xfffff200 - AT91_BASE_SYS)
++#define AT91_PIOA (0xfffff400 - AT91_BASE_SYS)
++#define AT91_PIOB (0xfffff600 - AT91_BASE_SYS)
++#define AT91_PIOC (0xfffff800 - AT91_BASE_SYS)
++#define AT91_PIOD (0xfffffa00 - AT91_BASE_SYS)
++#define AT91_PMC (0xfffffc00 - AT91_BASE_SYS)
++#define AT91_RSTC (0xfffffe00 - AT91_BASE_SYS)
++#define AT91_SHDWC (0xfffffe10 - AT91_BASE_SYS)
++#define AT91_PIT (0xfffffe30 - AT91_BASE_SYS)
++#define AT91_WDT (0xfffffe40 - AT91_BASE_SYS)
++#define AT91_GPBR (0xfffffe60 - AT91_BASE_SYS)
++#define AT91_RTC (0xfffffeb0 - AT91_BASE_SYS)
++
++#define AT91_USART0 AT91SAM9X5_BASE_US0
++#define AT91_USART1 AT91SAM9X5_BASE_US1
++#define AT91_USART2 AT91SAM9X5_BASE_US2
++#define AT91_USART3 AT91SAM9X5_BASE_US3
++
++/*
++ * Internal Memory.
++ */
++#define AT91SAM9X5_SRAM_BASE 0x00300000 /* Internal SRAM base address */
++#define AT91SAM9X5_SRAM_SIZE SZ_32K /* Internal SRAM size (32Kb) */
++
++#define AT91SAM9X5_ROM_BASE 0x00100000 /* Internal ROM base address */
++#define AT91SAM9X5_ROM_SIZE SZ_1M /* Internal ROM size (1Mb) */
++
++#define AT91SAM9X5_SMD_BASE 0x00400000 /* SMD Controller */
++#define AT91SAM9X5_UDPHS_FIFO 0x00500000 /* USB Device HS controller */
++#define AT91SAM9X5_OHCI_BASE 0x00600000 /* USB Host controller (OHCI) */
++#define AT91SAM9X5_EHCI_BASE 0x00700000 /* USB Host controller (EHCI) */
++
++#define CONFIG_DRAM_BASE AT91_CHIPSELECT_1
++
++#define CONSISTENT_DMA_SIZE SZ_4M
++
++/*
++ * DMA0 peripheral identifiers
++ * for hardware handshaking interface
++ */
++#define AT_DMA_ID_MCI0 0
++#define AT_DMA_ID_SPI0_TX 1
++#define AT_DMA_ID_SPI0_RX 2
++#define AT_DMA_ID_USART0_TX 3
++#define AT_DMA_ID_USART0_RX 4
++#define AT_DMA_ID_USART1_TX 5
++#define AT_DMA_ID_USART1_RX 6
++#define AT_DMA_ID_TWI0_TX 7
++#define AT_DMA_ID_TWI0_RX 8
++#define AT_DMA_ID_TWI2_TX 9
++#define AT_DMA_ID_TWI2_RX 10
++#define AT_DMA_ID_UART0_TX 11
++#define AT_DMA_ID_UART0_RX 12
++#define AT_DMA_ID_SSC_TX 13
++#define AT_DMA_ID_SSC_RX 14
++
++/*
++ * DMA1 peripheral identifiers
++ * for hardware handshaking interface
++ */
++#define AT_DMA_ID_MCI1 0
++#define AT_DMA_ID_SPI1_TX 1
++#define AT_DMA_ID_SPI1_RX 2
++#define AT_DMA_ID_SMD_TX 3
++#define AT_DMA_ID_SMD_RX 4
++#define AT_DMA_ID_TWI1_TX 5
++#define AT_DMA_ID_TWI1_RX 6
++#define AT_DMA_ID_ADC_RX 7
++#define AT_DMA_ID_DBGU_TX 8
++#define AT_DMA_ID_DBGU_RX 9
++#define AT_DMA_ID_UART1_TX 10
++#define AT_DMA_ID_UART1_RX 11
++#define AT_DMA_ID_USART2_TX 12
++#define AT_DMA_ID_USART2_RX 13
++#define AT_DMA_ID_USART3_TX 14
++#define AT_DMA_ID_USART3_RX 15
++
++#endif
+diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5_matrix.h b/arch/arm/mach-at91/include/mach/at91sam9x5_matrix.h
+new file mode 100644
+index 0000000..c3e6b64
+--- /dev/null
++++ b/arch/arm/mach-at91/include/mach/at91sam9x5_matrix.h
+@@ -0,0 +1,136 @@
++/*
++ * Matrix-centric header file for the AT91SAM9x5 family
++ *
++ * Copyright (C) 2009-2010 Atmel Corporation.
++ *
++ * Memory Controllers (MATRIX, EBI) - System peripherals registers.
++ * Based on AT91SAM9x5 preliminary datasheet.
++ *
++ * 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 AT91SAM9X5_MATRIX_H
++#define AT91SAM9X5_MATRIX_H
++
++#define AT91_MATRIX_MCFG0 (AT91_MATRIX + 0x00) /* Master Configuration Register 0 */
++#define AT91_MATRIX_MCFG1 (AT91_MATRIX + 0x04) /* Master Configuration Register 1 */
++#define AT91_MATRIX_MCFG2 (AT91_MATRIX + 0x08) /* Master Configuration Register 2 */
++#define AT91_MATRIX_MCFG3 (AT91_MATRIX + 0x0C) /* Master Configuration Register 3 */
++#define AT91_MATRIX_MCFG4 (AT91_MATRIX + 0x10) /* Master Configuration Register 4 */
++#define AT91_MATRIX_MCFG5 (AT91_MATRIX + 0x14) /* Master Configuration Register 5 */
++#define AT91_MATRIX_MCFG6 (AT91_MATRIX + 0x18) /* Master Configuration Register 6 */
++#define AT91_MATRIX_MCFG7 (AT91_MATRIX + 0x1C) /* Master Configuration Register 7 */
++#define AT91_MATRIX_MCFG8 (AT91_MATRIX + 0x20) /* Master Configuration Register 8 */
++#define AT91_MATRIX_MCFG9 (AT91_MATRIX + 0x24) /* Master Configuration Register 9 */
++#define AT91_MATRIX_MCFG10 (AT91_MATRIX + 0x28) /* Master Configuration Register 10 */
++#define AT91_MATRIX_MCFG11 (AT91_MATRIX + 0x2C) /* Master Configuration Register 11 */
++#define AT91_MATRIX_ULBT (7 << 0) /* Undefined Length Burst Type */
++#define AT91_MATRIX_ULBT_INFINITE (0 << 0)
++#define AT91_MATRIX_ULBT_SINGLE (1 << 0)
++#define AT91_MATRIX_ULBT_FOUR (2 << 0)
++#define AT91_MATRIX_ULBT_EIGHT (3 << 0)
++#define AT91_MATRIX_ULBT_SIXTEEN (4 << 0)
++#define AT91_MATRIX_ULBT_THIRTYTWO (5 << 0)
++#define AT91_MATRIX_ULBT_SIXTYFOUR (6 << 0)
++#define AT91_MATRIX_ULBT_128 (7 << 0)
++
++#define AT91_MATRIX_SCFG0 (AT91_MATRIX + 0x40) /* Slave Configuration Register 0 */
++#define AT91_MATRIX_SCFG1 (AT91_MATRIX + 0x44) /* Slave Configuration Register 1 */
++#define AT91_MATRIX_SCFG2 (AT91_MATRIX + 0x48) /* Slave Configuration Register 2 */
++#define AT91_MATRIX_SCFG3 (AT91_MATRIX + 0x4C) /* Slave Configuration Register 3 */
++#define AT91_MATRIX_SCFG4 (AT91_MATRIX + 0x50) /* Slave Configuration Register 4 */
++#define AT91_MATRIX_SCFG5 (AT91_MATRIX + 0x54) /* Slave Configuration Register 5 */
++#define AT91_MATRIX_SCFG6 (AT91_MATRIX + 0x58) /* Slave Configuration Register 6 */
++#define AT91_MATRIX_SCFG7 (AT91_MATRIX + 0x5C) /* Slave Configuration Register 7 */
++#define AT91_MATRIX_SCFG8 (AT91_MATRIX + 0x60) /* Slave Configuration Register 8 */
++#define AT91_MATRIX_SLOT_CYCLE (0x1ff << 0) /* Maximum Number of Allowed Cycles for a Burst */
++#define AT91_MATRIX_DEFMSTR_TYPE (3 << 16) /* Default Master Type */
++#define AT91_MATRIX_DEFMSTR_TYPE_NONE (0 << 16)
++#define AT91_MATRIX_DEFMSTR_TYPE_LAST (1 << 16)
++#define AT91_MATRIX_DEFMSTR_TYPE_FIXED (2 << 16)
++#define AT91_MATRIX_FIXED_DEFMSTR (0xf << 18) /* Fixed Index of Default Master */
++
++#define AT91_MATRIX_PRAS0 (AT91_MATRIX + 0x80) /* Priority Register A for Slave 0 */
++#define AT91_MATRIX_PRBS0 (AT91_MATRIX + 0x84) /* Priority Register B for Slave 0 */
++#define AT91_MATRIX_PRAS1 (AT91_MATRIX + 0x88) /* Priority Register A for Slave 1 */
++#define AT91_MATRIX_PRBS1 (AT91_MATRIX + 0x8C) /* Priority Register B for Slave 1 */
++#define AT91_MATRIX_PRAS2 (AT91_MATRIX + 0x90) /* Priority Register A for Slave 2 */
++#define AT91_MATRIX_PRBS2 (AT91_MATRIX + 0x94) /* Priority Register B for Slave 2 */
++#define AT91_MATRIX_PRAS3 (AT91_MATRIX + 0x98) /* Priority Register A for Slave 3 */
++#define AT91_MATRIX_PRBS3 (AT91_MATRIX + 0x9C) /* Priority Register B for Slave 3 */
++#define AT91_MATRIX_PRAS4 (AT91_MATRIX + 0xA0) /* Priority Register A for Slave 4 */
++#define AT91_MATRIX_PRBS4 (AT91_MATRIX + 0xA4) /* Priority Register B for Slave 4 */
++#define AT91_MATRIX_PRAS5 (AT91_MATRIX + 0xA8) /* Priority Register A for Slave 5 */
++#define AT91_MATRIX_PRBS5 (AT91_MATRIX + 0xAC) /* Priority Register B for Slave 5 */
++#define AT91_MATRIX_PRAS6 (AT91_MATRIX + 0xB0) /* Priority Register A for Slave 6 */
++#define AT91_MATRIX_PRBS6 (AT91_MATRIX + 0xB4) /* Priority Register B for Slave 6 */
++#define AT91_MATRIX_PRAS7 (AT91_MATRIX + 0xB8) /* Priority Register A for Slave 7 */
++#define AT91_MATRIX_PRBS7 (AT91_MATRIX + 0xBC) /* Priority Register B for Slave 7 */
++#define AT91_MATRIX_PRAS8 (AT91_MATRIX + 0xC0) /* Priority Register A for Slave 8 */
++#define AT91_MATRIX_PRBS8 (AT91_MATRIX + 0xC4) /* Priority Register B for Slave 8 */
++#define AT91_MATRIX_M0PR (3 << 0) /* Master 0 Priority */
++#define AT91_MATRIX_M1PR (3 << 4) /* Master 1 Priority */
++#define AT91_MATRIX_M2PR (3 << 8) /* Master 2 Priority */
++#define AT91_MATRIX_M3PR (3 << 12) /* Master 3 Priority */
++#define AT91_MATRIX_M4PR (3 << 16) /* Master 4 Priority */
++#define AT91_MATRIX_M5PR (3 << 20) /* Master 5 Priority */
++#define AT91_MATRIX_M6PR (3 << 24) /* Master 6 Priority */
++#define AT91_MATRIX_M7PR (3 << 28) /* Master 7 Priority */
++#define AT91_MATRIX_M8PR (3 << 0) /* Master 8 Priority (in Register B) */
++#define AT91_MATRIX_M9PR (3 << 4) /* Master 9 Priority (in Register B) */
++#define AT91_MATRIX_M10PR (3 << 8) /* Master 10 Priority (in Register B) */
++#define AT91_MATRIX_M11PR (3 << 12) /* Master 11 Priority (in Register B) */
++
++#define AT91_MATRIX_MRCR (AT91_MATRIX + 0x100) /* Master Remap Control Register */
++#define AT91_MATRIX_RCB0 (1 << 0) /* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */
++#define AT91_MATRIX_RCB1 (1 << 1) /* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
++#define AT91_MATRIX_RCB2 (1 << 2)
++#define AT91_MATRIX_RCB3 (1 << 3)
++#define AT91_MATRIX_RCB4 (1 << 4)
++#define AT91_MATRIX_RCB5 (1 << 5)
++#define AT91_MATRIX_RCB6 (1 << 6)
++#define AT91_MATRIX_RCB7 (1 << 7)
++#define AT91_MATRIX_RCB8 (1 << 8)
++#define AT91_MATRIX_RCB9 (1 << 9)
++#define AT91_MATRIX_RCB10 (1 << 10)
++#define AT91_MATRIX_RCB11 (1 << 11)
++
++#define AT91_MATRIX_EBICSA (AT91_MATRIX + 0x120) /* EBI Chip Select Assignment Register */
++#define AT91_MATRIX_EBI_CS1A (1 << 1) /* Chip Select 1 Assignment */
++#define AT91_MATRIX_EBI_CS1A_SMC (0 << 1)
++#define AT91_MATRIX_EBI_CS1A_SDRAMC (1 << 1)
++#define AT91_MATRIX_EBI_CS3A (1 << 3) /* Chip Select 3 Assignment */
++#define AT91_MATRIX_EBI_CS3A_SMC (0 << 3)
++#define AT91_MATRIX_EBI_CS3A_SMC_NANDFLASH (1 << 3)
++#define AT91_MATRIX_EBI_DBPUC (1 << 8) /* Data Bus Pull-up Configuration */
++#define AT91_MATRIX_EBI_DBPU_ON (0 << 8)
++#define AT91_MATRIX_EBI_DBPU_OFF (1 << 8)
++#define AT91_MATRIX_EBI_DBPDC (1 << 9) /* Data Bus Pull-up Configuration */
++#define AT91_MATRIX_EBI_DBPD_ON (0 << 9)
++#define AT91_MATRIX_EBI_DBPD_OFF (1 << 9)
++#define AT91_MATRIX_EBI_EBI_IOSR (1 << 17) /* EBI I/O slew rate selection */
++#define AT91_MATRIX_EBI_EBI_IOSR_REDUCED (0 << 17)
++#define AT91_MATRIX_EBI_EBI_IOSR_NORMAL (1 << 17)
++#define AT91_MATRIX_NFD0_SELECT (1 << 24) /* NAND Flash Data Bus Selection */
++#define AT91_MATRIX_NFD0_ON_D0 (0 << 24)
++#define AT91_MATRIX_NFD0_ON_D16 (1 << 24)
++#define AT91_MATRIX_DDR_MP_EN (1 << 25) /* DDR Multi-port Enable */
++#define AT91_MATRIX_MP_OFF (0 << 25)
++#define AT91_MATRIX_MP_ON (1 << 25)
++
++#define AT91_MATRIX_WPMR (AT91_MATRIX + 0x1E4) /* Write Protect Mode Register */
++#define AT91_MATRIX_WPMR_WPEN (1 << 0) /* Write Protect ENable */
++#define AT91_MATRIX_WPMR_WP_WPDIS (0 << 0)
++#define AT91_MATRIX_WPMR_WP_WPEN (1 << 0)
++#define AT91_MATRIX_WPMR_WPKEY (0xFFFFFF << 8) /* Write Protect KEY */
++
++#define AT91_MATRIX_WPSR (AT91_MATRIX + 0x1E8) /* Write Protect Status Register */
++#define AT91_MATRIX_WPSR_WPVS (1 << 0) /* Write Protect Violation Status */
++#define AT91_MATRIX_WPSR_NO_WPV (0 << 0)
++#define AT91_MATRIX_WPSR_WPV (1 << 0)
++#define AT91_MATRIX_WPSR_WPVSRC (0xFFFF << 8) /* Write Protect Violation Source */
++
++#endif
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0010-ARM-at91-PMC-header-add-5series-support.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0010-ARM-at91-PMC-header-add-5series-support.patch
new file mode 100644
index 0000000..b6dd5d4
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0010-ARM-at91-PMC-header-add-5series-support.patch
@@ -0,0 +1,121 @@
+From 70174744ea113add6279afb8642ea71acafb8d69 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Fri, 9 Jul 2010 19:33:10 +0200
+Subject: [PATCH 010/107] ARM: at91: PMC header: add 5series support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add 5series chips family support in PMC header file:
+Alternate prescaler location and CSS length for PCKR is added.
+The new Peripheral Control Register management is added.
+Protection mode register is modified to complete its management.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ arch/arm/mach-at91/include/mach/at91_pmc.h | 63 ++++++++++++++++++++++------
+ 1 files changed, 50 insertions(+), 13 deletions(-)
+
+diff --git a/arch/arm/mach-at91/include/mach/at91_pmc.h b/arch/arm/mach-at91/include/mach/at91_pmc.h
+index e46f93e..1782178 100644
+--- a/arch/arm/mach-at91/include/mach/at91_pmc.h
++++ b/arch/arm/mach-at91/include/mach/at91_pmc.h
+@@ -47,9 +47,13 @@
+ #define AT91_PMC_BIASCOUNT (0xf << 28) /* UTMI BIAS Start-up Time */
+
+ #define AT91_CKGR_MOR (AT91_PMC + 0x20) /* Main Oscillator Register [not on SAM9RL] */
+-#define AT91_PMC_MOSCEN (1 << 0) /* Main Oscillator Enable */
+-#define AT91_PMC_OSCBYPASS (1 << 1) /* Oscillator Bypass [SAM9x, CAP9] */
+-#define AT91_PMC_OSCOUNT (0xff << 8) /* Main Oscillator Start-up Time */
++#define AT91_PMC_MOSCEN (1 << 0) /* Main Oscillator Enable */
++#define AT91_PMC_OSCBYPASS (1 << 1) /* Oscillator Bypass [SAM9x, CAP9] */
++#define AT91_PMC_MOSCRCEN (1 << 3) /* Main On-Chip RC Oscillator Enable [some SAM9] */
++#define AT91_PMC_OSCOUNT (0xff << 8) /* Main Oscillator Start-up Time */
++#define AT91_PMC_KEY (0x37 << 16) /* MOR Writing Key */
++#define AT91_PMC_MOSCSEL (1 << 24) /* Main Oscillator Selection [some SAM9] */
++#define AT91_PMC_CFDEN (1 << 25) /* Clock Failure Detector Enable [some SAM9] */
+
+ #define AT91_CKGR_MCFR (AT91_PMC + 0x24) /* Main Clock Frequency Register */
+ #define AT91_PMC_MAINF (0xffff << 0) /* Main Clock Frequency */
+@@ -74,14 +78,24 @@
+ #define AT91_PMC_CSS_PLLA (2 << 0)
+ #define AT91_PMC_CSS_PLLB (3 << 0)
+ #define AT91_PMC_CSS_UPLL (3 << 0) /* [some SAM9 only] */
+-#define AT91_PMC_PRES (7 << 2) /* Master Clock Prescaler */
+-#define AT91_PMC_PRES_1 (0 << 2)
+-#define AT91_PMC_PRES_2 (1 << 2)
+-#define AT91_PMC_PRES_4 (2 << 2)
+-#define AT91_PMC_PRES_8 (3 << 2)
+-#define AT91_PMC_PRES_16 (4 << 2)
+-#define AT91_PMC_PRES_32 (5 << 2)
+-#define AT91_PMC_PRES_64 (6 << 2)
++#define PMC_PRES_OFFSET 2
++#define AT91_PMC_PRES (7 << PMC_PRES_OFFSET) /* Master Clock Prescaler */
++#define AT91_PMC_PRES_1 (0 << PMC_PRES_OFFSET)
++#define AT91_PMC_PRES_2 (1 << PMC_PRES_OFFSET)
++#define AT91_PMC_PRES_4 (2 << PMC_PRES_OFFSET)
++#define AT91_PMC_PRES_8 (3 << PMC_PRES_OFFSET)
++#define AT91_PMC_PRES_16 (4 << PMC_PRES_OFFSET)
++#define AT91_PMC_PRES_32 (5 << PMC_PRES_OFFSET)
++#define AT91_PMC_PRES_64 (6 << PMC_PRES_OFFSET)
++#define PMC_ALT_PRES_OFFSET 4
++#define AT91_PMC_ALT_PRES (7 << PMC_ALT_PRES_OFFSET) /* Master Clock Prescaler [alternate location] */
++#define AT91_PMC_ALT_PRES_1 (0 << PMC_ALT_PRES_OFFSET)
++#define AT91_PMC_ALT_PRES_2 (1 << PMC_ALT_PRES_OFFSET)
++#define AT91_PMC_ALT_PRES_4 (2 << PMC_ALT_PRES_OFFSET)
++#define AT91_PMC_ALT_PRES_8 (3 << PMC_ALT_PRES_OFFSET)
++#define AT91_PMC_ALT_PRES_16 (4 << PMC_ALT_PRES_OFFSET)
++#define AT91_PMC_ALT_PRES_32 (5 << PMC_ALT_PRES_OFFSET)
++#define AT91_PMC_ALT_PRES_64 (6 << PMC_ALT_PRES_OFFSET)
+ #define AT91_PMC_MDIV (3 << 8) /* Master Clock Division */
+ #define AT91RM9200_PMC_MDIV_1 (0 << 8) /* [AT91RM9200 only] */
+ #define AT91RM9200_PMC_MDIV_2 (1 << 8)
+@@ -105,7 +119,14 @@
+ #define AT91_PMC_USBS_UPLL (1 << 0)
+ #define AT91_PMC_OHCIUSBDIV (0xF << 8) /* Divider for USB OHCI Clock */
+
++#define AT91_PMC_SMD (AT91_PMC + 0x3c) /* Soft Modem Clock Register [some SAM9 only] */
++#define AT91_PMC_SMDS (0x1 << 0) /* SMD input clock selection */
++#define AT91_PMC_SMD_DIV (0x1f << 8) /* SMD input clock divider */
++#define AT91_PMC_SMDDIV(n) (((n) << 8) & AT91_PMC_SMD_DIV)
++
+ #define AT91_PMC_PCKR(n) (AT91_PMC + 0x40 + ((n) * 4)) /* Programmable Clock 0-N Registers */
++#define AT91_PMC_ALT_PCKR_CSS (0x7 << 0) /* Programmable Clock Source Selection [alternate length] */
++#define AT91_PMC_CSS_MASTER (4 << 0) /* [some SAM9 only] */
+ #define AT91_PMC_CSSMCK (0x1 << 8) /* CSS or Master Clock Selection */
+ #define AT91_PMC_CSSMCK_CSS (0 << 8)
+ #define AT91_PMC_CSSMCK_MCK (1 << 8)
+@@ -123,11 +144,27 @@
+ #define AT91_PMC_PCK1RDY (1 << 9) /* Programmable Clock 1 */
+ #define AT91_PMC_PCK2RDY (1 << 10) /* Programmable Clock 2 */
+ #define AT91_PMC_PCK3RDY (1 << 11) /* Programmable Clock 3 */
++#define AT91_PMC_MOSCSELS (1 << 16) /* Main Oscillator Selection [some SAM9] */
++#define AT91_PMC_MOSCRCS (1 << 17) /* Main On-Chip RC [some SAM9] */
++#define AT91_PMC_CFDEV (1 << 18) /* Clock Failure Detector Event [some SAM9] */
+ #define AT91_PMC_IMR (AT91_PMC + 0x6c) /* Interrupt Mask Register */
+
+-#define AT91_PMC_PROT (AT91_PMC + 0xe4) /* Protect Register [AT91CAP9 revC only] */
+-#define AT91_PMC_PROTKEY 0x504d4301 /* Activation Code */
++#define AT91_PMC_PROT (AT91_PMC + 0xe4) /* Write Protect Mode Register [some SAM9, AT91CAP9 revC only] */
++#define AT91_PMC_WPEN (0x1 << 0) /* Write Protect Enable */
++#define AT91_PMC_WPKEY (0xffffff << 8) /* Write Protect Key */
++#define AT91_PMC_PROTKEY (0x504d43 << 8) /* Activation Code */
++
++#define AT91_PMC_WPSR (AT91_PMC + 0xe8) /* Write Protect Status Register [some SAM9] */
++#define AT91_PMC_WPVS (0x1 << 0) /* Write Protect Violation Status */
++#define AT91_PMC_WPVSRC (0xffff << 8) /* Write Protect Violation Source */
+
+ #define AT91_PMC_VER (AT91_PMC + 0xfc) /* PMC Module Version [AT91CAP9 only] */
+
++#define AT91_PMC_PCR (AT91_PMC + 0x10c) /* Peripheral Control Register [some SAM9] */
++#define AT91_PMC_PCR_PID (0x3f << 0) /* Peripheral ID */
++#define AT91_PMC_PCR_CMD (0x1 << 12) /* Command */
++#define AT91_PMC_PCR_DIV (0x3 << 16) /* Divisor Value */
++#define AT91_PMC_PCRDIV(n) (((n) << 16) & AT91_PMC_PCR_DIV)
++#define AT91_PMC_PCR_EN (0x1 << 28) /* Enable */
++
+ #endif
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0011-ARM-at91-clock-add-5series-chip-family-support.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0011-ARM-at91-clock-add-5series-chip-family-support.patch
new file mode 100644
index 0000000..180e515
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0011-ARM-at91-clock-add-5series-chip-family-support.patch
@@ -0,0 +1,215 @@
+From 6a6e54c0091962d01f6b343958bbda95487bb9f5 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 12 Jul 2010 19:24:14 +0200
+Subject: [PATCH 011/107] ARM: at91: clock: add 5series chip family support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Several changes to PMC have to be managed for adding this 5series support:
+- alternate prescaler location for both MCKR and PCKR
+- alternate CSS length for PCKR
+- added cpu_is_at91sam9x5() to functional switches
+- manage UTMI bias like sam9g45 chip family
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ arch/arm/mach-at91/clock.c | 85 ++++++++++++++++++++++++++++++++++----------
+ 1 files changed, 66 insertions(+), 19 deletions(-)
+
+diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c
+index 9113da6..6c92db8 100644
+--- a/arch/arm/mach-at91/clock.c
++++ b/arch/arm/mach-at91/clock.c
+@@ -49,24 +49,37 @@
+ */
+ #define cpu_has_utmi() ( cpu_is_at91cap9() \
+ || cpu_is_at91sam9rl() \
+- || cpu_is_at91sam9g45())
++ || cpu_is_at91sam9g45() \
++ || cpu_is_at91sam9x5())
+
+ #define cpu_has_800M_plla() ( cpu_is_at91sam9g20() \
+- || cpu_is_at91sam9g45())
++ || cpu_is_at91sam9g45() \
++ || cpu_is_at91sam9x5())
+
+ #define cpu_has_300M_plla() (cpu_is_at91sam9g10())
+
+ #define cpu_has_pllb() (!(cpu_is_at91sam9rl() \
+- || cpu_is_at91sam9g45()))
++ || cpu_is_at91sam9g45() \
++ || cpu_is_at91sam9x5()))
+
+-#define cpu_has_upll() (cpu_is_at91sam9g45())
++#define cpu_has_upll() (cpu_is_at91sam9g45() \
++ || cpu_is_at91sam9x5())
+
+ /* USB host HS & FS */
+ #define cpu_has_uhp() (!cpu_is_at91sam9rl())
+
+ /* USB device FS only */
+ #define cpu_has_udpfs() (!(cpu_is_at91sam9rl() \
+- || cpu_is_at91sam9g45()))
++ || cpu_is_at91sam9g45() \
++ || cpu_is_at91sam9x5()))
++
++#define cpu_has_plladiv2() (cpu_is_at91sam9g45() \
++ || cpu_is_at91sam9x5())
++
++#define cpu_has_mdiv3() (cpu_is_at91sam9g45() \
++ || cpu_is_at91sam9x5())
++
++#define cpu_has_alt_prescaler() (cpu_is_at91sam9x5())
+
+ static LIST_HEAD(clocks);
+ static DEFINE_SPINLOCK(clk_lock);
+@@ -139,13 +152,6 @@ static void pmc_uckr_mode(struct clk *clk, int is_on)
+ {
+ unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR);
+
+- if (cpu_is_at91sam9g45()) {
+- if (is_on)
+- uckr |= AT91_PMC_BIASEN;
+- else
+- uckr &= ~AT91_PMC_BIASEN;
+- }
+-
+ if (is_on) {
+ is_on = AT91_PMC_LOCKU;
+ at91_sys_write(AT91_CKGR_UCKR, uckr | clk->pmc_mask);
+@@ -210,11 +216,26 @@ static struct clk __init *at91_css_to_clk(unsigned long css)
+ return &utmi_clk;
+ else if (cpu_has_pllb())
+ return &pllb;
++ break;
++ /* alternate PMC: can use master clock */
++ case AT91_PMC_CSS_MASTER:
++ return &mck;
+ }
+
+ return NULL;
+ }
+
++
++static int pmc_prescaler_divider(u32 reg)
++{
++ if (cpu_has_alt_prescaler()) {
++ return 1 << ((reg & AT91_PMC_ALT_PRES) >> PMC_ALT_PRES_OFFSET);
++ } else {
++ return 1 << ((reg & AT91_PMC_PRES) >> PMC_PRES_OFFSET);
++ }
++}
++
++
+ /*
+ * Associate a particular clock with a function (eg, "uart") and device.
+ * The drivers can then request the same 'function' with several different
+@@ -353,12 +374,22 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
+ {
+ unsigned long flags;
+ unsigned prescale;
++ unsigned long prescale_offset, css_mask;
+ unsigned long actual;
+
+ if (!clk_is_programmable(clk))
+ return -EINVAL;
+ if (clk->users)
+ return -EBUSY;
++
++ if (cpu_has_alt_prescaler()) {
++ prescale_offset = PMC_ALT_PRES_OFFSET;
++ css_mask = AT91_PMC_ALT_PCKR_CSS;
++ } else {
++ prescale_offset = PMC_PRES_OFFSET;
++ css_mask = AT91_PMC_CSS;
++ }
++
+ spin_lock_irqsave(&clk_lock, flags);
+
+ actual = clk->parent->rate_hz;
+@@ -367,8 +398,8 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
+ u32 pckr;
+
+ pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
+- pckr &= AT91_PMC_CSS; /* clock selection */
+- pckr |= prescale << 2;
++ pckr &= css_mask; /* keep clock selection */
++ pckr |= prescale << prescale_offset;
+ at91_sys_write(AT91_PMC_PCKR(clk->id), pckr);
+ clk->rate_hz = actual;
+ break;
+@@ -415,11 +446,17 @@ static void __init init_programmable_clock(struct clk *clk)
+ {
+ struct clk *parent;
+ u32 pckr;
++ unsigned int css_mask;
++
++ if (cpu_has_alt_prescaler())
++ css_mask = AT91_PMC_ALT_PCKR_CSS;
++ else
++ css_mask = AT91_PMC_CSS;
+
+ pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
+- parent = at91_css_to_clk(pckr & AT91_PMC_CSS);
++ parent = at91_css_to_clk(pckr & css_mask);
+ clk->parent = parent;
+- clk->rate_hz = parent->rate_hz / (1 << ((pckr & AT91_PMC_PRES) >> 2));
++ clk->rate_hz = parent->rate_hz / pmc_prescaler_divider(pckr);
+ }
+
+ #endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */
+@@ -697,7 +734,7 @@ int __init at91_clock_init(unsigned long main_clock)
+ if (pll_overclock)
+ pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000);
+
+- if (cpu_is_at91sam9g45()) {
++ if (cpu_has_plladiv2()) {
+ mckr = at91_sys_read(AT91_PMC_MCKR);
+ plla.rate_hz /= (1 << ((mckr & AT91_PMC_PLLADIV2) >> 12)); /* plla divisor by 2 */
+ }
+@@ -719,6 +756,10 @@ int __init at91_clock_init(unsigned long main_clock)
+ * (obtain the USB High Speed 480 MHz when input is 12 MHz)
+ */
+ utmi_clk.rate_hz = 40 * utmi_clk.parent->rate_hz;
++
++ /* UTMI bias and PLL are managed at the same time */
++ if (cpu_is_at91sam9g45() || cpu_is_at91sam9x5())
++ utmi_clk.pmc_mask |= AT91_PMC_BIASEN;
+ }
+
+ /*
+@@ -737,7 +778,7 @@ int __init at91_clock_init(unsigned long main_clock)
+ mckr = at91_sys_read(AT91_PMC_MCKR);
+ mck.parent = at91_css_to_clk(mckr & AT91_PMC_CSS);
+ freq = mck.parent->rate_hz;
+- freq /= (1 << ((mckr & AT91_PMC_PRES) >> 2)); /* prescale */
++ freq /= pmc_prescaler_divider(mckr); /* prescale */
+ if (cpu_is_at91rm9200()) {
+ mck.rate_hz = freq / (1 + ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */
+ } else if (cpu_is_at91sam9g20()) {
+@@ -745,13 +786,19 @@ int __init at91_clock_init(unsigned long main_clock)
+ freq / ((mckr & AT91_PMC_MDIV) >> 7) : freq; /* mdiv ; (x >> 7) = ((x >> 8) * 2) */
+ if (mckr & AT91_PMC_PDIV)
+ freq /= 2; /* processor clock division */
+- } else if (cpu_is_at91sam9g45()) {
++ } else if (cpu_has_mdiv3()) {
+ mck.rate_hz = (mckr & AT91_PMC_MDIV) == AT91SAM9_PMC_MDIV_3 ?
+ freq / 3 : freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */
+ } else {
+ mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */
+ }
+
++ if (cpu_has_alt_prescaler()) {
++ /* Programmable clocks can use MCK */
++ mck.type |= CLK_TYPE_PRIMARY;
++ mck.id = 4;
++ }
++
+ /* Register the PMC's standard clocks */
+ for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++)
+ list_add_tail(&standard_pmc_clocks[i]->node, &clocks);
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0012-ARM-at91-AT91SAM9x5-processors-and-EK-board-support.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0012-ARM-at91-AT91SAM9x5-processors-and-EK-board-support.patch
new file mode 100644
index 0000000..6078e73
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0012-ARM-at91-AT91SAM9x5-processors-and-EK-board-support.patch
@@ -0,0 +1,3216 @@
+From 31f087cd051928de83fe17aee4d1e2a6416e88ee Mon Sep 17 00:00:00 2001
+From: Dan Liang <dan.liang@atmel.com>
+Date: Fri, 23 Jul 2010 13:00:56 +0200
+Subject: [PATCH 012/107] ARM: at91: AT91SAM9x5 processors and EK board
+ support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch is based on many smaller patches by Dan Liang, Hong Xu, Josh
+Wu and Nicolas Ferre.
+
+XXX: try to put support for AT91SAM9x5 into an existing choice item
+
+Signed-off-by: Dan Liang <dan.liang@atmel.com>
+Signed-off-by: Hong Xu <hong.xu@atmel.com>
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+[ukleinek: remove .phys_io and .io_pg_offst]
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ arch/arm/mach-at91/Kconfig | 21 +
+ arch/arm/mach-at91/Makefile | 4 +
+ arch/arm/mach-at91/at91sam9x5.c | 416 ++++++
+ arch/arm/mach-at91/at91sam9x5_devices.c | 1785 ++++++++++++++++++++++++
+ arch/arm/mach-at91/board-sam9x5cm.c | 236 ++++
+ arch/arm/mach-at91/board-sam9x5ek.c | 358 +++++
+ arch/arm/mach-at91/generic.h | 2 +
+ arch/arm/mach-at91/include/mach/board-sam9x5.h | 91 ++
+ arch/arm/mach-at91/include/mach/board.h | 18 +-
+ arch/arm/mach-at91/include/mach/hardware.h | 2 +
+ arch/arm/mach-at91/include/mach/timex.h | 5 +
+ arch/arm/mach-at91/pm.h | 19 +
+ arch/arm/mach-at91/pm_slowclock.S | 11 +-
+ 13 files changed, 2961 insertions(+), 7 deletions(-)
+ create mode 100644 arch/arm/mach-at91/at91sam9x5.c
+ create mode 100644 arch/arm/mach-at91/at91sam9x5_devices.c
+ create mode 100644 arch/arm/mach-at91/board-sam9x5cm.c
+ create mode 100644 arch/arm/mach-at91/board-sam9x5ek.c
+ create mode 100644 arch/arm/mach-at91/include/mach/board-sam9x5.h
+
+diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
+index 2d299bf..b5d29ef 100644
+--- a/arch/arm/mach-at91/Kconfig
++++ b/arch/arm/mach-at91/Kconfig
+@@ -78,6 +78,13 @@ config ARCH_AT91SAM9G45
+ select HAVE_FB_ATMEL
+ select HAVE_NET_MACB
+
++config ARCH_AT91SAM9X5
++ bool "AT91SAM9X5"
++ select CPU_ARM926T
++ select GENERIC_CLOCKEVENTS
++ select HAVE_FB_ATMEL
++ select HAVE_NET_MACB
++
+ config ARCH_AT91CAP9
+ bool "AT91CAP9"
+ select CPU_ARM926T
+@@ -426,6 +433,20 @@ endif
+
+ # ----------------------------------------------------------
+
++if ARCH_AT91SAM9X5
++
++comment "AT91SAM9x5 Series Board Type"
++
++config MACH_AT91SAM9X5EK
++ bool "Atmel AT91SAM9x5 Series Evaluation Kit"
++ help
++ Select this if you re using Atmel's AT91SAM9x5-EK Evaluation Kit.
++ Supported chips are sam9g15, sam9g25, sam9x25, sam9g35 and sam9x35.
++
++endif
++
++# ----------------------------------------------------------
++
+ if ARCH_AT91CAP9
+
+ comment "AT91CAP9 Board Type"
+diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
+index a83835e..3d82460 100644
+--- a/arch/arm/mach-at91/Makefile
++++ b/arch/arm/mach-at91/Makefile
+@@ -18,6 +18,7 @@ obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam926x_time.o at91sam9263_d
+ obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o sam9_smc.o at91sam9_alt_reset.o
+ obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o at91sam9_alt_reset.o
+ obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam926x_time.o at91sam9g45_devices.o sam9_smc.o
++obj-$(CONFIG_ARCH_AT91SAM9X5) += at91sam9x5.o at91sam926x_time.o at91sam9x5_devices.o sam9_smc.o
+ obj-$(CONFIG_ARCH_AT91CAP9) += at91cap9.o at91sam926x_time.o at91cap9_devices.o sam9_smc.o
+ obj-$(CONFIG_ARCH_AT572D940HF) += at572d940hf.o at91sam926x_time.o at572d940hf_devices.o sam9_smc.o
+ obj-$(CONFIG_ARCH_AT91X40) += at91x40.o at91x40_time.o
+@@ -75,6 +76,9 @@ obj-$(CONFIG_MACH_SNAPPER_9260) += board-snapper9260.o
+ # AT91SAM9G45 board-specific support
+ obj-$(CONFIG_MACH_AT91SAM9M10G45EK) += board-sam9m10g45ek.o
+
++# AT91SAM9X5 board-specific support
++obj-$(CONFIG_MACH_AT91SAM9X5EK) += board-sam9x5cm.o board-sam9x5ek.o
++
+ # AT91CAP9 board-specific support
+ obj-$(CONFIG_MACH_AT91CAP9ADK) += board-cap9adk.o
+
+diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
+new file mode 100644
+index 0000000..de456e6
+--- /dev/null
++++ b/arch/arm/mach-at91/at91sam9x5.c
+@@ -0,0 +1,416 @@
++/*
++ * Chip-specific setup code for the AT91SAM9x5 family
++ *
++ * Copyright (C) 2010 Atmel Corporation.
++ *
++ * 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.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/pm.h>
++
++#include <asm/irq.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <mach/at91sam9x5.h>
++#include <mach/at91_pmc.h>
++#include <mach/at91_rstc.h>
++#include <mach/at91_shdwc.h>
++#include <mach/cpu.h>
++
++#include "generic.h"
++#include "clock.h"
++
++static struct map_desc at91sam9x5_io_desc[] __initdata = {
++ {
++ .virtual = AT91_VA_BASE_SYS,
++ .pfn = __phys_to_pfn(AT91_BASE_SYS),
++ .length = SZ_16K,
++ .type = MT_DEVICE,
++ }, {
++ .virtual = AT91_IO_VIRT_BASE - AT91SAM9X5_SRAM_SIZE,
++ .pfn = __phys_to_pfn(AT91SAM9X5_SRAM_BASE),
++ .length = AT91SAM9X5_SRAM_SIZE,
++ .type = MT_DEVICE,
++ }
++};
++
++/* --------------------------------------------------------------------
++ * Clocks
++ * -------------------------------------------------------------------- */
++
++/*
++ * The peripheral clocks.
++ */
++static struct clk pioAB_clk = {
++ .name = "pioAB_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_PIOAB,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk pioCD_clk = {
++ .name = "pioCD_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_PIOCD,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk smd_clk = {
++ .name = "smd_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_SMD,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk usart0_clk = {
++ .name = "usart0_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_USART0,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk usart1_clk = {
++ .name = "usart1_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_USART1,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk usart2_clk = {
++ .name = "usart2_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_USART2,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++/* USART3 clock - Only for sam9g25/sam9x25 */
++static struct clk usart3_clk = {
++ .name = "usart3_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_USART3,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk twi0_clk = {
++ .name = "twi0_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_TWI0,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk twi1_clk = {
++ .name = "twi1_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_TWI1,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk twi2_clk = {
++ .name = "twi2_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_TWI2,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk mmc0_clk = {
++ .name = "mci0_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_MCI0,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk spi0_clk = {
++ .name = "spi0_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_SPI0,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk spi1_clk = {
++ .name = "spi1_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_SPI1,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk uart0_clk = {
++ .name = "uart0_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_UART0,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk uart1_clk = {
++ .name = "uart1_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_UART1,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk tcb0_clk = {
++ .name = "tcb0_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_TCB,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk pwm_clk = {
++ .name = "pwm_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_PWM,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk adc_clk = {
++ .name = "adc_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_ADC,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk dma0_clk = {
++ .name = "dma0_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_DMA0,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk dma1_clk = {
++ .name = "dma1_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_DMA1,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk uhphs_clk = {
++ .name = "uhphs_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_UHPHS,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk udphs_clk = {
++ .name = "udphs_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_UDPHS,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++/* emac0 clock - Only for sam9g25/sam9x25/sam9g35/sam9x35 */
++static struct clk macb0_clk = {
++ .name = "macb0_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_EMAC0,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++/* lcd clock - Only for sam9g15/sam9g35/sam9x35 */
++static struct clk lcdc_clk = {
++ .name = "lcdc_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_LCDC,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++/* isi clock - Only for sam9g25 */
++static struct clk isi_clk = {
++ .name = "isi_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_ISI,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk mmc1_clk = {
++ .name = "mci1_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_MCI1,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++/* emac1 clock - Only for sam9x25 */
++static struct clk macb1_clk = {
++ .name = "macb1_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_EMAC1,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk ssc_clk = {
++ .name = "ssc_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_SSC,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++/* can0 clock - Only for sam9x35 */
++static struct clk can0_clk = {
++ .name = "can0_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_CAN0,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++/* can1 clock - Only for sam9x35 */
++static struct clk can1_clk = {
++ .name = "can1_clk",
++ .pmc_mask = 1 << AT91SAM9X5_ID_CAN1,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++
++/* One additional fake clock for ohci */
++static struct clk ohci_clk = {
++ .name = "ohci_clk",
++ .pmc_mask = 0,
++ .type = CLK_TYPE_PERIPHERAL,
++ .parent = &uhphs_clk,
++};
++
++/* One additional fake clock for second TC block */
++static struct clk tcb1_clk = {
++ .name = "tcb1_clk",
++ .pmc_mask = 0,
++ .type = CLK_TYPE_PERIPHERAL,
++ .parent = &tcb0_clk,
++};
++
++static struct clk *periph_clocks[] __initdata = {
++ &pioAB_clk,
++ &pioCD_clk,
++ &smd_clk,
++ &usart0_clk,
++ &usart1_clk,
++ &usart2_clk,
++ &twi0_clk,
++ &twi1_clk,
++ &twi2_clk,
++ &mmc0_clk,
++ &spi0_clk,
++ &spi1_clk,
++ &uart0_clk,
++ &uart1_clk,
++ &tcb0_clk,
++ &pwm_clk,
++ &adc_clk,
++ &dma0_clk,
++ &dma1_clk,
++ &uhphs_clk,
++ &udphs_clk,
++ &mmc1_clk,
++ &ssc_clk,
++ // irq0
++ &ohci_clk,
++ &tcb1_clk,
++};
++
++/*
++ * The two programmable clocks.
++ * You must configure pin multiplexing to bring these signals out.
++ */
++static struct clk pck0 = {
++ .name = "pck0",
++ .pmc_mask = AT91_PMC_PCK0,
++ .type = CLK_TYPE_PROGRAMMABLE,
++ .id = 0,
++};
++static struct clk pck1 = {
++ .name = "pck1",
++ .pmc_mask = AT91_PMC_PCK1,
++ .type = CLK_TYPE_PROGRAMMABLE,
++ .id = 1,
++};
++
++static void __init at91sam9x5_register_clocks(void)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
++ clk_register(periph_clocks[i]);
++
++ if (cpu_is_at91sam9g25()
++ || cpu_is_at91sam9x25())
++ clk_register(&usart3_clk);
++
++ if (cpu_is_at91sam9g25()
++ || cpu_is_at91sam9x25()
++ || cpu_is_at91sam9g35()
++ || cpu_is_at91sam9x35())
++ clk_register(&macb0_clk);
++
++ if (cpu_is_at91sam9g15()
++ || cpu_is_at91sam9g35()
++ || cpu_is_at91sam9x35())
++ clk_register(&lcdc_clk);
++
++ if (cpu_is_at91sam9g25())
++ clk_register(&isi_clk);
++
++ if (cpu_is_at91sam9x25())
++ clk_register(&macb1_clk);
++
++ if (cpu_is_at91sam9x35()) {
++ clk_register(&can0_clk);
++ clk_register(&can1_clk);
++ }
++
++ clk_register(&pck0);
++ clk_register(&pck1);
++}
++
++/* --------------------------------------------------------------------
++ * GPIO
++ * -------------------------------------------------------------------- */
++
++static struct at91_gpio_bank at91sam9x5_gpio[] = {
++ {
++ .id = AT91SAM9X5_ID_PIOAB,
++ .offset = AT91_PIOA,
++ .clock = &pioAB_clk,
++ }, {
++ .id = AT91SAM9X5_ID_PIOAB,
++ .offset = AT91_PIOB,
++ .clock = &pioAB_clk,
++ }, {
++ .id = AT91SAM9X5_ID_PIOCD,
++ .offset = AT91_PIOC,
++ .clock = &pioCD_clk,
++ }, {
++ .id = AT91SAM9X5_ID_PIOCD,
++ .offset = AT91_PIOD,
++ .clock = &pioCD_clk,
++ }
++};
++
++static void at91sam9x5_reset(void)
++{
++ at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
++}
++
++static void at91sam9x5_poweroff(void)
++{
++ at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW);
++}
++
++
++/* --------------------------------------------------------------------
++ * AT91SAM9x5 processor initialization
++ * -------------------------------------------------------------------- */
++
++void __init at91sam9x5_initialize(unsigned long main_clock)
++{
++ /* Map peripherals */
++ iotable_init(at91sam9x5_io_desc, ARRAY_SIZE(at91sam9x5_io_desc));
++
++ at91_arch_reset = at91sam9x5_reset;
++ pm_power_off = at91sam9x5_poweroff;
++ at91_extern_irq = (1 << AT91SAM9X5_ID_IRQ0);
++
++ /* Init clock subsystem */
++ at91_clock_init(main_clock);
++
++ /* Register the processor-specific clocks */
++ at91sam9x5_register_clocks();
++
++ /* Register GPIO subsystem */
++ at91_gpio_init(at91sam9x5_gpio, 4);
++}
++
++/* --------------------------------------------------------------------
++ * Interrupt initialization
++ * -------------------------------------------------------------------- */
++
++/*
++ * The default interrupt priority levels (0 = lowest, 7 = highest).
++ */
++static unsigned int at91sam9x5_default_irq_priority[NR_AIC_IRQS] __initdata = {
++ 7, /* Advanced Interrupt Controller (FIQ) */
++ 7, /* System Peripherals */
++ 1, /* Parallel IO Controller A and B */
++ 1, /* Parallel IO Controller C and D */
++ 4, /* Soft Modem */
++ 5, /* USART 0 */
++ 5, /* USART 1 */
++ 5, /* USART 2 */
++ 5, /* USART 3 */
++ 6, /* Two-Wire Interface 0 */
++ 6, /* Two-Wire Interface 1 */
++ 6, /* Two-Wire Interface 2 */
++ 0, /* Multimedia Card Interface 0 */
++ 5, /* Serial Peripheral Interface 0 */
++ 5, /* Serial Peripheral Interface 1 */
++ 5, /* UART 0 */
++ 5, /* UART 1 */
++ 0, /* Timer Counter 0, 1, 2, 3, 4 and 5 */
++ 0, /* Pulse Width Modulation Controller */
++ 0, /* ADC COntroller */
++ 0, /* DMA Controller 0 */
++ 0, /* DMA Controller 1 */
++ 2, /* USB Host High Speed port */
++ 2, /* USB Device High speed port */
++ 3, /* Ethernet MAC 0 */
++ 3, /* LDC Controller or Image Sensor Interface */
++ 0, /* Multimedia Card Interface 1 */
++ 3, /* Ethernet MAC 1 */
++ 4, /* Synchronous Serial Interface */
++ 4, /* CAN Controller 0 */
++ 4, /* CAN Controller 1 */
++ 0, /* Advanced Interrupt Controller (IRQ0) */
++};
++
++void __init at91sam9x5_init_interrupts(unsigned int priority[NR_AIC_IRQS])
++{
++ if (!priority)
++ priority = at91sam9x5_default_irq_priority;
++
++ /* Initialize the AIC interrupt controller */
++ at91_aic_init(priority);
++
++ /* Enable GPIO interrupts */
++ at91_gpio_irq_setup();
++}
+diff --git a/arch/arm/mach-at91/at91sam9x5_devices.c b/arch/arm/mach-at91/at91sam9x5_devices.c
+new file mode 100644
+index 0000000..e601ae4
+--- /dev/null
++++ b/arch/arm/mach-at91/at91sam9x5_devices.c
+@@ -0,0 +1,1785 @@
++/*
++ * On-Chip devices setup code for the AT91SAM9x5 family
++ *
++ * Copyright (C) 2010 Atmel Corporation.
++ *
++ * 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.
++ *
++ */
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++
++#include <linux/dma-mapping.h>
++#include <linux/platform_device.h>
++#include <linux/i2c-gpio.h>
++#include <linux/atmel-mci.h>
++
++#include <linux/fb.h>
++#include <video/atmel_lcdc.h>
++#include <mach/atmel_hlcdfb.h>
++
++#include <mach/board.h>
++#include <mach/gpio.h>
++#include <mach/cpu.h>
++#include <mach/at91sam9x5.h>
++#include <mach/at91sam9x5_matrix.h>
++#include <mach/at91sam9_smc.h>
++#include <mach/at_hdmac.h>
++#include <mach/atmel-mci.h>
++
++#include "generic.h"
++
++/* --------------------------------------------------------------------
++ * HDMAC - AHB DMA Controller
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE)
++static u64 hdmac_dmamask = DMA_BIT_MASK(32);
++
++/* a single platform data for both DMA controllers as they share
++ * the same characteristics */
++static struct at_dma_platform_data atdma_pdata = {
++ .nr_channels = 8,
++};
++
++static struct resource hdmac0_resources[] = {
++ [0] = {
++ .start = AT91_BASE_SYS + AT91_DMA0,
++ .end = AT91_BASE_SYS + AT91_DMA0 + SZ_512 - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_DMA0,
++ .end = AT91SAM9X5_ID_DMA0,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at_hdmac0_device = {
++ .name = "at_hdmac",
++ .id = 0,
++ .dev = {
++ .dma_mask = &hdmac_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &atdma_pdata,
++ },
++ .resource = hdmac0_resources,
++ .num_resources = ARRAY_SIZE(hdmac0_resources),
++};
++
++static struct resource hdmac1_resources[] = {
++ [0] = {
++ .start = AT91_BASE_SYS + AT91_DMA1,
++ .end = AT91_BASE_SYS + AT91_DMA1 + SZ_512 - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_DMA1,
++ .end = AT91SAM9X5_ID_DMA1,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at_hdmac1_device = {
++ .name = "at_hdmac",
++ .id = 1,
++ .dev = {
++ .dma_mask = &hdmac_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &atdma_pdata,
++ },
++ .resource = hdmac1_resources,
++ .num_resources = ARRAY_SIZE(hdmac1_resources),
++};
++
++void __init at91_add_device_hdmac(void)
++{
++ dma_cap_set(DMA_MEMCPY, atdma_pdata.cap_mask);
++ dma_cap_set(DMA_SLAVE, atdma_pdata.cap_mask);
++ dma_cap_set(DMA_CYCLIC, atdma_pdata.cap_mask);
++ at91_clock_associate("dma0_clk", &at_hdmac0_device.dev, "dma_clk");
++ platform_device_register(&at_hdmac0_device);
++ at91_clock_associate("dma1_clk", &at_hdmac1_device.dev, "dma_clk");
++ platform_device_register(&at_hdmac1_device);
++}
++#else
++void __init at91_add_device_hdmac(void) {}
++#endif
++
++
++/* --------------------------------------------------------------------
++ * USB Host (OHCI)
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
++static u64 ohci_dmamask = DMA_BIT_MASK(32);
++static struct at91_usbh_data usbh_ohci_data;
++
++static struct resource usbh_ohci_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_OHCI_BASE,
++ .end = AT91SAM9X5_OHCI_BASE + SZ_1M - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_UHPHS,
++ .end = AT91SAM9X5_ID_UHPHS,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91_usbh_ohci_device = {
++ .name = "at91_ohci",
++ .id = -1,
++ .dev = {
++ .dma_mask = &ohci_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &usbh_ohci_data,
++ },
++ .resource = usbh_ohci_resources,
++ .num_resources = ARRAY_SIZE(usbh_ohci_resources),
++};
++
++void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data)
++{
++ int i;
++
++ if (!data)
++ return;
++
++ /* Enable VBus control for UHP ports */
++ for (i = 0; i < data->ports; i++) {
++ if (data->vbus_pin[i])
++ at91_set_gpio_output(data->vbus_pin[i], 0);
++ }
++
++ usbh_ohci_data = *data;
++ platform_device_register(&at91_usbh_ohci_device);
++}
++#else
++void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data) {}
++#endif
++
++
++/* --------------------------------------------------------------------
++ * USB Host HS (EHCI)
++ * Needs an OHCI host for low and full speed management
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE)
++static u64 ehci_dmamask = DMA_BIT_MASK(32);
++static struct at91_usbh_data usbh_ehci_data;
++
++static struct resource usbh_ehci_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_EHCI_BASE,
++ .end = AT91SAM9X5_EHCI_BASE + SZ_1M - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_UHPHS,
++ .end = AT91SAM9X5_ID_UHPHS,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91_usbh_ehci_device = {
++ .name = "atmel-ehci",
++ .id = -1,
++ .dev = {
++ .dma_mask = &ehci_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &usbh_ehci_data,
++ },
++ .resource = usbh_ehci_resources,
++ .num_resources = ARRAY_SIZE(usbh_ehci_resources),
++};
++
++void __init at91_add_device_usbh_ehci(struct at91_usbh_data *data)
++{
++ int i;
++
++ if (!data)
++ return;
++
++ /* Enable VBus control for UHP ports */
++ for (i = 0; i < data->ports; i++) {
++ if (data->vbus_pin[i])
++ at91_set_gpio_output(data->vbus_pin[i], 0);
++ }
++
++ usbh_ehci_data = *data;
++ at91_clock_associate("uhphs_clk", &at91_usbh_ehci_device.dev, "ehci_clk");
++ platform_device_register(&at91_usbh_ehci_device);
++}
++#else
++void __init at91_add_device_usbh_ehci(struct at91_usbh_data *data) {}
++#endif
++
++
++/* --------------------------------------------------------------------
++ * USB HS Device (Gadget)
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_USB_GADGET_ATMEL_USBA) || defined(CONFIG_USB_GADGET_ATMEL_USBA_MODULE)
++static struct resource usba_udc_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_UDPHS_FIFO,
++ .end = AT91SAM9X5_UDPHS_FIFO + SZ_512K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_BASE_UDPHS,
++ .end = AT91SAM9X5_BASE_UDPHS + SZ_1K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [2] = {
++ .start = AT91SAM9X5_ID_UDPHS,
++ .end = AT91SAM9X5_ID_UDPHS,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \
++ [idx] = { \
++ .name = nam, \
++ .index = idx, \
++ .fifo_size = maxpkt, \
++ .nr_banks = maxbk, \
++ .can_dma = dma, \
++ .can_isoc = isoc, \
++ }
++
++static struct usba_ep_data usba_udc_ep[] __initdata = {
++ EP("ep0", 0, 64, 1, 0, 0),
++ EP("ep1", 1, 1024, 2, 1, 1),
++ EP("ep2", 2, 1024, 2, 1, 1),
++ EP("ep3", 3, 1024, 3, 1, 0),
++ EP("ep4", 4, 1024, 3, 1, 0),
++ EP("ep5", 5, 1024, 3, 1, 1),
++ EP("ep6", 6, 1024, 3, 1, 1),
++};
++
++#undef EP
++
++/*
++ * pdata doesn't have room for any endpoints, so we need to
++ * append room for the ones we need right after it.
++ */
++static struct {
++ struct usba_platform_data pdata;
++ struct usba_ep_data ep[7];
++} usba_udc_data;
++
++static struct platform_device at91_usba_udc_device = {
++ .name = "atmel_usba_udc",
++ .id = -1,
++ .dev = {
++ .platform_data = &usba_udc_data.pdata,
++ },
++ .resource = usba_udc_resources,
++ .num_resources = ARRAY_SIZE(usba_udc_resources),
++};
++
++void __init at91_add_device_usba(struct usba_platform_data *data)
++{
++ usba_udc_data.pdata.vbus_pin = -EINVAL;
++ usba_udc_data.pdata.num_ep = ARRAY_SIZE(usba_udc_ep);
++ memcpy(usba_udc_data.ep, usba_udc_ep, sizeof(usba_udc_ep));
++
++ if (data && data->vbus_pin > 0) {
++ at91_set_gpio_input(data->vbus_pin, 0);
++ at91_set_deglitch(data->vbus_pin, 1);
++ usba_udc_data.pdata.vbus_pin = data->vbus_pin;
++ }
++
++ /* Pullup pin is handled internally by USB device peripheral */
++
++ /* Clocks */
++ at91_clock_associate("utmi_clk", &at91_usba_udc_device.dev, "hclk");
++ at91_clock_associate("udphs_clk", &at91_usba_udc_device.dev, "pclk");
++
++ platform_device_register(&at91_usba_udc_device);
++}
++#else
++void __init at91_add_device_usba(struct usba_platform_data *data) {}
++#endif
++
++/* --------------------------------------------------------------------
++ * Ethernet
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE)
++static u64 eth0_dmamask = DMA_BIT_MASK(32);
++static struct at91_eth_data eth0_data;
++
++static struct resource eth0_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_BASE_EMAC0,
++ .end = AT91SAM9X5_BASE_EMAC0 + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_EMAC0,
++ .end = AT91SAM9X5_ID_EMAC0,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91sam9x5_eth0_device = {
++ .name = "macb",
++ .id = 0,
++ .dev = {
++ .dma_mask = &eth0_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &eth0_data,
++ },
++ .resource = eth0_resources,
++ .num_resources = ARRAY_SIZE(eth0_resources),
++};
++
++static u64 eth1_dmamask = DMA_BIT_MASK(32);
++static struct at91_eth_data eth1_data;
++
++static struct resource eth1_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_BASE_EMAC1,
++ .end = AT91SAM9X5_BASE_EMAC1 + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_EMAC1,
++ .end = AT91SAM9X5_ID_EMAC1,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91sam9x5_eth1_device = {
++ .name = "macb",
++ .id = 1,
++ .dev = {
++ .dma_mask = &eth1_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &eth1_data,
++ },
++ .resource = eth1_resources,
++ .num_resources = ARRAY_SIZE(eth1_resources),
++};
++
++void __init at91_add_device_eth(short eth_id, struct at91_eth_data *data)
++{
++ if (!data)
++ return;
++
++ if (cpu_is_at91sam9g15())
++ return;
++
++ if (eth_id && !cpu_is_at91sam9x25())
++ return;
++
++ if (data->phy_irq_pin) {
++ at91_set_gpio_input(data->phy_irq_pin, 0);
++ at91_set_deglitch(data->phy_irq_pin, 1);
++ }
++
++ if (eth_id == 0) {
++ /* Pins used for MII and RMII */
++ at91_set_A_periph(AT91_PIN_PB4, 0); /* ETXCK_EREFCK */
++ at91_set_A_periph(AT91_PIN_PB3, 0); /* ERXDV */
++ at91_set_A_periph(AT91_PIN_PB0, 0); /* ERX0 */
++ at91_set_A_periph(AT91_PIN_PB1, 0); /* ERX1 */
++ at91_set_A_periph(AT91_PIN_PB2, 0); /* ERXER */
++ at91_set_A_periph(AT91_PIN_PB7, 0); /* ETXEN */
++ at91_set_A_periph(AT91_PIN_PB9, 0); /* ETX0 */
++ at91_set_A_periph(AT91_PIN_PB10, 0); /* ETX1 */
++ at91_set_A_periph(AT91_PIN_PB5, 0); /* EMDIO */
++ at91_set_A_periph(AT91_PIN_PB6, 0); /* EMDC */
++
++ if (!data->is_rmii) {
++ at91_set_A_periph(AT91_PIN_PB16, 0); /* ECRS */
++ at91_set_A_periph(AT91_PIN_PB17, 0); /* ECOL */
++ at91_set_A_periph(AT91_PIN_PB13, 0); /* ERX2 */
++ at91_set_A_periph(AT91_PIN_PB14, 0); /* ERX3 */
++ at91_set_A_periph(AT91_PIN_PB15, 0); /* ERXCK */
++ at91_set_A_periph(AT91_PIN_PB11, 0); /* ETX2 */
++ at91_set_A_periph(AT91_PIN_PB12, 0); /* ETX3 */
++ at91_set_A_periph(AT91_PIN_PB8, 0); /* ETXER */
++ }
++
++ /* Clock */
++ at91_clock_associate("macb0_clk", &at91sam9x5_eth0_device.dev, "macb_clk");
++
++ eth0_data = *data;
++ platform_device_register(&at91sam9x5_eth0_device);
++ } else {
++ if (!data->is_rmii)
++ pr_warn("AT91: Only RMII available on interface %s %d.\n",
++ at91sam9x5_eth0_device.name, eth_id);
++
++ /* Pins used for RMII */
++ at91_set_B_periph(AT91_PIN_PC29, 0); /* ETXCK_EREFCK */
++ at91_set_B_periph(AT91_PIN_PC28, 0); /* ECRSDV */
++ at91_set_B_periph(AT91_PIN_PC20, 0); /* ERX0 */
++ at91_set_B_periph(AT91_PIN_PC21, 0); /* ERX1 */
++ at91_set_B_periph(AT91_PIN_PC16, 0); /* ERXER */
++ at91_set_B_periph(AT91_PIN_PC27, 0); /* ETXEN */
++ at91_set_B_periph(AT91_PIN_PC18, 0); /* ETX0 */
++ at91_set_B_periph(AT91_PIN_PC19, 0); /* ETX1 */
++ at91_set_B_periph(AT91_PIN_PC31, 0); /* EMDIO */
++ at91_set_B_periph(AT91_PIN_PC30, 0); /* EMDC */
++
++ /* Clock */
++ at91_clock_associate("macb1_clk", &at91sam9x5_eth1_device.dev, "macb_clk");
++
++ eth1_data = *data;
++ platform_device_register(&at91sam9x5_eth1_device);
++ }
++}
++#else
++void __init at91_add_device_eth(short eth_id, struct at91_eth_data *data) {}
++#endif
++
++
++/* --------------------------------------------------------------------
++ * MMC / SD
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
++static u64 mmc_dmamask = DMA_BIT_MASK(32);
++static struct mci_platform_data mmc0_data, mmc1_data;
++
++static struct resource mmc0_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_BASE_MCI0,
++ .end = AT91SAM9X5_BASE_MCI0 + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_MCI0,
++ .end = AT91SAM9X5_ID_MCI0,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91sam9x5_mmc0_device = {
++ .name = "atmel_mci",
++ .id = 0,
++ .dev = {
++ .dma_mask = &mmc_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &mmc0_data,
++ },
++ .resource = mmc0_resources,
++ .num_resources = ARRAY_SIZE(mmc0_resources),
++};
++
++static struct resource mmc1_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_BASE_MCI1,
++ .end = AT91SAM9X5_BASE_MCI1 + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_MCI1,
++ .end = AT91SAM9X5_ID_MCI1,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91sam9x5_mmc1_device = {
++ .name = "atmel_mci",
++ .id = 1,
++ .dev = {
++ .dma_mask = &mmc_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &mmc1_data,
++ },
++ .resource = mmc1_resources,
++ .num_resources = ARRAY_SIZE(mmc1_resources),
++};
++
++/* Consider only one slot : slot 0 */
++void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
++{
++
++ if (!data)
++ return;
++
++ /* Must have at least one usable slot */
++ if (!data->slot[0].bus_width)
++ return;
++
++#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE)
++ {
++ struct at_dma_slave *atslave;
++ struct mci_dma_data *alt_atslave;
++
++ alt_atslave = kzalloc(sizeof(struct mci_dma_data), GFP_KERNEL);
++ atslave = &alt_atslave->sdata;
++
++ /* DMA slave channel configuration */
++ atslave->reg_width = AT_DMA_SLAVE_WIDTH_32BIT;
++ atslave->cfg = ATC_FIFOCFG_HALFFIFO
++ | ATC_SRC_H2SEL_HW | ATC_DST_H2SEL_HW;
++ atslave->ctrla = ATC_SCSIZE_16 | ATC_DCSIZE_16;
++ if (mmc_id == 0) { /* MCI0 */
++ atslave->cfg |= ATC_SRC_PER(AT_DMA_ID_MCI0)
++ | ATC_DST_PER(AT_DMA_ID_MCI0);
++ atslave->dma_dev = &at_hdmac0_device.dev;
++
++ } else { /* MCI1 */
++ atslave->cfg |= ATC_SRC_PER(AT_DMA_ID_MCI1)
++ | ATC_DST_PER(AT_DMA_ID_MCI1);
++ atslave->dma_dev = &at_hdmac1_device.dev;
++ }
++
++ data->dma_slave = alt_atslave;
++ }
++#endif
++
++ /* input/irq */
++ if (data->slot[0].detect_pin) {
++ at91_set_gpio_input(data->slot[0].detect_pin, 1);
++ at91_set_deglitch(data->slot[0].detect_pin, 1);
++ }
++ if (data->slot[0].wp_pin)
++ at91_set_gpio_input(data->slot[0].wp_pin, 1);
++
++ if (mmc_id == 0) { /* MCI0 */
++
++ /* CLK */
++ at91_set_A_periph(AT91_PIN_PA17, 0);
++
++ /* CMD */
++ at91_set_A_periph(AT91_PIN_PA16, 1);
++
++ /* DAT0, maybe DAT1..DAT3 */
++ at91_set_A_periph(AT91_PIN_PA15, 1);
++ if (data->slot[0].bus_width == 4) {
++ at91_set_A_periph(AT91_PIN_PA18, 1);
++ at91_set_A_periph(AT91_PIN_PA19, 1);
++ at91_set_A_periph(AT91_PIN_PA20, 1);
++ }
++
++ mmc0_data = *data;
++ at91_clock_associate("mci0_clk", &at91sam9x5_mmc0_device.dev, "mci_clk");
++ platform_device_register(&at91sam9x5_mmc0_device);
++
++ } else { /* MCI1 */
++
++ /* CLK */
++ at91_set_B_periph(AT91_PIN_PA13, 0);
++
++ /* CMD */
++ at91_set_B_periph(AT91_PIN_PA12, 1);
++
++ /* DAT0, maybe DAT1..DAT3 */
++ at91_set_B_periph(AT91_PIN_PA11, 1);
++ if (data->slot[0].bus_width == 4) {
++ at91_set_B_periph(AT91_PIN_PA2, 1);
++ at91_set_B_periph(AT91_PIN_PA3, 1);
++ at91_set_B_periph(AT91_PIN_PA4, 1);
++ }
++
++ mmc1_data = *data;
++ at91_clock_associate("mci1_clk", &at91sam9x5_mmc1_device.dev, "mci_clk");
++ platform_device_register(&at91sam9x5_mmc1_device);
++
++ }
++}
++#else
++void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
++#endif
++
++
++/* --------------------------------------------------------------------
++ * NAND / SmartMedia
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_MTD_NAND_ATMEL) || defined(CONFIG_MTD_NAND_ATMEL_MODULE)
++static struct atmel_nand_data nand_data;
++
++#define NAND_BASE AT91_CHIPSELECT_3
++
++static struct resource nand_resources[] = {
++ [0] = {
++ .start = NAND_BASE,
++ .end = NAND_BASE + SZ_256M - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91_BASE_SYS + AT91_PMECC,
++ .end = AT91_BASE_SYS + AT91_PMECC + SZ_512 - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [2] = {
++ .start = AT91_BASE_SYS + AT91_PMERRLOC,
++ .end = AT91_BASE_SYS + AT91_PMERRLOC + SZ_512 - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [3] = {
++ .start = AT91SAM9X5_ROM_BASE,
++ .end = AT91SAM9X5_ROM_BASE + AT91SAM9X5_ROM_SIZE,
++ .flags = IORESOURCE_MEM,
++ }
++};
++
++static struct platform_device at91sam9x5_nand_device = {
++ .name = "atmel_nand",
++ .id = -1,
++ .dev = {
++ .platform_data = &nand_data,
++ },
++ .resource = nand_resources,
++ .num_resources = ARRAY_SIZE(nand_resources),
++};
++
++void __init at91_add_device_nand(struct atmel_nand_data *data)
++{
++ unsigned long csa;
++
++ if (!data)
++ return;
++
++ csa = at91_sys_read(AT91_MATRIX_EBICSA);
++ csa |= AT91_MATRIX_EBI_CS3A_SMC_NANDFLASH;
++
++ if (!data->bus_on_d0) {
++ csa |= AT91_MATRIX_NFD0_ON_D16;
++ if (!data->bus_width_16)
++ csa |= AT91_MATRIX_MP_ON;
++ } else
++ csa &= ~(AT91_MATRIX_NFD0_ON_D16 | AT91_MATRIX_MP_ON);
++
++ at91_sys_write(AT91_MATRIX_EBICSA, csa);
++
++ /* enable pin */
++ if (data->enable_pin)
++ at91_set_gpio_output(data->enable_pin, 1);
++
++ /* ready/busy pin */
++ if (data->rdy_pin)
++ at91_set_gpio_input(data->rdy_pin, 1);
++
++ /* card detect pin */
++ if (data->det_pin)
++ at91_set_gpio_input(data->det_pin, 1);
++
++ /* configure NANDOE */
++ at91_set_A_periph(AT91_PIN_PD0, 1);
++ /* configure NANDWE */
++ at91_set_A_periph(AT91_PIN_PD1, 1);
++ /* configure ALE */
++ at91_set_A_periph(AT91_PIN_PD2, 1);
++ /* configure CLE */
++ at91_set_A_periph(AT91_PIN_PD3, 1);
++
++ /* configure multiplexed pins for D16~D31 */
++ if (!data->bus_on_d0) {
++ at91_set_A_periph(AT91_PIN_PD6, 1);
++ at91_set_A_periph(AT91_PIN_PD7, 1);
++ at91_set_A_periph(AT91_PIN_PD8, 1);
++ at91_set_A_periph(AT91_PIN_PD9, 1);
++ at91_set_A_periph(AT91_PIN_PD10, 1);
++ at91_set_A_periph(AT91_PIN_PD11, 1);
++ at91_set_A_periph(AT91_PIN_PD12, 1);
++ at91_set_A_periph(AT91_PIN_PD13, 1);
++
++ if (data->bus_width_16) {
++ at91_set_A_periph(AT91_PIN_PD14, 1);
++ at91_set_A_periph(AT91_PIN_PD15, 1);
++ at91_set_A_periph(AT91_PIN_PD16, 1);
++ at91_set_A_periph(AT91_PIN_PD17, 1);
++ at91_set_A_periph(AT91_PIN_PD18, 1);
++ at91_set_A_periph(AT91_PIN_PD19, 1);
++ at91_set_A_periph(AT91_PIN_PD20, 1);
++ at91_set_A_periph(AT91_PIN_PD21, 1);
++ }
++
++ }
++
++ nand_data = *data;
++ platform_device_register(&at91sam9x5_nand_device);
++}
++#else
++void __init at91_add_device_nand(struct atmel_nand_data *data) {}
++#endif
++
++/* --------------------------------------------------------------------
++ * TWI (i2c)
++ * -------------------------------------------------------------------- */
++
++/*
++ * Prefer the GPIO code since the TWI controller isn't robust
++ * (gets overruns and underruns under load) and can only issue
++ * repeated STARTs in one scenario (the driver doesn't yet handle them).
++ */
++#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
++static struct i2c_gpio_platform_data pdata_i2c0 = {
++ .sda_pin = AT91_PIN_PA30,
++ .sda_is_open_drain = 1,
++ .scl_pin = AT91_PIN_PA31,
++ .scl_is_open_drain = 1,
++ .udelay = 2, /* ~100 kHz */
++};
++
++static struct platform_device at91sam9x5_twi0_device = {
++ .name = "i2c-gpio",
++ .id = 0,
++ .dev.platform_data = &pdata_i2c0,
++};
++
++void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices)
++{
++ i2c_register_board_info(i2c_id, devices, nr_devices);
++
++ if (i2c_id == 0) {
++ at91_set_GPIO_periph(AT91_PIN_PA30, 1); /* TWD (SDA) */
++ at91_set_multi_drive(AT91_PIN_PA30, 1);
++
++ at91_set_GPIO_periph(AT91_PIN_PA31, 1); /* TWCK (SCL) */
++ at91_set_multi_drive(AT91_PIN_PA31, 1);
++
++ platform_device_register(&at91sam9x5_twi0_device);
++ }
++}
++
++#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
++static struct resource twi0_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_BASE_TWI0,
++ .end = AT91SAM9X5_BASE_TWI0 + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_TWI0,
++ .end = AT91SAM9X5_ID_TWI0,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91sam9x5_twi0_device = {
++ .name = "at91_i2c",
++ .id = 0,
++ .resource = twi0_resources,
++ .num_resources = ARRAY_SIZE(twi0_resources),
++};
++
++void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices)
++{
++ i2c_register_board_info(i2c_id, devices, nr_devices);
++
++ /* pins used for TWI interface */
++ if (i2c_id == 0) {
++ at91_set_A_periph(AT91_PIN_PA30, 0); /* TWD */
++ at91_set_multi_drive(AT91_PIN_PA30, 1);
++
++ at91_set_A_periph(AT91_PIN_PA31, 0); /* TWCK */
++ at91_set_multi_drive(AT91_PIN_PA31, 1);
++
++ platform_device_register(&at91sam9x5_twi0_device);
++ }
++}
++#else
++void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices) {}
++#endif
++
++/* --------------------------------------------------------------------
++ * SPI
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
++static u64 spi_dmamask = DMA_BIT_MASK(32);
++static struct at_dma_slave spi0_sdata, spi1_sdata;
++
++static struct resource spi0_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_BASE_SPI0,
++ .end = AT91SAM9X5_BASE_SPI0 + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_SPI0,
++ .end = AT91SAM9X5_ID_SPI0,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91sam9x5_spi0_device = {
++ .name = "atmel_spi",
++ .id = 0,
++ .dev = {
++ .dma_mask = &spi_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &spi0_sdata,
++ },
++ .resource = spi0_resources,
++ .num_resources = ARRAY_SIZE(spi0_resources),
++};
++
++static const unsigned spi0_standard_cs[4] = { AT91_PIN_PA14, AT91_PIN_PA7, AT91_PIN_PA1, AT91_PIN_PB3 };
++
++static struct resource spi1_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_BASE_SPI1,
++ .end = AT91SAM9X5_BASE_SPI1 + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_SPI1,
++ .end = AT91SAM9X5_ID_SPI1,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91sam9x5_spi1_device = {
++ .name = "atmel_spi",
++ .id = 1,
++ .dev = {
++ .dma_mask = &spi_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &spi1_sdata,
++ },
++ .resource = spi1_resources,
++ .num_resources = ARRAY_SIZE(spi1_resources),
++};
++
++static const unsigned spi1_standard_cs[4] = { AT91_PIN_PA8, AT91_PIN_PA0, AT91_PIN_PA31, AT91_PIN_PA30 };
++
++void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
++{
++ int i;
++ unsigned long cs_pin;
++ short enable_spi0 = 0;
++ short enable_spi1 = 0;
++#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE)
++ struct at_dma_slave *atslave;
++#endif
++
++ /* Choose SPI chip-selects */
++ for (i = 0; i < nr_devices; i++) {
++ if (devices[i].controller_data)
++ cs_pin = (unsigned long) devices[i].controller_data;
++ else if (devices[i].bus_num == 0)
++ cs_pin = spi0_standard_cs[devices[i].chip_select];
++ else
++ cs_pin = spi1_standard_cs[devices[i].chip_select];
++
++ if (devices[i].bus_num == 0)
++ enable_spi0 = 1;
++ else
++ enable_spi1 = 1;
++
++ /* enable chip-select pin */
++ at91_set_gpio_output(cs_pin, 1);
++
++ /* pass chip-select pin to driver */
++ devices[i].controller_data = (void *) cs_pin;
++ }
++
++ spi_register_board_info(devices, nr_devices);
++
++
++ /* Configure SPI bus(es) */
++ if (enable_spi0) {
++ at91_set_A_periph(AT91_PIN_PA11, 0); /* SPI0_MISO */
++ at91_set_A_periph(AT91_PIN_PA12, 0); /* SPI0_MOSI */
++ at91_set_A_periph(AT91_PIN_PA13, 0); /* SPI0_SPCK */
++
++#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE)
++ atslave = at91sam9x5_spi0_device.dev.platform_data;
++
++ /* DMA slave channel configuration */
++ atslave->dma_dev = &at_hdmac0_device.dev;
++ atslave->reg_width = AT_DMA_SLAVE_WIDTH_8BIT; /* or 16bits??????? */
++ atslave->cfg = ATC_FIFOCFG_HALFFIFO
++ | ATC_SRC_H2SEL_HW | ATC_DST_H2SEL_HW
++ | ATC_SRC_PER(AT_DMA_ID_SPI0_RX)
++ | ATC_DST_PER(AT_DMA_ID_SPI0_TX);
++ /*atslave->ctrla = ATC_SCSIZE_16 | ATC_DCSIZE_16;*/ /* Chunk size to 0????? */
++#endif
++
++ at91_clock_associate("spi0_clk", &at91sam9x5_spi0_device.dev, "spi_clk");
++ platform_device_register(&at91sam9x5_spi0_device);
++ }
++ if (enable_spi1) {
++ at91_set_B_periph(AT91_PIN_PA21, 0); /* SPI1_MISO */
++ at91_set_B_periph(AT91_PIN_PA22, 0); /* SPI1_MOSI */
++ at91_set_B_periph(AT91_PIN_PA23, 0); /* SPI1_SPCK */
++
++#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE)
++ atslave = at91sam9x5_spi1_device.dev.platform_data;
++
++ /* DMA slave channel configuration */
++ atslave->dma_dev = &at_hdmac1_device.dev;
++ atslave->reg_width = AT_DMA_SLAVE_WIDTH_8BIT; /* or 16bits??????? */
++ atslave->cfg = ATC_FIFOCFG_HALFFIFO
++ | ATC_SRC_H2SEL_HW | ATC_DST_H2SEL_HW
++ | ATC_SRC_PER(AT_DMA_ID_SPI1_RX)
++ | ATC_DST_PER(AT_DMA_ID_SPI1_TX);
++ /*atslave->ctrla = ATC_SCSIZE_16 | ATC_DCSIZE_16;*/ /* Chunk size to 0????? */
++#endif
++
++ at91_clock_associate("spi1_clk", &at91sam9x5_spi1_device.dev, "spi_clk");
++ platform_device_register(&at91sam9x5_spi1_device);
++ }
++}
++#else
++void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {}
++#endif
++
++
++/* --------------------------------------------------------------------
++ * CAN Controllers
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_CAN_AT91) || defined(CONFIG_CAN_AT91_MODULE)
++static struct resource can_resources[][2] = {
++ {
++ {
++ .start = AT91SAM9X5_BASE_CAN0,
++ .end = AT91SAM9X5_BASE_CAN0 + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ }, {
++ .start = AT91SAM9X5_ID_CAN0,
++ .end = AT91SAM9X5_ID_CAN0,
++ .flags = IORESOURCE_IRQ,
++ },
++ }, {
++ {
++ .start = AT91SAM9X5_BASE_CAN1,
++ .end = AT91SAM9X5_BASE_CAN1 + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ }, {
++ .start = AT91SAM9X5_ID_CAN1,
++ .end = AT91SAM9X5_ID_CAN1,
++ .flags = IORESOURCE_IRQ,
++ },
++ },
++};
++
++static struct platform_device at91sam9x5_can_device[] = {
++ {
++ .name = "at91sam9x5_can",
++ .id = 0,
++ .resource = can_resources[0],
++ .num_resources = ARRAY_SIZE(can_resources[0]),
++ }, {
++ .name = "at91sam9x5_can",
++ .id = 1,
++ .resource = can_resources[1],
++ .num_resources = ARRAY_SIZE(can_resources[1]),
++ },
++};
++
++static const struct {
++ unsigned txpin;
++ unsigned rxpin;
++} at91sam9x5_can_pins[] __initconst = {
++ {
++ .txpin = AT91_PIN_PA10,
++ .rxpin = AT91_PIN_PA9,
++ }, {
++ .txpin = AT91_PIN_PA5,
++ .rxpin = AT91_PIN_PA6,
++ },
++};
++
++void __init at91_add_device_can(int id, struct at91_can_data *data)
++{
++ at91_clock_associate("can0_clk", &at91sam9x5_can_device[0].dev, "can_clk");
++ at91_clock_associate("can1_clk", &at91sam9x5_can_device[1].dev, "can_clk");
++ at91_set_B_periph(at91sam9x5_can_pins[id].txpin, 0);
++ at91_set_B_periph(at91sam9x5_can_pins[id].rxpin, 0);
++ at91sam9x5_can_device[id].dev.platform_data = data;
++
++ platform_device_register(&at91sam9x5_can_device[id]);
++}
++#else
++void __init at91_add_device_can(int id, struct at91_can_data *data) {}
++#endif
++
++/* --------------------------------------------------------------------
++ * LCD Controller
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
++static u64 lcdc_dmamask = DMA_BIT_MASK(32);
++static struct atmel_lcdfb_info lcdc_data;
++
++static struct resource lcdc_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_BASE_LCDC,
++ .end = AT91SAM9X5_BASE_LCDC + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_LCDC,
++ .end = AT91SAM9X5_ID_LCDC,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91_lcdc_device = {
++ .name = "atmel_lcdfb",
++ .id = 0,
++ .dev = {
++ .dma_mask = &lcdc_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &lcdc_data,
++ },
++ .resource = lcdc_resources,
++ .num_resources = ARRAY_SIZE(lcdc_resources),
++};
++
++void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
++{
++ if (!data)
++ return;
++
++ at91_set_A_periph(AT91_PIN_PC26, 0); /* LCDPWM */
++
++ at91_set_A_periph(AT91_PIN_PC27, 0); /* LCDVSYNC */
++ at91_set_A_periph(AT91_PIN_PC28, 0); /* LCDHSYNC */
++
++ at91_set_A_periph(AT91_PIN_PC24, 0); /* LCDDISP */
++ at91_set_A_periph(AT91_PIN_PC29, 0); /* LCDDEN */
++ at91_set_A_periph(AT91_PIN_PC30, 0); /* LCDPCK */
++
++ at91_set_A_periph(AT91_PIN_PC0, 0); /* LCDD0 */
++ at91_set_A_periph(AT91_PIN_PC1, 0); /* LCDD1 */
++ at91_set_A_periph(AT91_PIN_PC2, 0); /* LCDD2 */
++ at91_set_A_periph(AT91_PIN_PC3, 0); /* LCDD3 */
++ at91_set_A_periph(AT91_PIN_PC4, 0); /* LCDD4 */
++ at91_set_A_periph(AT91_PIN_PC5, 0); /* LCDD5 */
++ at91_set_A_periph(AT91_PIN_PC6, 0); /* LCDD6 */
++ at91_set_A_periph(AT91_PIN_PC7, 0); /* LCDD7 */
++ at91_set_A_periph(AT91_PIN_PC8, 0); /* LCDD8 */
++ at91_set_A_periph(AT91_PIN_PC9, 0); /* LCDD9 */
++ at91_set_A_periph(AT91_PIN_PC10, 0); /* LCDD10 */
++ at91_set_A_periph(AT91_PIN_PC11, 0); /* LCDD11 */
++ at91_set_A_periph(AT91_PIN_PC12, 0); /* LCDD12 */
++ at91_set_A_periph(AT91_PIN_PC13, 0); /* LCDD13 */
++ at91_set_A_periph(AT91_PIN_PC14, 0); /* LCDD14 */
++ at91_set_A_periph(AT91_PIN_PC15, 0); /* LCDD15 */
++ at91_set_A_periph(AT91_PIN_PC16, 0); /* LCDD16 */
++ at91_set_A_periph(AT91_PIN_PC17, 0); /* LCDD17 */
++ at91_set_A_periph(AT91_PIN_PC18, 0); /* LCDD18 */
++ at91_set_A_periph(AT91_PIN_PC19, 0); /* LCDD19 */
++ at91_set_A_periph(AT91_PIN_PC20, 0); /* LCDD20 */
++ at91_set_A_periph(AT91_PIN_PC21, 0); /* LCDD21 */
++ at91_set_A_periph(AT91_PIN_PC22, 0); /* LCDD22 */
++ at91_set_A_periph(AT91_PIN_PC23, 0); /* LCDD23 */
++
++ lcdc_data = *data;
++ platform_device_register(&at91_lcdc_device);
++}
++#else
++void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
++#endif
++
++/* --------------------------------------------------------------------
++ * Timer/Counter block
++ * -------------------------------------------------------------------- */
++
++#ifdef CONFIG_ATMEL_TCLIB
++static struct resource tcb0_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_BASE_TCB0,
++ .end = AT91SAM9X5_BASE_TCB0 + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_TCB,
++ .end = AT91SAM9X5_ID_TCB,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91sam9x5_tcb0_device = {
++ .name = "atmel_tcb",
++ .id = 0,
++ .resource = tcb0_resources,
++ .num_resources = ARRAY_SIZE(tcb0_resources),
++};
++
++/* TCB1 begins with TC3 */
++static struct resource tcb1_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_BASE_TCB1,
++ .end = AT91SAM9X5_BASE_TCB1 + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_TCB,
++ .end = AT91SAM9X5_ID_TCB,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91sam9x5_tcb1_device = {
++ .name = "atmel_tcb",
++ .id = 1,
++ .resource = tcb1_resources,
++ .num_resources = ARRAY_SIZE(tcb1_resources),
++};
++
++static void __init at91_add_device_tc(void)
++{
++ /* this chip has one clock and irq for all six TC channels */
++ at91_clock_associate("tcb0_clk", &at91sam9x5_tcb0_device.dev, "t0_clk");
++ platform_device_register(&at91sam9x5_tcb0_device);
++ at91_clock_associate("tcb1_clk", &at91sam9x5_tcb1_device.dev, "t0_clk");
++ platform_device_register(&at91sam9x5_tcb1_device);
++}
++#else
++static void __init at91_add_device_tc(void) { }
++#endif
++
++/* --------------------------------------------------------------------
++ * RTC
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_RTC_DRV_AT91RM9200) || defined(CONFIG_RTC_DRV_AT91RM9200_MODULE)
++static struct platform_device at91sam9x5_rtc_device = {
++ .name = "at91_rtc",
++ .id = -1,
++ .num_resources = 0,
++};
++
++static void __init at91_add_device_rtc(void)
++{
++ platform_device_register(&at91sam9x5_rtc_device);
++}
++#else
++static void __init at91_add_device_rtc(void) {}
++#endif
++
++/* --------------------------------------------------------------------
++ * Touchscreen
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) || defined(CONFIG_TOUCHSCREEN_ATMEL_TSADCC_MODULE)
++static u64 tsadcc_dmamask = DMA_BIT_MASK(32);
++static struct at91_tsadcc_data tsadcc_data;
++
++static struct resource tsadcc_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_BASE_ADC,
++ .end = AT91SAM9X5_BASE_ADC + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_ADC,
++ .end = AT91SAM9X5_ID_ADC,
++ .flags = IORESOURCE_IRQ,
++ }
++};
++
++static struct platform_device at91sam9x5_tsadcc_device = {
++ .name = "atmel_tsadcc",
++ .id = -1,
++ .dev = {
++ .dma_mask = &tsadcc_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &tsadcc_data,
++ },
++ .resource = tsadcc_resources,
++ .num_resources = ARRAY_SIZE(tsadcc_resources),
++};
++
++void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data)
++{
++ if (!data)
++ return;
++
++ /* In 9x5ek, using default pins for touch screen. */
++
++ tsadcc_data = *data;
++ at91_clock_associate("adc_clk", &at91sam9x5_tsadcc_device.dev, "tsc_clk");
++ platform_device_register(&at91sam9x5_tsadcc_device);
++}
++#else
++void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data) {}
++#endif
++
++/* --------------------------------------------------------------------
++ * Watchdog
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_AT91SAM9X_WATCHDOG) || defined(CONFIG_AT91SAM9X_WATCHDOG_MODULE)
++static struct platform_device at91sam9x5_wdt_device = {
++ .name = "at91_wdt",
++ .id = -1,
++ .num_resources = 0,
++};
++
++static void __init at91_add_device_watchdog(void)
++{
++ platform_device_register(&at91sam9x5_wdt_device);
++}
++#else
++static void __init at91_add_device_watchdog(void) {}
++#endif
++
++
++/* --------------------------------------------------------------------
++ * PWM
++ * --------------------------------------------------------------------*/
++
++#if defined(CONFIG_ATMEL_PWM) || defined(CONFIG_ATMEL_PWM_MODULE)
++static u32 pwm_mask;
++
++static struct resource pwm_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_BASE_PWMC,
++ .end = AT91SAM9X5_BASE_PWMC + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_PWMC,
++ .end = AT91SAM9X5_ID_PWMC,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91sam9x5_pwm_device = {
++ .name = "atmel_pwm",
++ .id = -1,
++ .dev = {
++ .platform_data = &pwm_mask,
++ },
++ .resource = pwm_resources,
++ .num_resources = ARRAY_SIZE(pwm_resources),
++};
++
++void __init at91_add_device_pwm(u32 mask)
++{
++ if (mask & (1 << AT91_PWM0))
++ at91_set_B_periph(AT91_PIN_PB11, 1); /* enable PWM0 */
++
++ if (mask & (1 << AT91_PWM1))
++ at91_set_B_periph(AT91_PIN_PB12, 1); /* enable PWM1 */
++
++ if (mask & (1 << AT91_PWM2))
++ at91_set_B_periph(AT91_PIN_PB13, 1); /* enable PWM2 */
++
++ if (mask & (1 << AT91_PWM3))
++ at91_set_B_periph(AT91_PIN_PB14, 1); /* enable PWM3 */
++
++ pwm_mask = mask;
++
++ platform_device_register(&at91sam9x5_pwm_device);
++}
++#else
++void __init at91_add_device_pwm(u32 mask) {}
++#endif
++
++
++/* --------------------------------------------------------------------
++ * SSC -- Synchronous Serial Controller
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
++static u64 ssc_dmamask = DMA_BIT_MASK(32);
++static struct at_dma_slave ssc_sdata;
++
++static struct resource ssc_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_BASE_SSC,
++ .end = AT91SAM9X5_BASE_SSC + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_SSC,
++ .end = AT91SAM9X5_ID_SSC,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91sam9x5_ssc_device = {
++ .name = "ssc",
++ .id = 0,
++ .dev = {
++ .dma_mask = &ssc_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &ssc_sdata,
++ },
++ .resource = ssc_resources,
++ .num_resources = ARRAY_SIZE(ssc_resources),
++};
++
++static inline void configure_ssc_pins(unsigned pins)
++{
++ if (pins & ATMEL_SSC_TF)
++ at91_set_B_periph(AT91_PIN_PA25, 1);
++ if (pins & ATMEL_SSC_TK)
++ at91_set_B_periph(AT91_PIN_PA24, 1);
++ if (pins & ATMEL_SSC_TD)
++ at91_set_B_periph(AT91_PIN_PA26, 1);
++ if (pins & ATMEL_SSC_RD)
++ at91_set_B_periph(AT91_PIN_PA27, 1);
++ if (pins & ATMEL_SSC_RK)
++ at91_set_B_periph(AT91_PIN_PA28, 1);
++ if (pins & ATMEL_SSC_RF)
++ at91_set_B_periph(AT91_PIN_PA29, 1);
++}
++
++/*
++ * SSC controllers are accessed through library code, instead of any
++ * kind of all-singing/all-dancing driver. For example one could be
++ * used by a particular I2S audio codec's driver, while another one
++ * on the same system might be used by a custom data capture driver.
++ */
++void __init at91_add_device_ssc(unsigned id, unsigned pins)
++{
++ struct platform_device *pdev;
++
++ /*
++ * NOTE: caller is responsible for passing information matching
++ * "pins" to whatever will be using each particular controller.
++ */
++ if (id == AT91SAM9X5_ID_SSC) {
++#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE)
++ struct at_dma_slave *atslave;
++
++ atslave = at91sam9x5_ssc_device.dev.platform_data;
++
++ /* DMA slave channel configuration */
++ atslave->dma_dev = &at_hdmac0_device.dev;
++ atslave->reg_width = AT_DMA_SLAVE_WIDTH_16BIT;
++ atslave->cfg = ATC_FIFOCFG_HALFFIFO
++ | ATC_SRC_H2SEL_HW | ATC_DST_H2SEL_HW
++ | ATC_SRC_PER(AT_DMA_ID_SSC_RX)
++ | ATC_DST_PER(AT_DMA_ID_SSC_TX);
++#endif
++
++ pdev = &at91sam9x5_ssc_device;
++ configure_ssc_pins(pins);
++ at91_clock_associate("ssc_clk", &pdev->dev, "pclk");
++ }
++ else
++ return;
++
++ platform_device_register(pdev);
++}
++
++#else
++void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
++#endif
++
++
++/* --------------------------------------------------------------------
++ * UART
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_SERIAL_ATMEL)
++static struct resource dbgu_resources[] = {
++ [0] = {
++ .start = AT91_VA_BASE_SYS + AT91_DBGU,
++ .end = AT91_VA_BASE_SYS + AT91_DBGU + SZ_512 - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91_ID_SYS,
++ .end = AT91_ID_SYS,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct atmel_uart_data dbgu_data = {
++ .use_dma_tx = 0,
++ .use_dma_rx = 0,
++ .regs = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
++};
++
++static u64 dbgu_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device at91sam9x5_dbgu_device = {
++ .name = "atmel_usart",
++ .id = 0,
++ .dev = {
++ .dma_mask = &dbgu_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &dbgu_data,
++ },
++ .resource = dbgu_resources,
++ .num_resources = ARRAY_SIZE(dbgu_resources),
++};
++
++static inline void configure_dbgu_pins(void)
++{
++ at91_set_A_periph(AT91_PIN_PA9, 0); /* DRXD */
++ at91_set_A_periph(AT91_PIN_PA10, 1); /* DTXD */
++}
++
++static struct resource usart0_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_BASE_USART0,
++ .end = AT91SAM9X5_BASE_USART0 + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_USART0,
++ .end = AT91SAM9X5_ID_USART0,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct atmel_uart_data usart0_data = {
++ .use_dma_tx = 1,
++ .use_dma_rx = 0, /* doesn't support */
++};
++
++static u64 usart0_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device at91sam9x5_usart0_device = {
++ .name = "atmel_usart",
++ .id = 1,
++ .dev = {
++ .dma_mask = &usart0_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &usart0_data,
++ },
++ .resource = usart0_resources,
++ .num_resources = ARRAY_SIZE(usart0_resources),
++};
++
++static inline void configure_usart0_pins(unsigned pins)
++{
++ at91_set_A_periph(AT91_PIN_PA0, 1); /* TXD0 */
++ at91_set_A_periph(AT91_PIN_PA1, 0); /* RXD0 */
++
++ if (pins & ATMEL_UART_RTS)
++ at91_set_A_periph(AT91_PIN_PA2, 0); /* RTS0 */
++ if (pins & ATMEL_UART_CTS)
++ at91_set_A_periph(AT91_PIN_PA3, 0); /* CTS0 */
++}
++
++
++static struct resource usart1_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_BASE_USART1,
++ .end = AT91SAM9X5_BASE_USART1 + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_USART1,
++ .end = AT91SAM9X5_ID_USART1,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct atmel_uart_data usart1_data = {
++ .use_dma_tx = 1,
++ .use_dma_rx = 1,
++};
++
++static u64 usart1_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device at91sam9x5_usart1_device = {
++ .name = "atmel_usart",
++ .id = 2,
++ .dev = {
++ .dma_mask = &usart1_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &usart1_data,
++ },
++ .resource = usart1_resources,
++ .num_resources = ARRAY_SIZE(usart1_resources),
++};
++
++static inline void configure_usart1_pins(unsigned pins)
++{
++ at91_set_A_periph(AT91_PIN_PA5, 1); /* TXD1 */
++ at91_set_A_periph(AT91_PIN_PA6, 0); /* RXD1 */
++
++ if (pins & ATMEL_UART_RTS)
++ at91_set_C_periph(AT91_PIN_PC27, 0); /* RTS1 */
++ if (pins & ATMEL_UART_CTS)
++ at91_set_C_periph(AT91_PIN_PC28, 0); /* CTS1 */
++}
++
++static struct resource usart2_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_BASE_USART2,
++ .end = AT91SAM9X5_BASE_USART2 + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_USART2,
++ .end = AT91SAM9X5_ID_USART2,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct atmel_uart_data usart2_data = {
++ .use_dma_tx = 1,
++ .use_dma_rx = 1,
++};
++
++static u64 usart2_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device at91sam9x5_usart2_device = {
++ .name = "atmel_usart",
++ .id = 3,
++ .dev = {
++ .dma_mask = &usart2_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &usart2_data,
++ },
++ .resource = usart2_resources,
++ .num_resources = ARRAY_SIZE(usart2_resources),
++};
++
++static inline void configure_usart2_pins(unsigned pins)
++{
++ at91_set_A_periph(AT91_PIN_PA7, 1); /* TXD2 */
++ at91_set_A_periph(AT91_PIN_PA8, 0); /* RXD2 */
++
++ if (pins & ATMEL_UART_RTS)
++ at91_set_B_periph(AT91_PIN_PB0, 0); /* RTS2 */
++ if (pins & ATMEL_UART_CTS)
++ at91_set_B_periph(AT91_PIN_PB1, 0); /* CTS2 */
++}
++
++static struct resource usart3_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_BASE_USART3,
++ .end = AT91SAM9X5_BASE_USART3 + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_USART3,
++ .end = AT91SAM9X5_ID_USART3,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct atmel_uart_data usart3_data = {
++ .use_dma_tx = 1,
++ .use_dma_rx = 1,
++};
++
++static u64 usart3_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device at91sam9x5_usart3_device = {
++ .name = "atmel_usart",
++ .id = 4,
++ .dev = {
++ .dma_mask = &usart3_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &usart3_data,
++ },
++ .resource = usart3_resources,
++ .num_resources = ARRAY_SIZE(usart3_resources),
++};
++
++static inline void configure_usart3_pins(unsigned pins)
++{
++ at91_set_B_periph(AT91_PIN_PC22, 1); /* TXD3 */
++ at91_set_B_periph(AT91_PIN_PC23, 0); /* RXD3 */
++
++ if (pins & ATMEL_UART_RTS)
++ at91_set_B_periph(AT91_PIN_PC24, 0); /* RTS3 */
++ if (pins & ATMEL_UART_CTS)
++ at91_set_B_periph(AT91_PIN_PC25, 0); /* CTS3 */
++}
++
++static struct resource uart0_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_BASE_UART0,
++ .end = AT91SAM9X5_BASE_UART0 + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_UART0,
++ .end = AT91SAM9X5_ID_UART0,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct atmel_uart_data uart0_data = {
++ .use_dma_tx = 1,
++ .use_dma_rx = 1,
++};
++
++static u64 uart0_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device at91sam9x5_uart0_device = {
++ .name = "atmel_usart",
++ .id = 5,
++ .dev = {
++ .dma_mask = &uart0_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &uart0_data,
++ },
++ .resource = uart0_resources,
++ .num_resources = ARRAY_SIZE(uart0_resources),
++};
++
++static inline void configure_uart0_pins(unsigned pins)
++{
++ at91_set_C_periph(AT91_PIN_PC8, 1); /* UTXD0 */
++ at91_set_C_periph(AT91_PIN_PC9, 0); /* URXD0 */
++}
++
++static struct resource uart1_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_BASE_UART1,
++ .end = AT91SAM9X5_BASE_UART1 + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_UART1,
++ .end = AT91SAM9X5_ID_UART1,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct atmel_uart_data uart1_data = {
++ .use_dma_tx = 1,
++ .use_dma_rx = 1,
++};
++
++static u64 uart1_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device at91sam9x5_uart1_device = {
++ .name = "atmel_usart",
++ .id = 6,
++ .dev = {
++ .dma_mask = &uart1_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &uart1_data,
++ },
++ .resource = uart1_resources,
++ .num_resources = ARRAY_SIZE(uart1_resources),
++};
++
++static inline void configure_uart1_pins(unsigned pins)
++{
++ at91_set_C_periph(AT91_PIN_PC16, 1); /* UTXD1 */
++ at91_set_C_periph(AT91_PIN_PC17, 0); /* URXD1 */
++}
++
++static struct platform_device *__initdata at91_usarts[ATMEL_MAX_UART]; /* the USARTs to use */
++struct platform_device *atmel_default_console_device; /* the serial console device */
++
++void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
++{
++ struct platform_device *pdev;
++
++ switch (id) {
++ case 0: /* DBGU */
++ pdev = &at91sam9x5_dbgu_device;
++ configure_dbgu_pins();
++ at91_clock_associate("mck", &pdev->dev, "usart");
++ break;
++ case AT91SAM9X5_ID_USART0:
++ pdev = &at91sam9x5_usart0_device;
++ configure_usart0_pins(pins);
++ at91_clock_associate("usart0_clk", &pdev->dev, "usart");
++ break;
++ case AT91SAM9X5_ID_USART1:
++ pdev = &at91sam9x5_usart1_device;
++ configure_usart1_pins(pins);
++ at91_clock_associate("usart1_clk", &pdev->dev, "usart");
++ break;
++ case AT91SAM9X5_ID_USART2:
++ pdev = &at91sam9x5_usart2_device;
++ configure_usart2_pins(pins);
++ at91_clock_associate("usart2_clk", &pdev->dev, "usart");
++ break;
++ case AT91SAM9X5_ID_USART3:
++ pdev = &at91sam9x5_usart3_device;
++ configure_usart3_pins(pins);
++ at91_clock_associate("usart3_clk", &pdev->dev, "usart");
++ break;
++ case AT91SAM9X5_ID_UART0:
++ pdev = &at91sam9x5_uart0_device;
++ configure_uart0_pins(pins);
++ at91_clock_associate("uart0_clk", &pdev->dev, "usart");
++ break;
++ case AT91SAM9X5_ID_UART1:
++ pdev = &at91sam9x5_uart1_device;
++ configure_uart1_pins(pins);
++ at91_clock_associate("uart1_clk", &pdev->dev, "usart");
++ break;
++ default:
++ return;
++ }
++ pdev->id = portnr; /* update to mapped ID */
++
++ if (portnr < ATMEL_MAX_UART)
++ at91_usarts[portnr] = pdev;
++}
++
++void __init at91_set_serial_console(unsigned portnr)
++{
++ if (portnr < ATMEL_MAX_UART)
++ atmel_default_console_device = at91_usarts[portnr];
++}
++
++void __init at91_add_device_serial(void)
++{
++ int i;
++
++ for (i = 0; i < ATMEL_MAX_UART; i++) {
++ if (at91_usarts[i]) {
++#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE)
++ int peripheral_id = platform_get_irq(at91_usarts[i], 0);
++ struct atmel_uart_data *pdata = at91_usarts[i]->dev.platform_data;
++
++ if (pdata->use_dma_tx) {
++ struct at_dma_slave *atslave;
++
++ atslave = kzalloc(sizeof(struct at_dma_slave), GFP_KERNEL);
++
++ /* DMA slave channel configuration */
++ if (peripheral_id == AT91SAM9X5_ID_USART0
++ || peripheral_id == AT91SAM9X5_ID_USART1
++ || peripheral_id == AT91SAM9X5_ID_UART0)
++ atslave->dma_dev = &at_hdmac0_device.dev;
++ else
++ atslave->dma_dev = &at_hdmac1_device.dev;
++
++ atslave->reg_width = DW_DMA_SLAVE_WIDTH_8BIT;
++ atslave->cfg = ATC_FIFOCFG_HALFFIFO
++ | ATC_SRC_H2SEL_SW | ATC_DST_H2SEL_HW
++ | (AT_DMA_ID_USART0_TX << 4); /*ATC_DST_PER(peripheral_id);*/
++
++ pdata->dma_tx_slave = atslave;
++ }
++#endif
++ platform_device_register(at91_usarts[i]);
++ }
++ }
++
++ if (!atmel_default_console_device)
++ printk(KERN_INFO "AT91: No default serial console defined.\n");
++}
++#else
++void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
++void __init at91_set_serial_console(unsigned portnr) {}
++void __init at91_add_device_serial(void) {}
++#endif
++
++
++/* -------------------------------------------------------------------- */
++/*
++ * These devices are always present and don't need any board-specific
++ * setup.
++ */
++static int __init at91_add_standard_devices(void)
++{
++ at91_add_device_hdmac();
++ at91_add_device_rtc();
++ at91_add_device_watchdog();
++ at91_add_device_tc();
++ return 0;
++}
++
++arch_initcall(at91_add_standard_devices);
+diff --git a/arch/arm/mach-at91/board-sam9x5cm.c b/arch/arm/mach-at91/board-sam9x5cm.c
+new file mode 100644
+index 0000000..4fcc150
+--- /dev/null
++++ b/arch/arm/mach-at91/board-sam9x5cm.c
+@@ -0,0 +1,236 @@
++/*
++ * CPU module specific setup code for the AT91SAM9x5 family
++ *
++ * Copyright (C) 2011 Atmel Corporation.
++ *
++ * 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.
++ *
++ */
++
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/spi/flash.h>
++#include <linux/spi/spi.h>
++#include <linux/fb.h>
++#include <linux/gpio_keys.h>
++#include <linux/input.h>
++#include <linux/leds.h>
++#include <linux/clk.h>
++#include <mach/cpu.h>
++
++#include <video/atmel_lcdc.h>
++
++#include <asm/setup.h>
++#include <asm/mach-types.h>
++#include <asm/irq.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/irq.h>
++
++#include <mach/hardware.h>
++#include <mach/board.h>
++#include <mach/gpio.h>
++#include <mach/at91sam9_smc.h>
++#include <mach/at91_shdwc.h>
++
++#include "sam9_smc.h"
++#include "generic.h"
++#include <mach/board-sam9x5.h>
++
++void __init cm_map_io(void)
++{
++ /* Initialize processor: 12.000 MHz crystal */
++ at91sam9x5_initialize(12000000);
++
++ /* DGBU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* set serial console to ttyS0 (ie, DBGU) */
++ at91_set_serial_console(0);
++}
++
++void __init cm_init_irq(void)
++{
++ at91sam9x5_init_interrupts(NULL);
++}
++
++/*
++ * SPI devices.
++ */
++static struct mtd_partition cm_spi_flash_parts[] = {
++ {
++ .name = "full",
++ .offset = 0,
++ .size = MTDPART_SIZ_FULL,
++ },
++ {
++ .name = "little",
++ .offset = 0,
++ .size = 24 * SZ_1K,
++ },
++ {
++ .name = "remaining",
++ .offset = MTDPART_OFS_NXTBLK,
++ .size = MTDPART_SIZ_FULL,
++ },
++};
++
++static const struct flash_platform_data cm_spi_flash_data = {
++ /*.type = "sst25vf032b",*/
++ .name = "spi_flash",
++ .parts = cm_spi_flash_parts,
++ .nr_parts = ARRAY_SIZE(cm_spi_flash_parts),
++};
++
++static struct spi_board_info cm_spi_devices[] = {
++#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
++#if defined(CONFIG_MTD_M25P80)
++ { /* serial flash chip */
++ .modalias = "m25p80",
++ .chip_select = 0,
++ .max_speed_hz = 15 * 1000 * 1000,
++ .bus_num = 0,
++ .mode = SPI_MODE_0,
++ .platform_data = &cm_spi_flash_data,
++ .irq = -1,
++ },
++#endif
++#endif
++};
++
++/*
++ * NAND flash
++ */
++static struct mtd_partition __initdata cm_nand_partition[] = {
++ {
++ .name = "Partition 1",
++ .offset = 0,
++ .size = SZ_64M,
++ },
++ {
++ .name = "Partition 2",
++ .offset = MTDPART_OFS_NXTBLK,
++ .size = MTDPART_SIZ_FULL,
++ },
++};
++
++static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
++{
++ *num_partitions = ARRAY_SIZE(cm_nand_partition);
++ return cm_nand_partition;
++}
++
++/* det_pin is not connected */
++static struct atmel_nand_data __initdata cm_nand_data = {
++ .ale = 21,
++ .cle = 22,
++ .enable_pin = AT91_PIN_PD4,
++ .partition_info = nand_partitions,
++#if defined(CONFIG_MTD_NAND_AT91_BUSWIDTH_16)
++ .bus_width_16 = 1,
++#endif
++};
++
++static struct sam9_smc_config __initdata cm_nand_smc_config = {
++ .ncs_read_setup = 0,
++ .nrd_setup = 1,
++ .ncs_write_setup = 0,
++ .nwe_setup = 1,
++
++ .ncs_read_pulse = 6,
++ .nrd_pulse = 4,
++ .ncs_write_pulse = 5,
++ .nwe_pulse = 3,
++
++ .read_cycle = 6,
++ .write_cycle = 5,
++
++ .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
++ .tdf_cycles = 1,
++};
++
++static void __init cm_add_device_nand(void)
++{
++ /* setup bus-width (8 or 16) */
++ if (cm_nand_data.bus_width_16)
++ cm_nand_smc_config.mode |= AT91_SMC_DBW_16;
++ else
++ cm_nand_smc_config.mode |= AT91_SMC_DBW_8;
++
++ /* revision of board modify NAND wiring */
++ if (cm_is_revA()) {
++ cm_nand_data.bus_on_d0 = 1;
++ cm_nand_data.rdy_pin = AT91_PIN_PD6;
++ } else {
++ cm_nand_data.bus_on_d0 = 0;
++ cm_nand_data.rdy_pin = AT91_PIN_PD5;
++ }
++
++ /* configure chip-select 3 (NAND) */
++ sam9_smc_configure(3, &cm_nand_smc_config);
++
++ at91_add_device_nand(&cm_nand_data);
++}
++
++/*
++ * LEDs
++ */
++static struct gpio_led cm_leds[] = {
++ { /* "left" led, blue, userled1 */
++ .name = "d1",
++ .gpio = AT91_PIN_PB18,
++ .default_trigger = "heartbeat",
++ },
++ { /* "right" led, red, userled2 */
++ .name = "d2",
++ .gpio = AT91_PIN_PD21,
++ .active_low = 1,
++ .default_trigger = "mmc0",
++ },
++};
++
++/*
++ * I2C Devices
++ */
++static struct i2c_board_info __initdata cm_i2c_devices[] = {
++ {
++ I2C_BOARD_INFO("24c512", 0x50)
++ },
++};
++
++void __init cm_board_init(u32 *cm_config)
++{
++ int i;
++
++ *cm_config = 0;
++
++ /* SPI */
++ at91_add_device_spi(cm_spi_devices, ARRAY_SIZE(cm_spi_devices));
++ /* Check SPI0 usage to take decision in mother board */
++ for (i = 0; i < ARRAY_SIZE(cm_spi_devices); i++) {
++ if (cm_spi_devices[i].bus_num == 0) {
++ *cm_config |= CM_CONFIG_SPI0_ENABLE;
++ break;
++ }
++ }
++ /* NAND */
++ cm_add_device_nand();
++ /* I2C */
++ at91_add_device_i2c(0, cm_i2c_devices, ARRAY_SIZE(cm_i2c_devices));
++ *cm_config |= CM_CONFIG_I2C0_ENABLE;
++ /* LEDs */
++ at91_gpio_leds(cm_leds, ARRAY_SIZE(cm_leds));
++
++ /* TODO Remove: only for debugging */
++ if (cm_is_revA())
++ printk(KERN_CRIT "AT91: CM rev A\n");
++ else
++ printk(KERN_CRIT "AT91: CM rev B and higher\n");
++}
+diff --git a/arch/arm/mach-at91/board-sam9x5ek.c b/arch/arm/mach-at91/board-sam9x5ek.c
+new file mode 100644
+index 0000000..d86124c
+--- /dev/null
++++ b/arch/arm/mach-at91/board-sam9x5ek.c
+@@ -0,0 +1,358 @@
++/*
++ * Board-specific setup code for the AT91SAM9x5 Evaluation Kit family
++ *
++ * Copyright (C) 2010 Atmel Corporation.
++ *
++ * 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.
++ *
++ */
++
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/spi/flash.h>
++#include <linux/spi/spi.h>
++#include <linux/fb.h>
++#include <linux/gpio_keys.h>
++#include <linux/input.h>
++#include <linux/leds.h>
++#include <linux/clk.h>
++#include <mach/cpu.h>
++
++#include <video/atmel_lcdc.h>
++#include <mach/atmel_hlcdfb.h>
++
++#include <asm/setup.h>
++#include <asm/mach-types.h>
++#include <asm/irq.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/irq.h>
++
++#include <mach/hardware.h>
++#include <mach/board.h>
++#include <mach/gpio.h>
++#include <mach/at91sam9_smc.h>
++#include <mach/at91_shdwc.h>
++
++#include "sam9_smc.h"
++#include "generic.h"
++#include <mach/board-sam9x5.h>
++
++static void __init ek_map_io(void)
++{
++ /* Initialize processor and DBGU */
++ cm_map_io();
++
++ /* USART0 on ttyS1. (Rx, Tx) */
++ at91_register_uart(AT91SAM9X5_ID_USART0, 1, 0);
++}
++
++/*
++ * USB Host port (OHCI)
++ */
++/* Port A is shared with gadget port & Port C is full-speed only */
++static struct at91_usbh_data __initdata ek_usbh_fs_data = {
++ .ports = 3,
++
++};
++
++/*
++ * USB HS Host port (EHCI)
++ */
++/* Port A is shared with gadget port */
++static struct at91_usbh_data __initdata ek_usbh_hs_data = {
++ .ports = 2,
++};
++
++
++/*
++ * USB HS Device port
++ */
++static struct usba_platform_data __initdata ek_usba_udc_data;
++
++
++/*
++ * MACB Ethernet devices
++ */
++static struct at91_eth_data __initdata ek_macb0_data = {
++ .is_rmii = 1,
++};
++
++static struct at91_eth_data __initdata ek_macb1_data = {
++ .phy_irq_pin = AT91_PIN_PC26,
++ .is_rmii = 1,
++};
++
++
++/*
++ * MCI (SD/MMC)
++ */
++/* mci0 detect_pin is revision dependent */
++static struct mci_platform_data __initdata mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .wp_pin = -1,
++ },
++};
++
++static struct mci_platform_data __initdata mci1_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PD14,
++ .wp_pin = -1,
++ },
++};
++
++
++/*
++ * LCD Controller
++ */
++#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
++static struct fb_videomode at91_tft_vga_modes[] = {
++ {
++ .name = "LG",
++ .refresh = 60,
++ .xres = 800, .yres = 480,
++ .pixclock = KHZ2PICOS(22223),
++
++ .left_margin = 64, .right_margin = 64,
++ .upper_margin = 22, .lower_margin = 21,
++ .hsync_len = 128, .vsync_len = 2,
++
++ .sync = 0,
++ .vmode = FB_VMODE_NONINTERLACED,
++ },
++};
++
++static struct fb_monspecs at91fb_default_monspecs = {
++ .manufacturer = "LG",
++ .monitor = "LB043WQ1",
++
++ .modedb = at91_tft_vga_modes,
++ .modedb_len = ARRAY_SIZE(at91_tft_vga_modes),
++ .hfmin = 15000,
++ .hfmax = 17640,
++ .vfmin = 57,
++ .vfmax = 67,
++};
++
++/* Default output mode is TFT 24 bit */
++#define AT91SAM9X5_DEFAULT_LCDCFG5 (LCDC_LCDCFG5_MODE_OUTPUT_24BPP)
++
++/* Driver datas */
++static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
++ .lcdcon_is_backlight = true,
++ .alpha_enabled = false,
++ .default_bpp = 24,
++ /* In 9x5 default_lcdcon2 is used for LCDCFG5 */
++ .default_lcdcon2 = AT91SAM9X5_DEFAULT_LCDCFG5,
++ .default_monspecs = &at91fb_default_monspecs,
++ .guard_time = 9,
++ .lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB,
++};
++
++#else
++static struct atmel_lcdfb_info __initdata ek_lcdc_data;
++#endif
++
++/*
++ * Touchscreen
++ */
++static struct at91_tsadcc_data ek_tsadcc_data = {
++ .adc_clock = 300000,
++ /*
++ * XXX: ukl: disable averaging for now at it's broken without a hardware
++ * change
++ */
++ .filtering_average = 0x00, /* averages 2^filtering_average ADC conversions */
++ .pendet_debounce = 0x0d,
++ .pendet_sensitivity = 0x03,
++ .ts_sample_hold_time = 0x0a,
++};
++
++/*
++ * GPIO Buttons
++ */
++#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
++static struct gpio_keys_button ek_buttons[] = {
++ { /* BP3, "leftclic" */
++ .code = BTN_LEFT,
++ .gpio = AT91_PIN_PD18,
++ .active_low = 1,
++ .desc = "left_click",
++ .wakeup = 1,
++ },
++ { /* BP4, "rightclic" */
++ .code = BTN_RIGHT,
++ .gpio = AT91_PIN_PD19,
++ .active_low = 1,
++ .desc = "right_click",
++ .wakeup = 1,
++ },
++};
++
++static struct gpio_keys_platform_data ek_button_data = {
++ .buttons = ek_buttons,
++ .nbuttons = ARRAY_SIZE(ek_buttons),
++};
++
++static struct platform_device ek_button_device = {
++ .name = "gpio-keys",
++ .id = -1,
++ .num_resources = 0,
++ .dev = {
++ .platform_data = &ek_button_data,
++ }
++};
++
++static void __init ek_add_device_buttons(void)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(ek_buttons); i++) {
++ at91_set_pulldown(ek_buttons[i].gpio, 0);
++ at91_set_gpio_input(ek_buttons[i].gpio, 1);
++ at91_set_deglitch(ek_buttons[i].gpio, 1);
++ }
++
++ platform_device_register(&ek_button_device);
++}
++#else
++static void __init ek_add_device_buttons(void) {}
++#endif
++
++/*
++ * I2C Devices
++ */
++static struct i2c_board_info __initdata ek_i2c_devices[] = {
++ {
++ I2C_BOARD_INFO("wm8731", 0x1a)
++ },
++#if defined(CONFIG_KEYBOARD_QT1070)
++ {
++ I2C_BOARD_INFO("qt1070", 0x1b),
++ .irq = AT91_PIN_PA7,
++ .flags = I2C_CLIENT_WAKE,
++ },
++#endif
++};
++
++static void __init ek_board_configure_pins(void)
++{
++ if (ek_is_revA()) {
++ /* Port A is shared with gadget port */
++ /*ek_usbh_fs_data.vbus_pin[0] = AT91_PIN_PD9;*/
++ /*ek_usbh_hs_data.vbus_pin[0] = AT91_PIN_PD9;*/
++ ek_usbh_fs_data.vbus_pin[1] = AT91_PIN_PD10;
++ ek_usbh_hs_data.vbus_pin[1] = AT91_PIN_PD10;
++ /* Port C is full-speed only */
++ ek_usbh_fs_data.vbus_pin[2] = AT91_PIN_PD11;
++
++ ek_usba_udc_data.vbus_pin = AT91_PIN_PB8;
++
++ ek_macb0_data.phy_irq_pin = 0;
++
++ mci0_data.slot[0].detect_pin = AT91_PIN_PD13;
++ } else {
++ /* Port A is shared with gadget port */
++ /*ek_usbh_fs_data.vbus_pin[0] = AT91_PIN_PD18;*/
++ /*ek_usbh_hs_data.vbus_pin[0] = AT91_PIN_PD18;*/
++ ek_usbh_fs_data.vbus_pin[1] = AT91_PIN_PD19;
++ ek_usbh_hs_data.vbus_pin[1] = AT91_PIN_PD19;
++ /* Port C is full-speed only */
++ ek_usbh_fs_data.vbus_pin[2] = AT91_PIN_PD20;
++
++ ek_usba_udc_data.vbus_pin = AT91_PIN_PB16;
++
++ ek_macb0_data.phy_irq_pin = AT91_PIN_PB8;
++
++ mci0_data.slot[0].detect_pin = AT91_PIN_PD15;
++
++#if defined(CONFIG_KEYBOARD_QT1070)
++ if (!cpu_is_at91sam9g25())
++ /* conflict with ISI */
++ at91_set_gpio_input(ek_i2c_devices[1].irq, 1);
++#endif
++ }
++}
++
++static void __init ek_board_init(void)
++{
++ u32 cm_config;
++
++ cm_board_init(&cm_config);
++ ek_board_configure_pins();
++ /* Serial */
++ at91_add_device_serial();
++ /* USB HS Host */
++ at91_add_device_usbh_ohci(&ek_usbh_fs_data);
++ at91_add_device_usbh_ehci(&ek_usbh_hs_data);
++ /* USB HS Device */
++ at91_add_device_usba(&ek_usba_udc_data);
++ /* Ethernet */
++ at91_add_device_eth(0, &ek_macb0_data);
++ at91_add_device_eth(1, &ek_macb1_data);
++ /* MMC */
++ at91_add_device_mci(0, &mci0_data);
++ /* Conflict between SPI0 and MCI1 pins */
++ if (!(cm_config & CM_CONFIG_SPI0_ENABLE))
++ at91_add_device_mci(1, &mci1_data);
++ /* I2C */
++ if (cm_config & CM_CONFIG_I2C0_ENABLE)
++ i2c_register_board_info(0,
++ ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
++ else
++ at91_add_device_i2c(0,
++ ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
++
++ if (!cpu_is_at91sam9g25() && !cpu_is_at91sam9x25()) {
++ /* LCD Controller */
++ at91_add_device_lcdc(&ek_lcdc_data);
++ /* Touch Screen */
++ at91_add_device_tsadcc(&ek_tsadcc_data);
++ }
++
++#if 0
++ if (cpu_is_at91sam9x25() || cpu_is_at91sam9x35())
++ /*
++ * open jumper/solderdrop JP11 to activate CAN0
++ *
++ * _note_: this will deactivate the debug uart
++ */
++ at91_add_device_can(0, NULL);
++#endif
++
++ if (cpu_is_at91sam9x25() || cpu_is_at91sam9x35())
++ /* XXX: this conflicts with usart.1 */
++ at91_add_device_can(1, NULL);
++
++ /* Push Buttons */
++ if (ek_is_revA())
++ ek_add_device_buttons();
++
++ /* SSC (for WM8731) */
++ at91_add_device_ssc(AT91SAM9X5_ID_SSC, ATMEL_SSC_TX | ATMEL_SSC_RX);
++
++ /* TODO Remove: only for debugging */
++ if (ek_is_revA())
++ printk(KERN_CRIT "AT91: EK rev A\n");
++ else
++ printk(KERN_CRIT "AT91: EK rev B and higher\n");
++}
++
++MACHINE_START(AT91SAM9X5EK, "Atmel AT91SAM9X5-EK")
++ /* Maintainer: Atmel */
++/* XXX/ukl: can we drop .boot_params? */
++ .boot_params = AT91_SDRAM_BASE + 0x100,
++ .timer = &at91sam926x_timer,
++ .map_io = ek_map_io,
++ .init_irq = cm_init_irq,
++ .init_machine = ek_board_init,
++MACHINE_END
+diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
+index 0c66deb..a775336 100644
+--- a/arch/arm/mach-at91/generic.h
++++ b/arch/arm/mach-at91/generic.h
+@@ -15,6 +15,7 @@ extern void __init at91sam9261_initialize(unsigned long main_clock);
+ extern void __init at91sam9263_initialize(unsigned long main_clock);
+ extern void __init at91sam9rl_initialize(unsigned long main_clock);
+ extern void __init at91sam9g45_initialize(unsigned long main_clock);
++extern void __init at91sam9x5_initialize(unsigned long main_clock);
+ extern void __init at91x40_initialize(unsigned long main_clock);
+ extern void __init at91cap9_initialize(unsigned long main_clock);
+ extern void __init at572d940hf_initialize(unsigned long main_clock);
+@@ -26,6 +27,7 @@ extern void __init at91sam9261_init_interrupts(unsigned int priority[]);
+ extern void __init at91sam9263_init_interrupts(unsigned int priority[]);
+ extern void __init at91sam9rl_init_interrupts(unsigned int priority[]);
+ extern void __init at91sam9g45_init_interrupts(unsigned int priority[]);
++extern void __init at91sam9x5_init_interrupts(unsigned int priority[]);
+ extern void __init at91x40_init_interrupts(unsigned int priority[]);
+ extern void __init at91cap9_init_interrupts(unsigned int priority[]);
+ extern void __init at572d940hf_init_interrupts(unsigned int priority[]);
+diff --git a/arch/arm/mach-at91/include/mach/board-sam9x5.h b/arch/arm/mach-at91/include/mach/board-sam9x5.h
+new file mode 100644
+index 0000000..be8e1ec
+--- /dev/null
++++ b/arch/arm/mach-at91/include/mach/board-sam9x5.h
+@@ -0,0 +1,91 @@
++/*
++ * Board-specific header file for the AT91SAM9x5 Evaluation Kit family
++ *
++ * Copyright (C) 2010 Atmel Corporation.
++ *
++ * 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.
++ *
++ */
++
++/*
++ * board revision encoding
++ *
++ * ATAG_SN lower 32 bits
++ * 0-4 cpu_module_board_id 5 bits
++ * 5-9 cpu_module_vendor_id 5 bits
++ * 10-14 display_module_board_id 5 bits
++ * 15-19 display_module_vendor_id 5 bits
++ * 20-24 mother_board_id 5 bits
++ * 25-29 mother_board_vendor_id 5 bits
++ * 30-31 reserved for future use 2 bits
++ *
++ * rev: stands for revision code letter: the 'B' in "B1" revision code for
++ * instance coded as a increment from 'A' starting at 0x0: 0x0 means 'A',
++ * 0x1 means 'B', etc.
++ *
++ * rev_id: stands for revision code identifier ; it is a number: the '1' in
++ * "B1" revision code for instance: coded as a increment from '0'
++ * starting at 0x0: 0x0 means '0', 0x1 means '1', etc.)
++ *
++ * ATAG_REV
++ * 0-4 cpu_module_board_rev 5 bits
++ * 5-9 display_module_board_rev 5 bits
++ * 10-14 mother_module_board_rev 5 bits
++ * 15-17 cpu_module_board_rev_id 3 bits
++ * 18-20 display_module_board_rev_id 3 bits
++ * 21-23 mother_module_board_rev_id 3 bits
++ * 24-31 reserved for future use 8 bits
++ *
++ * OWI sands for One Wire Information
++ * The information comes form the 1-wire component on each board
++ * and is encoded in ATAGs: both system_serial_low and system_rev
++ */
++
++#define CM_REV_OFFSET 0
++#define CM_REV_SIZE 5
++#define CM_REV_ID_OFFSET 15
++#define CM_REV_ID_SIZE 3
++#define DM_REV_OFFSET 5
++#define DM_REV_SIZE 5
++#define DM_REV_ID_OFFSET 18
++#define DM_REV_ID_SIZE 3
++#define EK_REV_OFFSET 10
++#define EK_REV_SIZE 5
++#define EK_REV_ID_OFFSET 21
++#define EK_REV_ID_SIZE 3
++
++/* Bit manipulation macros */
++#define OWI_BIT(name) \
++ (1 << name##_OFFSET)
++#define OWI_BF(name,value) \
++ (((value) & ((1 << name##_SIZE) - 1)) << name##_OFFSET)
++#define OWI_BFEXT(name,value) \
++ (((value) >> name##_OFFSET) & ((1 << name##_SIZE) - 1))
++#define OWI_BFINS(name,value,old) \
++ ( ((old) & ~(((1 << name##_SIZE) - 1) << name##_OFFSET)) \
++ | SPI_BF(name,value))
++
++#define cm_rev() OWI_BFEXT(CM_REV, system_rev)
++#define dm_rev() OWI_BFEXT(DM_REV, system_rev)
++#define ek_rev() OWI_BFEXT(EK_REV, system_rev)
++
++#define cm_is_revA() (cm_rev() == 0)
++#define cm_is_revB() (cm_rev() == ('B' - 'A'))
++
++#define ek_is_revA() (ek_rev() == 0)
++#define ek_is_revB() (ek_rev() == ('B' - 'A'))
++
++/* Configuration of CPU Module useful for mother board */
++#define CM_CONFIG_SPI0_ENABLE (1 << 0)
++#define CM_CONFIG_SPI1_ENABLE (1 << 1)
++#define CM_CONFIG_I2C0_ENABLE (1 << 2)
++#define CM_CONFIG_I2C1_ENABLE (1 << 3)
++
++
++/* CPU Module prototypes */
++void __init cm_map_io(void);
++void __init cm_init_irq(void);
++void __init cm_board_init(u32 *cm_config);
+diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
+index 2b499eb..42412d5 100644
+--- a/arch/arm/mach-at91/include/mach/board.h
++++ b/arch/arm/mach-at91/include/mach/board.h
+@@ -87,17 +87,21 @@ struct at91_eth_data {
+ u8 phy_irq_pin; /* PHY IRQ */
+ u8 is_rmii; /* using RMII interface? */
+ };
++#if defined(CONFIG_ARCH_AT91SAM9X5)
++extern void __init at91_add_device_eth(short eth_id, struct at91_eth_data *data);
++#else
+ extern void __init at91_add_device_eth(struct at91_eth_data *data);
++#endif
+
+ #if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91SAM9G20) || defined(CONFIG_ARCH_AT91CAP9) \
+- || defined(CONFIG_ARCH_AT91SAM9G45) || defined(CONFIG_ARCH_AT572D940HF)
++ || defined(CONFIG_ARCH_AT91SAM9G45) || defined(CONFIG_ARCH_AT91SAM9X5) || defined(CONFIG_ARCH_AT572D940HF)
+ #define eth_platform_data at91_eth_data
+ #endif
+
+ /* USB Host */
+ struct at91_usbh_data {
+ u8 ports; /* number of ports on root hub */
+- u8 vbus_pin[2]; /* port power-control pin */
++ u8 vbus_pin[3]; /* port power-control pin */
+ };
+ extern void __init at91_add_device_usbh(struct at91_usbh_data *data);
+ extern void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data);
+@@ -112,12 +116,13 @@ struct atmel_nand_data {
+ u8 ale; /* address line number connected to ALE */
+ u8 cle; /* address line number connected to CLE */
+ u8 bus_width_16; /* buswidth is 16 bit */
++ u8 bus_on_d0; /* pins of data bus are connected to D0~D15 */
+ struct mtd_partition* (*partition_info)(int, int*);
+ };
+ extern void __init at91_add_device_nand(struct atmel_nand_data *data);
+
+ /* I2C*/
+-#if defined(CONFIG_ARCH_AT91SAM9G45)
++#if defined(CONFIG_ARCH_AT91SAM9G45) || defined(CONFIG_ARCH_AT91SAM9X5)
+ extern void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices);
+ #else
+ extern void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices);
+@@ -143,6 +148,7 @@ struct atmel_uart_data {
+ short use_dma_tx; /* use transmit DMA? */
+ short use_dma_rx; /* use receive DMA? */
+ void __iomem *regs; /* virt. base address, if any */
++ struct at_dma_slave *dma_tx_slave;
+ struct serial_rs485 rs485; /* rs485 settings */
+ };
+ extern void __init at91_add_device_serial(void);
+@@ -187,7 +193,9 @@ extern void __init at91_add_device_isi(void);
+ /* Touchscreen Controller */
+ struct at91_tsadcc_data {
+ unsigned int adc_clock;
++ u8 filtering_average;
+ u8 pendet_debounce;
++ u8 pendet_sensitivity;
+ u8 ts_sample_hold_time;
+ };
+ extern void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data);
+@@ -196,7 +204,11 @@ extern void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data);
+ struct at91_can_data {
+ void (*transceiver_switch)(int on);
+ };
++#ifdef CONFIG_ARCH_AT91SAM9X5
++extern void __init at91_add_device_can(int id, struct at91_can_data *data);
++#else
+ extern void __init at91_add_device_can(struct at91_can_data *data);
++#endif
+
+ /* LEDs */
+ extern void __init at91_init_leds(u8 cpu_led, u8 timer_led);
+diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h
+index 3d64a75..6e270c2 100644
+--- a/arch/arm/mach-at91/include/mach/hardware.h
++++ b/arch/arm/mach-at91/include/mach/hardware.h
+@@ -28,6 +28,8 @@
+ #include <mach/at91sam9rl.h>
+ #elif defined(CONFIG_ARCH_AT91SAM9G45)
+ #include <mach/at91sam9g45.h>
++#elif defined(CONFIG_ARCH_AT91SAM9X5)
++#include <mach/at91sam9x5.h>
+ #elif defined(CONFIG_ARCH_AT91CAP9)
+ #include <mach/at91cap9.h>
+ #elif defined(CONFIG_ARCH_AT91X40)
+diff --git a/arch/arm/mach-at91/include/mach/timex.h b/arch/arm/mach-at91/include/mach/timex.h
+index 05a6e8a..23df905 100644
+--- a/arch/arm/mach-at91/include/mach/timex.h
++++ b/arch/arm/mach-at91/include/mach/timex.h
+@@ -72,6 +72,11 @@
+ #define AT91SAM9_MASTER_CLOCK 133333333
+ #define CLOCK_TICK_RATE (AT91SAM9_MASTER_CLOCK/16)
+
++#elif defined(CONFIG_ARCH_AT91SAM9X5)
++
++#define AT91SAM9_MASTER_CLOCK 133333333
++#define CLOCK_TICK_RATE (AT91SAM9_MASTER_CLOCK/16)
++
+ #elif defined(CONFIG_ARCH_AT91CAP9)
+
+ #define AT91CAP9_MASTER_CLOCK 100000000
+diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h
+index ce9a206..b93f259 100644
+--- a/arch/arm/mach-at91/pm.h
++++ b/arch/arm/mach-at91/pm.h
+@@ -79,6 +79,25 @@ static inline u32 sdram_selfrefresh_enable(void)
+ } while (0)
+ #define wait_for_interrupt_enable() cpu_do_idle()
+
++#elif defined(CONFIG_ARCH_AT91SAM9X5)
++#include <mach/at91sam9_ddrsdr.h>
++
++static inline u32 sdram_selfrefresh_enable(void)
++{
++ u32 lpr, saved_lpr;
++
++ saved_lpr = at91_ramc_read(0, AT91_DDRSDRC_LPR);
++ lpr = saved_lpr & ~AT91_DDRSDRC_LPCB;
++ lpr |= AT91_DDRSDRC_LPCB_SELF_REFRESH;
++
++ at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr);
++
++ return saved_lpr;
++}
++
++#define sdram_selfrefresh_disable(saved_lpr) at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr)
++#define wait_for_interrupt_enable() cpu_do_idle()
++
+ #else
+ #include <mach/at91sam9_sdramc.h>
+
+diff --git a/arch/arm/mach-at91/pm_slowclock.S b/arch/arm/mach-at91/pm_slowclock.S
+index f7922a4..1a44c98 100644
+--- a/arch/arm/mach-at91/pm_slowclock.S
++++ b/arch/arm/mach-at91/pm_slowclock.S
+@@ -20,7 +20,7 @@
+ #include <mach/at91rm9200_mc.h>
+ #elif defined(CONFIG_ARCH_AT91CAP9)
+ #include <mach/at91cap9_ddrsdr.h>
+-#elif defined(CONFIG_ARCH_AT91SAM9G45)
++#elif defined(CONFIG_ARCH_AT91SAM9G45) || defined(CONFIG_ARCH_AT91SAM9X5)
+ #include <mach/at91sam9_ddrsdr.h>
+ #else
+ #include <mach/at91sam9_sdramc.h>
+@@ -132,7 +132,8 @@ ENTRY(at91_slow_clock)
+ mov r3, #1
+ str r3, [r2, #AT91_SDRAMC_SRR]
+ #elif defined(CONFIG_ARCH_AT91CAP9) \
+- || defined(CONFIG_ARCH_AT91SAM9G45)
++ || defined(CONFIG_ARCH_AT91SAM9G45) \
++ || defined(CONFIG_ARCH_AT91SAM9X5)
+
+ /* prepare for DDRAM self-refresh mode */
+ ldr r3, [r2, #AT91_DDRSDRC_LPR]
+@@ -265,7 +266,8 @@ ENTRY(at91_slow_clock)
+ #ifdef CONFIG_ARCH_AT91RM9200
+ /* Do nothing - self-refresh is automatically disabled. */
+ #elif defined(CONFIG_ARCH_AT91CAP9) \
+- || defined(CONFIG_ARCH_AT91SAM9G45)
++ || defined(CONFIG_ARCH_AT91SAM9G45) \
++ || defined(CONFIG_ARCH_AT91SAM9X5)
+ /* Restore LPR on AT91 with DDRAM */
+ ldr r3, .saved_sam9_lpr
+ str r3, [r2, #AT91_DDRSDRC_LPR]
+@@ -307,7 +309,8 @@ ENTRY(at91_slow_clock)
+ .at91_va_base_sdramc:
+ .word AT91_VA_BASE_SYS
+ #elif defined(CONFIG_ARCH_AT91CAP9) \
+- || defined(CONFIG_ARCH_AT91SAM9G45)
++ || defined(CONFIG_ARCH_AT91SAM9G45) \
++ || defined(CONFIG_ARCH_AT91SAM9X5)
+ .at91_va_base_sdramc:
+ .word AT91_VA_BASE_SYS + AT91_DDRSDRC0
+ #else
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0013-ARM-at91-provide-defconfig-for-at91sam9x5ek.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0013-ARM-at91-provide-defconfig-for-at91sam9x5ek.patch
new file mode 100644
index 0000000..a0510fc
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0013-ARM-at91-provide-defconfig-for-at91sam9x5ek.patch
@@ -0,0 +1,218 @@
+From 480473dce3bc94a6f05bb69fcebf35b059ff77e3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
+Date: Wed, 20 Apr 2011 17:27:15 +0200
+Subject: [PATCH 013/107] ARM: at91: provide defconfig for at91sam9x5ek
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ arch/arm/configs/at91sam9x5ek_defconfig | 195 +++++++++++++++++++++++++++++++
+ 1 files changed, 195 insertions(+), 0 deletions(-)
+ create mode 100644 arch/arm/configs/at91sam9x5ek_defconfig
+
+diff --git a/arch/arm/configs/at91sam9x5ek_defconfig b/arch/arm/configs/at91sam9x5ek_defconfig
+new file mode 100644
+index 0000000..1b455fc
+--- /dev/null
++++ b/arch/arm/configs/at91sam9x5ek_defconfig
+@@ -0,0 +1,195 @@
++CONFIG_EXPERIMENTAL=y
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_UTS_NS is not set
++# CONFIG_IPC_NS is not set
++# CONFIG_USER_NS is not set
++# CONFIG_PID_NS is not set
++# CONFIG_NET_NS is not set
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_SLAB=y
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_LBDAF is not set
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_IOSCHED_DEADLINE is not set
++# CONFIG_IOSCHED_CFQ is not set
++CONFIG_ARCH_AT91=y
++CONFIG_ARCH_AT91SAM9X5=y
++CONFIG_MACH_AT91SAM9X5EK=y
++CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
++CONFIG_AT91_SLOW_CLOCK=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_AEABI=y
++CONFIG_LEDS=y
++CONFIG_LEDS_CPU=y
++CONFIG_UACCESS_WITH_MEMCPY=y
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="mem=128M console=ttyS0,115200 initrd=0x21100000,8000000 root=/dev/ram0 rw mtdparts=atmel_nand:4M(bootstrap/uboot/kernel)ro,60M(rootfs),-(data)"
++CONFIG_FPE_NWFPE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_NET=y
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++CONFIG_IP_ADVANCED_ROUTER=y
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++# CONFIG_INET_LRO is not set
++# CONFIG_IPV6 is not set
++CONFIG_NETFILTER=y
++CONFIG_NETFILTER_NETLINK_QUEUE=m
++CONFIG_NETFILTER_NETLINK_LOG=m
++CONFIG_NF_CONNTRACK=y
++CONFIG_NF_CONNTRACK_MARK=y
++CONFIG_NF_CONNTRACK_FTP=m
++CONFIG_NF_CT_NETLINK=m
++CONFIG_NF_CONNTRACK_IPV4=y
++CONFIG_IP_NF_IPTABLES=y
++CONFIG_IP_NF_FILTER=y
++CONFIG_IP_NF_TARGET_REJECT=m
++CONFIG_IP_NF_TARGET_LOG=m
++CONFIG_IP_NF_TARGET_ULOG=m
++CONFIG_NF_NAT=y
++CONFIG_IP_NF_TARGET_MASQUERADE=y
++CONFIG_IP_NF_TARGET_NETMAP=y
++CONFIG_IP_NF_TARGET_REDIRECT=y
++CONFIG_IP_NF_RAW=m
++CONFIG_IP_NF_ARPTABLES=m
++CONFIG_BRIDGE=y
++CONFIG_VLAN_8021Q=m
++CONFIG_NET_SCHED=y
++CONFIG_NET_SCH_CBQ=m
++CONFIG_NET_SCH_HTB=m
++CONFIG_NET_SCH_HFSC=m
++CONFIG_NET_SCH_TBF=m
++CONFIG_NET_CLS_FW=m
++CONFIG_CAN=y
++CONFIG_CAN_RAW=y
++CONFIG_CAN_DEV=y
++CONFIG_CAN_CALC_BITTIMING=y
++CONFIG_CAN_AT91=y
++# CONFIG_WIRELESS is not set
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++# CONFIG_STANDALONE is not set
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_MTD=y
++CONFIG_MTD_TESTS=m
++CONFIG_MTD_PARTITIONS=y
++CONFIG_MTD_CMDLINE_PARTS=y
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++CONFIG_MTD_M25P80=y
++CONFIG_MTD_NAND=y
++CONFIG_MTD_NAND_ATMEL=y
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=4
++CONFIG_BLK_DEV_RAM_SIZE=8192
++CONFIG_MISC_DEVICES=y
++CONFIG_ATMEL_TCLIB=y
++CONFIG_SCSI=y
++CONFIG_BLK_DEV_SD=y
++CONFIG_SCSI_MULTI_LUN=y
++# CONFIG_SCSI_LOWLEVEL is not set
++CONFIG_NETDEVICES=y
++CONFIG_MII=y
++CONFIG_DAVICOM_PHY=y
++CONFIG_NET_ETHERNET=y
++CONFIG_MACB=y
++# CONFIG_NETDEV_1000 is not set
++# CONFIG_NETDEV_10000 is not set
++# CONFIG_WLAN is not set
++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=800
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480
++CONFIG_INPUT_EVDEV=y
++# CONFIG_KEYBOARD_ATKBD is not set
++CONFIG_KEYBOARD_GPIO=y
++# CONFIG_INPUT_MOUSE is not set
++CONFIG_INPUT_TOUCHSCREEN=y
++CONFIG_TOUCHSCREEN_ATMEL_TSADCC=y
++CONFIG_LEGACY_PTY_COUNT=8
++CONFIG_SERIAL_ATMEL=y
++CONFIG_SERIAL_ATMEL_CONSOLE=y
++CONFIG_HW_RANDOM=y
++CONFIG_SPI=y
++CONFIG_SPI_ATMEL=y
++CONFIG_GPIO_SYSFS=y
++# CONFIG_HWMON is not set
++# CONFIG_MFD_SUPPORT is not set
++CONFIG_FB=y
++CONFIG_FB_ATMEL=y
++CONFIG_BACKLIGHT_LCD_SUPPORT=y
++# CONFIG_LCD_CLASS_DEVICE is not set
++CONFIG_BACKLIGHT_CLASS_DEVICE=y
++CONFIG_BACKLIGHT_ATMEL_LCDC=y
++# CONFIG_BACKLIGHT_GENERIC is not set
++CONFIG_USB=y
++# CONFIG_USB_DEVICE_CLASS is not set
++CONFIG_USB_EHCI_HCD=y
++# CONFIG_USB_EHCI_TT_NEWSCHED is not set
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_STORAGE=y
++CONFIG_USB_LIBUSUAL=y
++CONFIG_USB_GADGET=y
++CONFIG_USB_ZERO=m
++CONFIG_USB_ETH=m
++CONFIG_USB_FILE_STORAGE=m
++CONFIG_USB_G_SERIAL=m
++CONFIG_USB_CDC_COMPOSITE=m
++CONFIG_USB_G_MULTI=m
++CONFIG_USB_G_MULTI_CDC=y
++CONFIG_NEW_LEDS=y
++CONFIG_LEDS_CLASS=y
++CONFIG_LEDS_GPIO=y
++CONFIG_LEDS_TRIGGERS=y
++CONFIG_LEDS_TRIGGER_TIMER=y
++CONFIG_LEDS_TRIGGER_HEARTBEAT=y
++CONFIG_LEDS_TRIGGER_GPIO=y
++CONFIG_RTC_CLASS=y
++CONFIG_RTC_DRV_AT91RM9200=y
++CONFIG_DMADEVICES=y
++CONFIG_AT_HDMAC=y
++CONFIG_DMATEST=m
++CONFIG_UIO=y
++CONFIG_UIO_PDRV=m
++CONFIG_UIO_PDRV_GENIRQ=y
++CONFIG_EXT2_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_TMPFS=y
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_SUMMARY=y
++CONFIG_LOGFS=m
++CONFIG_CRAMFS=y
++CONFIG_SQUASHFS=m
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V4=y
++CONFIG_ROOT_NFS=y
++CONFIG_NLS_CODEPAGE_437=y
++CONFIG_NLS_CODEPAGE_850=y
++CONFIG_NLS_ISO8859_1=y
++CONFIG_NLS_ISO8859_15=y
++CONFIG_NLS_UTF8=y
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++CONFIG_DEBUG_FS=y
++CONFIG_DEBUG_KERNEL=y
++CONFIG_LOCKUP_DETECTOR=y
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_PROVE_LOCKING=y
++CONFIG_DEBUG_SPINLOCK_SLEEP=y
++CONFIG_DEBUG_INFO=y
++# CONFIG_FTRACE is not set
++# CONFIG_ARM_UNWIND is not set
++CONFIG_DEBUG_USER=y
++# CONFIG_CRYPTO_HW is not set
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0014-usb-AT91SAM9X5-has-EHCI.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0014-usb-AT91SAM9X5-has-EHCI.patch
new file mode 100644
index 0000000..8b648f1
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0014-usb-AT91SAM9X5-has-EHCI.patch
@@ -0,0 +1,32 @@
+From 1c36853cd7c5bdf65be94522ec34e1d8e9d843ff Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
+Date: Mon, 18 Apr 2011 16:53:25 +0200
+Subject: [PATCH 014/107] usb: AT91SAM9X5 has EHCI
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This change was part of a patch provided (non-publically) by Atmel. I
+split it off because it was unrelated to the commit log and the other
+changes in that commit.
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/usb/Kconfig | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
+index 006489d..041f324 100644
+--- a/drivers/usb/Kconfig
++++ b/drivers/usb/Kconfig
+@@ -60,6 +60,7 @@ config USB_ARCH_HAS_EHCI
+ default y if ARCH_IXP4XX
+ default y if ARCH_W90X900
+ default y if ARCH_AT91SAM9G45
++ default y if ARCH_AT91SAM9X5
+ default y if ARCH_MXC
+ default y if ARCH_OMAP3
+ default y if ARCH_CNS3XXX
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0015-ARM-at91-pio-add-new-PIO3a-features.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0015-ARM-at91-pio-add-new-PIO3a-features.patch
new file mode 100644
index 0000000..286cb00
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0015-ARM-at91-pio-add-new-PIO3a-features.patch
@@ -0,0 +1,440 @@
+From 0746bd00cceb9e00b74fe41a351de0674ade1c0f Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 20 Jul 2010 19:18:51 +0200
+Subject: [PATCH 015/107] ARM: at91: pio: add new PIO3a features
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch adds the support for new PIO controller found on some
+at91sam SOCs.
+- more peripheral multiplexing
+- more features to configure on a PIO (pull-down, Schmitt trigger, debouncer)
+- support for several irq triggering features (type and polarity)
+
+Debugfs at91_gpio file is updated to monitor configuration.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ arch/arm/mach-at91/gpio.c | 239 ++++++++++++++++++++++++++--
+ arch/arm/mach-at91/include/mach/at91_pio.h | 25 +++
+ arch/arm/mach-at91/include/mach/gpio.h | 5 +
+ 3 files changed, 257 insertions(+), 12 deletions(-)
+
+diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
+index 4615528..6735662 100644
+--- a/arch/arm/mach-at91/gpio.c
++++ b/arch/arm/mach-at91/gpio.c
+@@ -20,6 +20,7 @@
+ #include <linux/module.h>
+ #include <linux/io.h>
+
++#include <mach/cpu.h>
+ #include <mach/hardware.h>
+ #include <mach/at91_pio.h>
+ #include <mach/gpio.h>
+@@ -69,6 +70,12 @@ static struct at91_gpio_chip gpio_chip[] = {
+
+ static int gpio_banks;
+
++/*
++ * Functionnality can change with newer chips
++ */
++#define cpu_has_pio3() (cpu_is_at91sam9x5())
++
++
+ static inline void __iomem *pin_to_controller(unsigned pin)
+ {
+ pin -= PIN_BASE;
+@@ -86,6 +93,52 @@ static inline unsigned pin_to_mask(unsigned pin)
+ }
+
+
++static char peripheral_function(void __iomem *pio, unsigned mask)
++{
++ char ret = 'X';
++ u8 select;
++
++ if (pio) {
++ if (cpu_has_pio3()) {
++ select = !!(__raw_readl(pio + PIO_ABCDSR1) & mask);
++ select |= (!!(__raw_readl(pio + PIO_ABCDSR2) & mask) << 1);
++ ret = 'A' + select;
++ } else {
++ ret = __raw_readl(pio + PIO_ABSR) & mask ?
++ 'B' : 'A';
++ }
++ }
++
++ return ret;
++}
++
++static void gpio_printf(struct seq_file *s, void __iomem *pio, unsigned mask)
++{
++ char *trigger = NULL;
++ char *polarity = NULL;
++
++ if (__raw_readl(pio + PIO_IMR) & mask) {
++ if (!cpu_has_pio3() || !(__raw_readl(pio + PIO_AIMMR) & mask )) {
++ trigger = "edge";
++ polarity = "both";
++ } else {
++ if (__raw_readl(pio + PIO_ELSR) & mask) {
++ trigger = "level";
++ polarity = __raw_readl(pio + PIO_FRLHSR) & mask ?
++ "high" : "low";
++ } else {
++ trigger = "edge";
++ polarity = __raw_readl(pio + PIO_FRLHSR) & mask ?
++ "rising" : "falling";
++ }
++ }
++ seq_printf(s, "IRQ:%s-%s\t", trigger, polarity);
++ } else {
++ seq_printf(s, "GPIO:%s\t\t",
++ __raw_readl(pio + PIO_PDSR) & mask ? "1" : "0");
++ }
++}
++
+ /*--------------------------------------------------------------------------*/
+
+ /* Not all hardware capabilities are exposed through these calls; they
+@@ -133,7 +186,14 @@ int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup)
+
+ __raw_writel(mask, pio + PIO_IDR);
+ __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
+- __raw_writel(mask, pio + PIO_ASR);
++ if (cpu_has_pio3()) {
++ __raw_writel(__raw_readl(pio + PIO_ABCDSR1) & ~mask,
++ pio + PIO_ABCDSR1);
++ __raw_writel(__raw_readl(pio + PIO_ABCDSR2) & ~mask,
++ pio + PIO_ABCDSR2);
++ } else {
++ __raw_writel(mask, pio + PIO_ASR);
++ }
+ __raw_writel(mask, pio + PIO_PDR);
+ return 0;
+ }
+@@ -153,7 +213,14 @@ int __init_or_module at91_set_B_periph(unsigned pin, int use_pullup)
+
+ __raw_writel(mask, pio + PIO_IDR);
+ __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
+- __raw_writel(mask, pio + PIO_BSR);
++ if (cpu_has_pio3()) {
++ __raw_writel(__raw_readl(pio + PIO_ABCDSR1) | mask,
++ pio + PIO_ABCDSR1);
++ __raw_writel(__raw_readl(pio + PIO_ABCDSR2) & ~mask,
++ pio + PIO_ABCDSR2);
++ } else {
++ __raw_writel(mask, pio + PIO_BSR);
++ }
+ __raw_writel(mask, pio + PIO_PDR);
+ return 0;
+ }
+@@ -161,6 +228,48 @@ EXPORT_SYMBOL(at91_set_B_periph);
+
+
+ /*
++ * mux the pin to the "C" internal peripheral role.
++ */
++int __init_or_module at91_set_C_periph(unsigned pin, int use_pullup)
++{
++ void __iomem *pio = pin_to_controller(pin);
++ unsigned mask = pin_to_mask(pin);
++
++ if (!pio || !cpu_has_pio3())
++ return -EINVAL;
++
++ __raw_writel(mask, pio + PIO_IDR);
++ __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
++ __raw_writel(__raw_readl(pio + PIO_ABCDSR1) & ~mask, pio + PIO_ABCDSR1);
++ __raw_writel(__raw_readl(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
++ __raw_writel(mask, pio + PIO_PDR);
++ return 0;
++}
++EXPORT_SYMBOL(at91_set_C_periph);
++
++
++/*
++ * mux the pin to the "C" internal peripheral role.
++ */
++int __init_or_module at91_set_D_periph(unsigned pin, int use_pullup)
++{
++ void __iomem *pio = pin_to_controller(pin);
++ unsigned mask = pin_to_mask(pin);
++
++ if (!pio || !cpu_has_pio3())
++ return -EINVAL;
++
++ __raw_writel(mask, pio + PIO_IDR);
++ __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
++ __raw_writel(__raw_readl(pio + PIO_ABCDSR1) | mask, pio + PIO_ABCDSR1);
++ __raw_writel(__raw_readl(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
++ __raw_writel(mask, pio + PIO_PDR);
++ return 0;
++}
++EXPORT_SYMBOL(at91_set_D_periph);
++
++
++/*
+ * mux the pin to the gpio controller (instead of "A" or "B" peripheral), and
+ * configure it for an input.
+ */
+@@ -213,12 +322,37 @@ int __init_or_module at91_set_deglitch(unsigned pin, int is_on)
+
+ if (!pio)
+ return -EINVAL;
++
++ if (cpu_has_pio3() && is_on)
++ __raw_writel(mask, pio + PIO_IFSCDR);
+ __raw_writel(mask, pio + (is_on ? PIO_IFER : PIO_IFDR));
+ return 0;
+ }
+ EXPORT_SYMBOL(at91_set_deglitch);
+
+ /*
++ * enable/disable the debounce filter;
++ */
++int __init_or_module at91_set_debounce(unsigned pin, int is_on, int div)
++{
++ void __iomem *pio = pin_to_controller(pin);
++ unsigned mask = pin_to_mask(pin);
++
++ if (!pio || !cpu_has_pio3())
++ return -EINVAL;
++
++ if (is_on) {
++ __raw_writel(mask, pio + PIO_IFSCER);
++ __raw_writel(div & PIO_SCDR_DIV, pio + PIO_SCDR);
++ __raw_writel(mask, pio + PIO_IFER);
++ } else {
++ __raw_writel(mask, pio + PIO_IFDR);
++ }
++ return 0;
++}
++EXPORT_SYMBOL(at91_set_debounce);
++
++/*
+ * enable/disable the multi-driver; This is only valid for output and
+ * allows the output pin to run as an open collector output.
+ */
+@@ -236,6 +370,41 @@ int __init_or_module at91_set_multi_drive(unsigned pin, int is_on)
+ EXPORT_SYMBOL(at91_set_multi_drive);
+
+ /*
++ * enable/disable the pull-down.
++ * If pull-up already enabled while calling the function, we disable it.
++ */
++int __init_or_module at91_set_pulldown(unsigned pin, int is_on)
++{
++ void __iomem *pio = pin_to_controller(pin);
++ unsigned mask = pin_to_mask(pin);
++
++ if (!pio || !cpu_has_pio3())
++ return -EINVAL;
++
++ /* Disable pull-up anyway */
++ __raw_writel(mask, pio + PIO_PUDR);
++ __raw_writel(mask, pio + (is_on ? PIO_PPDER : PIO_PPDDR));
++ return 0;
++}
++EXPORT_SYMBOL(at91_set_pulldown);
++
++/*
++ * disable Schmitt trigger
++ */
++int __init_or_module at91_disable_schmitt_trig(unsigned pin)
++{
++ void __iomem *pio = pin_to_controller(pin);
++ unsigned mask = pin_to_mask(pin);
++
++ if (!pio || !cpu_has_pio3())
++ return -EINVAL;
++
++ __raw_writel(__raw_readl(pio + PIO_SCHMITT) | mask, pio + PIO_SCHMITT);
++ return 0;
++}
++EXPORT_SYMBOL(at91_disable_schmitt_trig);
++
++/*
+ * assuming the pin is muxed as a gpio output, set its value.
+ */
+ int at91_set_gpio_value(unsigned pin, int value)
+@@ -337,7 +506,10 @@ void at91_gpio_resume(void)
+ * To use any AT91_PIN_* as an externally triggered IRQ, first call
+ * at91_set_gpio_input() then maybe enable its glitch filter.
+ * Then just request_irq() with the pin ID; it works like any ARM IRQ
+- * handler, though it always triggers on rising and falling edges.
++ * handler.
++ * First implementation always triggers on rising and falling edges
++ * whereas the newer PIO3a can be additionally configured to trigger on
++ * level, edge with any polarity.
+ *
+ * Alternatively, certain pins may be used directly as IRQ0..IRQ6 after
+ * configuring them with at91_set_a_periph() or at91_set_b_periph().
+@@ -373,12 +545,52 @@ static int gpio_irq_type(struct irq_data *d, unsigned type)
+ }
+ }
+
++/* Alternate irq type for PIO3a support */
++static int alt_gpio_irq_type(struct irq_data *d, unsigned type)
++{
++ void __iomem *pio = pin_to_controller(d->irq);
++ unsigned mask = pin_to_mask(d->irq);
++
++ switch (type) {
++ case IRQ_TYPE_EDGE_RISING:
++ __raw_writel(mask, pio + PIO_ESR);
++ __raw_writel(mask, pio + PIO_REHLSR);
++ break;
++ case IRQ_TYPE_EDGE_FALLING:
++ __raw_writel(mask, pio + PIO_ESR);
++ __raw_writel(mask, pio + PIO_FELLSR);
++ break;
++ case IRQ_TYPE_LEVEL_LOW:
++ __raw_writel(mask, pio + PIO_LSR);
++ __raw_writel(mask, pio + PIO_FELLSR);
++ break;
++ case IRQ_TYPE_LEVEL_HIGH:
++ __raw_writel(mask, pio + PIO_LSR);
++ __raw_writel(mask, pio + PIO_REHLSR);
++ break;
++ case IRQ_TYPE_EDGE_BOTH:
++ /* disable additional interrupt modes:
++ * fall back to default behavior */
++ __raw_writel(mask, pio + PIO_AIMDR);
++ return 0;
++ case IRQ_TYPE_NONE:
++ default:
++ pr_warn("AT91: No type for irq %d\n", gpio_to_irq(d->irq));
++ return -EINVAL;
++ }
++
++ /* enable additional interrupt modes */
++ __raw_writel(mask, pio + PIO_AIMER);
++
++ return 0;
++}
++
+ static struct irq_chip gpio_irqchip = {
+ .name = "GPIO",
+ .irq_disable = gpio_irq_mask,
+ .irq_mask = gpio_irq_mask,
+ .irq_unmask = gpio_irq_unmask,
+- .irq_set_type = gpio_irq_type,
++ /* .irq_set_type is set in at91_gpio_irq_setup */
+ .irq_set_wake = gpio_irq_set_wake,
+ };
+
+@@ -431,7 +643,7 @@ static int at91_gpio_show(struct seq_file *s, void *unused)
+ /* print heading */
+ seq_printf(s, "Pin\t");
+ for (bank = 0; bank < gpio_banks; bank++) {
+- seq_printf(s, "PIO%c\t", 'A' + bank);
++ seq_printf(s, "PIO%c\t\t", 'A' + bank);
+ };
+ seq_printf(s, "\n\n");
+
+@@ -445,11 +657,10 @@ static int at91_gpio_show(struct seq_file *s, void *unused)
+ unsigned mask = pin_to_mask(pin);
+
+ if (__raw_readl(pio + PIO_PSR) & mask)
+- seq_printf(s, "GPIO:%s", __raw_readl(pio + PIO_PDSR) & mask ? "1" : "0");
++ gpio_printf(s, pio, mask);
+ else
+- seq_printf(s, "%s", __raw_readl(pio + PIO_ABSR) & mask ? "B" : "A");
+-
+- seq_printf(s, "\t");
++ seq_printf(s, "%c\t\t",
++ peripheral_function(pio, mask));
+ }
+
+ seq_printf(s, "\n");
+@@ -496,6 +707,11 @@ void __init at91_gpio_irq_setup(void)
+ unsigned pioc, pin;
+ struct at91_gpio_chip *this, *prev;
+
++ if (cpu_has_pio3())
++ gpio_irqchip.irq_set_type = alt_gpio_irq_type;
++ else
++ gpio_irqchip.irq_set_type = gpio_irq_type;
++
+ for (pioc = 0, pin = PIN_BASE, this = gpio_chip, prev = NULL;
+ pioc++ < gpio_banks;
+ prev = this, this++) {
+@@ -592,9 +808,8 @@ static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+ at91_get_gpio_value(pin) ?
+ "set" : "clear");
+ else
+- seq_printf(s, "[periph %s]\n",
+- __raw_readl(pio + PIO_ABSR) &
+- mask ? "B" : "A");
++ seq_printf(s, "[periph %c]\n",
++ peripheral_function(pio, mask));
+ }
+ }
+ }
+diff --git a/arch/arm/mach-at91/include/mach/at91_pio.h b/arch/arm/mach-at91/include/mach/at91_pio.h
+index c6a31bf..732b11c 100644
+--- a/arch/arm/mach-at91/include/mach/at91_pio.h
++++ b/arch/arm/mach-at91/include/mach/at91_pio.h
+@@ -40,10 +40,35 @@
+ #define PIO_PUER 0x64 /* Pull-up Enable Register */
+ #define PIO_PUSR 0x68 /* Pull-up Status Register */
+ #define PIO_ASR 0x70 /* Peripheral A Select Register */
++#define PIO_ABCDSR1 0x70 /* Peripheral ABCD Select Register 1 [some sam9 only] */
+ #define PIO_BSR 0x74 /* Peripheral B Select Register */
++#define PIO_ABCDSR2 0x74 /* Peripheral ABCD Select Register 2 [some sam9 only] */
+ #define PIO_ABSR 0x78 /* AB Status Register */
++#define PIO_IFSCDR 0x80 /* Input Filter Slow Clock Disable Register */
++#define PIO_IFSCER 0x84 /* Input Filter Slow Clock Enable Register */
++#define PIO_IFSCSR 0x88 /* Input Filter Slow Clock Status Register */
++#define PIO_SCDR 0x8c /* Slow Clock Divider Debouncing Register */
++#define PIO_SCDR_DIV (0x3fff << 0) /* Slow Clock Divider Mask */
++#define PIO_PPDDR 0x90 /* Pad Pull-down Disable Register */
++#define PIO_PPDER 0x94 /* Pad Pull-down Enable Register */
++#define PIO_PPDSR 0x98 /* Pad Pull-down Status Register */
+ #define PIO_OWER 0xa0 /* Output Write Enable Register */
+ #define PIO_OWDR 0xa4 /* Output Write Disable Register */
+ #define PIO_OWSR 0xa8 /* Output Write Status Register */
++#define PIO_AIMER 0xb0 /* Additional Interrupt Modes Enable Register */
++#define PIO_AIMDR 0xb4 /* Additional Interrupt Modes Disable Register */
++#define PIO_AIMMR 0xb8 /* Additional Interrupt Modes Mask Register */
++#define PIO_ESR 0xc0 /* Edge Select Register */
++#define PIO_LSR 0xc4 /* Level Select Register */
++#define PIO_ELSR 0xc8 /* Edge/Level Status Register */
++#define PIO_FELLSR 0xd0 /* Falling Edge/Low Level Select Register */
++#define PIO_REHLSR 0xd4 /* Rising Edge/ High Level Select Register */
++#define PIO_FRLHSR 0xd8 /* Fall/Rise - Low/High Status Register */
++#define PIO_SCHMITT 0x100 /* Schmitt Trigger Register */
++
++#define ABCDSR_PERIPH_A 0x0
++#define ABCDSR_PERIPH_B 0x1
++#define ABCDSR_PERIPH_C 0x2
++#define ABCDSR_PERIPH_D 0x3
+
+ #endif
+diff --git a/arch/arm/mach-at91/include/mach/gpio.h b/arch/arm/mach-at91/include/mach/gpio.h
+index 056dc66..4e4cc4b 100644
+--- a/arch/arm/mach-at91/include/mach/gpio.h
++++ b/arch/arm/mach-at91/include/mach/gpio.h
+@@ -193,10 +193,15 @@
+ extern int __init_or_module at91_set_GPIO_periph(unsigned pin, int use_pullup);
+ extern int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup);
+ extern int __init_or_module at91_set_B_periph(unsigned pin, int use_pullup);
++extern int __init_or_module at91_set_C_periph(unsigned pin, int use_pullup);
++extern int __init_or_module at91_set_D_periph(unsigned pin, int use_pullup);
+ extern int __init_or_module at91_set_gpio_input(unsigned pin, int use_pullup);
+ extern int __init_or_module at91_set_gpio_output(unsigned pin, int value);
+ extern int __init_or_module at91_set_deglitch(unsigned pin, int is_on);
++extern int __init_or_module at91_set_debounce(unsigned pin, int is_on, int div);
+ extern int __init_or_module at91_set_multi_drive(unsigned pin, int is_on);
++extern int __init_or_module at91_set_pulldown(unsigned pin, int is_on);
++extern int __init_or_module at91_disable_schmitt_trig(unsigned pin);
+
+ /* callable at any time */
+ extern int at91_set_gpio_value(unsigned pin, int value);
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0016-usb-AT91SAM9X5-has-a-atmel_usba_udc-device.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0016-usb-AT91SAM9X5-has-a-atmel_usba_udc-device.patch
new file mode 100644
index 0000000..2b46fb5
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0016-usb-AT91SAM9X5-has-a-atmel_usba_udc-device.patch
@@ -0,0 +1,39 @@
+From 1027ba75ecaaff666df01c0e60e64ddb747a4b65 Mon Sep 17 00:00:00 2001
+From: Dan Liang <dan.liang@atmel.com>
+Date: Mon, 23 Aug 2010 16:09:46 +0200
+Subject: [PATCH 016/107] usb: AT91SAM9X5 has a atmel_usba_udc device
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Dan Liang <dan.liang@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/usb/gadget/Kconfig | 4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
+index bc5123c..926d0ea 100644
+--- a/drivers/usb/gadget/Kconfig
++++ b/drivers/usb/gadget/Kconfig
+@@ -124,7 +124,7 @@ choice
+
+ config USB_GADGET_AT91
+ boolean "Atmel AT91 USB Device Port"
+- depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9 && !ARCH_AT91SAM9G45
++ depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9 && !ARCH_AT91SAM9G45 && !ARCH_AT91SAM9X5
+ select USB_GADGET_SELECTED
+ help
+ Many Atmel AT91 processors (such as the AT91RM2000) have a
+@@ -143,7 +143,7 @@ config USB_AT91
+ config USB_GADGET_ATMEL_USBA
+ boolean "Atmel USBA"
+ select USB_GADGET_DUALSPEED
+- depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
++ depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 || ARCH_AT91SAM9X5
+ help
+ USBA is the integrated high-speed USB Device controller on
+ the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0017-clocksource-tcb-add-support-for-32-bit-mode.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0017-clocksource-tcb-add-support-for-32-bit-mode.patch
new file mode 100644
index 0000000..a6d6f22
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0017-clocksource-tcb-add-support-for-32-bit-mode.patch
@@ -0,0 +1,114 @@
+From 5e65851fa541a9e420c85eb90858a909139b5df5 Mon Sep 17 00:00:00 2001
+From: Dan Liang <dan.liang@atmel.com>
+Date: Thu, 2 Sep 2010 13:07:42 +0800
+Subject: [PATCH 017/107] clocksource/tcb: add support for 32-bit mode
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Support for 32 bit wide Timer Counter blocks. Those TC blocks
+are present in 5 series AT91 SOC family.
+
+CONFIG_ATMEL_TCB_CLKSRC_32BIT is used to distinguish old timer
+and new one. Since channel 0 is wide enough, channel 1 is not
+configured and unused.
+
+XXX: make selecting 32 bit support runtime conditional
+
+Signed-off-by: Dan Liang <dan.liang@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/clocksource/tcb_clksrc.c | 21 +++++++++++++++++++--
+ drivers/misc/Kconfig | 4 ++++
+ 2 files changed, 23 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c
+index 79c47e8..4f612de 100644
+--- a/drivers/clocksource/tcb_clksrc.c
++++ b/drivers/clocksource/tcb_clksrc.c
+@@ -20,6 +20,9 @@
+ * with a base rate of 5+ MHz, packaged as a clocksource (with
+ * resolution better than 200 nsec).
+ *
++ * - Some chips support 32 bit counter in one channel, then the second
++ * channel is not used.
++ *
+ * - The third channel may be used to provide a 16-bit clockevent
+ * source, used in either periodic or oneshot mode. This runs
+ * at 32 KiHZ, and can handle delays of up to two seconds.
+@@ -45,10 +48,15 @@ static cycle_t tc_get_cycles(struct clocksource *cs)
+ u32 lower, upper;
+
+ raw_local_irq_save(flags);
++#ifndef CONFIG_ATMEL_TCB_CLKSRC_32BIT
+ do {
+ upper = __raw_readl(tcaddr + ATMEL_TC_REG(1, CV));
+ lower = __raw_readl(tcaddr + ATMEL_TC_REG(0, CV));
+ } while (upper != __raw_readl(tcaddr + ATMEL_TC_REG(1, CV)));
++#else
++ upper = 0;
++ lower = __raw_readl(tcaddr + ATMEL_TC_REG(0, CV));
++#endif
+
+ raw_local_irq_restore(flags);
+ return (upper << 16) | lower;
+@@ -271,14 +279,21 @@ static int __init tcb_clksrc_init(void)
+ __raw_writel(best_divisor_idx /* likely divide-by-8 */
+ | ATMEL_TC_WAVE
+ | ATMEL_TC_WAVESEL_UP /* free-run */
++#ifndef CONFIG_ATMEL_TCB_CLKSRC_32BIT
+ | ATMEL_TC_ACPA_SET /* TIOA0 rises at 0 */
+- | ATMEL_TC_ACPC_CLEAR, /* (duty cycle 50%) */
++ | ATMEL_TC_ACPC_CLEAR /* (duty cycle 50%) */
++#endif
++ ,
+ tcaddr + ATMEL_TC_REG(0, CMR));
++
++#ifndef CONFIG_ATMEL_TCB_CLKSRC_32BIT
+ __raw_writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA));
+ __raw_writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC));
++#endif
+ __raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR)); /* no irqs */
+ __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
+
++#ifndef CONFIG_ATMEL_TCB_CLKSRC_32BIT
+ /* channel 1: waveform mode, input TIOA0 */
+ __raw_writel(ATMEL_TC_XC1 /* input: TIOA0 */
+ | ATMEL_TC_WAVE
+@@ -287,8 +302,10 @@ static int __init tcb_clksrc_init(void)
+ __raw_writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR)); /* no irqs */
+ __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR));
+
+- /* chain channel 0 to channel 1, then reset all the timers */
++ /* chain channel 0 to channel 1 */
+ __raw_writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR);
++#endif
++ /* reset all the timers */
+ __raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
+
+ /* and away we go! */
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index 4e007c6..a43126c 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -90,6 +90,7 @@ config ATMEL_TCLIB
+ config ATMEL_TCB_CLKSRC
+ bool "TC Block Clocksource"
+ depends on ATMEL_TCLIB
++ select ATMEL_TCB_CLKSRC_32BIT if ARCH_AT91SAM9X5
+ default y
+ help
+ Select this to get a high precision clocksource based on a
+@@ -112,6 +113,9 @@ config ATMEL_TCB_CLKSRC_BLOCK
+ TC can be used for other purposes, such as PWM generation and
+ interval timing.
+
++config ATMEL_TCB_CLKSRC_32BIT
++ boolean
++
+ config IBM_ASM
+ tristate "Device driver for IBM RSA service processor"
+ depends on X86 && PCI && INPUT && EXPERIMENTAL
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0018-mmc-atmel-mci-add-support-for-ARCH_AT91SAM9X5.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0018-mmc-atmel-mci-add-support-for-ARCH_AT91SAM9X5.patch
new file mode 100644
index 0000000..9f8c4a3
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0018-mmc-atmel-mci-add-support-for-ARCH_AT91SAM9X5.patch
@@ -0,0 +1,100 @@
+From f78b602acdc2f4868a9a8d508a1d736c84a67855 Mon Sep 17 00:00:00 2001
+From: Dan Liang <dan.liang@atmel.com>
+Date: Tue, 21 Sep 2010 17:30:15 +0800
+Subject: [PATCH 018/107] mmc/atmel-mci: add support for ARCH_AT91SAM9X5
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Change the calculation method for mci clock divider to match new
+MCI IP that is present on 5 series chips.
+Add Kconfig item to enable dma for mci on those chips.
+
+XXX: this patch interdepends with SAM9x5 support
+
+Signed-off-by: Dan Liang <dan.liang@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/mmc/host/Kconfig | 2 +-
+ drivers/mmc/host/atmel-mci-regs.h | 1 +
+ drivers/mmc/host/atmel-mci.c | 31 ++++++++++++++++++++++---------
+ 3 files changed, 24 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
+index 94df405..0cfb38d 100644
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -282,7 +282,7 @@ endchoice
+
+ config MMC_ATMELMCI_DMA
+ bool "Atmel MCI DMA support (EXPERIMENTAL)"
+- depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE && EXPERIMENTAL
++ depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45 || ARCH_AT91SAM9X5) && DMA_ENGINE && EXPERIMENTAL
+ help
+ Say Y here to have the Atmel MCI driver use a DMA engine to
+ do data transfers and thus increase the throughput and
+diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h
+index fc8a0fe..bf51583 100644
+--- a/drivers/mmc/host/atmel-mci-regs.h
++++ b/drivers/mmc/host/atmel-mci-regs.h
+@@ -31,6 +31,7 @@
+ # define MCI_MR_PDCFBYTE ( 1 << 13) /* Force Byte Transfer */
+ # define MCI_MR_PDCPADV ( 1 << 14) /* Padding Value */
+ # define MCI_MR_PDCMODE ( 1 << 15) /* PDC-oriented Mode */
++# define MCI_MR_CLKODD(x) ((x) << 16) /* LSB of clock divider */
+ #define MCI_DTOR 0x0008 /* Data Timeout */
+ # define MCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */
+ # define MCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index ea3888b..f6b2552 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -236,7 +236,7 @@ static bool mci_has_rwproof(void)
+ */
+ static inline bool atmci_is_mci2(void)
+ {
+- if (cpu_is_at91sam9g45())
++ if (cpu_is_at91sam9g45() || cpu_is_at91sam9x5())
+ return true;
+
+ return false;
+@@ -943,15 +943,28 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+ }
+
+ /* Calculate clock divider */
+- clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1;
+- if (clkdiv > 255) {
+- dev_warn(&mmc->class_dev,
+- "clock %u too slow; using %lu\n",
+- clock_min, host->bus_hz / (2 * 256));
+- clkdiv = 255;
+- }
++ if (!cpu_is_at91sam9x5()) {
++ clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1;
++ if (clkdiv > 255) {
++ dev_warn(&mmc->class_dev,
++ "clock %u too slow; using %lu\n",
++ clock_min, host->bus_hz / (2 * 256));
++ clkdiv = 255;
++ }
++
++ host->mode_reg = MCI_MR_CLKDIV(clkdiv);
++ } else {
++ clkdiv = DIV_ROUND_UP(host->bus_hz, clock_min) - 2;
++ if (clkdiv > 511) {
++ dev_warn(&mmc->class_dev,
++ "clock %u too slow; using %lu\n",
++ clock_min, host->bus_hz / (511 + 2));
++ clkdiv = 511;
++ }
+
+- host->mode_reg = MCI_MR_CLKDIV(clkdiv);
++ host->mode_reg = MCI_MR_CLKDIV(clkdiv >> 1)
++ | MCI_MR_CLKODD(clkdiv & 1);
++ }
+
+ /*
+ * WRPROOF and RDPROOF prevent overruns/underruns by
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0019-serial-atmel-convert-to-use-dma-engine.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0019-serial-atmel-convert-to-use-dma-engine.patch
new file mode 100644
index 0000000..8d0e6c3
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0019-serial-atmel-convert-to-use-dma-engine.patch
@@ -0,0 +1,562 @@
+From 205c6f82d62bc708de77fb3f3a221c4fef53d2eb Mon Sep 17 00:00:00 2001
+From: Dan Liang <dan.liang@atmel.com>
+Date: Mon, 18 Apr 2011 17:33:47 +0200
+Subject: [PATCH 019/107] serial/atmel: convert to use dma engine
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+XXX: make it runtime conditional or convert PDC to dma engine?
+XXX: why is it necessary to #include <mach/at_hdmac.h>?
+
+Signed-off-by: Dan Liang <dan.liang@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/tty/serial/Kconfig | 10 +-
+ drivers/tty/serial/atmel_serial.c | 293 +++++++++++++++++++++++++++++++++---
+ 2 files changed, 277 insertions(+), 26 deletions(-)
+
+diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
+index 80484af..9bbe2d0 100644
+--- a/drivers/tty/serial/Kconfig
++++ b/drivers/tty/serial/Kconfig
+@@ -371,7 +371,7 @@ config SERIAL_ATMEL_CONSOLE
+
+ config SERIAL_ATMEL_PDC
+ bool "Support DMA transfers on AT91 / AT32 serial port"
+- depends on SERIAL_ATMEL
++ depends on SERIAL_ATMEL && !(ARCH_AT91SAM9X5)
+ default y
+ help
+ Say Y here if you wish to use the PDC to do DMA transfers to
+@@ -384,6 +384,14 @@ config SERIAL_ATMEL_PDC
+ properly when DMA is enabled. Make sure that ports where
+ this matters don't use DMA.
+
++config SERIAL_ATMEL_DMA
++ bool "Atmel Serial DMA support"
++ depends on SERIAL_ATMEL && ARCH_AT91SAM9X5 && DMA_ENGINE && EXPERIMENTAL
++ default y
++ help
++ Say Y here to have the Atmel serial driver use a DMA engine to do data
++ transfers and thus increase the throughput and reduce the CPU utilization.
++
+ config SERIAL_ATMEL_TTYAT
+ bool "Install as device ttyATn instead of ttySn"
+ depends on SERIAL_ATMEL=y
+diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
+index f119d17..205e496 100644
+--- a/drivers/tty/serial/atmel_serial.c
++++ b/drivers/tty/serial/atmel_serial.c
+@@ -45,6 +45,7 @@
+
+ #include <asm/mach/serial_at91.h>
+ #include <mach/board.h>
++#include <mach/at_hdmac.h>
+
+ #ifdef CONFIG_ARM
+ #include <mach/cpu.h>
+@@ -141,13 +142,22 @@ struct atmel_uart_port {
+ u32 backup_imr; /* IMR saved during suspend */
+ int break_active; /* break being received */
+
+- short use_dma_rx; /* enable PDC receiver */
++ short use_dma_rx; /* enable DMA receiver */
+ short pdc_rx_idx; /* current PDC RX buffer */
+ struct atmel_dma_buffer pdc_rx[2]; /* PDC receier */
+
+- short use_dma_tx; /* enable PDC transmitter */
++ short use_dma_tx; /* enable DMA transmitter */
+ struct atmel_dma_buffer pdc_tx; /* PDC transmitter */
+
++ spinlock_t lock_tx; /* port lock */
++ struct dma_chan *chan_tx;
++ struct dma_async_tx_descriptor *desc_tx;
++ dma_cookie_t cookie_tx;
++
++ signed int xmit_head;
++ struct scatterlist sg_tx;
++ unsigned int sg_len_tx;
++
+ struct tasklet_struct tasklet;
+ unsigned int irq_status;
+ unsigned int irq_status_prev;
+@@ -171,25 +181,39 @@ to_atmel_uart_port(struct uart_port *uart)
+ }
+
+ #ifdef CONFIG_SERIAL_ATMEL_PDC
+-static bool atmel_use_dma_rx(struct uart_port *port)
++static bool atmel_use_pdc_rx(struct uart_port *port)
+ {
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+ return atmel_port->use_dma_rx;
+ }
+
+-static bool atmel_use_dma_tx(struct uart_port *port)
++static bool atmel_use_pdc_tx(struct uart_port *port)
+ {
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+ return atmel_port->use_dma_tx;
+ }
+ #else
+-static bool atmel_use_dma_rx(struct uart_port *port)
++static bool atmel_use_pdc_rx(struct uart_port *port)
++{
++ return false;
++}
++
++static bool atmel_use_pdc_tx(struct uart_port *port)
+ {
+ return false;
+ }
++#endif
+
++#ifdef CONFIG_SERIAL_ATMEL_DMA
++static bool atmel_use_dma_tx(struct uart_port *port)
++{
++ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
++
++ return atmel_port->use_dma_tx;
++}
++#else
+ static bool atmel_use_dma_tx(struct uart_port *port)
+ {
+ return false;
+@@ -222,7 +246,7 @@ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
+ mode |= ATMEL_US_USMODE_RS485;
+ } else {
+ dev_dbg(port->dev, "Setting UART to RS232\n");
+- if (atmel_use_dma_tx(port))
++ if (atmel_use_pdc_tx(port))
+ atmel_port->tx_done_mask = ATMEL_US_ENDTX |
+ ATMEL_US_TXBUFE;
+ else
+@@ -334,10 +358,11 @@ static void atmel_stop_tx(struct uart_port *port)
+ {
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+- if (atmel_use_dma_tx(port)) {
++ if (atmel_use_pdc_tx(port)) {
+ /* disable PDC transmit */
+ UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
+ }
++
+ /* Disable interrupts */
+ UART_PUT_IDR(port, atmel_port->tx_done_mask);
+
+@@ -352,7 +377,7 @@ static void atmel_start_tx(struct uart_port *port)
+ {
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+- if (atmel_use_dma_tx(port)) {
++ if (atmel_use_pdc_tx(port)) {
+ if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN)
+ /* The transmitter is already running. Yes, we
+ really need this.*/
+@@ -364,6 +389,7 @@ static void atmel_start_tx(struct uart_port *port)
+ /* re-enable PDC transmit */
+ UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
+ }
++
+ /* Enable interrupts */
+ UART_PUT_IER(port, atmel_port->tx_done_mask);
+ }
+@@ -375,7 +401,7 @@ static void atmel_start_rx(struct uart_port *port)
+ {
+ UART_PUT_CR(port, ATMEL_US_RSTSTA); /* reset status and receiver */
+
+- if (atmel_use_dma_rx(port)) {
++ if (atmel_use_pdc_rx(port)) {
+ /* enable PDC controller */
+ UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
+ port->read_status_mask);
+@@ -390,7 +416,7 @@ static void atmel_start_rx(struct uart_port *port)
+ */
+ static void atmel_stop_rx(struct uart_port *port)
+ {
+- if (atmel_use_dma_rx(port)) {
++ if (atmel_use_pdc_rx(port)) {
+ /* disable PDC receive */
+ UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS);
+ UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
+@@ -547,6 +573,207 @@ static void atmel_tx_chars(struct uart_port *port)
+ UART_PUT_IER(port, atmel_port->tx_done_mask);
+ }
+
++#ifdef CONFIG_SERIAL_ATMEL_DMA
++static void atmel_dma_tx_complete(void *arg)
++{
++ struct atmel_uart_port *atmel_port = arg;
++ struct uart_port *port = &atmel_port->uart;
++ struct circ_buf *xmit = &port->state->xmit;
++ unsigned long flags;
++
++ spin_lock_irqsave(&port->lock, flags);
++
++ xmit->tail += sg_dma_len(&atmel_port->sg_tx);
++ xmit->tail &= UART_XMIT_SIZE - 1;
++
++ port->icount.tx += sg_dma_len(&atmel_port->sg_tx);
++
++ spin_lock_irq(&atmel_port->lock_tx);
++ async_tx_ack(atmel_port->desc_tx);
++ atmel_port->cookie_tx = -EINVAL;
++ atmel_port->desc_tx = NULL;
++ spin_unlock_irq(&atmel_port->lock_tx);
++
++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
++ uart_write_wakeup(port);
++
++ /* Do we really need this? */
++ if (!uart_circ_empty(xmit)) {
++ tasklet_schedule(&atmel_port->tasklet);
++ }
++
++ spin_unlock_irqrestore(&port->lock, flags);
++}
++
++static void atmel_tx_dma_release(struct atmel_uart_port *atmel_port)
++{
++ struct dma_chan *chan = atmel_port->chan_tx;
++
++ atmel_port->chan_tx = NULL;
++ atmel_port->cookie_tx = -EINVAL;
++ if (chan) {
++ chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
++ dma_release_channel(chan);
++ }
++}
++
++/*
++ * Called from tasklet with TXRDY interrupt is disabled.
++ */
++static void atmel_tx_dma(struct uart_port *port)
++{
++ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
++ struct circ_buf *xmit = &port->state->xmit;
++ struct dma_chan *chan = atmel_port->chan_tx;
++ struct dma_async_tx_descriptor *desc;
++ struct scatterlist *sg = &atmel_port->sg_tx;
++
++ spin_lock_irq(&atmel_port->lock_tx);
++ /* Make sure we have an idle channel */
++ if (atmel_port->desc_tx != NULL) {
++ spin_lock_irq(&atmel_port->lock_tx);
++ return;
++ }
++ spin_unlock_irq(&atmel_port->lock_tx);
++
++ if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
++ /*
++ * DMA is idle now.
++ * Port xmit buffer is already mapped, and it is one page... Just adjust
++ * offsets and lengths. Since it is a circular buffer, we have to
++ * transmit till the end, and then the rest. Take the port lock to get a
++ * consistent xmit buffer state.
++ */
++ spin_lock_irq(&port->lock);
++ if (atmel_port->xmit_head != -1) {
++ if (atmel_port->xmit_head != xmit->head) {
++ atmel_port->xmit_head = xmit->head;
++ } else {
++ spin_unlock_irq(&port->lock);
++ return;
++ }
++ } else {
++ atmel_port->xmit_head = xmit->head;
++ }
++
++ sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
++ sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1))
++ + sg->offset;
++ sg_dma_len(sg) = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
++ spin_unlock_irq(&port->lock);
++
++ BUG_ON(!sg_dma_len(sg));
++
++ desc = chan->device->device_prep_slave_sg(chan,
++ sg, atmel_port->sg_len_tx, DMA_TO_DEVICE,
++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ if (!desc) {
++ spin_unlock_irq(&port->lock);
++ printk (KERN_ERR "#### Error! Failed to send via dma!\n");
++ return;
++ }
++
++ dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
++
++ spin_lock_irq(&port->lock);
++ atmel_port->desc_tx = desc;
++ desc->callback = atmel_dma_tx_complete;
++ desc->callback_param = atmel_port;
++ spin_unlock_irq(&port->lock);
++ atmel_port->cookie_tx = desc->tx_submit(desc);
++ if (atmel_port->cookie_tx < 0) {
++ dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n");
++ /* switch to PIO */
++ atmel_tx_dma_release(atmel_port);
++ return;
++ }
++
++ dma_async_issue_pending(chan);
++ } else {
++ if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
++ /* DMA done, stop TX, start RX for RS485 */
++ atmel_start_rx(port);
++ }
++ }
++
++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
++ uart_write_wakeup(port);
++}
++
++static bool filter(struct dma_chan *chan, void *slave)
++{
++ struct at_dma_slave *sl = slave;
++
++ if (sl->dma_dev == chan->device->dev) {
++ chan->private = sl;
++ return true;
++ } else {
++ return false;
++ }
++}
++
++static void atmel_tx_request_dma(struct atmel_uart_port *atmel_port)
++{
++ struct uart_port *port;
++ struct atmel_uart_data *pdata;
++ dma_cap_mask_t mask;
++ struct dma_chan *chan = NULL;
++
++ if (atmel_port == NULL)
++ return;
++
++ port = &(atmel_port->uart);
++ pdata = (struct atmel_uart_data *)port->private_data;
++
++ if (!pdata) {
++ dev_notice(port->dev, "DMA not available, using PIO\n");
++ return;
++ }
++
++ dma_cap_zero(mask);
++ dma_cap_set(DMA_SLAVE, mask);
++
++ if (atmel_use_dma_tx(port) && pdata->dma_tx_slave) {
++ pdata->dma_tx_slave->tx_reg = port->mapbase + ATMEL_US_THR;
++ chan = dma_request_channel(mask, filter, pdata->dma_tx_slave);
++ dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan);
++ }
++
++ if (chan) {
++ int nent;
++
++ spin_lock_init(&atmel_port->lock_tx);
++ atmel_port->chan_tx = chan;
++
++ sg_init_table(&atmel_port->sg_tx, 1);
++ /* UART circular tx buffer is an aligned page. */
++ BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK);
++ sg_set_page(&atmel_port->sg_tx,
++ virt_to_page(port->state->xmit.buf),
++ UART_XMIT_SIZE,
++ (int)port->state->xmit.buf & ~PAGE_MASK);
++ nent = dma_map_sg(port->dev, &atmel_port->sg_tx, 1,
++ DMA_TO_DEVICE);
++
++ if (!nent)
++ dev_dbg(port->dev, "need to release resource of dma\n");
++ else
++ dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__,
++ sg_dma_len(&atmel_port->sg_tx),
++ port->state->xmit.buf,
++ sg_dma_address(&atmel_port->sg_tx));
++
++ atmel_port->sg_len_tx = nent;
++ atmel_port->xmit_head = -1;
++ }
++}
++#else
++static void atmel_dma_tx_complete(void *arg) {}
++static void atmel_tx_dma_release(struct atmel_uart_port *atmel_port) {}
++static void atmel_tx_dma(struct uart_port *port) {}
++static void atmel_tx_request_dma(struct atmel_uart_port *atmel_port) {}
++#endif
++
+ /*
+ * receive interrupt handler.
+ */
+@@ -555,7 +782,7 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending)
+ {
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+- if (atmel_use_dma_rx(port)) {
++ if (atmel_use_pdc_rx(port)) {
+ /*
+ * PDC receive. Just schedule the tasklet and let it
+ * figure out the details.
+@@ -644,7 +871,7 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
+ /*
+ * Called from tasklet with ENDTX and TXBUFE interrupts disabled.
+ */
+-static void atmel_tx_dma(struct uart_port *port)
++static void atmel_tx_pdc(struct uart_port *port)
+ {
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ struct circ_buf *xmit = &port->state->xmit;
+@@ -760,7 +987,7 @@ static void atmel_rx_from_ring(struct uart_port *port)
+ spin_lock(&port->lock);
+ }
+
+-static void atmel_rx_from_dma(struct uart_port *port)
++static void atmel_rx_from_pdc(struct uart_port *port)
+ {
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ struct tty_struct *tty = port->state->port.tty;
+@@ -849,7 +1076,9 @@ static void atmel_tasklet_func(unsigned long data)
+ /* The interrupt handler does not take the lock */
+ spin_lock(&port->lock);
+
+- if (atmel_use_dma_tx(port))
++ if (atmel_use_pdc_tx(port))
++ atmel_tx_pdc(port);
++ else if (atmel_use_dma_tx(port))
+ atmel_tx_dma(port);
+ else
+ atmel_tx_chars(port);
+@@ -874,8 +1103,8 @@ static void atmel_tasklet_func(unsigned long data)
+ atmel_port->irq_status_prev = status;
+ }
+
+- if (atmel_use_dma_rx(port))
+- atmel_rx_from_dma(port);
++ if (atmel_use_pdc_rx(port))
++ atmel_rx_from_pdc(port);
+ else
+ atmel_rx_from_ring(port);
+
+@@ -911,7 +1140,7 @@ static int atmel_startup(struct uart_port *port)
+ /*
+ * Initialize DMA (if necessary)
+ */
+- if (atmel_use_dma_rx(port)) {
++ if (atmel_use_pdc_rx(port)) {
+ int i;
+
+ for (i = 0; i < 2; i++) {
+@@ -945,7 +1174,8 @@ static int atmel_startup(struct uart_port *port)
+ UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr);
+ UART_PUT_RNCR(port, PDC_BUFFER_SIZE);
+ }
+- if (atmel_use_dma_tx(port)) {
++ if (atmel_use_pdc_tx(port)) {
++
+ struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+ struct circ_buf *xmit = &port->state->xmit;
+
+@@ -958,6 +1188,9 @@ static int atmel_startup(struct uart_port *port)
+ pdc->ofs = 0;
+ }
+
++ if (atmel_use_dma_tx(port))
++ atmel_tx_request_dma(atmel_port);
++
+ /*
+ * If there is a specific "open" function (to register
+ * control line interrupts)
+@@ -981,7 +1214,7 @@ static int atmel_startup(struct uart_port *port)
+ /* enable xmit & rcvr */
+ UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
+
+- if (atmel_use_dma_rx(port)) {
++ if (atmel_use_pdc_rx(port)) {
+ /* set UART timeout */
+ UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
+ UART_PUT_CR(port, ATMEL_US_STTTO);
+@@ -1012,7 +1245,7 @@ static void atmel_shutdown(struct uart_port *port)
+ /*
+ * Shut-down the DMA.
+ */
+- if (atmel_use_dma_rx(port)) {
++ if (atmel_use_pdc_rx(port)) {
+ int i;
+
+ for (i = 0; i < 2; i++) {
+@@ -1025,7 +1258,7 @@ static void atmel_shutdown(struct uart_port *port)
+ kfree(pdc->buf);
+ }
+ }
+- if (atmel_use_dma_tx(port)) {
++ if (atmel_use_pdc_tx(port)) {
+ struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+
+ dma_unmap_single(port->dev,
+@@ -1034,6 +1267,9 @@ static void atmel_shutdown(struct uart_port *port)
+ DMA_TO_DEVICE);
+ }
+
++ if (atmel_use_dma_tx(port)) {
++ atmel_tx_dma_release(atmel_port);
++ }
+ /*
+ * Disable all interrupts, port and break condition.
+ */
+@@ -1061,10 +1297,16 @@ static void atmel_flush_buffer(struct uart_port *port)
+ {
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+- if (atmel_use_dma_tx(port)) {
++ if (atmel_use_pdc_tx(port)) {
+ UART_PUT_TCR(port, 0);
+ atmel_port->pdc_tx.ofs = 0;
+ }
++
++ if (atmel_use_dma_tx(port)) {
++ struct dma_chan *chan = atmel_port->chan_tx;
++ if (chan)
++ chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
++ }
+ }
+
+ /*
+@@ -1174,7 +1416,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= ATMEL_US_RXBRK;
+
+- if (atmel_use_dma_rx(port))
++ if (atmel_use_pdc_rx(port))
+ /* need to enable error interrupts */
+ UART_PUT_IER(port, port->read_status_mask);
+
+@@ -1426,6 +1668,7 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
+ port->dev = &pdev->dev;
+ port->mapbase = pdev->resource[0].start;
+ port->irq = pdev->resource[1].start;
++ port->private_data = data;
+
+ tasklet_init(&atmel_port->tasklet, atmel_tasklet_func,
+ (unsigned long)port);
+@@ -1455,7 +1698,7 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
+ /* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
+ if (atmel_port->rs485.flags & SER_RS485_ENABLED)
+ atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
+- else if (atmel_use_dma_tx(port)) {
++ else if (atmel_use_pdc_tx(port)) {
+ port->fifosize = PDC_BUFFER_SIZE;
+ atmel_port->tx_done_mask = ATMEL_US_ENDTX | ATMEL_US_TXBUFE;
+ } else {
+@@ -1721,7 +1964,7 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
+
+ atmel_init_port(port, pdev);
+
+- if (!atmel_use_dma_rx(&port->uart)) {
++ if (!atmel_use_pdc_rx(&port->uart)) {
+ ret = -ENOMEM;
+ data = kmalloc(sizeof(struct atmel_uart_char)
+ * ATMEL_SERIAL_RINGSIZE, GFP_KERNEL);
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0020-video-atmel_lcdfb-add-support-for-AT91SAM9x5.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0020-video-atmel_lcdfb-add-support-for-AT91SAM9x5.patch
new file mode 100644
index 0000000..03f999c
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0020-video-atmel_lcdfb-add-support-for-AT91SAM9x5.patch
@@ -0,0 +1,1803 @@
+From 71d1ed74b58a2b9d368ef95de74bd3480190a7d1 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Mon, 1 Nov 2010 16:38:41 +0800
+Subject: [PATCH 020/107] video/atmel_lcdfb: add support for AT91SAM9x5
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+Signed-off-by: Dan Liang <dan.liang@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+[ukleinek: forward-port to 2.6.39ish, fixed LCDC_LCDIxR_HEOIx]
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ arch/arm/mach-at91/include/mach/atmel_hlcdfb.h | 868 ++++++++++++++++++++++++
+ drivers/video/atmel_lcdfb.c | 661 ++++++++++++++-----
+ include/video/atmel_lcdc.h | 15 +
+ 3 files changed, 1388 insertions(+), 156 deletions(-)
+ create mode 100644 arch/arm/mach-at91/include/mach/atmel_hlcdfb.h
+
+diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h b/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h
+new file mode 100644
+index 0000000..debb8ce
+--- /dev/null
++++ b/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h
+@@ -0,0 +1,868 @@
++/*
++ * Header file for AT91 High end LCD Controller
++ *
++ * Data structure and register user interface
++ *
++ * Copyright (C) 2010 Atmel Corporation
++ *
++ * 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.
++ *
++ * 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 PUROFFSETE. 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 __ATMEL_HLCD_H__
++#define __ATMEL_HLCD_H__
++
++/* Lcdc hardware registers */
++#define ATMEL_LCDC_LCDCFG0 0x0000
++#define LCDC_LCDCFG0_CLKPOL (0x1 << 0)
++#define LCDC_LCDCFG0_CLKSEL (0x1 << 2)
++#define LCDC_LCDCFG0_CLKPWMSEL (0x1 << 3)
++#define LCDC_LCDCFG0_CGDISBASE (0x1 << 8)
++#define LCDC_LCDCFG0_CGDISOVR1 (0x1 << 9)
++/* XXX: maybe this is 1 << 10? At least the LCD Interrupt registers
++ * use 10 while the documentation specifies 11.
++ */
++#define LCDC_LCDCFG0_CGDISHEO (0x1 << 11)
++#define LCDC_LCDCFG0_CGDISHCR (0x1 << 12)
++#define LCDC_LCDCFG0_CLKDIV_OFFSET 16
++#define LCDC_LCDCFG0_CLKDIV (0xff << LCDC_LCDCFG0_CLKDIV_OFFSET)
++
++#define ATMEL_LCDC_LCDCFG1 0x0004
++#define LCDC_LCDCFG1_HSPW_OFFSET 0
++#define LCDC_LCDCFG1_HSPW (0x3f << LCDC_LCDCFG1_HSPW_OFFSET)
++#define LCDC_LCDCFG1_VSPW_OFFSET 16
++#define LCDC_LCDCFG1_VSPW (0x3f << LCDC_LCDCFG1_VSPW_OFFSET)
++
++#define ATMEL_LCDC_LCDCFG2 0x0008
++#define LCDC_LCDCFG2_VFPW_OFFSET 0
++#define LCDC_LCDCFG2_VFPW (0x3f << LCDC_LCDCFG2_VFPW_OFFSET)
++#define LCDC_LCDCFG2_VBPW_OFFSET 16
++#define LCDC_LCDCFG2_VBPW (0x3f << LCDC_LCDCFG2_VBPW_OFFSET)
++
++#define ATMEL_LCDC_LCDCFG3 0x000C
++#define LCDC_LCDCFG3_HFPW_OFFSET 0
++#define LCDC_LCDCFG3_HFPW (0xff << LCDC_LCDCFG3_HFPW_OFFSET)
++#define LCDC_LCDCFG3_HBPW_OFFSET 16
++#define LCDC_LCDCFG3_HBPW (0xff << LCDC_LCDCFG3_HBPW_OFFSET)
++
++#define ATMEL_LCDC_LCDCFG4 0x0010
++#define LCDC_LCDCFG4_PPL_OFFSET 0
++#define LCDC_LCDCFG4_PPL (0x7ff << LCDC_LCDCFG4_PPL_OFFSET)
++#define LCDC_LCDCFG4_RPF_OFFSET 16
++#define LCDC_LCDCFG4_RPF (0x7ff << LCDC_LCDCFG4_RPF_OFFSET)
++
++#define ATMEL_LCDC_LCDCFG5 0x0014
++#define LCDC_LCDCFG5_HSPOL (0x1 << 0)
++#define LCDC_LCDCFG5_VSPOL (0x1 << 1)
++#define LCDC_LCDCFG5_VSPDLYS (0x1 << 2)
++#define LCDC_LCDCFG5_VSPDLYE (0x1 << 3)
++#define LCDC_LCDCFG5_DISPPOL (0x1 << 4)
++#define LCDC_LCDCFG5_SERIAL (0x1 << 5)
++#define LCDC_LCDCFG5_DITHER (0x1 << 6)
++#define LCDC_LCDCFG5_DISPDLY (0x1 << 7)
++#define LCDC_LCDCFG5_MODE_OFFSET 8
++#define LCDC_LCDCFG5_MODE (0x3 << LCDC_LCDCFG5_MODE_OFFSET)
++#define LCDC_LCDCFG5_MODE_OUTPUT_12BPP (0x0 << 8)
++#define LCDC_LCDCFG5_MODE_OUTPUT_16BPP (0x1 << 8)
++#define LCDC_LCDCFG5_MODE_OUTPUT_18BPP (0x2 << 8)
++#define LCDC_LCDCFG5_MODE_OUTPUT_24BPP (0x3 << 8)
++#define LCDC_LCDCFG5_VSPSU (0x1 << 12)
++#define LCDC_LCDCFG5_VSPHO (0x1 << 13)
++#define LCDC_LCDCFG5_GUARDTIME_OFFSET 16
++#define LCDC_LCDCFG5_GUARDTIME (0x1f << LCDC_LCDCFG5_GUARDTIME_OFFSET)
++
++#define ATMEL_LCDC_LCDCFG6 0x0018
++#define LCDC_LCDCFG6_PWMPS_OFFSET 0
++#define LCDC_LCDCFG6_PWMPS (0x7 << LCDC_LCDCFG6_PWMPS_OFFSET)
++#define LCDC_LCDCFG6_PWMPOL (0x1 << 4)
++#define LCDC_LCDCFG6_PWMCVAL_OFFSET 8
++#define LCDC_LCDCFG6_PWMCVAL (0xff << LCDC_LCDCFG6_PWMCVAL_OFFSET)
++
++#define ATMEL_LCDC_LCDEN 0x0020
++#define LCDC_LCDEN_CLKEN (0x1 << 0)
++#define LCDC_LCDEN_SYNCEN (0x1 << 1)
++#define LCDC_LCDEN_DISPEN (0x1 << 2)
++#define LCDC_LCDEN_PWMEN (0x1 << 3)
++
++#define ATMEL_LCDC_LCDDIS 0x0024
++#define LCDC_LCDDIS_CLKDIS (0x1 << 0)
++#define LCDC_LCDDIS_SYNCDIS (0x1 << 1)
++#define LCDC_LCDDIS_DISPDIS (0x1 << 2)
++#define LCDC_LCDDIS_PWMDIS (0x1 << 3)
++#define LCDC_LCDDIS_CLKRST (0x1 << 8)
++#define LCDC_LCDDIS_SYNCRST (0x1 << 9)
++#define LCDC_LCDDIS_DISPRST (0x1 << 10)
++#define LCDC_LCDDIS_PWMRST (0x1 << 11)
++
++#define ATMEL_LCDC_LCDSR 0x0028
++#define LCDC_LCDSR_CLKSTS (0x1 << 0)
++#define LCDC_LCDSR_LCDSTS (0x1 << 1)
++#define LCDC_LCDSR_DISPSTS (0x1 << 2)
++#define LCDC_LCDSR_PWMSTS (0x1 << 3)
++#define LCDC_LCDSR_SIPSTS (0x1 << 4)
++
++#define ATMEL_LCDC_LCDIER 0x002C
++#define LCDC_LCDIER_SOFIE (0x1 << 0)
++#define LCDC_LCDIER_DISIE (0x1 << 1)
++#define LCDC_LCDIER_DISPIE (0x1 << 2)
++#define LCDC_LCDIER_FIFOERRIE (0x1 << 4)
++#define LCDC_LCDIER_BASEIE (0x1 << 8)
++#define LCDC_LCDIER_OVR1IE (0x1 << 9)
++#define LCDC_LCDIER_HEOIE (0x1 << 10)
++#define LCDC_LCDIER_HCRIE (0x1 << 12)
++
++#define ATMEL_LCDC_LCDIDR 0x0030
++#define LCDC_LCDIDR_SOFID (0x1 << 0)
++#define LCDC_LCDIDR_DISID (0x1 << 1)
++#define LCDC_LCDIDR_DISPID (0x1 << 2)
++#define LCDC_LCDIDR_FIFOERRID (0x1 << 4)
++#define LCDC_LCDIDR_BASEID (0x1 << 8)
++#define LCDC_LCDIDR_OVR1ID (0x1 << 9)
++#define LCDC_LCDIDR_HEOID (0x1 << 10)
++#define LCDC_LCDIDR_HCRID (0x1 << 12)
++
++#define ATMEL_LCDC_LCDIMR 0x0034
++#define LCDC_LCDIMR_SOFIM (0x1 << 0)
++#define LCDC_LCDIMR_DISIM (0x1 << 1)
++#define LCDC_LCDIMR_DISPIM (0x1 << 2)
++#define LCDC_LCDIMR_FIFOERRIM (0x1 << 4)
++#define LCDC_LCDIMR_BASEIM (0x1 << 8)
++#define LCDC_LCDIMR_OVR1IM (0x1 << 9)
++#define LCDC_LCDIMR_HEOIM (0x1 << 10)
++#define LCDC_LCDIMR_HCRIM (0x1 << 12)
++
++#define ATMEL_LCDC_LCDISR 0x0038
++#define LCDC_LCDISR_SOF (0x1 << 0)
++#define LCDC_LCDISR_DIS (0x1 << 1)
++#define LCDC_LCDISR_DISP (0x1 << 2)
++#define LCDC_LCDISR_FIFOERR (0x1 << 4)
++#define LCDC_LCDISR_BASE (0x1 << 8)
++#define LCDC_LCDISR_OVR1 (0x1 << 9)
++#define LCDC_LCDISR_HEO (0x1 << 10)
++#define LCDC_LCDISR_HCR (0x1 << 12)
++
++#define ATMEL_LCDC_BASECHER 0x0040
++#define LCDC_BASECHER_CHEN (0x1 << 0)
++#define LCDC_BASECHER_UPDATEEN (0x1 << 1)
++#define LCDC_BASECHER_A2QEN (0x1 << 2)
++
++#define ATMEL_LCDC_BASECHDR 0x0044
++#define LCDC_BASECHDR_CHDIS (0x1 << 0)
++#define LCDC_BASECHDR_CHRST (0x1 << 8)
++
++#define ATMEL_LCDC_BASECHSR 0x0048
++#define LCDC_BASECHSR_CHSR (0x1 << 0)
++#define LCDC_BASECHSR_UPDATESR (0x1 << 1)
++#define LCDC_BASECHSR_A2QSR (0x1 << 2)
++
++#define ATMEL_LCDC_BASEIER 0x004C
++#define LCDC_BASEIER_DMA (0x1 << 2)
++#define LCDC_BASEIER_DSCR (0x1 << 3)
++#define LCDC_BASEIER_ADD (0x1 << 4)
++#define LCDC_BASEIER_DONE (0x1 << 5)
++#define LCDC_BASEIER_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_BASEIDR 0x0050
++#define LCDC_BASEIDR_DMA (0x1 << 2)
++#define LCDC_BASEIDR_DSCR (0x1 << 3)
++#define LCDC_BASEIDR_ADD (0x1 << 4)
++#define LCDC_BASEIDR_DONE (0x1 << 5)
++#define LCDC_BASEIDR_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_BASEIMR 0x0054
++#define LCDC_BASEIMR_DMA (0x1 << 2)
++#define LCDC_BASEIMR_DSCR (0x1 << 3)
++#define LCDC_BASEIMR_ADD (0x1 << 4)
++#define LCDC_BASEIMR_DONE (0x1 << 5)
++#define LCDC_BASEIMR_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_BASEISR 0x0058
++#define LCDC_BASEISR_DMA (0x1 << 2)
++#define LCDC_BASEISR_DSCR (0x1 << 3)
++#define LCDC_BASEISR_ADD (0x1 << 4)
++#define LCDC_BASEISR_DONE (0x1 << 5)
++#define LCDC_BASEISR_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_BASEHEAD 0x005C
++
++#define ATMEL_LCDC_BASEADDR 0x0060
++
++#define ATMEL_LCDC_BASECTRL 0x0064
++#define LCDC_BASECTRL_DFETCH (0x1 << 0)
++#define LCDC_BASECTRL_LFETCH (0x1 << 1)
++#define LCDC_BASECTRL_DMAIEN (0x1 << 2)
++#define LCDC_BASECTRL_DSCRIEN (0x1 << 3)
++#define LCDC_BASECTRL_ADDIEN (0x1 << 4)
++#define LCDC_BASECTRL_DONEIEN (0x1 << 5)
++
++#define ATMEL_LCDC_BASENEXT 0x0068
++
++#define ATMEL_LCDC_BASECFG0 0x006C
++#define LCDC_BASECFG0_BLEN_OFFSET 4
++#define LCDC_BASECFG0_BLEN (0x3 << LCDC_BASECFG0_BLEN_OFFSET)
++#define LCDC_BASECFG0_BLEN_AHB_SINGLE (0x0 << 4)
++#define LCDC_BASECFG0_BLEN_AHB_INCR4 (0x1 << 4)
++#define LCDC_BASECFG0_BLEN_AHB_INCR8 (0x2 << 4)
++#define LCDC_BASECFG0_BLEN_AHB_INCR16 (0x3 << 4)
++#define LCDC_BASECFG0_DLBO (0x1 << 8)
++
++#define ATMEL_LCDC_BASECFG1 0x0070
++#define LCDC_BASECFG1_CLUTEN (0x1 << 0)
++#define LCDC_BASECFG1_RGBMODE_OFFSET 4
++#define LCDC_BASECFG1_RGBMODE (0xf << LCDC_BASECFG1_RGBMODE_OFFSET)
++#define LCDC_BASECFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
++#define LCDC_BASECFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
++#define LCDC_BASECFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
++#define LCDC_BASECFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
++#define LCDC_BASECFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
++#define LCDC_BASECFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
++#define LCDC_BASECFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
++#define LCDC_BASECFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
++#define LCDC_BASECFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
++#define LCDC_BASECFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
++#define LCDC_BASECFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
++#define LCDC_BASECFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
++#define LCDC_BASECFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
++#define LCDC_BASECFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
++#define LCDC_BASECFG1_CLUTMODE_OFFSET 8
++#define LCDC_BASECFG1_CLUTMODE (0x3 << LCDC_BASECFG1_CLUTMODE_OFFSET)
++#define LCDC_BASECFG1_CLUTMODE_1BPP (0x0 << 8)
++#define LCDC_BASECFG1_CLUTMODE_2BPP (0x1 << 8)
++#define LCDC_BASECFG1_CLUTMODE_4BPP (0x2 << 8)
++#define LCDC_BASECFG1_CLUTMODE_8BPP (0x3 << 8)
++
++#define ATMEL_LCDC_BASECFG2 0x0074
++
++#define ATMEL_LCDC_BASECFG3 0x0078
++#define LCDC_BASECFG3_BDEF_OFFSET 0
++#define LCDC_BASECFG3_BDEF (0xff << LCDC_BASECFG3_BDEF_OFFSET)
++#define LCDC_BASECFG3_GDEF_OFFSET 8
++#define LCDC_BASECFG3_GDEF (0xff << LCDC_BASECFG3_GDEF_OFFSET)
++#define LCDC_BASECFG3_RDEF_OFFSET 16
++#define LCDC_BASECFG3_RDEF (0xff << LCDC_BASECFG3_RDEF_OFFSET)
++
++#define ATMEL_LCDC_BASECFG4 0x007C
++#define LCDC_BASECFG4_DMA (0x1 << 8)
++#define LCDC_BASECFG4_REP (0x1 << 9)
++
++#define ATMEL_LCDC_OVRCHER1 0x0100
++#define LCDC_OVRCHER1_CHEN (0x1 << 0)
++#define LCDC_OVRCHER1_UPDATEEN (0x1 << 1)
++#define LCDC_OVRCHER1_A2QEN (0x1 << 2)
++
++#define ATMEL_LCDC_OVRCHDR1 0x0104
++#define LCDC_OVRCHDR1_CHDIS (0x1 << 0)
++#define LCDC_OVRCHDR1_CHRST (0x1 << 8)
++
++#define ATMEL_LCDC_OVRCHSR1 0x0108
++#define LCDC_OVRCHSR1_CHSR (0x1 << 0)
++#define LCDC_OVRCHSR1_UPDATESR (0x1 << 1)
++#define LCDC_OVRCHSR1_A2QSR (0x1 << 2)
++
++#define ATMEL_LCDC_OVRIER1 0x010C
++#define LCDC_OVRIER1_DMA (0x1 << 2)
++#define LCDC_OVRIER1_DSCR (0x1 << 3)
++#define LCDC_OVRIER1_ADD (0x1 << 4)
++#define LCDC_OVRIER1_DONE (0x1 << 5)
++#define LCDC_OVRIER1_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_OVRIDR1 0x0110
++#define LCDC_OVRIDR1_DMA (0x1 << 2)
++#define LCDC_OVRIDR1_DSCR (0x1 << 3)
++#define LCDC_OVRIDR1_ADD (0x1 << 4)
++#define LCDC_OVRIDR1_DONE (0x1 << 5)
++#define LCDC_OVRIDR1_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_OVRIMR1 0x0114
++#define LCDC_OVRIMR1_DMA (0x1 << 2)
++#define LCDC_OVRIMR1_DSCR (0x1 << 3)
++#define LCDC_OVRIMR1_ADD (0x1 << 4)
++#define LCDC_OVRIMR1_DONE (0x1 << 5)
++#define LCDC_OVRIMR1_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_OVRISR1 0x0118
++#define LCDC_OVRISR1_DMA (0x1 << 2)
++#define LCDC_OVRISR1_DSCR (0x1 << 3)
++#define LCDC_OVRISR1_ADD (0x1 << 4)
++#define LCDC_OVRISR1_DONE (0x1 << 5)
++#define LCDC_OVRISR1_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_OVRHEAD1 0x011C
++
++#define ATMEL_LCDC_OVRADDR1 0x0120
++
++#define ATMEL_LCDC_OVRCTRL1 0x0124
++#define LCDC_OVRCTRL1_DFETCH (0x1 << 0)
++#define LCDC_OVRCTRL1_LFETCH (0x1 << 1)
++#define LCDC_OVRCTRL1_DMAIEN (0x1 << 2)
++#define LCDC_OVRCTRL1_DSCRIEN (0x1 << 3)
++#define LCDC_OVRCTRL1_ADDIEN (0x1 << 4)
++#define LCDC_OVRCTRL1_DONEIEN (0x1 << 5)
++
++#define ATMEL_LCDC_OVRNEXT1 0x0128
++
++#define ATMEL_LCDC_OVR1CFG0 0x012C
++#define LCDC_OVR1CFG0_BLEN_OFFSET 4
++#define LCDC_OVR1CFG0_BLEN (0x3 << LCDC_OVR1CFG0_BLEN_OFFSET)
++#define LCDC_OVR1CFG0_BLEN_AHB_SINGLE (0x0 << 4)
++#define LCDC_OVR1CFG0_BLEN_AHB_INCR4 (0x1 << 4)
++#define LCDC_OVR1CFG0_BLEN_AHB_INCR8 (0x2 << 4)
++#define LCDC_OVR1CFG0_BLEN_AHB_INCR16 (0x3 << 4)
++#define LCDC_OVR1CFG0_DLBO (0x1 << 8)
++#define LCDC_OVR1CFG0_ROTDIS (0x1 << 12)
++#define LCDC_OVR1CFG0_LOCKDIS (0x1 << 13)
++
++#define ATMEL_LCDC_OVR1CFG1 0x0130
++#define LCDC_OVR1CFG1_CLUTEN (0x1 << 0)
++#define LCDC_OVR1CFG1_RGBMODE_OFFSET 4
++#define LCDC_OVR1CFG1_RGBMODE (0xf << LCDC_OVR1CFG1_RGBMODE_OFFSET)
++#define LCDC_OVR1CFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
++#define LCDC_OVR1CFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
++#define LCDC_OVR1CFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
++#define LCDC_OVR1CFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
++#define LCDC_OVR1CFG1_CLUTMODE_OFFSET 8
++#define LCDC_OVR1CFG1_CLUTMODE (0x3 << LCDC_OVR1CFG1_CLUTMODE_OFFSET)
++#define LCDC_OVR1CFG1_CLUTMODE_1BPP (0x0 << 8)
++#define LCDC_OVR1CFG1_CLUTMODE_2BPP (0x1 << 8)
++#define LCDC_OVR1CFG1_CLUTMODE_4BPP (0x2 << 8)
++#define LCDC_OVR1CFG1_CLUTMODE_8BPP (0x3 << 8)
++
++#define ATMEL_LCDC_OVR1CFG2 0x0134
++#define LCDC_OVR1CFG2_XOFFSET_OFFSET 0
++#define LCDC_OVR1CFG2_XOFFSET (0x7ff << LCDC_OVR1CFG2_XOFFSET_OFFSET)
++#define LCDC_OVR1CFG2_YOFFSET_OFFSET 16
++#define LCDC_OVR1CFG2_YOFFSET (0x7ff << LCDC_OVR1CFG2_YOFFSET_OFFSET)
++
++#define ATMEL_LCDC_OVR1CFG3 0x0138
++#define LCDC_OVR1CFG3_XSIZE_OFFSET 0
++#define LCDC_OVR1CFG3_XSIZE (0x7ff << LCDC_OVR1CFG3_XSIZE_OFFSET)
++#define LCDC_OVR1CFG3_YSIZE_OFFSET 16
++#define LCDC_OVR1CFG3_YSIZE (0x7ff << LCDC_OVR1CFG3_YSIZE_OFFSET)
++
++#define ATMEL_LCDC_OVR1CFG4 0x013C
++
++#define ATMEL_LCDC_OVR1CFG5 0x0140
++
++#define ATMEL_LCDC_OVR1CFG6 0x0144
++#define LCDC_OVR1CFG6_BDEF_OFFSET 0
++#define LCDC_OVR1CFG6_BDEF (0xff << LCDC_OVR1CFG6_BDEF_OFFSET)
++#define LCDC_OVR1CFG6_GDEF_OFFSET 8
++#define LCDC_OVR1CFG6_GDEF (0xff << LCDC_OVR1CFG6_GDEF_OFFSET)
++#define LCDC_OVR1CFG6_RDEF_OFFSET 16
++#define LCDC_OVR1CFG6_RDEF (0xff << LCDC_OVR1CFG6_RDEF_OFFSET)
++
++#define ATMEL_LCDC_OVR1CFG7 0x0148
++#define LCDC_OVR1CFG7_BKEY_OFFSET 0
++#define LCDC_OVR1CFG7_BKEY (0xff << LCDC_OVR1CFG7_BKEY_OFFSET)
++#define LCDC_OVR1CFG7_GKEY_OFFSET 8
++#define LCDC_OVR1CFG7_GKEY (0xff << LCDC_OVR1CFG7_GKEY_OFFST)
++#define LCDC_OVR1CFG7_RKEY_OFFSET 16
++#define LCDC_OVR1CFG7_RKEY (0xff << LCDC_OVR1CFG7_RKEY_OFFSET)
++
++#define ATMEL_LCDC_OVR1CFG8 0x014C
++#define LCDC_OVR1CFG8_BMASK_OFFSET 0
++#define LCDC_OVR1CFG8_BMASK (0xff << LCDC_OVR1CFG8_BMASK_OFFSET)
++#define LCDC_OVR1CFG8_GMASK_OFFSET 8
++#define LCDC_OVR1CFG8_GMASK (0xff << LCDC_OVR1CFG8_GMASK_OFFSET)
++#define LCDC_OVR1CFG8_RMASK_OFFSET 16
++#define LCDC_OVR1CFG8_RMASK (0xff << LCDC_OVR1CFG8_RMASK_OFFSET)
++
++#define ATMEL_LCDC_OVR1CFG9 0x0150
++#define LCDC_OVR1CFG9_CRKEY (0x1 << 0)
++#define LCDC_OVR1CFG9_INV (0x1 << 1)
++#define LCDC_OVR1CFG9_ITER2BL (0x1 << 2)
++#define LCDC_OVR1CFG9_ITER (0x1 << 3)
++#define LCDC_OVR1CFG9_REVALPHA (0x1 << 4)
++#define LCDC_OVR1CFG9_GAEN (0x1 << 5)
++#define LCDC_OVR1CFG9_LAEN (0x1 << 6)
++#define LCDC_OVR1CFG9_OVR (0x1 << 7)
++#define LCDC_OVR1CFG9_DMA (0x1 << 8)
++#define LCDC_OVR1CFG9_REP (0x1 << 9)
++#define LCDC_OVR1CFG9_DSTKEY (0x1 << 10)
++#define LCDC_OVR1CFG9_GA_OFFSET 16
++#define LCDC_OVR1CFG9_GA (0xff << LCDC_OVR1CFG9_GA_OFFSET)
++
++#define ATMEL_LCDC_HEOCHER 0x0280
++#define LCDC_HEOCHER_CHEN (0x1 << 0)
++#define LCDC_HEOCHER_UPDATEEN (0x1 << 1)
++#define LCDC_HEOCHER_A2QEN (0x1 << 2)
++
++#define ATMEL_LCDC_HEOCHDR 0x0284
++#define LCDC_HEOCHDR_CHDIS (0x1 << 0)
++#define LCDC_HEOCHDR_CHRST (0x1 << 8)
++
++#define ATMEL_LCDC_HEOCHSR 0x0288
++#define LCDC_HEOCHSR_CHSR (0x1 << 0)
++#define LCDC_HEOCHSR_UPDATESR (0x1 << 1)
++#define LCDC_HEOCHSR_A2QSR (0x1 << 2)
++
++#define ATMEL_LCDC_HEOIER 0x028C
++#define LCDC_HEOIER_DMA (0x1 << 2)
++#define LCDC_HEOIER_DSCR (0x1 << 3)
++#define LCDC_HEOIER_ADD (0x1 << 4)
++#define LCDC_HEOIER_DONE (0x1 << 5)
++#define LCDC_HEOIER_OVR (0x1 << 6)
++#define LCDC_HEOIER_UDMA (0x1 << 10)
++#define LCDC_HEOIER_UDSCR (0x1 << 11)
++#define LCDC_HEOIER_UADD (0x1 << 12)
++#define LCDC_HEOIER_UDONE (0x1 << 13)
++#define LCDC_HEOIER_UOVR (0x1 << 14)
++#define LCDC_HEOIER_VDMA (0x1 << 18)
++#define LCDC_HEOIER_VDSCR (0x1 << 19)
++#define LCDC_HEOIER_VADD (0x1 << 20)
++#define LCDC_HEOIER_VDONE (0x1 << 21)
++#define LCDC_HEOIER_VOVR (0x1 << 22)
++
++#define ATMEL_LCDC_HEOIDR 0x0290
++#define LCDC_HEOIDR_DMA (0x1 << 2)
++#define LCDC_HEOIDR_DSCR (0x1 << 3)
++#define LCDC_HEOIDR_ADD (0x1 << 4)
++#define LCDC_HEOIDR_DONE (0x1 << 5)
++#define LCDC_HEOIDR_OVR (0x1 << 6)
++#define LCDC_HEOIDR_UDMA (0x1 << 10)
++#define LCDC_HEOIDR_UDSCR (0x1 << 11)
++#define LCDC_HEOIDR_UADD (0x1 << 12)
++#define LCDC_HEOIDR_UDONE (0x1 << 13)
++#define LCDC_HEOIDR_UOVR (0x1 << 14)
++#define LCDC_HEOIDR_VDMA (0x1 << 18)
++#define LCDC_HEOIDR_VDSCR (0x1 << 19)
++#define LCDC_HEOIDR_VADD (0x1 << 20)
++#define LCDC_HEOIDR_VDONE (0x1 << 21)
++#define LCDC_HEOIDR_VOVR (0x1 << 22)
++
++#define ATMEL_LCDC_HEOIMR 0x0294
++#define LCDC_HEOIMR_DMA (0x1 << 2)
++#define LCDC_HEOIMR_DSCR (0x1 << 3)
++#define LCDC_HEOIMR_ADD (0x1 << 4)
++#define LCDC_HEOIMR_DONE (0x1 << 5)
++#define LCDC_HEOIMR_OVR (0x1 << 6)
++#define LCDC_HEOIMR_UDMA (0x1 << 10)
++#define LCDC_HEOIMR_UDSCR (0x1 << 11)
++#define LCDC_HEOIMR_UADD (0x1 << 12)
++#define LCDC_HEOIMR_UDONE (0x1 << 13)
++#define LCDC_HEOIMR_UOVR (0x1 << 14)
++#define LCDC_HEOIMR_VDMA (0x1 << 18)
++#define LCDC_HEOIMR_VDSCR (0x1 << 19)
++#define LCDC_HEOIMR_VADD (0x1 << 20)
++#define LCDC_HEOIMR_VDONE (0x1 << 21)
++#define LCDC_HEOIMR_VOVR (0x1 << 22)
++
++#define ATMEL_LCDC_HEOISR 0x0298
++#define LCDC_HEOISR_DMA (0x1 << 2)
++#define LCDC_HEOISR_DSCR (0x1 << 3)
++#define LCDC_HEOISR_ADD (0x1 << 4)
++#define LCDC_HEOISR_DONE (0x1 << 5)
++#define LCDC_HEOISR_OVR (0x1 << 6)
++#define LCDC_HEOISR_UDMA (0x1 << 10)
++#define LCDC_HEOISR_UDSCR (0x1 << 11)
++#define LCDC_HEOISR_UADD (0x1 << 12)
++#define LCDC_HEOISR_UDONE (0x1 << 13)
++#define LCDC_HEOISR_UOVR (0x1 << 14)
++#define LCDC_HEOISR_VDMA (0x1 << 18)
++#define LCDC_HEOISR_VDSCR (0x1 << 19)
++#define LCDC_HEOISR_VADD (0x1 << 20)
++#define LCDC_HEOISR_VDONE (0x1 << 21)
++#define LCDC_HEOISR_VOVR (0x1 << 22)
++
++#define ATMEL_LCDC_HEOHEAD 0x029C
++
++#define ATMEL_LCDC_HEOADDR 0x02A0
++
++#define ATMEL_LCDC_HEOCTRL 0x02A4
++#define LCDC_HEOCTRL_DFETCH (0x1 << 0)
++#define LCDC_HEOCTRL_LFETCH (0x1 << 1)
++#define LCDC_HEOCTRL_DMAIEN (0x1 << 2)
++#define LCDC_HEOCTRL_DSCRIEN (0x1 << 3)
++#define LCDC_HEOCTRL_ADDIEN (0x1 << 4)
++#define LCDC_HEOCTRL_DONEIEN (0x1 << 5)
++
++#define ATMEL_LCDC_HEONEXT 0x02A8
++
++#define ATMEL_LCDC_HEOUHEAD 0x02AC
++
++#define ATMEL_LCDC_HEOUADDR 0x02B0
++
++#define ATMEL_LCDC_HEOUCTRL 0x02B4
++#define LCDC_HEOUCTRL_UDFETCH (0x1 << 0)
++#define LCDC_HEOUCTRL_UDMAIEN (0x1 << 2)
++#define LCDC_HEOUCTRL_UDSCRIEN (0x1 << 3)
++#define LCDC_HEOUCTRL_UADDIEN (0x1 << 4)
++#define LCDC_HEOUCTRL_UDONEIEN (0x1 << 5)
++
++#define ATMEL_LCDC_HEOUNEXT 0x02B8
++
++#define ATMEL_LCDC_HEOVHEAD 0x02BC
++
++#define ATMEL_LCDC_HEOVADDR 0x02C0
++
++#define ATMEL_LCDC_HEOVCTRL 0x02C4
++#define LCDC_HEOVCTRL_VDFETCH (0x1 << 0)
++#define LCDC_HEOVCTRL_VDMAIEN (0x1 << 2)
++#define LCDC_HEOVCTRL_VDSCRIEN (0x1 << 3)
++#define LCDC_HEOVCTRL_VADDIEN (0x1 << 4)
++#define LCDC_HEOVCTRL_VDONEIEN (0x1 << 5)
++
++#define ATMEL_LCDC_HEOVNEXT 0x02C8
++
++#define ATMEL_LCDC_HEOCFG0 0x02CC
++#define LCDC_HEOCFG0_BLEN_OFFSET 4
++#define LCDC_HEOCFG0_BLEN (0x3 << LCDC_HEOCFG0_BLEN_OFFSET)
++#define LCDC_HEOCFG0_BLEN_AHB_SINGLE (0x0 << 4)
++#define LCDC_HEOCFG0_BLEN_AHB_INCR4 (0x1 << 4)
++#define LCDC_HEOCFG0_BLEN_AHB_INCR8 (0x2 << 4)
++#define LCDC_HEOCFG0_BLEN_AHB_INCR16 (0x3 << 4)
++#define LCDC_HEOCFG0_BLENUV_OFFSET 6
++#define LCDC_HEOCFG0_BLENUV (0x3 << LCDC_HEOCFG0_BLENUV_OFFSET)
++#define LCDC_HEOCFG0_BLENUV_AHB_SINGLE (0x0 << 6)
++#define LCDC_HEOCFG0_BLENUV_AHB_INCR4 (0x1 << 6)
++#define LCDC_HEOCFG0_BLENUV_AHB_INCR8 (0x2 << 6)
++#define LCDC_HEOCFG0_BLENUV_AHB_INCR16 (0x3 << 6)
++#define LCDC_HEOCFG0_DLBO (0x1 << 8)
++#define LCDC_HEOCFG0_ROTDIS (0x1 << 12)
++#define LCDC_HEOCFG0_LOCKDIS (0x1 << 13)
++
++#define ATMEL_LCDC_HEOCFG1 0x02D0
++#define LCDC_HEOCFG1_CLUTEN (0x1 << 0)
++#define LCDC_HEOCFG1_YUVEN (0x1 << 1)
++#define LCDC_HEOCFG1_RGBMODE_OFFSET 4
++#define LCDC_HEOCFG1_RGBMODE (0xf << LCDC_HEOCFG1_RGBMODE_OFFSET)
++#define LCDC_HEOCFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
++#define LCDC_HEOCFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
++#define LCDC_HEOCFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
++#define LCDC_HEOCFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
++#define LCDC_HEOCFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
++#define LCDC_HEOCFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
++#define LCDC_HEOCFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
++#define LCDC_HEOCFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
++#define LCDC_HEOCFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
++#define LCDC_HEOCFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
++#define LCDC_HEOCFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
++#define LCDC_HEOCFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
++#define LCDC_HEOCFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
++#define LCDC_HEOCFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
++#define LCDC_HEOCFG1_CLUTMODE_OFFSET 8
++#define LCDC_HEOCFG1_CLUTMODE (0x3 << LCDC_HEOCFG1_CLUTMODE_OFFSET)
++#define LCDC_HEOCFG1_CLUTMODE_1BPP (0x0 << 8)
++#define LCDC_HEOCFG1_CLUTMODE_2BPP (0x1 << 8)
++#define LCDC_HEOCFG1_CLUTMODE_4BPP (0x2 << 8)
++#define LCDC_HEOCFG1_CLUTMODE_8BPP (0x3 << 8)
++#define LCDC_HEOCFG1_YUVMODE_OFFSET 12
++#define LCDC_HEOCFG1_YUVMODE (0xf << LCDC_HEOCFG1_YUVMODE_OFFSET)
++#define LCDC_HEOCFG1_YUVMODE_32BPP_AYCBCR (0x0 << 12)
++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE0 (0x1 << 12)
++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE1 (0x2 << 12)
++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE2 (0x3 << 12)
++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE3 (0x4 << 12)
++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_SEMIPLANAR (0x5 << 12)
++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_PLANAR (0x6 << 12)
++#define LCDC_HEOCFG1_YUVMODE_12BPP_YCBCR_SEMIPLANAR (0x7 << 12)
++#define LCDC_HEOCFG1_YUVMODE_12BPP_YCBCR_PLANAR (0x8 << 12)
++#define LCDC_HEOCFG1_YUV422ROT (0x1 << 16)
++#define LCDC_HEOCFG1_YUV422SWP (0x1 << 17)
++
++#define ATMEL_LCDC_HEOCFG2 0x02D4
++#define LCDC_HEOCFG2_XOFFSET_OFFSET 0
++#define LCDC_HEOCFG2_XOFFSET (0x7ff << LCDC_HEOCFG2_XOFFSET_OFFSET)
++#define LCDC_HEOCFG2_YOFFSET_OFFSET 16
++#define LCDC_HEOCFG2_YOFFSET (0x7ff << LCDC_HEOCFG2_YOFFSET_OFFSET)
++
++#define ATMEL_LCDC_HEOCFG3 0x02D8
++#define LCDC_HEOCFG3_XSIZE_OFFSET 0
++#define LCDC_HEOCFG3_XSIZE (0x7ff << LCDC_HEOCFG3_XSIZE_OFFSET)
++#define LCDC_HEOCFG3_YSIZE_OFFSET 16
++#define LCDC_HEOCFG3_YSIZE (0x7ff << LCDC_HEOCFG3_YSIZE_OFFSET)
++
++#define ATMEL_LCDC_HEOCFG4 0x02DC
++#define LCDC_HEOCFG4_XMEM_SIZE_OFFSET 0
++#define LCDC_HEOCFG4_XMEM_SIZE (0x7ff << LCDC_HEOCFG4_XMEM_SIZE_OFFSET)
++#define LCDC_HEOCFG4_YMEM_SIZE_OFFSET 16
++#define LCDC_HEOCFG4_YMEM_SIZE (0x7ff << LCDC_HEOCFG4_YMEM_SIZE_OFFSET)
++
++#define ATMEL_LCDC_HEOCFG5 0x02E0
++
++#define ATMEL_LCDC_HEOCFG6 0x02E4
++
++#define ATMEL_LCDC_HEOCFG7 0x02E8
++
++#define ATMEL_LCDC_HEOCFG8 0x02EC
++
++#define ATMEL_LCDC_HEOCFG9 0x02F0
++#define LCDC_HEOCFG9_BDEF_OFFSET 0
++#define LCDC_HEOCFG9_BDEF (0xff << LCDC_HEOCFG9_BDEF_OFFSET)
++#define LCDC_HEOCFG9_GDEF_OFFSET 8
++#define LCDC_HEOCFG9_GDEF (0xff << LCDC_HEOCFG9_GDEF_OFFSET)
++#define LCDC_HEOCFG9_RDEF_OFFSET 16
++#define LCDC_HEOCFG9_RDEF (0xff << LCDC_HEOCFG9_RDEF_OFFSET)
++
++#define ATMEL_LCDC_HEOCFG10 0x02F4
++#define LCDC_HEOCFG10_BKEY_OFFSET 0
++#define LCDC_HEOCFG10_BKEY (0xff << LCDC_HEOCFG10_BKEY_OFFSET)
++#define LCDC_HEOCFG10_GKEY_OFFSET 8
++#define LCDC_HEOCFG10_GKEY (0xff << LCDC_HEOCFG10_GKEY_OFFSET)
++#define LCDC_HEOCFG10_RKEY_OFFSET 16
++#define LCDC_HEOCFG10_RKEY (0xff << LCDC_HEOCFG10_RKEY_OFFSET)
++
++#define ATMEL_LCDC_HEOCFG11 0x02F8
++#define LCDC_HEOCFG11_BMASK_OFFSET 0
++#define LCDC_HEOCFG11_BMASK (0xff << LCDC_HEOCFG11_BMASK_OFFSET)
++#define LCDC_HEOCFG11_GMASK_OFFSET 8
++#define LCDC_HEOCFG11_GMASK (0xff << LCDC_HEOCFG11_GMASK_OFFSET)
++#define LCDC_HEOCFG11_RMASK_OFFSET 16
++#define LCDC_HEOCFG11_RMASK (0xff << LCDC_HEOCFG11_RMASK_OFFSET)
++
++#define ATMEL_LCDC_HEOCFG12 0x02FC
++#define LCDC_HEOCFG12_CRKEY (0x1 << 0)
++#define LCDC_HEOCFG12_INV (0x1 << 1)
++#define LCDC_HEOCFG12_ITER2BL (0x1 << 2)
++#define LCDC_HEOCFG12_ITER (0x1 << 3)
++#define LCDC_HEOCFG12_REVALPHA (0x1 << 4)
++#define LCDC_HEOCFG12_GAEN (0x1 << 5)
++#define LCDC_HEOCFG12_LAEN (0x1 << 6)
++#define LCDC_HEOCFG12_OVR (0x1 << 7)
++#define LCDC_HEOCFG12_DMA (0x1 << 8)
++#define LCDC_HEOCFG12_REP (0x1 << 9)
++#define LCDC_HEOCFG12_DSTKEY (0x1 << 10)
++#define LCDC_HEOCFG12_VIDPRI (0x1 << 12)
++#define LCDC_HEOCFG12_GA_OFFSET 16
++#define LCDC_HEOCFG12_GA (0xff << LCDC_HEOCFG12_GA_OFFSET)
++
++#define ATMEL_LCDC_HEOCFG13 0x0300
++#define LCDC_HEOCFG13_XFACTOR_OFFSET 0
++#define LCDC_HEOCFG13_XFACTOR (0x1fff << LCDC_HEOCFG13_XFACTOR_OFFSET)
++#define LCDC_HEOCFG13_YFACTOR_OFFSET 16
++#define LCDC_HEOCFG13_YFACTOR (0x1fff << LCDC_HEOCFG13_YFACTOR_OFFSET)
++#define LCDC_HEOCFG13_SCALEN (0x1 << 31)
++
++#define ATMEL_LCDC_HEOCFG14 0x0304
++#define LCDC_HEOCFG14_CSCRY_OFFSET 0
++#define LCDC_HEOCFG14_CSCRY (0x3ff << LCDC_HEOCFG14_CSCRY_OFFSET)
++#define LCDC_HEOCFG14_CSCRU_OFFSET 10
++#define LCDC_HEOCFG14_CSCRU (0x3ff << LCDC_HEOCFG14_CSCRU_OFFSET)
++#define LCDC_HEOCFG14_CSCRV_OFFSET 20
++#define LCDC_HEOCFG14_CSCRV (0x3ff << LCDC_HEOCFG14_CSCRV_OFFSET)
++#define LCDC_HEOCFG14_CSCYOFF (0x1 << 30)
++
++#define ATMEL_LCDC_HEOCFG15 0x0308
++#define LCDC_HEOCFG15_CSCGY_OFFSET 0
++#define LCDC_HEOCFG15_CSCGY (0x3ff << LCDC_HEOCFG15_CSCGY_OFFSET)
++#define LCDC_HEOCFG15_CSCGU_OFFSET 10
++#define LCDC_HEOCFG15_CSCGU (0x3ff << LCDC_HEOCFG15_CSCGU_OFFSET)
++#define LCDC_HEOCFG15_CSCGV_OFFSET 20
++#define LCDC_HEOCFG15_CSCGV (0x3ff << LCDC_HEOCFG15_CSCGV_OFFSET)
++#define LCDC_HEOCFG15_CSCUOFF (0x1 << 30)
++
++#define ATMEL_LCDC_HEOCFG16 0x030C
++#define LCDC_HEOCFG16_CSCBY_OFFSET 0
++#define LCDC_HEOCFG16_CSCBY (0x3ff << LCDC_HEOCFG16_CSCBY_OFFSET)
++#define LCDC_HEOCFG16_CSCBU_OFFSET 10
++#define LCDC_HEOCFG16_CSCBU (0x3ff << LCDC_HEOCFG16_CSCBU_OFFSET)
++#define LCDC_HEOCFG16_CSCBV_OFFSET 20
++#define LCDC_HEOCFG16_CSCBV (0x3ff << LCDC_HEOCFG16_CSCBV_OFFSET)
++#define LCDC_HEOCFG16_CSCVOFF (0x1 << 30)
++
++#define ATMEL_LCDC_HCRCHER 0x0340
++#define LCDC_HCRCHER_CHEN (0x1 << 0)
++#define LCDC_HCRCHER_UPDATEEN (0x1 << 1)
++#define LCDC_HCRCHER_A2QEN (0x1 << 2)
++
++#define ATMEL_LCDC_HCRCHDR 0x0344
++#define LCDC_HCRCHDR_CHDIS (0x1 << 0)
++#define LCDC_HCRCHDR_CHRST (0x1 << 8)
++
++#define ATMEL_LCDC_HCRCHSR 0x0348
++#define LCDC_HCRCHSR_CHSR (0x1 << 0)
++#define LCDC_HCRCHSR_UPDATESR (0x1 << 1)
++#define LCDC_HCRCHSR_A2QSR (0x1 << 2)
++
++#define ATMEL_LCDC_HCRIER 0x034C
++#define LCDC_HCRIER_DMA (0x1 << 2)
++#define LCDC_HCRIER_DSCR (0x1 << 3)
++#define LCDC_HCRIER_ADD (0x1 << 4)
++#define LCDC_HCRIER_DONE (0x1 << 5)
++#define LCDC_HCRIER_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_HCRIDR 0x0350
++#define LCDC_HCRIDR_DMA (0x1 << 2)
++#define LCDC_HCRIDR_DSCR (0x1 << 3)
++#define LCDC_HCRIDR_ADD (0x1 << 4)
++#define LCDC_HCRIDR_DONE (0x1 << 5)
++#define LCDC_HCRIDR_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_HCRIMR 0x0354
++#define LCDC_HCRIMR_DMA (0x1 << 2)
++#define LCDC_HCRIMR_DSCR (0x1 << 3)
++#define LCDC_HCRIMR_ADD (0x1 << 4)
++#define LCDC_HCRIMR_DONE (0x1 << 5)
++#define LCDC_HCRIMR_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_HCRISR 0x0358
++#define LCDC_HCRISR_DMA (0x1 << 2)
++#define LCDC_HCRISR_DSCR (0x1 << 3)
++#define LCDC_HCRISR_ADD (0x1 << 4)
++#define LCDC_HCRISR_DONE (0x1 << 5)
++#define LCDC_HCRISR_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_HCRHEAD 0x035C
++
++#define ATMEL_LCDC_HCRADDR 0x0360
++
++#define ATMEL_LCDC_HCRCTRL 0x0364
++#define LCDC_HCRCTRL_DFETCH (0x1 << 0)
++#define LCDC_HCRCTRL_LFETCH (0x1 << 1)
++#define LCDC_HCRCTRL_DMAIEN (0x1 << 2)
++#define LCDC_HCRCTRL_DSCRIEN (0x1 << 3)
++#define LCDC_HCRCTRL_ADDIEN (0x1 << 4)
++#define LCDC_HCRCTRL_DONEIEN (0x1 << 5)
++
++#define ATMEL_LCDC_HCRNEXT 0x0368
++
++#define ATMEL_LCDC_HCRCFG0 0x036C
++#define LCDC_HCRCFG0_BLEN_OFFSET 4
++#define LCDC_HCRCFG0_BLEN (0x3 << LCDC_HCRCFG0_BLEN_OFFSET)
++#define LCDC_HCRCFG0_BLEN_AHB_SINGLE (0x0 << 4)
++#define LCDC_HCRCFG0_BLEN_AHB_INCR4 (0x1 << 4)
++#define LCDC_HCRCFG0_BLEN_AHB_INCR8 (0x2 << 4)
++#define LCDC_HCRCFG0_BLEN_AHB_INCR16 (0x3 << 4)
++#define LCDC_HCRCFG0_DLBO (0x1 << 8)
++
++#define ATMEL_LCDC_HCRCFG1 0x0370
++#define LCDC_HCRCFG1_CLUTEN (0x1 << 0)
++#define LCDC_HCRCFG1_RGBMODE_OFFSET 4
++#define LCDC_HCRCFG1_RGBMODE (0xf << LCDC_HCRCFG1_RGBMODE_OFFSET)
++#define LCDC_HCRCFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
++#define LCDC_HCRCFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
++#define LCDC_HCRCFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
++#define LCDC_HCRCFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
++#define LCDC_HCRCFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
++#define LCDC_HCRCFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
++#define LCDC_HCRCFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
++#define LCDC_HCRCFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
++#define LCDC_HCRCFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
++#define LCDC_HCRCFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
++#define LCDC_HCRCFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
++#define LCDC_HCRCFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
++#define LCDC_HCRCFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
++#define LCDC_HCRCFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
++#define LCDC_HCRCFG1_CLUTMODE_OFFSET 8
++#define LCDC_HCRCFG1_CLUTMODE (0x3 << LCDC_HCRCFG1_CLUTMODE_OFFSET)
++#define LCDC_HCRCFG1_CLUTMODE_1BPP (0x0 << 8)
++#define LCDC_HCRCFG1_CLUTMODE_2BPP (0x1 << 8)
++#define LCDC_HCRCFG1_CLUTMODE_4BPP (0x2 << 8)
++#define LCDC_HCRCFG1_CLUTMODE_8BPP (0x3 << 8)
++
++#define ATMEL_LCDC_HCRCFG2 0x0374
++#define LCDC_HCRCFG2_XOFFSET_OFFSET 0
++#define LCDC_HCRCFG2_XOFFSET (0x7ff << LCDC_HCRCFG2_XOFFSET_OFFSET)
++#define LCDC_HCRCFG2_YOFFSET_OFFSET 16
++#define LCDC_HCRCFG2_YOFFSET (0x7ff << LCDC_HCRCFG2_YOFFSET_OFFSET)
++
++#define ATMEL_LCDC_HCRCFG3 0x0378
++#define LCDC_HCRCFG3_XSIZE_OFFSET 0
++#define LCDC_HCRCFG3_XSIZE (0x7f << LCDC_HCRCFG3_XSIZE_OFFSET)
++#define LCDC_HCRCFG3_YSIZE_OFFSET 16
++#define LCDC_HCRCFG3_YSIZE (0x7f << LCDC_HCRCFG3_YSIZE_OFFSET)
++
++#define ATMEL_LCDC_HCRCFG4 0x037C
++
++#define ATMEL_LCDC_HCRCFG6 0x0384
++#define LCDC_HCRCFG6_BDEF_OFFSET 0
++#define LCDC_HCRCFG6_BDEF (0xff << LCDC_HCRCFG6_BDEF_OFFSET)
++#define LCDC_HCRCFG6_GDEF_OFFSET 8
++#define LCDC_HCRCFG6_GDEF (0xff << LCDC_HCRCFG6_GDEF_OFFSET)
++#define LCDC_HCRCFG6_RDEF_OFFSET 16
++#define LCDC_HCRCFG6_RDEF (0xff << LCDC_HCRCFG6_RDEF_OFFSET)
++
++#define ATMEL_LCDC_HCRCFG7 0x0388
++#define LCDC_HCRCFG7_BKEY_OFFSET 0
++#define LCDC_HCRCFG7_BKEY (0xff << LCDC_HCRCFG7_BKEY_OFFSET)
++#define LCDC_HCRCFG7_GKEY_OFFSET 8
++#define LCDC_HCRCFG7_GKEY (0xff << LCDC_HCRCFG7_GKEY_OFFSET)
++#define LCDC_HCRCFG7_RKEY_OFFSET 16
++#define LCDC_HCRCFG7_RKEY (0xff << LCDC_HCRCFG7_RKEY_OFFSET)
++
++#define ATMEL_LCDC_HCRCFG8 0x038C
++#define LCDC_HCRCFG8_BMASK_OFFSET 0
++#define LCDC_HCRCFG8_BMASK (0xff << LCDC_HCRCFG8_BMASK_OFFSET)
++#define LCDC_HCRCFG8_GMASK_OFFSET 8
++#define LCDC_HCRCFG8_GMASK (0xff << LCDC_HCRCFG8_GMASK_OFFSET)
++#define LCDC_HCRCFG8_RMASK_OFFSET 16
++#define LCDC_HCRCFG8_RMASK (0xff << LCDC_HCRCFG8_RMASK_OFFSET)
++
++#define ATMEL_LCDC_HCRCFG9 0x0390
++#define LCDC_HCRCFG9_CRKEY (0x1 << 0)
++#define LCDC_HCRCFG9_INV (0x1 << 1)
++#define LCDC_HCRCFG9_ITER2BL (0x1 << 2)
++#define LCDC_HCRCFG9_ITER (0x1 << 3)
++#define LCDC_HCRCFG9_REVALPHA (0x1 << 4)
++#define LCDC_HCRCFG9_GAEN (0x1 << 5)
++#define LCDC_HCRCFG9_LAEN (0x1 << 6)
++#define LCDC_HCRCFG9_OVR (0x1 << 7)
++#define LCDC_HCRCFG9_DMA (0x1 << 8)
++#define LCDC_HCRCFG9_REP (0x1 << 9)
++#define LCDC_HCRCFG9_DSTKEY (0x1 << 10)
++#define LCDC_HCRCFG9_GA_OFFSET 16
++#define LCDC_HCRCFG9_GA_Msk (0xff << LCDC_HCRCFG9_GA_OFFSET)
++
++#define ATMEL_LCDC_BASECLUT 0x400
++#define LCDC_BASECLUT_BCLUT_OFFSET 0
++#define LCDC_BASECLUT_BCLUT (0xff << LCDC_BASECLUT_BCLUT_OFFSET)
++#define LCDC_BASECLUT_GCLUT_OFFSET 8
++#define LCDC_BASECLUT_GCLUT (0xff << LCDC_BASECLUT_GCLUT_OFFSET)
++#define LCDC_BASECLUT_RCLUT_OFFSET 16
++#define LCDC_BASECLUT_RCLUT (0xff << LCDC_BASECLUT_RCLUT_OFFSET)
++
++#define ATMEL_LCDC_OVR1CLUT 0x800
++#define LCDC_OVR1CLUT_BCLUT_OFFSET 0
++#define LCDC_OVR1CLUT_BCLUT (0xff << LCDC_OVR1CLUT_BCLUT_OFFSET)
++#define LCDC_OVR1CLUT_GCLUT_OFFSET 8
++#define LCDC_OVR1CLUT_GCLUT (0xff << LCDC_OVR1CLUT_GCLUT_OFFSET)
++#define LCDC_OVR1CLUT_RCLUT_OFFSET 16
++#define LCDC_OVR1CLUT_RCLUT (0xff << LCDC_OVR1CLUT_RCLUT_OFFSET)
++#define LCDC_OVR1CLUT_ACLUT_OFFSET 24
++#define LCDC_OVR1CLUT_ACLUT (0xff << LCDC_OVR1CLUT_ACLUT_OFFSET)
++
++#define ATMEL_LCDC_HEOCLUT 0x1000
++#define LCDC_HEOCLUT_BCLUT_OFFSET 0
++#define LCDC_HEOCLUT_BCLUT (0xff << LCDC_HEOCLUT_BCLUT_OFFSET)
++#define LCDC_HEOCLUT_GCLUT_OFFSET 8
++#define LCDC_HEOCLUT_GCLUT (0xff << LCDC_HEOCLUT_GCLUT_OFFSET)
++#define LCDC_HEOCLUT_RCLUT_OFFSET 16
++#define LCDC_HEOCLUT_RCLUT (0xff << LCDC_HEOCLUT_RCLUT_OFFSET)
++#define LCDC_HEOCLUT_ACLUT_OFFSET 24
++#define LCDC_HEOCLUT_ACLUT (0xff << LCDC_HEOCLUT_ACLUT_OFFSET)
++
++#define ATMEL_LCDC_HCRCLUT 0x1400
++#define LCDC_HCRCLUT_BCLUT_OFFSET 0
++#define LCDC_HCRCLUT_BCLUT (0xff << LCDC_HCRCLUT_BCLUT_OFFSET)
++#define LCDC_HCRCLUT_GCLUT_OFFSET 8
++#define LCDC_HCRCLUT_GCLUT (0xff << LCDC_HCRCLUT_GCLUT_OFFSET)
++#define LCDC_HCRCLUT_RCLUT_OFFSET 16
++#define LCDC_HCRCLUT_RCLUT (0xff << LCDC_HCRCLUT_RCLUT_OFFSET)
++#define LCDC_HCRCLUT_ACLUT_OFFSET 24
++#define LCDC_HCRCLUT_ACLUT (0xff << LCDC_HCRCLUT_ACLUT_OFFSET)
++
++/* Base layer CLUT */
++#define ATMEL_LCDC_LUT(n) (0x0400 + ((n)*4))
++
++
++#endif /* __ATMEL_HLCDC4_H__ */
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 4484c72..fa9431b 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -1,7 +1,7 @@
+ /*
+ * Driver for AT91/AT32 LCD Controller
+ *
+- * Copyright (C) 2007 Atmel Corporation
++ * Copyright (C) 2007-2010 Atmel Corporation
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+@@ -24,6 +24,7 @@
+ #include <mach/gpio.h>
+
+ #include <video/atmel_lcdc.h>
++#include <mach/atmel_hlcdfb.h>
+
+ #define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg))
+ #define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg))
+@@ -72,6 +73,9 @@ static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
+ | ATMEL_LCDC_POL_POSITIVE
+ | ATMEL_LCDC_ENA_PWMENABLE;
+
++static const u32 contrast_pwm_ctr = LCDC_LCDCFG6_PWMPOL
++ | (ATMEL_LCDC_CVAL_DEFAULT << LCDC_LCDCFG6_PWMCVAL_OFFSET);
++
+ #ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+
+ /* some bl->props field just changed */
+@@ -80,6 +84,7 @@ static int atmel_bl_update_status(struct backlight_device *bl)
+ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+ int power = sinfo->bl_power;
+ int brightness = bl->props.brightness;
++ u32 reg;
+
+ /* REVISIT there may be a meaningful difference between
+ * fb_blank and power ... there seem to be some cases
+@@ -90,14 +95,25 @@ static int atmel_bl_update_status(struct backlight_device *bl)
+ else if (bl->props.power != sinfo->bl_power)
+ power = bl->props.power;
+
+- if (brightness < 0 && power == FB_BLANK_UNBLANK)
+- brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+- else if (power != FB_BLANK_UNBLANK)
++ if (brightness < 0 && power == FB_BLANK_UNBLANK) {
++ if (cpu_is_at91sam9x5())
++ brightness = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6)
++ >> LCDC_LCDCFG6_PWMCVAL_OFFSET;
++ else
++ brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
++ } else if (power != FB_BLANK_UNBLANK) {
+ brightness = 0;
++ }
+
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
+- brightness ? contrast_ctr : 0);
++ if (cpu_is_at91sam9x5()) {
++ reg = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) & ~LCDC_LCDCFG6_PWMCVAL;
++ reg |= brightness << LCDC_LCDCFG6_PWMCVAL_OFFSET;
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, reg);
++ } else {
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
++ brightness ? contrast_ctr : 0);
++ }
+
+ bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
+
+@@ -108,7 +124,10 @@ static int atmel_bl_get_brightness(struct backlight_device *bl)
+ {
+ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+
+- return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
++ if (cpu_is_at91sam9x5())
++ return lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) >> LCDC_LCDCFG6_PWMCVAL_OFFSET;
++ else
++ return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+ }
+
+ static const struct backlight_ops atmel_lcdc_bl_ops = {
+@@ -164,14 +183,17 @@ static void exit_backlight(struct atmel_lcdfb_info *sinfo)
+
+ static void init_contrast(struct atmel_lcdfb_info *sinfo)
+ {
+- /* contrast pwm can be 'inverted' */
+- if (sinfo->lcdcon_pol_negative)
+- contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
+-
+- /* have some default contrast/backlight settings */
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+-
++ if (cpu_is_at91sam9x5()) {
++ /* have some default contrast/backlight settings */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, contrast_pwm_ctr);
++ } else {
++ /* contrast pwm can be 'inverted' */
++ if (sinfo->lcdcon_pol_negative)
++ contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
++ /* have some default contrast/backlight settings */
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
++ }
+ if (sinfo->lcdcon_is_backlight)
+ init_backlight(sinfo);
+ }
+@@ -213,32 +235,78 @@ static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
+
+ static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
+ {
+- /* Turn off the LCD controller and the DMA controller */
+- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+- sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
++ if (cpu_is_at91sam9x5()) {
++ /* Disable DISP signal */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_DISPDIS);
++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS))
++ msleep(1);
++ /* Disable synchronization */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_SYNCDIS);
++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS))
++ msleep(1);
++ /* Disable pixel clock */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_CLKDIS);
++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS))
++ msleep(1);
++ /* Disable PWM */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_PWMDIS);
++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS))
++ msleep(1);
++ } else {
++ /* Turn off the LCD controller and the DMA controller */
++ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
++ sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
+
+- /* Wait for the LCDC core to become idle */
+- while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
+- msleep(10);
++ /* Wait for the LCDC core to become idle */
++ while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
++ msleep(10);
+
+- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
++ }
+ }
+
+ static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo)
+ {
+ atmel_lcdfb_stop_nowait(sinfo);
+
+- /* Wait for DMA engine to become idle... */
+- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+- msleep(10);
++ if (cpu_is_at91sam9x5()) {
++ /* Wait for the end of DMA transfer */
++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_BASEISR) & LCDC_BASEISR_DMA))
++ msleep(10);
++ } else {
++ /* Wait for DMA engine to become idle... */
++ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
++ msleep(10);
++ }
+ }
+
+ static void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
+ {
+- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
+- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+- (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
+- | ATMEL_LCDC_PWR);
++ u32 value;
++
++ if (cpu_is_at91sam9x5()) {
++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_CLKEN);
++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS))
++ msleep(1);
++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_SYNCEN);
++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS))
++ msleep(1);
++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_DISPEN);
++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS))
++ msleep(1);
++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_PWMEN);
++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS))
++ msleep(1);
++ } else {
++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
++ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
++ (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
++ | ATMEL_LCDC_PWR);
++ }
+ }
+
+ static void atmel_lcdfb_update_dma(struct fb_info *info,
+@@ -247,14 +315,31 @@ static void atmel_lcdfb_update_dma(struct fb_info *info,
+ struct atmel_lcdfb_info *sinfo = info->par;
+ struct fb_fix_screeninfo *fix = &info->fix;
+ unsigned long dma_addr;
++ struct lcd_dma_desc *desc;
+
+ dma_addr = (fix->smem_start + var->yoffset * fix->line_length
+ + var->xoffset * var->bits_per_pixel / 8);
+
+ dma_addr &= ~3UL;
+
+- /* Set framebuffer DMA base address and pixel offset */
+- lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
++ if (cpu_is_at91sam9x5()) {
++ /* Setup the DMA descriptor, this descriptor will loop to itself */
++ desc = (struct lcd_dma_desc *)sinfo->p_dma_desc;
++
++ desc->address = dma_addr;
++ /* Disable DMA transfer interrupt & descriptor loaded interrupt. */
++ desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN
++ | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH;
++ desc->next = sinfo->dma_desc_phys;
++
++ lcdc_writel(sinfo, ATMEL_LCDC_BASEADDR, dma_addr);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECTRL, desc->control);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASENEXT, sinfo->dma_desc_phys);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECHER, LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN);
++ } else {
++ /* Set framebuffer DMA base address and pixel offset */
++ lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
++ }
+
+ atmel_lcdfb_update_dma2d(sinfo, var);
+ }
+@@ -265,12 +350,18 @@ static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
+
+ dma_free_writecombine(info->device, info->fix.smem_len,
+ info->screen_base, info->fix.smem_start);
++
++ if (cpu_is_at91sam9x5()) {
++ if (sinfo->p_dma_desc)
++ dma_free_writecombine(info->device, sizeof(struct lcd_dma_desc),
++ sinfo->p_dma_desc, sinfo->dma_desc_phys);
++ }
+ }
+
+ /**
+ * atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory
+ * @sinfo: the frame buffer to allocate memory for
+- *
++ *
+ * This function is called only from the atmel_lcdfb_probe()
+ * so no locking by fb_info->mm_lock around smem_len setting is needed.
+ */
+@@ -293,6 +384,19 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
+
+ memset(info->screen_base, 0, info->fix.smem_len);
+
++ if (cpu_is_at91sam9x5()) {
++ sinfo->p_dma_desc = dma_alloc_writecombine(info->device,
++ sizeof(struct lcd_dma_desc),
++ (dma_addr_t *)&(sinfo->dma_desc_phys),
++ GFP_KERNEL);
++
++ if (!sinfo->p_dma_desc) {
++ dma_free_writecombine(info->device, info->fix.smem_len,
++ info->screen_base, info->fix.smem_start);
++ return -ENOMEM;
++ }
++ }
++
+ return 0;
+ }
+
+@@ -386,18 +490,33 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
+ }
+
+ /* Saturate vertical and horizontal timings at maximum values */
+- var->vsync_len = min_t(u32, var->vsync_len,
+- (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
+- var->upper_margin = min_t(u32, var->upper_margin,
+- ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
+- var->lower_margin = min_t(u32, var->lower_margin,
+- ATMEL_LCDC_VFP);
+- var->right_margin = min_t(u32, var->right_margin,
+- (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
+- var->hsync_len = min_t(u32, var->hsync_len,
+- (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
+- var->left_margin = min_t(u32, var->left_margin,
+- ATMEL_LCDC_HBP + 1);
++ if (cpu_is_at91sam9x5()) {
++ var->vsync_len = min_t(u32, var->vsync_len,
++ (LCDC_LCDCFG1_VSPW >> LCDC_LCDCFG1_VSPW_OFFSET) + 1);
++ var->upper_margin = min_t(u32, var->upper_margin,
++ (LCDC_LCDCFG2_VFPW >> LCDC_LCDCFG2_VFPW_OFFSET) + 1);
++ var->lower_margin = min_t(u32, var->lower_margin,
++ LCDC_LCDCFG2_VBPW >> LCDC_LCDCFG2_VBPW_OFFSET);
++ var->right_margin = min_t(u32, var->right_margin,
++ (LCDC_LCDCFG3_HBPW >> LCDC_LCDCFG3_HBPW_OFFSET) + 1);
++ var->hsync_len = min_t(u32, var->hsync_len,
++ (LCDC_LCDCFG1_HSPW >> LCDC_LCDCFG1_HSPW_OFFSET) + 1);
++ var->left_margin = min_t(u32, var->left_margin,
++ (LCDC_LCDCFG3_HFPW >> LCDC_LCDCFG3_HFPW_OFFSET) + 1);
++ } else {
++ var->vsync_len = min_t(u32, var->vsync_len,
++ (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
++ var->upper_margin = min_t(u32, var->upper_margin,
++ ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
++ var->lower_margin = min_t(u32, var->lower_margin,
++ ATMEL_LCDC_VFP);
++ var->right_margin = min_t(u32, var->right_margin,
++ (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
++ var->hsync_len = min_t(u32, var->hsync_len,
++ (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
++ var->left_margin = min_t(u32, var->left_margin,
++ ATMEL_LCDC_HBP + 1);
++ }
+
+ /* Some parameters can't be zero */
+ var->vsync_len = max_t(u32, var->vsync_len, 1);
+@@ -412,10 +531,53 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
+ case 8:
+ var->red.offset = var->green.offset = var->blue.offset = 0;
+ var->red.length = var->green.length = var->blue.length
+- = var->bits_per_pixel;
++ = var->bits_per_pixel;
++ break;
++ case 12:
++ if (cpu_is_at91sam9x5()) {
++ /* RGB:444 mode */
++ var->red.offset = 8;
++ var->blue.offset = 0;
++ var->green.offset = 4;
++ var->red.length = var->green.length = var->blue.length = 4;
++ } else {
++ /*TODO: rework*/
++ BUG();
++ }
+ break;
+ case 15:
++ if (cpu_is_at91sam9x5()) {
++ /* RGB:555 mode */
++ var->red.offset = 10;
++ var->blue.offset = 0;
++ var->green.length = 5;
++ var->red.length = var->green.length = var->blue.length = 5;
++ } else {
++ /*TODO: rework*/
++ BUG();
++ }
++ break;
+ case 16:
++ if (cpu_is_at91sam9x5()) {
++ if (sinfo->alpha_enabled) {
++ /* ARGB:4444 mode */
++ var->red.offset = 8;
++ var->blue.offset = 0;
++ var->green.offset = 4;
++ var->transp.offset = 12;
++ var->red.length = var->green.length
++ = var->blue.length
++ = var->transp.length = 4;
++ } else {
++ /* RGB:565 mode */
++ var->red.offset = 11;
++ var->blue.offset = 0;
++ var->green.offset = 5;
++ var->green.length = 6;
++ var->red.length = var->blue.length = 5;
++ }
++ break;
++ }
+ if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
+ /* RGB:565 mode */
+ var->red.offset = 11;
+@@ -435,6 +597,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
+ var->red.length = var->blue.length = 5;
+ break;
+ case 32:
++ /* TODO 32 & 24 modes */
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ /* fall through */
+@@ -471,6 +634,252 @@ static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
+ atmel_lcdfb_start(sinfo);
+ }
+
++static int atmel_lcdfb_setup_9x5_core(struct fb_info *info)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ unsigned long value;
++ unsigned long clk_value_khz;
++
++ dev_dbg(info->device, "%s:\n", __func__);
++ /* Set pixel clock */
++ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
++
++ value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
++
++ if (value < 1) {
++ dev_notice(info->device, "using system clock as pixel clock\n");
++ value = LCDC_LCDCFG0_CLKPOL | LCDC_LCDCFG0_CLKPWMSEL | LCDC_LCDCFG0_CGDISBASE;
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value);
++ } else {
++ info->var.pixclock = KHZ2PICOS(clk_value_khz / value);
++ dev_dbg(info->device, " updated pixclk: %lu KHz\n",
++ PICOS2KHZ(info->var.pixclock));
++ value = value - 2;
++ dev_dbg(info->device, " * programming CLKDIV = 0x%08lx\n",
++ value);
++ value = (value << LCDC_LCDCFG0_CLKDIV_OFFSET)
++ | LCDC_LCDCFG0_CLKPOL
++ | LCDC_LCDCFG0_CGDISBASE;
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value);
++ }
++
++ /* Initialize control register 5 */
++ value = (sinfo->guard_time << LCDC_LCDCFG5_GUARDTIME_OFFSET)
++ | LCDC_LCDCFG5_DISPDLY
++ | LCDC_LCDCFG5_VSPDLYS;
++
++ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
++ value |= LCDC_LCDCFG5_HSPOL;
++ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
++ value |= LCDC_LCDCFG5_VSPOL;
++
++ switch (info->var.bits_per_pixel) {
++ case 12:
++ value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP;
++ break;
++ case 16:
++ if (info->var.transp.offset != 0)
++ value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP;
++ else
++ value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP;
++ break;
++ case 18:
++ value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP;
++ break;
++ case 24:
++ case 32:
++ value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP;
++ break;
++ default:
++ BUG();
++ break;
++ }
++ dev_dbg(info->device, " * LCDC_LCDCFG5 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG5, value);
++
++ /* Vertical & Horizontal Timing */
++ value = (info->var.vsync_len - 1) << LCDC_LCDCFG1_VSPW_OFFSET;
++ value |= (info->var.hsync_len - 1) << LCDC_LCDCFG1_HSPW_OFFSET;
++ dev_dbg(info->device, " * LCDC_LCDCFG1 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG1, value);
++
++ value = (info->var.lower_margin) << LCDC_LCDCFG2_VBPW_OFFSET;
++ value |= (info->var.upper_margin - 1) << LCDC_LCDCFG2_VFPW_OFFSET;
++ dev_dbg(info->device, " * LCDC_LCDCFG2 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG2, value);
++
++ value = (info->var.right_margin - 1) << LCDC_LCDCFG3_HBPW_OFFSET;
++ value |= (info->var.left_margin - 1) << LCDC_LCDCFG3_HFPW_OFFSET;
++ dev_dbg(info->device, " * LCDC_LCDCFG3 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG3, value);
++
++ /* Display size */
++ value = (info->var.yres - 1) << LCDC_LCDCFG4_RPF_OFFSET;
++ value |= (info->var.xres - 1) << LCDC_LCDCFG4_PPL_OFFSET;
++ dev_dbg(info->device, " * LCDC_LCDCFG4 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG4, value);
++
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG0, LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO);
++ switch (info->var.bits_per_pixel) {
++ case 12:
++ value = LCDC_BASECFG1_RGBMODE_12BPP_RGB_444;
++ break;
++ case 16:
++ if (info->var.transp.offset != 0)
++ value = LCDC_BASECFG1_RGBMODE_16BPP_ARGB_4444;
++ else
++ value = LCDC_BASECFG1_RGBMODE_16BPP_RGB_565;
++ break;
++ case 18:
++ value = LCDC_BASECFG1_RGBMODE_18BPP_RGB_666_PACKED;
++ break;
++ case 24:
++ value = LCDC_BASECFG1_RGBMODE_24BPP_RGB_888_PACKED;
++ break;
++ case 32:
++ value = LCDC_BASECFG1_RGBMODE_32BPP_ARGB_8888;
++ break;
++ default:
++ BUG();
++ break;
++ }
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG1, value);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG2, 0);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG3, 0); /* Default color */
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG4, LCDC_BASECFG4_DMA);
++
++ /* Disable all interrupts */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL);
++ /* Enable BASE LAYER overflow interrupts, if want to enable DMA interrupt, also need set it at LCDC_BASECTRL reg */
++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | LCDC_LCDIER_BASEIE);
++
++ return 0;
++}
++
++static int atmel_lcdfb_setup_core(struct fb_info *info)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ unsigned long hozval_linesz;
++ unsigned long value;
++ unsigned long clk_value_khz;
++ unsigned long pix_factor = 2;
++
++ if (cpu_is_at91sam9x5()) {
++ return atmel_lcdfb_setup_9x5_core(info);
++ } else {
++ /* ...set frame size and burst length = 8 words (?) */
++ value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
++ value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
++ lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
++
++ /* Set pixel clock */
++ if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
++ pix_factor = 1;
++
++ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
++
++ value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
++
++ if (value < pix_factor) {
++ dev_notice(info->device, "Bypassing pixel clock divider\n");
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
++ } else {
++ value = (value / pix_factor) - 1;
++ dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n",
++ value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
++ value << ATMEL_LCDC_CLKVAL_OFFSET);
++ info->var.pixclock =
++ KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
++ dev_dbg(info->device, " updated pixclk: %lu KHz\n",
++ PICOS2KHZ(info->var.pixclock));
++ }
++
++
++ /* Initialize control register 2 */
++ value = sinfo->default_lcdcon2;
++
++ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
++ value |= ATMEL_LCDC_INVLINE_INVERTED;
++ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
++ value |= ATMEL_LCDC_INVFRAME_INVERTED;
++
++ switch (info->var.bits_per_pixel) {
++ case 1:
++ value |= ATMEL_LCDC_PIXELSIZE_1;
++ break;
++ case 2:
++ value |= ATMEL_LCDC_PIXELSIZE_2;
++ break;
++ case 4:
++ value |= ATMEL_LCDC_PIXELSIZE_4;
++ break;
++ case 8:
++ value |= ATMEL_LCDC_PIXELSIZE_8;
++ break;
++ case 15: /* fall through */
++ case 16:
++ value |= ATMEL_LCDC_PIXELSIZE_16;
++ break;
++ case 24:
++ value |= ATMEL_LCDC_PIXELSIZE_24;
++ break;
++ case 32:
++ value |= ATMEL_LCDC_PIXELSIZE_32;
++ break;
++ default:
++ BUG();
++ break;
++ }
++ dev_dbg(info->device, " * LCDCON2 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
++
++ /* Vertical timing */
++ value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
++ value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
++ value |= info->var.lower_margin;
++ dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
++
++ /* Horizontal timing */
++ value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
++ value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
++ value |= (info->var.left_margin - 1);
++ dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
++
++ /* Horizontal value (aka line size) */
++ hozval_linesz = compute_hozval(info->var.xres,
++ lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
++
++ /* Display size */
++ value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
++ value |= info->var.yres - 1;
++ dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
++
++ /* FIFO Threshold: Use formula from data sheet */
++ value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
++ lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
++
++ /* Toggle LCD_MODE every frame */
++ lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
++
++ /* Disable all interrupts */
++ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
++ /* Enable FIFO & DMA errors */
++ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
++
++ /* ...wait for DMA engine to become idle... */
++ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
++ msleep(10);
++
++ return 0;
++ }
++}
++
+ /**
+ * atmel_lcdfb_set_par - Alters the hardware state.
+ * @info: frame buffer structure that represents a single frame buffer
+@@ -488,11 +897,7 @@ static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
+ static int atmel_lcdfb_set_par(struct fb_info *info)
+ {
+ struct atmel_lcdfb_info *sinfo = info->par;
+- unsigned long hozval_linesz;
+- unsigned long value;
+- unsigned long clk_value_khz;
+ unsigned long bits_per_line;
+- unsigned long pix_factor = 2;
+
+ might_sleep();
+
+@@ -517,98 +922,8 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
+ dev_dbg(info->device, " * update DMA engine\n");
+ atmel_lcdfb_update_dma(info, &info->var);
+
+- /* ...set frame size and burst length = 8 words (?) */
+- value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
+- value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
+- lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
+-
+ /* Now, the LCDC core... */
+-
+- /* Set pixel clock */
+- if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
+- pix_factor = 1;
+-
+- clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+-
+- value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
+-
+- if (value < pix_factor) {
+- dev_notice(info->device, "Bypassing pixel clock divider\n");
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
+- } else {
+- value = (value / pix_factor) - 1;
+- dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n",
+- value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
+- value << ATMEL_LCDC_CLKVAL_OFFSET);
+- info->var.pixclock =
+- KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
+- dev_dbg(info->device, " updated pixclk: %lu KHz\n",
+- PICOS2KHZ(info->var.pixclock));
+- }
+-
+-
+- /* Initialize control register 2 */
+- value = sinfo->default_lcdcon2;
+-
+- if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
+- value |= ATMEL_LCDC_INVLINE_INVERTED;
+- if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+- value |= ATMEL_LCDC_INVFRAME_INVERTED;
+-
+- switch (info->var.bits_per_pixel) {
+- case 1: value |= ATMEL_LCDC_PIXELSIZE_1; break;
+- case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
+- case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
+- case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
+- case 15: /* fall through */
+- case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
+- case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
+- case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
+- default: BUG(); break;
+- }
+- dev_dbg(info->device, " * LCDCON2 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
+-
+- /* Vertical timing */
+- value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
+- value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
+- value |= info->var.lower_margin;
+- dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
+-
+- /* Horizontal timing */
+- value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
+- value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
+- value |= (info->var.left_margin - 1);
+- dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
+-
+- /* Horizontal value (aka line size) */
+- hozval_linesz = compute_hozval(info->var.xres,
+- lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
+-
+- /* Display size */
+- value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
+- value |= info->var.yres - 1;
+- dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
+-
+- /* FIFO Threshold: Use formula from data sheet */
+- value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
+- lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
+-
+- /* Toggle LCD_MODE every frame */
+- lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
+-
+- /* Disable all interrupts */
+- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
+- /* Enable FIFO & DMA errors */
+- lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
+-
+- /* ...wait for DMA engine to become idle... */
+- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+- msleep(10);
++ atmel_lcdfb_setup_core(info);
+
+ atmel_lcdfb_start(sinfo);
+
+@@ -755,14 +1070,32 @@ static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
+ struct fb_info *info = dev_id;
+ struct atmel_lcdfb_info *sinfo = info->par;
+ u32 status;
++ u32 baselayer_status;
++
++ if (cpu_is_at91sam9x5()) {
++ /* Check for error status via interrupt.*/
++ status = lcdc_readl(sinfo, ATMEL_LCDC_LCDISR);
++ if (status & LCDC_LCDISR_FIFOERR) {
++ dev_warn(info->device, "FIFO underflow %#x\n", status);
++ } else if (status & LCDC_LCDISR_BASE) {
++ /* Check base layer's overflow error. */
++ baselayer_status = lcdc_readl(sinfo, ATMEL_LCDC_BASEISR);
++
++ if (baselayer_status & LCDC_BASEISR_OVR)
++ dev_warn(info->device, "base layer overflow %#x\n",
++ baselayer_status);
+
+- status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
+- if (status & ATMEL_LCDC_UFLWI) {
+- dev_warn(info->device, "FIFO underflow %#x\n", status);
+- /* reset DMA and FIFO to avoid screen shifting */
+- schedule_work(&sinfo->task);
++ }
++ } else {
++ status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
++ if (status & ATMEL_LCDC_UFLWI) {
++ dev_warn(info->device, "FIFO underflow %#x\n", status);
++ /* reset DMA and FIFO to avoid screen shifting */
++ schedule_work(&sinfo->task);
++ }
++ lcdc_writel(sinfo, ATMEL_LCDC_ICR, status);
+ }
+- lcdc_writel(sinfo, ATMEL_LCDC_ICR, status);
++
+ return IRQ_HANDLED;
+ }
+
+@@ -903,6 +1236,8 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+
+ /* Initialize video memory */
+ map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ sinfo->p_dma_desc = NULL;
++ sinfo->dma_desc_phys = 0;
+ if (map) {
+ /* use a pre-allocated memory buffer */
+ info->fix.smem_start = map->start;
+@@ -1013,7 +1348,7 @@ unmap_mmio:
+ exit_backlight(sinfo);
+ iounmap(sinfo->mmio);
+ release_mem:
+- release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
++ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+ free_fb:
+ if (map)
+ iounmap(info->screen_base);
+@@ -1058,7 +1393,7 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
+ fb_dealloc_cmap(&info->cmap);
+ free_irq(sinfo->irq_base, info);
+ iounmap(sinfo->mmio);
+- release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
++ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+ if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) {
+ iounmap(info->screen_base);
+ release_mem_region(info->fix.smem_start, info->fix.smem_len);
+@@ -1083,10 +1418,17 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
+ * We don't want to handle interrupts while the clock is
+ * stopped. It may take forever.
+ */
+- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
++ if (cpu_is_at91sam9x5()) {
++ /* Disable all interrupts */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL);
++ } else {
++ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
++
++ sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
++ }
+
+- sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
+ if (sinfo->atmel_lcdfb_power_control)
+ sinfo->atmel_lcdfb_power_control(0);
+
+@@ -1105,11 +1447,18 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
+ atmel_lcdfb_start(sinfo);
+ if (sinfo->atmel_lcdfb_power_control)
+ sinfo->atmel_lcdfb_power_control(1);
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon);
+
+- /* Enable FIFO & DMA errors */
+- lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI
+- | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
++ if (cpu_is_at91sam9x5()) {
++ /* Enable fifo error & BASE LAYER overflow interrupts */
++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | LCDC_LCDIER_BASEIE);
++ } else {
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon);
++
++ /* Enable FIFO & DMA errors */
++ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI
++ | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
++ }
+
+ return 0;
+ }
+diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
+index 28447f1..5183ab7 100644
+--- a/include/video/atmel_lcdc.h
++++ b/include/video/atmel_lcdc.h
+@@ -47,12 +47,16 @@ struct atmel_lcdfb_info {
+ struct clk *bus_clk;
+ struct clk *lcdc_clk;
+
++ struct lcd_dma_desc *p_dma_desc;
++ dma_addr_t dma_desc_phys;
++
+ #ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+ struct backlight_device *backlight;
+ u8 bl_power;
+ #endif
+ bool lcdcon_is_backlight;
+ bool lcdcon_pol_negative;
++ bool alpha_enabled;
+ u8 saved_lcdcon;
+
+ u8 default_bpp;
+@@ -64,6 +68,12 @@ struct atmel_lcdfb_info {
+ u32 pseudo_palette[16];
+ };
+
++struct lcd_dma_desc {
++ u32 address;
++ u32 control;
++ u32 next;
++};
++
+ #define ATMEL_LCDC_DMABADDR1 0x00
+ #define ATMEL_LCDC_DMABADDR2 0x04
+ #define ATMEL_LCDC_DMAFRMPT1 0x08
+@@ -214,6 +224,11 @@ struct atmel_lcdfb_info {
+ #define ATMEL_LCDC_OWRI (1 << 5)
+ #define ATMEL_LCDC_MERI (1 << 6)
+
++#if !defined(CONFIG_ARCH_AT91SAM9X5)
+ #define ATMEL_LCDC_LUT(n) (0x0c00 + ((n)*4))
++#else
++/* Base layer CLUT */
++#define ATMEL_LCDC_LUT(n) (0x0400 + ((n)*4))
++#endif
+
+ #endif /* __ATMEL_LCDC_H__ */
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0021-video-atmel_lcdfb-The-output-bpp-should-not-change-a.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0021-video-atmel_lcdfb-The-output-bpp-should-not-change-a.patch
new file mode 100644
index 0000000..4e6b7f3
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0021-video-atmel_lcdfb-The-output-bpp-should-not-change-a.patch
@@ -0,0 +1,66 @@
+From f3d06832afe329d55759ec28d719925a10abc7ac Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Wed, 9 Mar 2011 11:21:51 +0800
+Subject: [PATCH 021/107] video/atmel_lcdfb: The output bpp should not change
+ according to memory bpp
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The 9x5-ek using 24 bits output for its connection to LCD screen.
+The output bpp can now be configurated in board file.
+
+XXX: these are two different changes?
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/atmel_lcdfb.c | 25 +++----------------------
+ 1 files changed, 3 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index fa9431b..7ba17cb 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -664,7 +664,9 @@ static int atmel_lcdfb_setup_9x5_core(struct fb_info *info)
+ }
+
+ /* Initialize control register 5 */
+- value = (sinfo->guard_time << LCDC_LCDCFG5_GUARDTIME_OFFSET)
++ /* In 9x5, the default_lcdcon2 will use for LCDCFG5 */
++ value = sinfo->default_lcdcon2;
++ value |= (sinfo->guard_time << LCDC_LCDCFG5_GUARDTIME_OFFSET)
+ | LCDC_LCDCFG5_DISPDLY
+ | LCDC_LCDCFG5_VSPDLYS;
+
+@@ -673,27 +675,6 @@ static int atmel_lcdfb_setup_9x5_core(struct fb_info *info)
+ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+ value |= LCDC_LCDCFG5_VSPOL;
+
+- switch (info->var.bits_per_pixel) {
+- case 12:
+- value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP;
+- break;
+- case 16:
+- if (info->var.transp.offset != 0)
+- value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP;
+- else
+- value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP;
+- break;
+- case 18:
+- value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP;
+- break;
+- case 24:
+- case 32:
+- value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP;
+- break;
+- default:
+- BUG();
+- break;
+- }
+ dev_dbg(info->device, " * LCDC_LCDCFG5 = %08lx\n", value);
+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG5, value);
+
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0022-input-atmel_tsadcc-add-support-for-ARCH_AT91SAM9X5.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0022-input-atmel_tsadcc-add-support-for-ARCH_AT91SAM9X5.patch
new file mode 100644
index 0000000..042b118
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0022-input-atmel_tsadcc-add-support-for-ARCH_AT91SAM9X5.patch
@@ -0,0 +1,410 @@
+From e8a10c60910fc34ef8d0ac97e19cc8efef10680c Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Wed, 17 Nov 2010 12:28:13 +0100
+Subject: [PATCH 022/107] input: atmel_tsadcc: add support for ARCH_AT91SAM9X5
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+XXX: split header creation in a new patch (or don't do it)
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/input/touchscreen/Kconfig | 2 +-
+ drivers/input/touchscreen/atmel_tsadcc.c | 150 +++++++++++-----------------
+ drivers/input/touchscreen/atmel_tsadcc.h | 162 ++++++++++++++++++++++++++++++
+ 3 files changed, 223 insertions(+), 91 deletions(-)
+ create mode 100644 drivers/input/touchscreen/atmel_tsadcc.h
+
+diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
+index 434fd80..4b252ce 100644
+--- a/drivers/input/touchscreen/Kconfig
++++ b/drivers/input/touchscreen/Kconfig
+@@ -397,7 +397,7 @@ config TOUCHSCREEN_TOUCHWIN
+
+ config TOUCHSCREEN_ATMEL_TSADCC
+ tristate "Atmel Touchscreen Interface"
+- depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
++ depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 || ARCH_AT91SAM9X5
+ help
+ Say Y here if you have a 4-wire touchscreen connected to the
+ ADC Controller on your Atmel SoC (such as the AT91SAM9RL).
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
+index 3d9b516..f307b6e 100644
+--- a/drivers/input/touchscreen/atmel_tsadcc.c
++++ b/drivers/input/touchscreen/atmel_tsadcc.c
+@@ -25,74 +25,9 @@
+ #include <mach/board.h>
+ #include <mach/cpu.h>
+
+-/* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */
+-
+-#define ATMEL_TSADCC_CR 0x00 /* Control register */
+-#define ATMEL_TSADCC_SWRST (1 << 0) /* Software Reset*/
+-#define ATMEL_TSADCC_START (1 << 1) /* Start conversion */
+-
+-#define ATMEL_TSADCC_MR 0x04 /* Mode register */
+-#define ATMEL_TSADCC_TSAMOD (3 << 0) /* ADC mode */
+-#define ATMEL_TSADCC_TSAMOD_ADC_ONLY_MODE (0x0) /* ADC Mode */
+-#define ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE (0x1) /* Touch Screen Only Mode */
+-#define ATMEL_TSADCC_LOWRES (1 << 4) /* Resolution selection */
+-#define ATMEL_TSADCC_SLEEP (1 << 5) /* Sleep mode */
+-#define ATMEL_TSADCC_PENDET (1 << 6) /* Pen Detect selection */
+-#define ATMEL_TSADCC_PRES (1 << 7) /* Pressure Measurement Selection */
+-#define ATMEL_TSADCC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */
+-#define ATMEL_TSADCC_EPRESCAL (0xff << 8) /* Prescalar Rate Selection (Extended) */
+-#define ATMEL_TSADCC_STARTUP (0x7f << 16) /* Start Up time */
+-#define ATMEL_TSADCC_SHTIM (0xf << 24) /* Sample & Hold time */
+-#define ATMEL_TSADCC_PENDBC (0xf << 28) /* Pen Detect debouncing time */
+-
+-#define ATMEL_TSADCC_TRGR 0x08 /* Trigger register */
+-#define ATMEL_TSADCC_TRGMOD (7 << 0) /* Trigger mode */
+-#define ATMEL_TSADCC_TRGMOD_NONE (0 << 0)
+-#define ATMEL_TSADCC_TRGMOD_EXT_RISING (1 << 0)
+-#define ATMEL_TSADCC_TRGMOD_EXT_FALLING (2 << 0)
+-#define ATMEL_TSADCC_TRGMOD_EXT_ANY (3 << 0)
+-#define ATMEL_TSADCC_TRGMOD_PENDET (4 << 0)
+-#define ATMEL_TSADCC_TRGMOD_PERIOD (5 << 0)
+-#define ATMEL_TSADCC_TRGMOD_CONTINUOUS (6 << 0)
+-#define ATMEL_TSADCC_TRGPER (0xffff << 16) /* Trigger period */
+-
+-#define ATMEL_TSADCC_TSR 0x0C /* Touch Screen register */
+-#define ATMEL_TSADCC_TSFREQ (0xf << 0) /* TS Frequency in Interleaved mode */
+-#define ATMEL_TSADCC_TSSHTIM (0xf << 24) /* Sample & Hold time */
+-
+-#define ATMEL_TSADCC_CHER 0x10 /* Channel Enable register */
+-#define ATMEL_TSADCC_CHDR 0x14 /* Channel Disable register */
+-#define ATMEL_TSADCC_CHSR 0x18 /* Channel Status register */
+-#define ATMEL_TSADCC_CH(n) (1 << (n)) /* Channel number */
+-
+-#define ATMEL_TSADCC_SR 0x1C /* Status register */
+-#define ATMEL_TSADCC_EOC(n) (1 << ((n)+0)) /* End of conversion for channel N */
+-#define ATMEL_TSADCC_OVRE(n) (1 << ((n)+8)) /* Overrun error for channel N */
+-#define ATMEL_TSADCC_DRDY (1 << 16) /* Data Ready */
+-#define ATMEL_TSADCC_GOVRE (1 << 17) /* General Overrun Error */
+-#define ATMEL_TSADCC_ENDRX (1 << 18) /* End of RX Buffer */
+-#define ATMEL_TSADCC_RXBUFF (1 << 19) /* TX Buffer full */
+-#define ATMEL_TSADCC_PENCNT (1 << 20) /* Pen contact */
+-#define ATMEL_TSADCC_NOCNT (1 << 21) /* No contact */
+-
+-#define ATMEL_TSADCC_LCDR 0x20 /* Last Converted Data register */
+-#define ATMEL_TSADCC_DATA (0x3ff << 0) /* Channel data */
+-
+-#define ATMEL_TSADCC_IER 0x24 /* Interrupt Enable register */
+-#define ATMEL_TSADCC_IDR 0x28 /* Interrupt Disable register */
+-#define ATMEL_TSADCC_IMR 0x2C /* Interrupt Mask register */
+-#define ATMEL_TSADCC_CDR0 0x30 /* Channel Data 0 */
+-#define ATMEL_TSADCC_CDR1 0x34 /* Channel Data 1 */
+-#define ATMEL_TSADCC_CDR2 0x38 /* Channel Data 2 */
+-#define ATMEL_TSADCC_CDR3 0x3C /* Channel Data 3 */
+-#define ATMEL_TSADCC_CDR4 0x40 /* Channel Data 4 */
+-#define ATMEL_TSADCC_CDR5 0x44 /* Channel Data 5 */
+-
+-#define ATMEL_TSADCC_XPOS 0x50
+-#define ATMEL_TSADCC_Z1DAT 0x54
+-#define ATMEL_TSADCC_Z2DAT 0x58
+-
+-#define PRESCALER_VAL(x) ((x) >> 8)
++#include "atmel_tsadcc.h"
++
++#define cpu_has_9x5_adc() (cpu_is_at91sam9x5())
+
+ #define ADC_DEFAULT_CLOCK 100000
+
+@@ -124,12 +59,17 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+
+ if (status & ATMEL_TSADCC_NOCNT) {
+ /* Contact lost */
+- reg = atmel_tsadcc_read(ATMEL_TSADCC_MR) | ATMEL_TSADCC_PENDBC;
+-
+- atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
++ if (cpu_has_9x5_adc()) {
++ /* 9X5 using TSMR to set PENDBC time */
++ reg = atmel_tsadcc_read(ATMEL_TSADCC_TSMR) | ATMEL_TSADCC_PENDBC;
++ atmel_tsadcc_write(ATMEL_TSADCC_TSMR, reg);
++ } else {
++ reg = atmel_tsadcc_read(ATMEL_TSADCC_MR) | ATMEL_TSADCC_PENDBC;
++ atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
++ }
+ atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE);
+ atmel_tsadcc_write(ATMEL_TSADCC_IDR,
+- ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT);
++ ATMEL_TSADCC_CONVERSION_END | ATMEL_TSADCC_NOCNT);
+ atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
+
+ input_report_key(input_dev, BTN_TOUCH, 0);
+@@ -138,23 +78,31 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+
+ } else if (status & ATMEL_TSADCC_PENCNT) {
+ /* Pen detected */
+- reg = atmel_tsadcc_read(ATMEL_TSADCC_MR);
+- reg &= ~ATMEL_TSADCC_PENDBC;
++ if (cpu_has_9x5_adc()) {
++ reg = atmel_tsadcc_read(ATMEL_TSADCC_TSMR);
++ reg &= ~ATMEL_TSADCC_PENDBC;
++ atmel_tsadcc_write(ATMEL_TSADCC_TSMR, reg);
++ } else {
++ reg = atmel_tsadcc_read(ATMEL_TSADCC_MR);
++ reg &= ~ATMEL_TSADCC_PENDBC;
++ atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
++ }
+
+ atmel_tsadcc_write(ATMEL_TSADCC_IDR, ATMEL_TSADCC_PENCNT);
+- atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
+ atmel_tsadcc_write(ATMEL_TSADCC_IER,
+- ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT);
++ ATMEL_TSADCC_CONVERSION_END | ATMEL_TSADCC_NOCNT);
+ atmel_tsadcc_write(ATMEL_TSADCC_TRGR,
+ ATMEL_TSADCC_TRGMOD_PERIOD | (0x0FFF << 16));
+
+- } else if (status & ATMEL_TSADCC_EOC(3)) {
++ } else if ((status & ATMEL_TSADCC_CONVERSION_END) == ATMEL_TSADCC_CONVERSION_END) {
+ /* Conversion finished */
+
+ if (ts_dev->bufferedmeasure) {
+ /* Last measurement is always discarded, since it can
+ * be erroneous.
+ * Always report previous measurement */
++ dev_dbg(&input_dev->dev, "x = %d, y = %d\n",
++ ts_dev->prev_absx, ts_dev->prev_absy);
+ input_report_abs(input_dev, ABS_X, ts_dev->prev_absx);
+ input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy);
+ input_report_key(input_dev, BTN_TOUCH, 1);
+@@ -163,11 +111,16 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ ts_dev->bufferedmeasure = 1;
+
+ /* Now make new measurement */
+- ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10;
+- ts_dev->prev_absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2);
+-
+- ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10;
+- ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0);
++ if (cpu_has_9x5_adc()) {
++ ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_XPOSR) & 0xffff;
++ ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_YPOSR) & 0xffff;
++ } else {
++ ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10;
++ ts_dev->prev_absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2);
++
++ ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10;
++ ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0);
++ }
+ }
+
+ return IRQ_HANDLED;
+@@ -284,18 +237,35 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+
+ dev_info(&pdev->dev, "Prescaler is set at: %d\n", prsc);
+
+- reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE |
+- ((0x00 << 5) & ATMEL_TSADCC_SLEEP) | /* Normal Mode */
+- ((0x01 << 6) & ATMEL_TSADCC_PENDET) | /* Enable Pen Detect */
+- (prsc << 8) |
+- ((0x26 << 16) & ATMEL_TSADCC_STARTUP) |
+- ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC);
++ if (cpu_has_9x5_adc()) {
++ reg = ((0x01 << 5) & ATMEL_TSADCC_SLEEP) | /* Sleep Mode */
++ (prsc << 8) |
++ ((0x8 << 16) & ATMEL_TSADCC_STARTUP) |
++ ((pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TRACKTIM);
++ } else {
++ reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE |
++ ((0x00 << 5) & ATMEL_TSADCC_SLEEP) | /* Normal Mode */
++ ((0x01 << 6) & ATMEL_TSADCC_PENDET) | /* Enable Pen Detect */
++ (prsc << 8) |
++ ((0x26 << 16) & ATMEL_TSADCC_STARTUP) |
++ ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC);
++ }
+
+ atmel_tsadcc_write(ATMEL_TSADCC_CR, ATMEL_TSADCC_SWRST);
+ atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
+ atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE);
+- atmel_tsadcc_write(ATMEL_TSADCC_TSR,
+- (pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM);
++
++ if (cpu_has_9x5_adc()) {
++ atmel_tsadcc_write(ATMEL_TSADCC_TSMR,
++ ATMEL_TSADCC_TSMODE_4WIRE_NO_PRESS |
++ ATMEL_TSADCC_NOTSDMA |
++ ATMEL_TSADCC_PENDET_ENA |
++ (pdata->pendet_debounce << 28) |
++ (0x0 << 8));
++ } else {
++ atmel_tsadcc_write(ATMEL_TSADCC_TSR,
++ (pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM);
++ }
+
+ atmel_tsadcc_read(ATMEL_TSADCC_SR);
+ atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.h b/drivers/input/touchscreen/atmel_tsadcc.h
+new file mode 100644
+index 0000000..5918c20
+--- /dev/null
++++ b/drivers/input/touchscreen/atmel_tsadcc.h
+@@ -0,0 +1,162 @@
++/*
++ * Header file for AT91/AT32 ADC + touchscreen Controller
++ *
++ * Data structure and register user interface
++ *
++ * Copyright (C) 2010 Atmel Corporation
++ *
++ * 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.
++ *
++ * 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 __ATMEL_TSADCC_H__
++#define __ATMEL_TSADCC_H__
++
++/* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */
++#define ATMEL_TSADCC_CR 0x00 /* Control register */
++#define ATMEL_TSADCC_SWRST (1 << 0) /* Software Reset*/
++#define ATMEL_TSADCC_START (1 << 1) /* Start conversion */
++
++#define ATMEL_TSADCC_MR 0x04 /* Mode register */
++#define ATMEL_TSADCC_TSAMOD (3 << 0) /* ADC mode */
++#define ATMEL_TSADCC_TSAMOD_ADC_ONLY_MODE (0x0) /* ADC Mode */
++#define ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE (0x1) /* Touch Screen Only Mode */
++#define ATMEL_TSADCC_LOWRES (1 << 4) /* Resolution selection */
++#define ATMEL_TSADCC_SLEEP (1 << 5) /* Sleep mode */
++#define ATMEL_TSADCC_PENDET (1 << 6) /* Pen Detect selection */
++#define ATMEL_TSADCC_PRES (1 << 7) /* Pressure Measurement Selection */
++#define ATMEL_TSADCC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */
++#define ATMEL_TSADCC_EPRESCAL (0xff << 8) /* Prescalar Rate Selection (Extended) */
++#define ATMEL_TSADCC_STARTUP (0x7f << 16) /* Start Up time */
++#define ATMEL_TSADCC_SHTIM (0xf << 24) /* Sample & Hold time */
++#define ATMEL_TSADCC_PENDBC (0xf << 28) /* Pen Detect debouncing time */
++
++#define ATMEL_TSADCC_TRGR 0x08 /* Trigger register */
++#define ATMEL_TSADCC_TRGMOD (7 << 0) /* Trigger mode */
++#define ATMEL_TSADCC_TRGMOD_NONE (0 << 0)
++#define ATMEL_TSADCC_TRGMOD_EXT_RISING (1 << 0)
++#define ATMEL_TSADCC_TRGMOD_EXT_FALLING (2 << 0)
++#define ATMEL_TSADCC_TRGMOD_EXT_ANY (3 << 0)
++#define ATMEL_TSADCC_TRGMOD_PENDET (4 << 0)
++#define ATMEL_TSADCC_TRGMOD_PERIOD (5 << 0)
++#define ATMEL_TSADCC_TRGMOD_CONTINUOUS (6 << 0)
++#define ATMEL_TSADCC_TRGPER (0xffff << 16) /* Trigger period */
++
++#define ATMEL_TSADCC_TSR 0x0C /* Touch Screen register */
++#define ATMEL_TSADCC_TSFREQ (0xf << 0) /* TS Frequency in Interleaved mode */
++#define ATMEL_TSADCC_TSSHTIM (0xf << 24) /* Sample & Hold time */
++
++#define ATMEL_TSADCC_CHER 0x10 /* Channel Enable register */
++#define ATMEL_TSADCC_CHDR 0x14 /* Channel Disable register */
++#define ATMEL_TSADCC_CHSR 0x18 /* Channel Status register */
++#define ATMEL_TSADCC_CH(n) (1 << (n)) /* Channel number */
++
++#define ATMEL_TSADCC_SR 0x1C /* Status register */
++#define ATMEL_TSADCC_EOC(n) (1 << ((n)+0)) /* End of conversion for channel N */
++#define ATMEL_TSADCC_OVRE(n) (1 << ((n)+8)) /* Overrun error for channel N */
++#define ATMEL_TSADCC_DRDY (1 << 16) /* Data Ready */
++#define ATMEL_TSADCC_GOVRE (1 << 17) /* General Overrun Error */
++#define ATMEL_TSADCC_ENDRX (1 << 18) /* End of RX Buffer */
++#define ATMEL_TSADCC_RXBUFF (1 << 19) /* TX Buffer full */
++#define ATMEL_TSADCC_PENCNT (1 << 20) /* Pen contact */
++#define ATMEL_TSADCC_NOCNT (1 << 21) /* No contact */
++
++#define ATMEL_TSADCC_LCDR 0x20 /* Last Converted Data register */
++#define ATMEL_TSADCC_DATA (0x3ff << 0) /* Channel data */
++
++#define ATMEL_TSADCC_IER 0x24 /* Interrupt Enable register */
++#define ATMEL_TSADCC_IDR 0x28 /* Interrupt Disable register */
++#define ATMEL_TSADCC_IMR 0x2C /* Interrupt Mask register */
++#define ATMEL_TSADCC_CDR0 0x30 /* Channel Data 0 */
++#define ATMEL_TSADCC_CDR1 0x34 /* Channel Data 1 */
++#define ATMEL_TSADCC_CDR2 0x38 /* Channel Data 2 */
++#define ATMEL_TSADCC_CDR3 0x3C /* Channel Data 3 */
++#define ATMEL_TSADCC_CDR4 0x40 /* Channel Data 4 */
++#define ATMEL_TSADCC_CDR5 0x44 /* Channel Data 5 */
++
++#define ATMEL_TSADCC_XPOS 0x50
++#define ATMEL_TSADCC_Z1DAT 0x54
++#define ATMEL_TSADCC_Z2DAT 0x58
++
++#define ATMEL_TSADCC_CONVERSION_END (ATMEL_TSADCC_EOC(3))
++
++/* Register definitions based on AT91SAM9X5 preliminary draft datasheet */
++#define ATMEL_TSADCC_TRACKTIM (0x0f << 24) /* Tracking Time */
++
++#define ATMEL_TSADCC_ISR 0x30 /* Interrupt Status register */
++#define ATMEL_TSADCC_XRDY (1 << 20) /* Measure XPOS Ready */
++#define ATMEL_TSADCC_YRDY (1 << 21) /* Measure YPOS Ready */
++#define ATMEL_TSADCC_PRDY (1 << 22) /* Measure Pressure Ready */
++#define ATMEL_TSADCC_COMPE (1 << 26) /* Comparison Event */
++#define ATMEL_TSADCC_PEN (1 << 29) /* Pen Contact */
++#define ATMEL_TSADCC_NOPEN (1 << 30) /* No Pen Contact */
++#define ATMEL_TSADCC_PENDET_STATUS (1 << 31) /* Pen Detect Status (not interrupt source) */
++
++#define ATMEL_TSADCC_TSMR 0xb0
++#define ATMEL_TSADCC_TSMODE (3 << 0) /* Touch Screen Mode */
++#define ATMEL_TSADCC_TSMODE_NO (0 << 0) /* No Touch Screen */
++#define ATMEL_TSADCC_TSMODE_4WIRE_NO_PRESS (1 << 0) /* 4-wire Touch Screen without pressure measurement */
++#define ATMEL_TSADCC_TSMODE_4WIRE_PRESS (2 << 0) /* 4-wire Touch Screen with pressure measurement */
++#define ATMEL_TSADCC_TSMODE_5WIRE (3 << 0) /* 5-wire Touch Screen */
++#define ATMEL_TSADCC_TSAV (3 << 4) /* Touch Screen Average */
++#define ATMEL_TSADCC_TSAV_1 (0 << 4) /* No filtering. Only one conversion ADC per measure */
++#define ATMEL_TSADCC_TSAV_2 (1 << 4) /* Averages 2 ADC conversions */
++#define ATMEL_TSADCC_TSAV_4 (2 << 4) /* Averages 4 ADC conversions */
++#define ATMEL_TSADCC_TSAV_8 (3 << 4) /* Averages 8 ADC conversions */
++#define ATMEL_TSADCC_TSSCTIM (0x0f << 16) /* Touch Screen switches closure time */
++
++#define ATMEL_TSADCC_NOTSDMA (1 << 22) /* No Touchscreen DMA */
++#define ATMEL_TSADCC_PENDET_DIS (0 << 24) /* Pen contact detection disable */
++#define ATMEL_TSADCC_PENDET_ENA (1 << 24) /* Pen contact detection enable */
++
++#define ATMEL_TSADCC_XPOSR 0xb4
++#define ATMEL_TSADCC_XSCALE (0x3ff << 16) /* Scale of X Position */
++
++#define ATMEL_TSADCC_YPOSR 0xb8
++#define ATMEL_TSADCC_YPOS (0x3ff << 0) /* Y Position */
++#define ATMEL_TSADCC_YSCALE (0x3ff << 16) /* Scale of Y Position */
++
++/* 9x5 ADC registers which conflict with previous definition */
++#ifdef CONFIG_ARCH_AT91SAM9X5
++#undef ATMEL_TSADCC_TRGR
++#undef ATMEL_TSADCC_SR
++#define ATMEL_TSADCC_SR ATMEL_TSADCC_ISR
++#define ATMEL_TSADCC_TRGR 0xc0
++
++/* For code compatiable, redefine with 9x5 value */
++#undef ATMEL_TSADCC_STARTUP
++#define ATMEL_TSADCC_STARTUP (0x0f << 16) /* Startup Time */
++#undef ATMEL_TSADCC_DRDY
++#define ATMEL_TSADCC_DRDY (1 << 24) /* Data Ready */
++#undef ATMEL_TSADCC_GOVRE
++#define ATMEL_TSADCC_GOVRE (1 << 25) /* General Overrun */
++#undef ATMEL_TSADCC_TSFREQ
++#define ATMEL_TSADCC_TSFREQ (0x0f << 8) /* Touch Screen Frequency */
++#undef ATMEL_TSADCC_PENDET
++#define ATMEL_TSADCC_PENDET (1 << 24) /* Pen Contact Detection Enable */
++#undef ATMEL_TSADCC_XPOS
++#define ATMEL_TSADCC_XPOS (0x3ff << 0) /* X Position */
++
++#undef ATMEL_TSADCC_NOCNT
++#define ATMEL_TSADCC_NOCNT ATMEL_TSADCC_NOPEN
++#undef ATMEL_TSADCC_PENCNT
++#define ATMEL_TSADCC_PENCNT ATMEL_TSADCC_PEN
++#undef ATMEL_TSADCC_CONVERSION_END
++#define ATMEL_TSADCC_CONVERSION_END (ATMEL_TSADCC_XRDY | ATMEL_TSADCC_YRDY | ATMEL_TSADCC_PRDY)
++
++#endif
++
++/* Retrieve prescaler value */
++#define PRESCALER_VAL(x) ((x) >> 8)
++
++#endif /* __ATMEL_TSADCC_H__ */
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0023-input-atmel_tsadcc-add-touch-screen-pressure-measure.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0023-input-atmel_tsadcc-add-touch-screen-pressure-measure.patch
new file mode 100644
index 0000000..3597bba
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0023-input-atmel_tsadcc-add-touch-screen-pressure-measure.patch
@@ -0,0 +1,109 @@
+From b119d5f73277fc94d42927cb998333844d9c8fb1 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Wed, 17 Nov 2010 13:12:11 +0100
+Subject: [PATCH 023/107] input: atmel_tsadcc: add touch screen pressure
+ measurement
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/input/touchscreen/atmel_tsadcc.c | 26 +++++++++++++++++++++++---
+ drivers/input/touchscreen/atmel_tsadcc.h | 4 ++++
+ 2 files changed, 27 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
+index f307b6e..732b99b 100644
+--- a/drivers/input/touchscreen/atmel_tsadcc.c
++++ b/drivers/input/touchscreen/atmel_tsadcc.c
+@@ -38,6 +38,7 @@ struct atmel_tsadcc {
+ int irq;
+ unsigned int prev_absx;
+ unsigned int prev_absy;
++ unsigned int prev_absz;
+ unsigned char bufferedmeasure;
+ };
+
+@@ -53,6 +54,9 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+
+ unsigned int status;
+ unsigned int reg;
++ unsigned int z1, z2;
++ unsigned int Rxp = 1;
++ unsigned int factor = 1000;
+
+ status = atmel_tsadcc_read(ATMEL_TSADCC_SR);
+ status &= atmel_tsadcc_read(ATMEL_TSADCC_IMR);
+@@ -101,11 +105,15 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ /* Last measurement is always discarded, since it can
+ * be erroneous.
+ * Always report previous measurement */
+- dev_dbg(&input_dev->dev, "x = %d, y = %d\n",
+- ts_dev->prev_absx, ts_dev->prev_absy);
++ dev_dbg(&input_dev->dev,
++ "x = %d, y = %d, pressure = %d\n",
++ ts_dev->prev_absx, ts_dev->prev_absy,
++ ts_dev->prev_absz);
+ input_report_abs(input_dev, ABS_X, ts_dev->prev_absx);
+ input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy);
+ input_report_key(input_dev, BTN_TOUCH, 1);
++ if (cpu_has_9x5_adc())
++ input_report_abs(input_dev, ABS_PRESSURE, ts_dev->prev_absz);
+ input_sync(input_dev);
+ } else
+ ts_dev->bufferedmeasure = 1;
+@@ -114,6 +122,17 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ if (cpu_has_9x5_adc()) {
+ ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_XPOSR) & 0xffff;
+ ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_YPOSR) & 0xffff;
++
++ /* calculate the pressure */
++ reg = atmel_tsadcc_read(ATMEL_TSADCC_PRESSR);
++ z1 = reg & ATMEL_TSADCC_PRESSR_Z1;
++ z2 = (reg & ATMEL_TSADCC_PRESSR_Z2) >> 16;
++
++ if (z1 != 0)
++ ts_dev->prev_absz = Rxp * (ts_dev->prev_absx * factor / 1024) * (z2 * factor / z1 - factor) / factor;
++ else
++ ts_dev->prev_absz = 0;
++
+ } else {
+ ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10;
+ ts_dev->prev_absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2);
+@@ -209,6 +228,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+ __set_bit(EV_ABS, input_dev->evbit);
+ input_set_abs_params(input_dev, ABS_X, 0, 0x3FF, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, 0x3FF, 0, 0);
++ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xffffff, 0, 0);
+
+ input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
+
+@@ -257,7 +277,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+
+ if (cpu_has_9x5_adc()) {
+ atmel_tsadcc_write(ATMEL_TSADCC_TSMR,
+- ATMEL_TSADCC_TSMODE_4WIRE_NO_PRESS |
++ ATMEL_TSADCC_TSMODE_4WIRE_PRESS |
+ ATMEL_TSADCC_NOTSDMA |
+ ATMEL_TSADCC_PENDET_ENA |
+ (pdata->pendet_debounce << 28) |
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.h b/drivers/input/touchscreen/atmel_tsadcc.h
+index 5918c20..231497e 100644
+--- a/drivers/input/touchscreen/atmel_tsadcc.h
++++ b/drivers/input/touchscreen/atmel_tsadcc.h
+@@ -126,6 +126,10 @@
+ #define ATMEL_TSADCC_YPOS (0x3ff << 0) /* Y Position */
+ #define ATMEL_TSADCC_YSCALE (0x3ff << 16) /* Scale of Y Position */
+
++#define ATMEL_TSADCC_PRESSR 0xbc /* Touchscreen Pressure Register */
++#define ATMEL_TSADCC_PRESSR_Z1 (0x3ff << 0) /* Data of Z1 Measurement */
++#define ATMEL_TSADCC_PRESSR_Z2 (0x3ff << 16) /* Data of Z2 Measurement */
++
+ /* 9x5 ADC registers which conflict with previous definition */
+ #ifdef CONFIG_ARCH_AT91SAM9X5
+ #undef ATMEL_TSADCC_TRGR
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0024-input-atmel_tsadcc-enable-touchscreen-averaging-and-.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0024-input-atmel_tsadcc-enable-touchscreen-averaging-and-.patch
new file mode 100644
index 0000000..8a0b499
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0024-input-atmel_tsadcc-enable-touchscreen-averaging-and-.patch
@@ -0,0 +1,81 @@
+From fb7765b71accce169455b701eda556fb981a78eb Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Tue, 5 Apr 2011 17:30:03 +0200
+Subject: [PATCH 024/107] input: atmel_tsadcc: enable touchscreen averaging
+ and add fast wake up
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Enable the touchscreen average to improve the resulting events. For this
+to work the trigger period needs to be reduced.
+
+This puts a field into at91_tsadcc_data to allow platforms to specify
+the number of conversions to average over.
+
+XXX: should the trigger period passed by the platform, too, as this
+depends on the number of conversions?
+XXX: seperate fast wake up into a seperate patch? What does it?
+XXX: don't use bare constants
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/input/touchscreen/atmel_tsadcc.c | 14 ++++++++------
+ drivers/input/touchscreen/atmel_tsadcc.h | 1 +
+ 2 files changed, 9 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
+index 732b99b..4b6fb94 100644
+--- a/drivers/input/touchscreen/atmel_tsadcc.c
++++ b/drivers/input/touchscreen/atmel_tsadcc.c
+@@ -96,7 +96,7 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ atmel_tsadcc_write(ATMEL_TSADCC_IER,
+ ATMEL_TSADCC_CONVERSION_END | ATMEL_TSADCC_NOCNT);
+ atmel_tsadcc_write(ATMEL_TSADCC_TRGR,
+- ATMEL_TSADCC_TRGMOD_PERIOD | (0x0FFF << 16));
++ ATMEL_TSADCC_TRGMOD_PERIOD | (0x00D0 << 16));
+
+ } else if ((status & ATMEL_TSADCC_CONVERSION_END) == ATMEL_TSADCC_CONVERSION_END) {
+ /* Conversion finished */
+@@ -259,6 +259,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+
+ if (cpu_has_9x5_adc()) {
+ reg = ((0x01 << 5) & ATMEL_TSADCC_SLEEP) | /* Sleep Mode */
++ ((0x01 << 6) & ATMEL_TSADCC_FWUP) | /* Fast Wake Up */
+ (prsc << 8) |
+ ((0x8 << 16) & ATMEL_TSADCC_STARTUP) |
+ ((pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TRACKTIM);
+@@ -277,11 +278,12 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+
+ if (cpu_has_9x5_adc()) {
+ atmel_tsadcc_write(ATMEL_TSADCC_TSMR,
+- ATMEL_TSADCC_TSMODE_4WIRE_PRESS |
+- ATMEL_TSADCC_NOTSDMA |
+- ATMEL_TSADCC_PENDET_ENA |
+- (pdata->pendet_debounce << 28) |
+- (0x0 << 8));
++ ATMEL_TSADCC_TSMODE_4WIRE_PRESS |
++ (pdata->filtering_average << 4) | /* Touchscreen average */
++ ATMEL_TSADCC_NOTSDMA |
++ ATMEL_TSADCC_PENDET_ENA |
++ (pdata->pendet_debounce << 28) |
++ (0x3 << 8)); /* Touchscreen freq */
+ } else {
+ atmel_tsadcc_write(ATMEL_TSADCC_TSR,
+ (pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM);
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.h b/drivers/input/touchscreen/atmel_tsadcc.h
+index 231497e..572770a 100644
+--- a/drivers/input/touchscreen/atmel_tsadcc.h
++++ b/drivers/input/touchscreen/atmel_tsadcc.h
+@@ -34,6 +34,7 @@
+ #define ATMEL_TSADCC_LOWRES (1 << 4) /* Resolution selection */
+ #define ATMEL_TSADCC_SLEEP (1 << 5) /* Sleep mode */
+ #define ATMEL_TSADCC_PENDET (1 << 6) /* Pen Detect selection */
++#define ATMEL_TSADCC_FWUP (1 << 6) /* Fast Wake Up selection (5series) */
+ #define ATMEL_TSADCC_PRES (1 << 7) /* Pressure Measurement Selection */
+ #define ATMEL_TSADCC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */
+ #define ATMEL_TSADCC_EPRESCAL (0xff << 8) /* Prescalar Rate Selection (Extended) */
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0025-input-atmel_tsadcc-add-ACR-register-and-change-trigg.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0025-input-atmel_tsadcc-add-ACR-register-and-change-trigg.patch
new file mode 100644
index 0000000..4d6e9bb
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0025-input-atmel_tsadcc-add-ACR-register-and-change-trigg.patch
@@ -0,0 +1,97 @@
+From 8a9cb430dfa0b998dc4a3c939e993e676a312fed Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Fri, 6 May 2011 17:54:45 +0200
+Subject: [PATCH 025/107] input: atmel_tsadcc: add ACR register and change
+ trigger period value
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add ACR register which allows to configure internal ADC resistor, that should
+prevent from adding resistor on display module. Furthermore increase
+trigger period which seems to be related with resistor value. A Too small
+value causes continuous irq.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/input/touchscreen/atmel_tsadcc.c | 30 +++++++++++++++++++++++++++++-
+ drivers/input/touchscreen/atmel_tsadcc.h | 3 +++
+ 2 files changed, 32 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
+index 4b6fb94..9c3b330 100644
+--- a/drivers/input/touchscreen/atmel_tsadcc.c
++++ b/drivers/input/touchscreen/atmel_tsadcc.c
+@@ -47,6 +47,17 @@ static void __iomem *tsc_base;
+ #define atmel_tsadcc_read(reg) __raw_readl(tsc_base + (reg))
+ #define atmel_tsadcc_write(reg, val) __raw_writel((val), tsc_base + (reg))
+
++static void atmel_tsadcc_dump_conf(struct platform_device *pdev)
++{
++ dev_info(&pdev->dev, "--- configuration ---\n");
++ dev_info(&pdev->dev, "Mode Register: %#x\n", atmel_tsadcc_read(ATMEL_TSADCC_MR));
++ dev_info(&pdev->dev, "Trigger Register: %#x\n", atmel_tsadcc_read(ATMEL_TSADCC_TRGR));
++ dev_info(&pdev->dev, "Touchscreen Mode Register: %#x\n", atmel_tsadcc_read(ATMEL_TSADCC_TSMR));
++ dev_info(&pdev->dev, "Analog Control Register: %#x\n", atmel_tsadcc_read(ATMEL_TSADCC_ACR));
++ dev_info(&pdev->dev, "ADC Channel Status Register: %#x\n", atmel_tsadcc_read(ATMEL_TSADCC_CHSR));
++ dev_info(&pdev->dev, "---------------------\n");
++}
++
+ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ {
+ struct atmel_tsadcc *ts_dev = (struct atmel_tsadcc *)dev;
+@@ -95,8 +106,14 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ atmel_tsadcc_write(ATMEL_TSADCC_IDR, ATMEL_TSADCC_PENCNT);
+ atmel_tsadcc_write(ATMEL_TSADCC_IER,
+ ATMEL_TSADCC_CONVERSION_END | ATMEL_TSADCC_NOCNT);
++ /* this value is related to the resistor bits value of
++ * ACR register and R64. If internal resistor value is
++ * increased then this value has to be increased. This
++ * behavior seems to happen only with averaging on 8
++ * values
++ */
+ atmel_tsadcc_write(ATMEL_TSADCC_TRGR,
+- ATMEL_TSADCC_TRGMOD_PERIOD | (0x00D0 << 16));
++ ATMEL_TSADCC_TRGMOD_PERIOD | (0x0FF << 16));
+
+ } else if ((status & ATMEL_TSADCC_CONVERSION_END) == ATMEL_TSADCC_CONVERSION_END) {
+ /* Conversion finished */
+@@ -289,9 +306,20 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+ (pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM);
+ }
+
++ /* Change adc internal resistor value for better pen detection,
++ * default value is 100 kOhm.
++ * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
++ * option only available on ES2 and higher
++ */
++ if (cpu_has_9x5_adc()) {
++ atmel_tsadcc_write(ATMEL_TSADCC_ACR, pdata->pendet_sensitivity);
++ }
++
+ atmel_tsadcc_read(ATMEL_TSADCC_SR);
+ atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
+
++ /* atmel_tsadcc_dump_conf(pdev); */
++
+ /* All went ok, so register to the input system */
+ err = input_register_device(input_dev);
+ if (err)
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.h b/drivers/input/touchscreen/atmel_tsadcc.h
+index 572770a..fe74506 100644
+--- a/drivers/input/touchscreen/atmel_tsadcc.h
++++ b/drivers/input/touchscreen/atmel_tsadcc.h
+@@ -103,6 +103,9 @@
+ #define ATMEL_TSADCC_NOPEN (1 << 30) /* No Pen Contact */
+ #define ATMEL_TSADCC_PENDET_STATUS (1 << 31) /* Pen Detect Status (not interrupt source) */
+
++#define ATMEL_TSADCC_ACR 0x94 /* Analog Control Register */
++#define ATMEL_TSADCC_PENDET_SENSITIVITY (0x3 << 0) /* ADC internal resistor */
++
+ #define ATMEL_TSADCC_TSMR 0xb0
+ #define ATMEL_TSADCC_TSMODE (3 << 0) /* Touch Screen Mode */
+ #define ATMEL_TSADCC_TSMODE_NO (0 << 0) /* No Touch Screen */
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0026-MTD-atmel_nand-Add-PMECC-controller-support.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0026-MTD-atmel_nand-Add-PMECC-controller-support.patch
new file mode 100644
index 0000000..9fdf2d6
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0026-MTD-atmel_nand-Add-PMECC-controller-support.patch
@@ -0,0 +1,1175 @@
+From f3b6daeff4340b90ce98966871fbbdd3e1249578 Mon Sep 17 00:00:00 2001
+From: Hong Xu <hong.xu@atmel.com>
+Date: Wed, 26 Jan 2011 10:40:30 +0800
+Subject: [PATCH 026/107] MTD: atmel_nand: Add PMECC controller support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The PMECC controller is a programmable binary BCH (Bose, Chaudhuri and
+Hocquenghem) encoder/decoder. This controller can be used to generate redundancy
+information for both SLC and MLC NAND Flash devices.
+
+This patch adds support for PMECC controller and was tested on AT91SAM9X5-EK.
+
+Signed-off-by: Hong Xu <hong.xu@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/mtd/nand/Kconfig | 17 +
+ drivers/mtd/nand/atmel_nand.c | 236 +++++++++----
+ drivers/mtd/nand/atmel_nand_ecc.h | 84 +++++
+ drivers/mtd/nand/atmel_nand_pmecc.c | 674 +++++++++++++++++++++++++++++++++++
+ 4 files changed, 947 insertions(+), 64 deletions(-)
+ create mode 100644 drivers/mtd/nand/atmel_nand_pmecc.c
+
+diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
+index edec457..b7b870c 100644
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -371,6 +371,23 @@ config MTD_NAND_ATMEL_ECC_HW
+
+ If unsure, say Y
+
++config MTD_NAND_ATMEL_PMECC_HW
++ bool "Programmable Hardware ECC (BCH code)"
++ depends on ARCH_AT91SAM9X5
++ help
++ Use Programmable Hardware ECC controller.
++
++ The PMECC Controller is a programmable binary BCH (Bose, Chaudhuri
++ and Hocquenghem) encoder/decoder. This controller can be used to
++ generate redundancy information for both SLC and MLC NAND Flash
++ devices.
++
++ NB : hardware and software ECC schemes are incompatible.
++ If you switch from one to another, you'll have to erase your
++ mtd partition.
++
++ If unsure, say Y
++
+ config MTD_NAND_ATMEL_ECC_SOFT
+ bool "Software ECC"
+ help
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index 950646a..2145c6e 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -15,6 +15,8 @@
+ * (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
+ * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
+ *
++ * Add PMECC support for AT91SAM9X5 Series
++ * (C) Copyright 2011 ATMEL, Hong Xu
+ *
+ * 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
+@@ -36,7 +38,9 @@
+ #include <mach/board.h>
+ #include <mach/cpu.h>
+
+-#ifdef CONFIG_MTD_NAND_ATMEL_ECC_HW
++#if defined(CONFIG_MTD_NAND_ATMEL_ECC_HW)
++#define hard_ecc 1
++#elif defined(CONFIG_MTD_NAND_ATMEL_PMECC_HW)
+ #define hard_ecc 1
+ #else
+ #define hard_ecc 0
+@@ -51,6 +55,8 @@
+ static int use_dma = 1;
+ module_param(use_dma, int, 0);
+
++#define NB_ERROR_MAX 25
++
+ static int on_flash_bbt = 0;
+ module_param(on_flash_bbt, int, 0);
+
+@@ -60,8 +66,38 @@ module_param(on_flash_bbt, int, 0);
+ #define ecc_writel(add, reg, value) \
+ __raw_writel((value), add + ATMEL_ECC_##reg)
+
+-#include "atmel_nand_ecc.h" /* Hardware ECC registers */
++/* Register access macros for PMECC */
++#define pmecc_readl(addr, reg) \
++ __raw_readl((addr) + ATMEL_PMECC_##reg)
++
++#define pmecc_writel(addr, reg, value) \
++ __raw_writel((value), (addr) + ATMEL_PMECC_##reg)
++
++#define pmecc_readb_ecc(addr, sector, n) \
++ __raw_readb((addr) + ATMEL_PMECC_ECCx + ((sector) * 0x40) + (n))
++
++#define pmecc_readl_rem(addr, sector, n) \
++ __raw_readl((addr) + ATMEL_PMECC_REMx + ((sector) * 0x40) + (n))
++
++#define pmerrloc_readl(addr, reg) \
++ __raw_readl((addr) + ATMEL_PMERRLOC_##reg)
++
++#define pmerrloc_writel(addr, reg, value) \
++ __raw_writel((value), (addr) + ATMEL_PMERRLOC_##reg)
++
++#define pmerrloc_writel_sigma(addr, n, value) \
++ __raw_writel((value), (addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
++
++#define pmerrloc_readl_sigma(addr, n) \
++ __raw_readl((addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
++
++#define pmerrloc_readl_el(addr, n) \
++ __raw_readl((addr) + ATMEL_PMERRLOC_ELx + ((n) * 4))
+
++/* Include Hardware ECC registers */
++#include "atmel_nand_ecc.h"
++
++#if defined(CONFIG_MTD_NAND_ATMEL_ECC_HW)
+ /* oob layout for large page size
+ * bad block info is on bytes 0 and 1
+ * the bytes have to be consecutives to avoid
+@@ -87,6 +123,7 @@ static struct nand_ecclayout atmel_oobinfo_small = {
+ {6, 10}
+ },
+ };
++#endif
+
+ struct atmel_nand_host {
+ struct nand_chip nand_chip;
+@@ -99,11 +136,45 @@ struct atmel_nand_host {
+
+ struct completion comp;
+ struct dma_chan *dma_chan;
++
++#if defined(CONFIG_MTD_NAND_ATMEL_PMECC_HW)
++ void __iomem *pmerrloc_base;
++ void __iomem *rom_base;
++ /* defines the error correcting capability */
++ int tt;
++ /* The number of ecc bytes for one sector */
++ int ecc_bytes_per_sector;
++ /* degree of the remainders, GF(2**mm) */
++ int mm;
++ /* length of codeword, nn=2**mm -1 */
++ int nn;
++ /* sector number per page */
++ int sector_number;
++ /* sector size in bytes */
++ int sector_size;
++
++ /* PMECC lookup table for alpha_to and index_of */
++ int16_t *alpha_to;
++ int16_t *index_of;
++
++ int16_t partial_syn[100];
++ int16_t si[100];
++ /* Sigma table */
++ int16_t smu[NB_ERROR_MAX + 2][2 * NB_ERROR_MAX + 1];
++ /** polynomal order */
++ int16_t lmu[NB_ERROR_MAX + 1];
++ uint8_t ecc_table[42 * 8];
++#endif
+ };
+
++#if defined(CONFIG_MTD_NAND_ATMEL_PMECC_HW)
++#include "atmel_nand_pmecc.c"
++#endif
++
+ static int cpu_has_dma(void)
+ {
+- return cpu_is_at91sam9rl() || cpu_is_at91sam9g45();
++ return cpu_is_at91sam9rl() || cpu_is_at91sam9g45()
++ || cpu_is_at91sam9x5();
+ }
+
+ /*
+@@ -293,6 +364,7 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+ atmel_write_buf8(mtd, buf, len);
+ }
+
++#if defined(CONFIG_MTD_NAND_ATMEL_ECC_HW)
+ /*
+ * Calculate HW ECC
+ *
+@@ -479,6 +551,84 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
+ }
+ }
+
++static int __init atmel_nand_init_params(struct platform_device *pdev,
++ struct atmel_nand_host *host)
++{
++ struct resource *regs;
++ struct nand_chip *nand_chip;
++ struct mtd_info *mtd;
++
++ nand_chip = &host->nand_chip;
++ mtd = &host->mtd;
++
++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ if (!regs && hard_ecc) {
++ dev_err(host->dev, "atmel_nand: can't get I/O resource "
++ "regs\nFalling back on software ECC\n");
++ }
++
++ nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */
++ if (no_ecc)
++ nand_chip->ecc.mode = NAND_ECC_NONE;
++ if (hard_ecc && regs) {
++ host->ecc = ioremap(regs->start, regs->end - regs->start + 1);
++ if (host->ecc == NULL) {
++ printk(KERN_ERR "atmel_nand: ioremap failed\n");
++ goto err_ecc_ioremap;
++ }
++
++ nand_chip->ecc.mode = NAND_ECC_HW;
++ nand_chip->ecc.calculate = atmel_nand_calculate;
++ nand_chip->ecc.correct = atmel_nand_correct;
++ nand_chip->ecc.hwctl = atmel_nand_hwctl;
++ nand_chip->ecc.read_page = atmel_nand_read_page;
++ nand_chip->ecc.bytes = 4;
++ }
++
++ if (nand_chip->ecc.mode == NAND_ECC_HW) {
++ /* ECC is calculated for the whole page (1 step) */
++ nand_chip->ecc.size = mtd->writesize;
++
++ /* set ECC page size and oob layout */
++ switch (mtd->writesize) {
++ case 512:
++ nand_chip->ecc.layout = &atmel_oobinfo_small;
++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528);
++ break;
++ case 1024:
++ nand_chip->ecc.layout = &atmel_oobinfo_large;
++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056);
++ break;
++ case 2048:
++ nand_chip->ecc.layout = &atmel_oobinfo_large;
++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112);
++ break;
++ case 4096:
++ nand_chip->ecc.layout = &atmel_oobinfo_large;
++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224);
++ break;
++ default:
++ /* page size not handled by HW ECC */
++ /* switching back to soft ECC */
++ nand_chip->ecc.mode = NAND_ECC_SOFT;
++ nand_chip->ecc.calculate = NULL;
++ nand_chip->ecc.correct = NULL;
++ nand_chip->ecc.hwctl = NULL;
++ nand_chip->ecc.read_page = NULL;
++ nand_chip->ecc.postpad = 0;
++ nand_chip->ecc.prepad = 0;
++ nand_chip->ecc.bytes = 0;
++ break;
++ }
++ }
++
++ return 0;
++
++err_ecc_ioremap:
++ return -EIO;
++}
++#endif
++
+ #ifdef CONFIG_MTD_CMDLINE_PARTS
+ static const char *part_probes[] = { "cmdlinepart", NULL };
+ #endif
+@@ -491,9 +641,8 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ struct atmel_nand_host *host;
+ struct mtd_info *mtd;
+ struct nand_chip *nand_chip;
+- struct resource *regs;
+ struct resource *mem;
+- int res;
++ int res = 0;
+
+ #ifdef CONFIG_MTD_PARTITIONS
+ struct mtd_partition *partitions = NULL;
+@@ -539,29 +688,9 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ if (host->board->rdy_pin)
+ nand_chip->dev_ready = atmel_nand_device_ready;
+
+- regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+- if (!regs && hard_ecc) {
+- printk(KERN_ERR "atmel_nand: can't get I/O resource "
+- "regs\nFalling back on software ECC\n");
+- }
+-
+ nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */
+ if (no_ecc)
+ nand_chip->ecc.mode = NAND_ECC_NONE;
+- if (hard_ecc && regs) {
+- host->ecc = ioremap(regs->start, regs->end - regs->start + 1);
+- if (host->ecc == NULL) {
+- printk(KERN_ERR "atmel_nand: ioremap failed\n");
+- res = -EIO;
+- goto err_ecc_ioremap;
+- }
+- nand_chip->ecc.mode = NAND_ECC_HW;
+- nand_chip->ecc.calculate = atmel_nand_calculate;
+- nand_chip->ecc.correct = atmel_nand_correct;
+- nand_chip->ecc.hwctl = atmel_nand_hwctl;
+- nand_chip->ecc.read_page = atmel_nand_read_page;
+- nand_chip->ecc.bytes = 4;
+- }
+
+ nand_chip->chip_delay = 20; /* 20us command delay time */
+
+@@ -613,42 +742,13 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ goto err_scan_ident;
+ }
+
+- if (nand_chip->ecc.mode == NAND_ECC_HW) {
+- /* ECC is calculated for the whole page (1 step) */
+- nand_chip->ecc.size = mtd->writesize;
+-
+- /* set ECC page size and oob layout */
+- switch (mtd->writesize) {
+- case 512:
+- nand_chip->ecc.layout = &atmel_oobinfo_small;
+- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528);
+- break;
+- case 1024:
+- nand_chip->ecc.layout = &atmel_oobinfo_large;
+- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056);
+- break;
+- case 2048:
+- nand_chip->ecc.layout = &atmel_oobinfo_large;
+- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112);
+- break;
+- case 4096:
+- nand_chip->ecc.layout = &atmel_oobinfo_large;
+- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224);
+- break;
+- default:
+- /* page size not handled by HW ECC */
+- /* switching back to soft ECC */
+- nand_chip->ecc.mode = NAND_ECC_SOFT;
+- nand_chip->ecc.calculate = NULL;
+- nand_chip->ecc.correct = NULL;
+- nand_chip->ecc.hwctl = NULL;
+- nand_chip->ecc.read_page = NULL;
+- nand_chip->ecc.postpad = 0;
+- nand_chip->ecc.prepad = 0;
+- nand_chip->ecc.bytes = 0;
+- break;
+- }
+- }
++#if defined(CONFIG_MTD_NAND_ATMEL_ECC_HW)
++ res = atmel_nand_init_params(pdev, host);
++#elif defined(CONFIG_MTD_NAND_ATMEL_PMECC_HW)
++ res = atmel_pmecc_init_params(pdev, host);
++#endif
++ if (res != 0)
++ goto err;
+
+ /* second phase scan */
+ if (nand_scan_tail(mtd)) {
+@@ -680,6 +780,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ if (!res)
+ return res;
+
++err:
+ #ifdef CONFIG_MTD_PARTITIONS
+ err_no_partitions:
+ #endif
+@@ -691,9 +792,6 @@ err_no_card:
+ platform_set_drvdata(pdev, NULL);
+ if (host->dma_chan)
+ dma_release_channel(host->dma_chan);
+- if (host->ecc)
+- iounmap(host->ecc);
+-err_ecc_ioremap:
+ iounmap(host->io_base);
+ err_nand_ioremap:
+ kfree(host);
+@@ -712,6 +810,16 @@ static int __exit atmel_nand_remove(struct platform_device *pdev)
+
+ atmel_nand_disable(host);
+
++#if defined(CONFIG_MTD_NAND_ATMEL_PMECC_HW)
++ if (cpu_has_pmecc())
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
++ if (host->pmerrloc_base) {
++ pmerrloc_writel(host->pmerrloc_base, ELDIS, 0xffffffff);
++ iounmap(host->pmerrloc_base);
++ }
++ if (host->rom_base)
++ iounmap(host->rom_base);
++#endif
+ if (host->ecc)
+ iounmap(host->ecc);
+
+diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h
+index 578c776..6e0e2f3 100644
+--- a/drivers/mtd/nand/atmel_nand_ecc.h
++++ b/drivers/mtd/nand/atmel_nand_ecc.h
+@@ -36,4 +36,88 @@
+ #define ATMEL_ECC_NPR 0x10 /* NParity register */
+ #define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */
+
++/* PMECC Register Definitions */
++#define ATMEL_PMECC_CFG 0x000 /* Configuration Register */
++#define PMECC_CFG_BCH_ERR2 (0 << 0)
++#define PMECC_CFG_BCH_ERR4 (1 << 0)
++#define PMECC_CFG_BCH_ERR8 (2 << 0)
++#define PMECC_CFG_BCH_ERR12 (3 << 0)
++#define PMECC_CFG_BCH_ERR24 (4 << 0)
++
++#define PMECC_CFG_SECTOR512 (0 << 4)
++#define PMECC_CFG_SECTOR1024 (1 << 4)
++
++#define PMECC_CFG_PAGE_1SECTOR (0 << 8)
++#define PMECC_CFG_PAGE_2SECTORS (1 << 8)
++#define PMECC_CFG_PAGE_4SECTORS (2 << 8)
++#define PMECC_CFG_PAGE_8SECTORS (3 << 8)
++
++#define PMECC_CFG_READ_OP (0 << 12)
++#define PMECC_CFG_WRITE_OP (1 << 12)
++
++#define PMECC_CFG_SPARE_ENABLE (1 << 16)
++#define PMECC_CFG_SPARE_DISABLE (0 << 16)
++
++#define PMECC_CFG_AUTO_ENABLE (1 << 20)
++#define PMECC_CFG_AUTO_DISABLE (0 << 20)
++
++#define ATMEL_PMECC_SAREA 0x004 /* Spare area size */
++#define ATMEL_PMECC_SADDR 0x008 /* PMECC starting address */
++#define ATMEL_PMECC_EADDR 0x00c /* PMECC ending address */
++#define ATMEL_PMECC_CLK 0x010 /* PMECC clock control */
++#define PMECC_CLK_133MHZ (2 << 0)
++
++#define ATMEL_PMECC_CTRL 0x014 /* PMECC control register */
++#define PMECC_CTRL_RST (1 << 0)
++#define PMECC_CTRL_DATA (1 << 1)
++#define PMECC_CTRL_USER (1 << 2)
++#define PMECC_CTRL_ENABLE (1 << 4)
++#define PMECC_CTRL_DISABLE (1 << 5)
++
++#define ATMEL_PMECC_SR 0x018 /* PMECC status register */
++#define PMECC_SR_BUSY (1 << 0)
++#define PMECC_SR_ENABLE (1 << 4)
++
++#define ATMEL_PMECC_IER 0x01c /* PMECC interrupt enable */
++#define PMECC_IER_ENABLE (1 << 0)
++#define ATMEL_PMECC_IDR 0x020 /* PMECC interrupt disable */
++#define PMECC_IER_DISABLE (1 << 0)
++#define ATMEL_PMECC_IMR 0x024 /* PMECC interrupt mask */
++#define PMECC_IER_MASK (1 << 0)
++#define ATMEL_PMECC_ISR 0x028 /* PMECC interrupt status */
++#define ATMEL_PMECC_ECCx 0x040 /* PMECC ECC x */
++#define ATMEL_PMECC_REMx 0x240 /* PMECC REM x */
++
++/* PMERRLOC Register Definitions */
++#define ATMEL_PMERRLOC_ELCFG 0x000 /* Error location config */
++#define PMERRLOC_ELCFG_SECTOR_512 (0 << 0)
++#define PMERRLOC_ELCFG_SECTOR_1024 (1 << 0)
++#define PMERRLOC_ELCFG_NUM_ERRORS(n) ((n) << 16)
++
++#define ATMEL_PMERRLOC_ELPRIM 0x004 /* Error location primitive */
++#define ATMEL_PMERRLOC_ELEN 0x008 /* Error location enable */
++#define ATMEL_PMERRLOC_ELDIS 0x00c /* Error location disable */
++#define PMERRLOC_DISABLE (1 << 0)
++
++#define ATMEL_PMERRLOC_ELSR 0x010 /* Error location status */
++#define PMERRLOC_ELSR_BUSY (1 << 0)
++#define ATMEL_PMERRLOC_ELIER 0x014 /* Error location int enable */
++#define ATMEL_PMERRLOC_ELIDR 0x018 /* Error location int disable */
++#define ATMEL_PMERRLOC_ELIMR 0x01c /* Error location int mask */
++#define ATMEL_PMERRLOC_ELISR 0x020 /* Error location int status */
++#define PMERRLOC_ERR_NUM_MASK (0x1f << 8)
++#define PMERRLOC_CALC_DONE (1 << 0)
++#define ATMEL_PMERRLOC_SIGMAx 0x028 /* Error location SIGMA x */
++#define ATMEL_PMERRLOC_ELx 0x08c /* Error location x */
++
++/* Galois field dimension */
++#define GF_DIMENSION_13 13
++#define GF_DIMENSION_14 14
++
++#define PMECC_LOOKUP_TABLE_SIZE_512 0x2000
++#define PMECC_LOOKUP_TABLE_SIZE_1024 0x4000
++
++#define PMECC_LOOKUP_TABLE_OFFSET_512 0x8000
++#define PMECC_LOOKUP_TABLE_OFFSET_1024 0x10000
++
+ #endif
+diff --git a/drivers/mtd/nand/atmel_nand_pmecc.c b/drivers/mtd/nand/atmel_nand_pmecc.c
+new file mode 100644
+index 0000000..3230666
+--- /dev/null
++++ b/drivers/mtd/nand/atmel_nand_pmecc.c
+@@ -0,0 +1,674 @@
++/*
++ * (C) Copyright 2011 ATMEL, Hong Xu
++ *
++ * PMECC related definitions and routines
++ *
++ * 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.
++ *
++ */
++
++static struct nand_ecclayout pmecc_oobinfo_2048 = {
++ .eccbytes = 16,
++ .eccpos = { 48, 49, 50, 51, 52, 53, 54, 55,
++ 56, 57, 58, 59, 60, 61, 62, 63
++ },
++ .oobfree = {
++ {2, 46},
++ },
++};
++
++static int cpu_has_pmecc(void)
++{
++ return cpu_is_at91sam9x5();
++}
++
++static int16_t *pmecc_get_alpha_to(struct atmel_nand_host *host)
++{
++ int16_t *p;
++
++ if (cpu_is_at91sam9x5()) {
++ if (host->sector_size == 512) {
++ p = (int16_t *)((u32)host->rom_base +
++ PMECC_LOOKUP_TABLE_OFFSET_512);
++ return p + PMECC_LOOKUP_TABLE_SIZE_512;
++ } else {
++ p = (int16_t *)((u32)host->rom_base +
++ PMECC_LOOKUP_TABLE_OFFSET_1024);
++ return p + PMECC_LOOKUP_TABLE_SIZE_1024;
++ }
++ }
++
++ return NULL;
++}
++
++static int16_t *pmecc_get_index_of(struct atmel_nand_host *host)
++{
++ int16_t *p = (int16_t *)host->rom_base;
++
++ if (cpu_is_at91sam9x5()) {
++ if (host->sector_size == 512)
++ p = (int16_t *)((u32)host->rom_base +
++ PMECC_LOOKUP_TABLE_OFFSET_512);
++ else
++ p = (int16_t *)((u32)host->rom_base +
++ PMECC_LOOKUP_TABLE_OFFSET_1024);
++
++ return p;
++ }
++
++ return NULL;
++}
++
++static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector)
++{
++ int i;
++ uint32_t value;
++ struct nand_chip *nand_chip = mtd->priv;
++ struct atmel_nand_host *host = nand_chip->priv;
++
++ /* Fill odd syndromes */
++ for (i = 0; i < host->tt; i++) {
++ value = pmecc_readl_rem(host->ecc, sector, i / 2);
++ if (i % 2 == 0)
++ host->partial_syn[(2 * i) + 1] = value & 0xffff;
++ else
++ host->partial_syn[(2 * i) + 1] = (value & 0xffff0000)
++ >> 16;
++ }
++}
++
++static void pmecc_substitute(struct mtd_info *mtd)
++{
++ int i, j;
++ struct nand_chip *nand_chip = mtd->priv;
++ struct atmel_nand_host *host = nand_chip->priv;
++ int16_t *si;
++ int16_t *partial_syn = host->partial_syn;
++ int16_t *alpha_to = host->alpha_to;
++ int16_t *index_of = host->index_of;
++
++ /* si[] is a table that holds the current syndrome value,
++ * an element of that table belongs to the field
++ */
++ si = host->si;
++
++ for (i = 1; i < 2 * NB_ERROR_MAX; i++)
++ si[i] = 0;
++
++ /* Computation 2t syndromes based on S(x) */
++ /* Odd syndromes */
++ for (i = 1; i <= 2 * host->tt - 1; i = i + 2) {
++ si[i] = 0;
++ for (j = 0; j < host->mm; j++) {
++ if (partial_syn[i] & ((unsigned short)0x1 << j))
++ si[i] = alpha_to[(i * j)] ^ si[i];
++ }
++ }
++ /* Even syndrome = (Odd syndrome) ** 2 */
++ for (i = 2; i <= 2 * host->tt; i = i + 2) {
++ j = i / 2;
++ if (si[j] == 0)
++ si[i] = 0;
++ else
++ si[i] = alpha_to[(2 * index_of[si[j]]) % host->nn];
++ }
++
++ return;
++}
++
++static void pmecc_get_sigma(struct mtd_info *mtd)
++{
++ int i, j, k;
++ struct nand_chip *nand_chip = mtd->priv;
++ struct atmel_nand_host *host = nand_chip->priv;
++ uint32_t dmu_0_count, tmp;
++ int16_t *lmu = host->lmu;
++ int16_t *si = host->si;
++ int16_t tt = host->tt;
++ int16_t *index_of = host->index_of;
++
++ /* mu */
++ int mu[NB_ERROR_MAX + 1];
++
++ /* discrepancy */
++ int dmu[NB_ERROR_MAX + 1];
++
++ /* delta order */
++ int delta[NB_ERROR_MAX + 1];
++
++ /* index of largest delta */
++ int ro;
++ int largest;
++ int diff;
++
++ dmu_0_count = 0;
++
++ /* First Row */
++
++ /* Mu */
++ mu[0] = -1;
++
++ /* Actually -1/2 */
++ /* Sigma(x) set to 1 */
++ for (i = 0; i < 2 * NB_ERROR_MAX + 1; i++)
++ host->smu[0][i] = 0;
++
++ host->smu[0][0] = 1;
++
++ /* discrepancy set to 1 */
++ dmu[0] = 1;
++ /* polynom order set to 0 */
++ lmu[0] = 0;
++ /* delta set to -1 */
++ delta[0] = (mu[0] * 2 - lmu[0]) >> 1;
++
++ /* Second Row */
++
++ /* Mu */
++ mu[1] = 0;
++ /* Sigma(x) set to 1 */
++ for (i = 0; i < (2 * NB_ERROR_MAX + 1); i++)
++ host->smu[1][i] = 0;
++
++ host->smu[1][0] = 1;
++
++ /* discrepancy set to S1 */
++ dmu[1] = si[1];
++
++ /* polynom order set to 0 */
++ lmu[1] = 0;
++
++ /* delta set to 0 */
++ delta[1] = (mu[1] * 2 - lmu[1]) >> 1;
++
++ /* Init the Sigma(x) last row */
++ for (i = 0; i < (2 * NB_ERROR_MAX + 1); i++)
++ host->smu[tt + 1][i] = 0;
++
++ for (i = 1; i <= tt; i++) {
++ mu[i+1] = i << 1;
++ /* Begin Computing Sigma (Mu+1) and L(mu) */
++ /* check if discrepancy is set to 0 */
++ if (dmu[i] == 0) {
++ dmu_0_count++;
++
++ if ((tt - (lmu[i] >> 1) - 1) & 0x1)
++ tmp = ((tt - (lmu[i] >> 1) - 1) / 2) + 2;
++ else
++ tmp = ((tt - (lmu[i] >> 1) - 1) / 2) + 1;
++
++ if (dmu_0_count == tmp) {
++ for (j = 0; j <= (lmu[i] >> 1) + 1; j++)
++ host->smu[tt + 1][j] = host->smu[i][j];
++
++ lmu[tt + 1] = lmu[i];
++ return;
++ }
++
++ /* copy polynom */
++ for (j = 0; j <= lmu[i] >> 1; j++)
++ host->smu[i + 1][j] = host->smu[i][j];
++
++ /* copy previous polynom order to the next */
++ lmu[i + 1] = lmu[i];
++ } else {
++ ro = 0;
++ largest = -1;
++ /* find largest delta with dmu != 0 */
++ for (j = 0; j < i; j++) {
++ if ((dmu[j]) && (delta[j] > largest)) {
++ largest = delta[j];
++ ro = j;
++ }
++ }
++
++ /* compute difference */
++ diff = (mu[i] - mu[ro]);
++
++ /* Compute degree of the new smu polynomial */
++ if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff))
++ lmu[i + 1] = lmu[i];
++ else
++ lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2;
++
++ /* Init smu[i+1] with 0 */
++ for (k = 0; k < (2 * NB_ERROR_MAX + 1); k++)
++ host->smu[i+1][k] = 0;
++
++ /* Compute smu[i+1] */
++ for (k = 0; k <= lmu[ro] >> 1; k++) {
++ if (!(host->smu[ro][k] && dmu[i]))
++ continue;
++
++ tmp = host->index_of[dmu[i]] + (host->nn -
++ host->index_of[dmu[ro]]) +
++ host->index_of[host->smu[ro][k]];
++ host->smu[i + 1][k + diff] =
++ host->alpha_to[tmp % host->nn];
++ }
++
++ for (k = 0; k <= lmu[i] >> 1; k++)
++ host->smu[i + 1][k] ^= host->smu[i][k];
++ }
++
++ /* End Computing Sigma (Mu+1) and L(mu) */
++ /* In either case compute delta */
++ delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1;
++
++ /* Do not compute discrepancy for the last iteration */
++ if (i >= tt)
++ continue;
++
++ for (k = 0 ; k <= (lmu[i + 1] >> 1); k++) {
++ tmp = 2 * (i - 1);
++ if (k == 0)
++ dmu[i + 1] = si[tmp + 3];
++ else if (host->smu[i+1][k] && si[tmp + 3 - k]) {
++ tmp = index_of[host->smu[i + 1][k]] +
++ index_of[si[2 * (i - 1) + 3 - k]];
++ tmp %= host->nn;
++ dmu[i + 1] = host->alpha_to[tmp] ^ dmu[i + 1];
++ }
++ }
++ }
++
++ return;
++}
++
++
++static int pmecc_err_location(struct mtd_info *mtd)
++{
++ int i;
++ /* number of error */
++ int err_nbr;
++ /* number of roots */
++ int roots_nbr;
++ int gf_dimension;
++ uint32_t val;
++ struct nand_chip *nand_chip = mtd->priv;
++ struct atmel_nand_host *host = nand_chip->priv;
++
++ if (host->sector_size == 512)
++ gf_dimension = GF_DIMENSION_13;
++ else
++ gf_dimension = GF_DIMENSION_14;
++
++ /* Disable PMECC Error Location IP */
++ pmerrloc_writel(host->pmerrloc_base, ELDIS, 0xffffffff);
++ err_nbr = 0;
++
++ for (i = 0; i <= host->lmu[host->tt + 1] >> 1; i++) {
++ pmerrloc_writel_sigma(host->pmerrloc_base, i,
++ host->smu[host->tt + 1][i]);
++ err_nbr++;
++ }
++
++ val = pmerrloc_readl(host->pmerrloc_base, ELCFG);
++ val |= ((err_nbr - 1) << 16);
++ pmerrloc_writel(host->pmerrloc_base, ELCFG, val);
++
++ pmerrloc_writel(host->pmerrloc_base, ELEN,
++ host->sector_size * 8 + gf_dimension * host->tt);
++
++ while (!(pmerrloc_readl(host->pmerrloc_base, ELISR)
++ & PMERRLOC_CALC_DONE))
++ cpu_relax();
++
++ roots_nbr = (pmerrloc_readl(host->pmerrloc_base, ELISR)
++ & PMERRLOC_ERR_NUM_MASK) >> 8;
++
++ /* Number of roots == degree of smu hence <= tt */
++ if (roots_nbr == host->lmu[host->tt + 1] >> 1)
++ return err_nbr - 1;
++
++ /* Number of roots does not match the degree of smu
++ * unable to correct error */
++ return -1;
++}
++
++static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf,
++ int extra_bytes, int err_nbr)
++{
++ int i = 0;
++ int byte_pos, bit_pos;
++ int sector_size, ecc_size;
++ uint32_t tmp;
++ struct nand_chip *nand_chip = mtd->priv;
++ struct atmel_nand_host *host = nand_chip->priv;
++
++ sector_size = host->sector_size;
++ /* Get number of ECC bytes */
++ ecc_size = nand_chip->ecc.bytes;
++
++ while (err_nbr) {
++ byte_pos = (pmerrloc_readl_el(host->pmerrloc_base, i) - 1) / 8;
++ bit_pos = (pmerrloc_readl_el(host->pmerrloc_base, i) - 1) % 8;
++ dev_dbg(host->dev, "bad : %02x: byte_pos: %d, bit_pos: %d\n",
++ *(buf + byte_pos), byte_pos, bit_pos);
++
++ if (byte_pos < (sector_size + extra_bytes)) {
++ tmp = sector_size + pmecc_readl(host->ecc, SADDR);
++ if (byte_pos < tmp) {
++ if (*(buf + byte_pos) & (1 << bit_pos))
++ *(buf + byte_pos) &=
++ (0xFF ^ (1 << bit_pos));
++ else
++ *(buf + byte_pos) |= (1 << bit_pos);
++ } else {
++ if (*(buf + byte_pos + ecc_size) &
++ (1 << bit_pos))
++ *(buf + byte_pos + ecc_size) &=
++ (0xFF ^ (1 << bit_pos));
++ else
++ *(buf + byte_pos + ecc_size) |=
++ (1 << bit_pos);
++ }
++ }
++ dev_dbg(host->dev, "corr: %02x\n", *(buf + byte_pos));
++ i++;
++ err_nbr--;
++ }
++
++ return;
++}
++
++static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
++ u8 *ecc)
++{
++ int i, err_nbr;
++ uint8_t *buf_pos;
++ struct nand_chip *nand_chip = mtd->priv;
++ int eccbytes = nand_chip->ecc.bytes;
++ struct atmel_nand_host *host = nand_chip->priv;
++
++ for (i = 0; i < eccbytes; i++)
++ if (ecc[i] != 0xff)
++ break;
++ /* Erased page, return OK */
++ if (i == eccbytes)
++ return 0;
++
++ pmerrloc_writel(host->pmerrloc_base, ELCFG,
++ (host->sector_size == 512) ? 0 : 1);
++
++ i = 0;
++ while (i < host->sector_number) {
++ err_nbr = 0;
++ if (pmecc_stat & 0x1) {
++ buf_pos = buf + i * host->sector_size;
++
++ pmecc_gen_syndrome(mtd, i);
++ pmecc_substitute(mtd);
++ pmecc_get_sigma(mtd);
++
++ err_nbr = pmecc_err_location(mtd);
++ if (err_nbr == -1) {
++ dev_err(host->dev, "Too many error.\n");
++ mtd->ecc_stats.failed++;
++ return -EFAULT;
++ } else {
++ dev_dbg(host->dev, "Correct bits...\n");
++ pmecc_correct_data(mtd, buf_pos, 0, err_nbr);
++ mtd->ecc_stats.corrected += err_nbr;
++ }
++ }
++ i++;
++ pmecc_stat >>= 1;
++ }
++
++ return 0;
++}
++
++static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
++ struct nand_chip *chip, uint8_t *buf, int32_t page)
++{
++ struct atmel_nand_host *host = chip->priv;
++ int eccsize = chip->ecc.size;
++ uint32_t *eccpos = chip->ecc.layout->eccpos;
++ int err = 0, stat;
++ int timeout = 10;
++ uint8_t *oob = chip->oob_poi;
++
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
++ pmecc_writel(host->ecc, CFG, (pmecc_readl(host->ecc, CFG)
++ & ~PMECC_CFG_WRITE_OP) | PMECC_CFG_AUTO_ENABLE);
++
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
++
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
++
++ chip->read_buf(mtd, buf, eccsize);
++ chip->read_buf(mtd, oob, mtd->oobsize);
++
++ while ((pmecc_readl(host->ecc, SR) & PMECC_SR_BUSY) && (timeout-- > 0))
++ cpu_relax();
++
++ stat = pmecc_readl(host->ecc, ISR);
++
++ if (stat != 0) {
++ if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]))
++ err = -1;
++ }
++
++ return err;
++}
++
++static void atmel_nand_pmecc_write_page(struct mtd_info *mtd,
++ struct nand_chip *chip, const uint8_t *buf)
++{
++ int i, j;
++ int timeout = 10;
++ struct atmel_nand_host *host = chip->priv;
++ uint32_t *eccpos = chip->ecc.layout->eccpos;
++
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
++
++ pmecc_writel(host->ecc, CFG, (pmecc_readl(host->ecc, CFG) |
++ PMECC_CFG_WRITE_OP) & ~PMECC_CFG_AUTO_ENABLE);
++
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
++
++ chip->write_buf(mtd, (u8 *)buf, mtd->writesize);
++
++ while ((pmecc_readl(host->ecc, SR) & PMECC_SR_BUSY) && (timeout-- > 0))
++ cpu_relax();
++
++ for (i = 0; i < host->sector_number; i++) {
++ for (j = 0; j < host->ecc_bytes_per_sector; j++) {
++ int pos;
++
++ pos = i * host->ecc_bytes_per_sector + j;
++ chip->oob_poi[eccpos[pos]] =
++ pmecc_readb_ecc(host->ecc, i, j);
++ }
++ }
++ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++ return;
++}
++
++static void atmel_init_pmecc(struct mtd_info *mtd)
++{
++ uint32_t val;
++ struct nand_chip *nand_chip = mtd->priv;
++ struct atmel_nand_host *host = nand_chip->priv;
++ struct nand_ecclayout *ecc_layout;
++
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
++
++ switch (host->tt) {
++ case 2:
++ val = PMECC_CFG_BCH_ERR2;
++ break;
++ case 4:
++ val = PMECC_CFG_BCH_ERR4;
++ break;
++ case 8:
++ val = PMECC_CFG_BCH_ERR8;
++ break;
++ case 12:
++ val = PMECC_CFG_BCH_ERR12;
++ break;
++ case 24:
++ val = PMECC_CFG_BCH_ERR24;
++ break;
++ }
++
++ if (host->sector_size == 512)
++ val |= PMECC_CFG_SECTOR512;
++ else if (host->sector_size == 1024)
++ val |= PMECC_CFG_SECTOR1024;
++
++ switch (host->sector_number) {
++ case 1:
++ val |= PMECC_CFG_PAGE_1SECTOR;
++ break;
++ case 2:
++ val |= PMECC_CFG_PAGE_2SECTORS;
++ break;
++ case 4:
++ val |= PMECC_CFG_PAGE_4SECTORS;
++ break;
++ case 8:
++ val |= PMECC_CFG_PAGE_8SECTORS;
++ break;
++ }
++
++ val |= PMECC_CFG_READ_OP | PMECC_CFG_SPARE_DISABLE
++ | PMECC_CFG_AUTO_DISABLE;
++ pmecc_writel(host->ecc, CFG, val);
++
++ ecc_layout = nand_chip->ecc.layout;
++ pmecc_writel(host->ecc, SAREA, mtd->oobsize - 1);
++ pmecc_writel(host->ecc, SADDR, ecc_layout->eccpos[0]);
++ pmecc_writel(host->ecc, EADDR,
++ ecc_layout->eccpos[ecc_layout->eccbytes - 1]);
++ pmecc_writel(host->ecc, CLK, PMECC_CLK_133MHZ);
++ pmecc_writel(host->ecc, IDR, 0xff);
++
++ val = pmecc_readl(host->ecc, CTRL);
++ val |= PMECC_CTRL_ENABLE;
++ pmecc_writel(host->ecc, CTRL, val);
++}
++
++static int __init atmel_pmecc_init_params(struct platform_device *pdev,
++ struct atmel_nand_host *host)
++{
++ struct resource *regs;
++ struct resource *regs_pmerr, *regs_rom;
++ struct nand_chip *nand_chip;
++ struct mtd_info *mtd;
++ int res;
++
++ printk(KERN_ERR "atmel_pmecc_init_params\n");
++
++ nand_chip = &host->nand_chip;
++ mtd = &host->mtd;
++
++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ if (!regs && hard_ecc) {
++ dev_warn(host->dev, "Can't get I/O resource regs\nFalling "
++ "back on software ECC\n");
++ }
++
++ nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */
++ if (no_ecc)
++ nand_chip->ecc.mode = NAND_ECC_NONE;
++ if (hard_ecc && regs) {
++ host->ecc = ioremap(regs->start, regs->end - regs->start + 1);
++ if (host->ecc == NULL) {
++ printk(KERN_ERR "atmel_nand: ioremap failed\n");
++ res = -EIO;
++ goto err_pmecc_ioremap;
++ }
++
++ regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM,
++ 2);
++ regs_rom = platform_get_resource(pdev, IORESOURCE_MEM,
++ 3);
++ if (regs_pmerr && regs_rom) {
++ host->pmerrloc_base = ioremap(regs_pmerr->start,
++ regs_pmerr->end - regs_pmerr->start + 1);
++ host->rom_base = ioremap(regs_rom->start,
++ regs_rom->end - regs_rom->start + 1);
++
++ if (host->pmerrloc_base && host->rom_base) {
++ nand_chip->ecc.mode = NAND_ECC_HW;
++ nand_chip->ecc.read_page =
++ atmel_nand_pmecc_read_page;
++ nand_chip->ecc.write_page =
++ atmel_nand_pmecc_write_page;
++ } else {
++ dev_err(host->dev, "Can not get I/O resource"
++ " for HW PMECC controller!\n");
++ goto err_pmloc_remap;
++ }
++ }
++
++ if (nand_chip->ecc.mode != NAND_ECC_HW)
++ printk(KERN_ERR "atmel_nand: Can not get I/O resource"
++ " for HW ECC Rolling back to software ECC\n");
++ }
++
++ if (nand_chip->ecc.mode == NAND_ECC_HW) {
++ /* ECC is calculated for the whole page (1 step) */
++ nand_chip->ecc.size = mtd->writesize;
++
++ /* set ECC page size and oob layout */
++ switch (mtd->writesize) {
++ case 2048:
++ nand_chip->ecc.bytes = 16;
++ nand_chip->ecc.steps = 1;
++ nand_chip->ecc.layout = &pmecc_oobinfo_2048;
++ host->mm = GF_DIMENSION_13;
++ host->nn = (1 << host->mm) - 1;
++ /* 2-bits correction */
++ host->tt = 2;
++ host->sector_size = 512;
++ host->sector_number = mtd->writesize /
++ host->sector_size;
++ host->ecc_bytes_per_sector = 4;
++ host->alpha_to = pmecc_get_alpha_to(host);
++ host->index_of = pmecc_get_index_of(host);
++ break;
++ case 512:
++ case 1024:
++ case 4096:
++ /* TODO */
++ dev_warn(host->dev, "Only 2048 page size is currently"
++ "supported, Rolling back to software ECC\n");
++ default:
++ /* page size not handled by HW ECC */
++ /* switching back to soft ECC */
++ nand_chip->ecc.mode = NAND_ECC_SOFT;
++ nand_chip->ecc.calculate = NULL;
++ nand_chip->ecc.correct = NULL;
++ nand_chip->ecc.hwctl = NULL;
++ nand_chip->ecc.read_page = NULL;
++ nand_chip->ecc.postpad = 0;
++ nand_chip->ecc.prepad = 0;
++ nand_chip->ecc.bytes = 0;
++ break;
++ }
++ }
++
++ /* Initialize PMECC core if applicable */
++ if ((nand_chip->ecc.mode == NAND_ECC_HW) && cpu_has_pmecc())
++ atmel_init_pmecc(mtd);
++
++ return 0;
++err_pmloc_remap:
++ iounmap(host->ecc);
++ if (host->pmerrloc_base)
++ iounmap(host->pmerrloc_base);
++ if (host->rom_base)
++ iounmap(host->rom_base);
++err_pmecc_ioremap:
++ return -EIO;
++}
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0027-MTD-atmel_nand-optimize-read-write-buffer-functions.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0027-MTD-atmel_nand-optimize-read-write-buffer-functions.patch
new file mode 100644
index 0000000..c8d8232
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0027-MTD-atmel_nand-optimize-read-write-buffer-functions.patch
@@ -0,0 +1,130 @@
+From 6ddc4f41327a2782c63817dc8b94dd92edad8352 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 16 Feb 2011 18:43:37 +0100
+Subject: [PATCH 027/107] MTD: atmel_nand: optimize read/write buffer
+ functions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+For PIO NAND access functions, we use the features of the SMC:
+- no need to take into account the NAND bus width: SMC will deal with this
+- an word aligned memcpy on the NAND chip-select space is able to generate
+ proper SMC behavior while optimizing AHB bus usage thanks to optimized memcpy
+ implementation.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/mtd/nand/atmel_nand.c | 71 +++++++++++++++++-----------------------
+ 1 files changed, 30 insertions(+), 41 deletions(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index 2145c6e..e89c8c7 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -230,37 +230,6 @@ static int atmel_nand_device_ready(struct mtd_info *mtd)
+ !!host->board->rdy_pin_active_low;
+ }
+
+-/*
+- * Minimal-overhead PIO for data access.
+- */
+-static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len)
+-{
+- struct nand_chip *nand_chip = mtd->priv;
+-
+- __raw_readsb(nand_chip->IO_ADDR_R, buf, len);
+-}
+-
+-static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len)
+-{
+- struct nand_chip *nand_chip = mtd->priv;
+-
+- __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2);
+-}
+-
+-static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len)
+-{
+- struct nand_chip *nand_chip = mtd->priv;
+-
+- __raw_writesb(nand_chip->IO_ADDR_W, buf, len);
+-}
+-
+-static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len)
+-{
+- struct nand_chip *nand_chip = mtd->priv;
+-
+- __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2);
+-}
+-
+ static void dma_complete_func(void *completion)
+ {
+ complete(completion);
+@@ -335,33 +304,53 @@ err_buf:
+ static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+ {
+ struct nand_chip *chip = mtd->priv;
+- struct atmel_nand_host *host = chip->priv;
++ u32 align;
++ u8 *pbuf;
+
+ if (use_dma && len > mtd->oobsize)
+ /* only use DMA for bigger than oob size: better performances */
+ if (atmel_nand_dma_op(mtd, buf, len, 1) == 0)
+ return;
+
+- if (host->board->bus_width_16)
+- atmel_read_buf16(mtd, buf, len);
+- else
+- atmel_read_buf8(mtd, buf, len);
++ /* if no DMA operation possible, use PIO */
++ pbuf = buf;
++ align = 0x03 & ((unsigned)pbuf);
++
++ if (align) {
++ u32 align_len = 4 - align;
++
++ /* non aligned buffer: re-align to next word boundary */
++ ioread8_rep(chip->IO_ADDR_R, pbuf, align_len);
++ pbuf += align_len;
++ len -= align_len;
++ }
++ memcpy((void *)pbuf, chip->IO_ADDR_R, len);
+ }
+
+ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+ {
+ struct nand_chip *chip = mtd->priv;
+- struct atmel_nand_host *host = chip->priv;
++ u32 align;
++ const u8 *pbuf;
+
+ if (use_dma && len > mtd->oobsize)
+ /* only use DMA for bigger than oob size: better performances */
+ if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) == 0)
+ return;
+
+- if (host->board->bus_width_16)
+- atmel_write_buf16(mtd, buf, len);
+- else
+- atmel_write_buf8(mtd, buf, len);
++ /* if no DMA operation possible, use PIO */
++ pbuf = buf;
++ align = 0x03 & ((unsigned)pbuf);
++
++ if (align) {
++ u32 align_len = 4 - align;
++
++ /* non aligned buffer: re-align to next word boundary */
++ iowrite8_rep(chip->IO_ADDR_W, pbuf, align_len);
++ pbuf += align_len;
++ len -= align_len;
++ }
++ memcpy(chip->IO_ADDR_W, (void *)pbuf, len);
+ }
+
+ #if defined(CONFIG_MTD_NAND_ATMEL_ECC_HW)
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0028-spi-atmel_spi-trivial-change-some-comments.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0028-spi-atmel_spi-trivial-change-some-comments.patch
new file mode 100644
index 0000000..8f41ddb
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0028-spi-atmel_spi-trivial-change-some-comments.patch
@@ -0,0 +1,40 @@
+From 1d7219fce90e166edfd523cdd081753d55117baa Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 16 Mar 2011 10:55:39 +0800
+Subject: [PATCH 028/107] spi/atmel_spi: trivial: change some comments
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+To be accurate with introduction of dmaengine enabled driver.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/spi/atmel_spi.c | 3 ++-
+ 1 files changed, 2 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
+index 1a478bf..033aa52 100644
+--- a/drivers/spi/atmel_spi.c
++++ b/drivers/spi/atmel_spi.c
+@@ -48,6 +48,7 @@ struct atmel_spi {
+ struct spi_transfer *next_transfer;
+ unsigned long next_remaining_bytes;
+
++ /* scratch buffer */
+ void *buffer;
+ dma_addr_t buffer_dma;
+ };
+@@ -211,7 +212,7 @@ static void atmel_spi_next_xfer_data(struct spi_master *master,
+ }
+
+ /*
+- * Submit next transfer for DMA.
++ * Submit next transfer for PDC.
+ * lock is held, spi irq is blocked
+ */
+ static void atmel_spi_next_xfer(struct spi_master *master,
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0029-spi-atmel_spi-add-physical-base-address.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0029-spi-atmel_spi-add-physical-base-address.patch
new file mode 100644
index 0000000..33531dc
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0029-spi-atmel_spi-add-physical-base-address.patch
@@ -0,0 +1,39 @@
+From c49c24fe68646dd74999a52fce7e6d0f32912033 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 16 Mar 2011 10:50:13 +0800
+Subject: [PATCH 029/107] spi/atmel_spi: add physical base address
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Needed for future use with dmaengine enabled driver.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/spi/atmel_spi.c | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
+index 033aa52..c7967c8 100644
+--- a/drivers/spi/atmel_spi.c
++++ b/drivers/spi/atmel_spi.c
+@@ -35,6 +35,7 @@
+ struct atmel_spi {
+ spinlock_t lock;
+
++ resource_size_t phybase;
+ void __iomem *regs;
+ int irq;
+ struct clk *clk;
+@@ -809,6 +810,7 @@ static int __init atmel_spi_probe(struct platform_device *pdev)
+ as->regs = ioremap(regs->start, resource_size(regs));
+ if (!as->regs)
+ goto out_free_buffer;
++ as->phybase = regs->start;
+ as->irq = irq;
+ as->clk = clk;
+
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0030-spi-atmel_spi-call-unmapping-on-transfers-buffers.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0030-spi-atmel_spi-call-unmapping-on-transfers-buffers.patch
new file mode 100644
index 0000000..753115f
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0030-spi-atmel_spi-call-unmapping-on-transfers-buffers.patch
@@ -0,0 +1,43 @@
+From 899a00e7d9329dd469569b5270cce53fee85ea73 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 16 Mar 2011 10:51:31 +0800
+Subject: [PATCH 030/107] spi/atmel_spi: call unmapping on transfers buffers
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/spi/atmel_spi.c | 8 +++++---
+ 1 files changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
+index c7967c8..add1f2b 100644
+--- a/drivers/spi/atmel_spi.c
++++ b/drivers/spi/atmel_spi.c
+@@ -858,6 +858,7 @@ static int __exit atmel_spi_remove(struct platform_device *pdev)
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct atmel_spi *as = spi_master_get_devdata(master);
+ struct spi_message *msg;
++ struct spi_transfer *xfer;
+
+ /* reset the hardware and block queue progress */
+ spin_lock_irq(&as->lock);
+@@ -869,9 +870,10 @@ static int __exit atmel_spi_remove(struct platform_device *pdev)
+
+ /* Terminate remaining queued transfers */
+ list_for_each_entry(msg, &as->queue, queue) {
+- /* REVISIT unmapping the dma is a NOP on ARM and AVR32
+- * but we shouldn't depend on that...
+- */
++ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
++ if (!msg->is_dma_mapped)
++ atmel_spi_dma_unmap_xfer(master, xfer);
++ }
+ msg->status = -ESHUTDOWN;
+ msg->complete(msg->context);
+ }
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0031-spi-atmel_spi-status-information-passed-through-cont.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0031-spi-atmel_spi-status-information-passed-through-cont.patch
new file mode 100644
index 0000000..aa83190
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0031-spi-atmel_spi-status-information-passed-through-cont.patch
@@ -0,0 +1,80 @@
+From f048800de322b4cf93a4c9f1c493875c1105308e Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 16 Mar 2011 11:29:12 +0800
+Subject: [PATCH 031/107] spi/atmel_spi: status information passed through
+ controller data
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The status of transfer is stored in controller data structure
+so that it can be used not only by atmel_spi_msg_done() function.
+This will be useful for upcoming dmaengine enabled driver.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/spi/atmel_spi.c | 13 ++++++++-----
+ 1 files changed, 8 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
+index add1f2b..f5e7f84 100644
+--- a/drivers/spi/atmel_spi.c
++++ b/drivers/spi/atmel_spi.c
+@@ -48,6 +48,7 @@ struct atmel_spi {
+ unsigned long current_remaining_bytes;
+ struct spi_transfer *next_transfer;
+ unsigned long next_remaining_bytes;
++ int done_status;
+
+ /* scratch buffer */
+ void *buffer;
+@@ -392,15 +393,15 @@ static void atmel_spi_dma_unmap_xfer(struct spi_master *master,
+
+ static void
+ atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
+- struct spi_message *msg, int status, int stay)
++ struct spi_message *msg, int stay)
+ {
+- if (!stay || status < 0)
++ if (!stay || as->done_status < 0)
+ cs_deactivate(as, msg->spi);
+ else
+ as->stay = msg->spi;
+
+ list_del(&msg->queue);
+- msg->status = status;
++ msg->status = as->done_status;
+
+ dev_dbg(master->dev.parent,
+ "xfer complete: %u bytes transferred\n",
+@@ -412,6 +413,7 @@ atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
+
+ as->current_transfer = NULL;
+ as->next_transfer = NULL;
++ as->done_status = 0;
+
+ /* continue if needed */
+ if (list_empty(&as->queue) || as->stopping)
+@@ -489,7 +491,8 @@ atmel_spi_interrupt(int irq, void *dev_id)
+ /* Clear any overrun happening while cleaning up */
+ spi_readl(as, SR);
+
+- atmel_spi_msg_done(master, as, msg, -EIO, 0);
++ as->done_status = -EIO;
++ atmel_spi_msg_done(master, as, msg, 0);
+ } else if (pending & (SPI_BIT(RXBUFF) | SPI_BIT(ENDRX))) {
+ ret = IRQ_HANDLED;
+
+@@ -507,7 +510,7 @@ atmel_spi_interrupt(int irq, void *dev_id)
+
+ if (atmel_spi_xfer_is_last(msg, xfer)) {
+ /* report completed message */
+- atmel_spi_msg_done(master, as, msg, 0,
++ atmel_spi_msg_done(master, as, msg,
+ xfer->cs_change);
+ } else {
+ if (xfer->cs_change) {
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0032-spi-atmel_spi-add-flag-to-controller-data-for-lock-o.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0032-spi-atmel_spi-add-flag-to-controller-data-for-lock-o.patch
new file mode 100644
index 0000000..fbec5a8
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0032-spi-atmel_spi-add-flag-to-controller-data-for-lock-o.patch
@@ -0,0 +1,119 @@
+From 432d1ee3fc28e73e3ef4ddebd1ced25c5d88dfa3 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 16 Mar 2011 13:42:40 +0800
+Subject: [PATCH 032/107] spi/atmel_spi: add flag to controller data for lock
+ operations
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Will allow to drop the lock during DMA operations.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/spi/atmel_spi.c | 31 +++++++++++++++++++------------
+ 1 files changed, 19 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
+index f5e7f84..31293f6 100644
+--- a/drivers/spi/atmel_spi.c
++++ b/drivers/spi/atmel_spi.c
+@@ -34,6 +34,7 @@
+ */
+ struct atmel_spi {
+ spinlock_t lock;
++ unsigned long flags;
+
+ resource_size_t phybase;
+ void __iomem *regs;
+@@ -171,6 +172,16 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
+ gpio_set_value(asd->npcs_pin, !active);
+ }
+
++static void atmel_spi_lock(struct atmel_spi *as)
++{
++ spin_lock_irqsave(&as->lock, as->flags);
++}
++
++static void atmel_spi_unlock(struct atmel_spi *as)
++{
++ spin_unlock_irqrestore(&as->lock, as->flags);
++}
++
+ static inline int atmel_spi_xfer_is_last(struct spi_message *msg,
+ struct spi_transfer *xfer)
+ {
+@@ -407,9 +418,9 @@ atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
+ "xfer complete: %u bytes transferred\n",
+ msg->actual_length);
+
+- spin_unlock(&as->lock);
++ atmel_spi_unlock(as);
+ msg->complete(msg->context);
+- spin_lock(&as->lock);
++ atmel_spi_lock(as);
+
+ as->current_transfer = NULL;
+ as->next_transfer = NULL;
+@@ -636,13 +647,11 @@ static int atmel_spi_setup(struct spi_device *spi)
+ spi->controller_state = asd;
+ gpio_direction_output(npcs_pin, !(spi->mode & SPI_CS_HIGH));
+ } else {
+- unsigned long flags;
+-
+- spin_lock_irqsave(&as->lock, flags);
++ atmel_spi_lock(as);
+ if (as->stay == spi)
+ as->stay = NULL;
+ cs_deactivate(as, spi);
+- spin_unlock_irqrestore(&as->lock, flags);
++ atmel_spi_unlock(as);
+ }
+
+ asd->csr = csr;
+@@ -661,7 +670,6 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
+ {
+ struct atmel_spi *as;
+ struct spi_transfer *xfer;
+- unsigned long flags;
+ struct device *controller = spi->master->dev.parent;
+ u8 bits;
+ struct atmel_spi_device *asd;
+@@ -726,11 +734,11 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
+ msg->status = -EINPROGRESS;
+ msg->actual_length = 0;
+
+- spin_lock_irqsave(&as->lock, flags);
++ atmel_spi_lock(as);
+ list_add_tail(&msg->queue, &as->queue);
+ if (!as->current_transfer)
+ atmel_spi_next_message(spi->master);
+- spin_unlock_irqrestore(&as->lock, flags);
++ atmel_spi_unlock(as);
+
+ return 0;
+ }
+@@ -740,17 +748,16 @@ static void atmel_spi_cleanup(struct spi_device *spi)
+ struct atmel_spi *as = spi_master_get_devdata(spi->master);
+ struct atmel_spi_device *asd = spi->controller_state;
+ unsigned gpio = (unsigned) spi->controller_data;
+- unsigned long flags;
+
+ if (!asd)
+ return;
+
+- spin_lock_irqsave(&as->lock, flags);
++ atmel_spi_lock(as);
+ if (as->stay == spi) {
+ as->stay = NULL;
+ cs_deactivate(as, spi);
+ }
+- spin_unlock_irqrestore(&as->lock, flags);
++ atmel_spi_unlock(as);
+
+ spi->controller_state = NULL;
+ gpio_free(gpio);
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0033-spi-atmel_spi-add-dmaengine-support.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0033-spi-atmel_spi-add-dmaengine-support.patch
new file mode 100644
index 0000000..016f511
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0033-spi-atmel_spi-add-dmaengine-support.patch
@@ -0,0 +1,654 @@
+From be84b03606698da41300ef1dec2e4584874d7f39 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 21 Mar 2011 17:35:44 +0800
+Subject: [PATCH 033/107] spi/atmel_spi: add dmaengine support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/spi/Kconfig | 9 +
+ drivers/spi/atmel_spi.c | 483 ++++++++++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 482 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
+index fc14b8d..1080a0a 100644
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -74,6 +74,15 @@ config SPI_ATMEL
+ This selects a driver for the Atmel SPI Controller, present on
+ many AT32 (AVR32) and AT91 (ARM) chips.
+
++config SPI_ATMEL_DMA
++ bool "Atmel SPI DMA support"
++ depends on SPI_ATMEL && (ARCH_AT91SAM9G45 || ARCH_AT91SAM9X5) && DMA_ENGINE && EXPERIMENTAL
++ default y
++ help
++ Say Y here if you want the Atmel SPI driver to use the DMA engine. Data transfers
++ will be handled by the DMA controller: it will increase throughput and reduce
++ CPU utilization.
++
+ config SPI_BFIN
+ tristate "SPI controller driver for ADI Blackfin5xx"
+ depends on BLACKFIN
+diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
+index 31293f6..12d8a81 100644
+--- a/drivers/spi/atmel_spi.c
++++ b/drivers/spi/atmel_spi.c
+@@ -15,6 +15,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/delay.h>
+ #include <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
+ #include <linux/err.h>
+ #include <linux/interrupt.h>
+ #include <linux/spi/spi.h>
+@@ -24,9 +25,26 @@
+ #include <mach/board.h>
+ #include <mach/gpio.h>
+ #include <mach/cpu.h>
++#include <mach/at_hdmac.h>
+
+ #include "atmel_spi.h"
+
++#if defined(CONFIG_SPI_ATMEL_DMA)
++/* use PIO for small transfers, avoiding DMA setup/teardown overhead and
++ * cache operations; better heuristics consider wordsize and bitrate.
++ */
++#define DMA_MIN_BYTES 16
++
++struct atmel_spi_dma {
++ struct dma_chan *chan_rx;
++ struct dma_chan *chan_tx;
++ struct scatterlist sgrx;
++ struct scatterlist sgtx;
++ struct dma_async_tx_descriptor *data_desc_rx;
++ struct dma_async_tx_descriptor *data_desc_tx;
++};
++#endif
++
+ /*
+ * The core SPI transfer engine just talks to a register bank to set up
+ * DMA transfers; transfer queue progress is driven by IRQs. The clock
+@@ -45,6 +63,7 @@ struct atmel_spi {
+
+ u8 stopping;
+ struct list_head queue;
++ struct tasklet_struct tasklet;
+ struct spi_transfer *current_transfer;
+ unsigned long current_remaining_bytes;
+ struct spi_transfer *next_transfer;
+@@ -54,6 +73,11 @@ struct atmel_spi {
+ /* scratch buffer */
+ void *buffer;
+ dma_addr_t buffer_dma;
++
++#if defined(CONFIG_SPI_ATMEL_DMA)
++ /* dmaengine data */
++ struct atmel_spi_dma dma;
++#endif
+ };
+
+ /* Controller-specific per-slave state */
+@@ -182,6 +206,17 @@ static void atmel_spi_unlock(struct atmel_spi *as)
+ spin_unlock_irqrestore(&as->lock, as->flags);
+ }
+
++static inline bool atmel_spi_use_dma(struct spi_transfer *xfer)
++{
++#if defined(CONFIG_SPI_ATMEL_DMA)
++ if (xfer->len < DMA_MIN_BYTES)
++ return false;
++ return true;
++#else
++ return false;
++#endif
++}
++
+ static inline int atmel_spi_xfer_is_last(struct spi_message *msg,
+ struct spi_transfer *xfer)
+ {
+@@ -193,6 +228,258 @@ static inline int atmel_spi_xfer_can_be_chained(struct spi_transfer *xfer)
+ return xfer->delay_usecs == 0 && !xfer->cs_change;
+ }
+
++#if defined(CONFIG_SPI_ATMEL_DMA)
++static bool __init filter(struct dma_chan *chan, void *slave)
++{
++ struct at_dma_slave *sl = slave;
++
++ if (sl->dma_dev == chan->device->dev) {
++ chan->private = sl;
++ return true;
++ } else {
++ return false;
++ }
++}
++
++static int __init atmel_spi_configure_dma(struct spi_master *master)
++{
++ struct atmel_spi *as = spi_master_get_devdata(master);
++ struct device *controller = master->dev.parent;
++ struct at_dma_slave *sdata;
++
++ sdata = controller->platform_data;
++
++ if (sdata && sdata->dma_dev) {
++ dma_cap_mask_t mask;
++
++ /* setup DMA addresses */
++ sdata->rx_reg = (dma_addr_t)as->phybase + SPI_RDR;
++ sdata->tx_reg = (dma_addr_t)as->phybase + SPI_TDR;
++
++ /* Try to grab two DMA channels */
++ dma_cap_zero(mask);
++ dma_cap_set(DMA_SLAVE, mask);
++ as->dma.chan_tx = dma_request_channel(mask, filter, sdata);
++ if (as->dma.chan_tx)
++ as->dma.chan_rx = dma_request_channel(mask, filter, sdata);
++ }
++ if (!as->dma.chan_rx || !as->dma.chan_tx) {
++ if (as->dma.chan_rx)
++ dma_release_channel(as->dma.chan_rx);
++ if (as->dma.chan_tx)
++ dma_release_channel(as->dma.chan_tx);
++ dev_err(&as->pdev->dev, "DMA channel not available, "
++ "unable to use SPI\n");
++ return -EBUSY;
++ }
++
++ dev_info(&as->pdev->dev, "Using %s (tx) and "
++ " %s (rx) for DMA transfers\n",
++ dma_chan_name(as->dma.chan_tx),
++ dma_chan_name(as->dma.chan_rx));
++
++ return 0;
++}
++
++static void atmel_spi_stop_dma(struct atmel_spi *as)
++{
++ if (as->dma.chan_rx)
++ as->dma.chan_rx->device->device_control(as->dma.chan_rx,
++ DMA_TERMINATE_ALL, 0);
++ if (as->dma.chan_tx)
++ as->dma.chan_tx->device->device_control(as->dma.chan_tx,
++ DMA_TERMINATE_ALL, 0);
++}
++
++static void atmel_spi_release_dma(struct atmel_spi *as)
++{
++ if (as->dma.chan_rx)
++ dma_release_channel(as->dma.chan_rx);
++ if (as->dma.chan_tx)
++ dma_release_channel(as->dma.chan_tx);
++}
++
++/* This function is called by the DMA driver from tasklet context */
++static void dma_callback(void *data)
++{
++ struct spi_master *master = data;
++ struct atmel_spi *as = spi_master_get_devdata(master);
++
++ /* trigger SPI tasklet */
++ tasklet_schedule(&as->tasklet);
++}
++
++/*
++ * Next transfer using PIO.
++ * lock is held, spi tasklet is blocked
++ */
++static void atmel_spi_next_xfer_pio(struct spi_master *master,
++ struct spi_transfer *xfer)
++{
++ struct atmel_spi *as = spi_master_get_devdata(master);
++
++ dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_pio\n");
++
++ as->current_remaining_bytes = xfer->len;
++
++ /* Make sure data is not remaining in RDR */
++ spi_readl(as, RDR);
++ while (spi_readl(as, SR) & SPI_BIT(RDRF)) {
++ spi_readl(as, RDR);
++ cpu_relax();
++ }
++
++ if (xfer->tx_buf)
++ spi_writel(as, TDR, *(u8 *)(xfer->tx_buf));
++ else
++ spi_writel(as, TDR, 0);
++
++ dev_dbg(master->dev.parent,
++ " start pio xfer %p: len %u tx %p rx %p\n",
++ xfer, xfer->len, xfer->tx_buf, xfer->rx_buf);
++
++ /* Enable relevant interrupts */
++ spi_writel(as, IER, SPI_BIT(RDRF) | SPI_BIT(OVRES));
++}
++
++/*
++ * Submit next transfer for DMA.
++ * lock is held, spi tasklet is blocked
++ */
++static int atmel_spi_next_xfer_dma(struct spi_master *master,
++ struct spi_transfer *xfer)
++{
++ struct atmel_spi *as = spi_master_get_devdata(master);
++ struct dma_chan *rxchan = as->dma.chan_rx;
++ struct dma_chan *txchan = as->dma.chan_tx;
++ struct dma_async_tx_descriptor *rxdesc;
++ struct dma_async_tx_descriptor *txdesc;
++ dma_cookie_t cookie;
++
++ dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_dma\n");
++
++ /* Check that the channels are available */
++ if (!rxchan || !txchan)
++ return -ENODEV;
++
++ /* release lock for DMA operations */
++ atmel_spi_unlock(as);
++
++ /* prepare the RX dma transfer */
++ sg_init_table(&as->dma.sgrx, 1);
++ sg_dma_len(&as->dma.sgrx) = xfer->len;
++ if (xfer->rx_buf)
++ as->dma.sgrx.dma_address = xfer->rx_dma;
++ else
++ as->dma.sgrx.dma_address = as->buffer_dma;
++
++ /* prepare the TX dma transfer */
++ sg_init_table(&as->dma.sgtx, 1);
++ sg_dma_len(&as->dma.sgtx) = xfer->len;
++ if (xfer->tx_buf) {
++ as->dma.sgtx.dma_address = xfer->tx_dma;
++ } else {
++ as->dma.sgtx.dma_address = as->buffer_dma;
++ memset(as->buffer, 0, xfer->len);
++ }
++
++ /* Send both scatterlists */
++ rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
++ &as->dma.sgrx,
++ 1,
++ DMA_FROM_DEVICE,
++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ if (!rxdesc)
++ goto err_dma;
++
++ txdesc = txchan->device->device_prep_slave_sg(txchan,
++ &as->dma.sgtx,
++ 1,
++ DMA_TO_DEVICE,
++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ if (!txdesc)
++ goto err_dma;
++
++ dev_dbg(master->dev.parent,
++ " start dma xfer %p: len %u tx %p/%08x rx %p/%08x\n",
++ xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
++ xfer->rx_buf, xfer->rx_dma);
++
++ /* Enable relevant interrupts */
++ spi_writel(as, IER, SPI_BIT(OVRES));
++
++ /* Put the callback on the RX transfer only, that should finish last */
++ rxdesc->callback = dma_callback;
++ rxdesc->callback_param = master;
++
++ /* Submit and fire RX and TX with TX last so we're ready to read! */
++ cookie = rxdesc->tx_submit(rxdesc);
++ if (dma_submit_error(cookie))
++ goto err_dma;
++ cookie = txdesc->tx_submit(txdesc);
++ if (dma_submit_error(cookie))
++ goto err_dma;
++ rxchan->device->device_issue_pending(rxchan);
++ txchan->device->device_issue_pending(txchan);
++
++ /* take back lock */
++ atmel_spi_lock(as);
++ return 0;
++
++err_dma:
++ spi_writel(as, IDR, SPI_BIT(OVRES));
++ atmel_spi_stop_dma(as);
++ atmel_spi_lock(as);
++ return -ENOMEM;
++}
++
++/*
++ * Choose way to submit next transfer and start it.
++ * lock is held, spi tasklet is blocked
++ */
++static void atmel_spi_next_xfer(struct spi_master *master,
++ struct spi_message *msg)
++{
++ struct atmel_spi *as = spi_master_get_devdata(master);
++ struct spi_transfer *xfer;
++
++ dev_vdbg(&msg->spi->dev, "atmel_spi_next_xfer\n");
++
++ if (!as->current_transfer)
++ xfer = list_entry(msg->transfers.next,
++ struct spi_transfer, transfer_list);
++ else
++ xfer = list_entry(as->current_transfer->transfer_list.next,
++ struct spi_transfer, transfer_list);
++
++ as->current_transfer = xfer;
++
++ if (atmel_spi_use_dma(xfer)) {
++ if (!atmel_spi_next_xfer_dma(master, xfer))
++ return;
++ else
++ dev_err(&msg->spi->dev, "unable to use DMA, fallback to PIO\n");
++ }
++
++ /* use PIO if xfer is short or error appened using DMA */
++ atmel_spi_next_xfer_pio(master, xfer);
++}
++
++static void atmel_spi_disable_dma_irq(struct atmel_spi *as) {}
++#else
++static void atmel_spi_disable_dma_irq(struct atmel_spi *as)
++{
++ spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
++}
++
++static int __init atmel_spi_configure_dma(struct spi_master *master)
++{
++ struct atmel_spi *as = spi_master_get_devdata(master);
++
++ atmel_spi_disable_dma_irq(as);
++ return 0;
++}
++
+ static void atmel_spi_next_xfer_data(struct spi_master *master,
+ struct spi_transfer *xfer,
+ dma_addr_t *tx_dma,
+@@ -325,6 +612,10 @@ static void atmel_spi_next_xfer(struct spi_master *master,
+ spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));
+ }
+
++static void atmel_spi_stop_dma(struct atmel_spi *as) {}
++static void atmel_spi_release_dma(struct atmel_spi *as) {}
++#endif
++
+ static void atmel_spi_next_message(struct spi_master *master)
+ {
+ struct atmel_spi *as = spi_master_get_devdata(master);
+@@ -428,11 +719,175 @@ atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
+
+ /* continue if needed */
+ if (list_empty(&as->queue) || as->stopping)
+- spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
++ atmel_spi_disable_dma_irq(as);
+ else
+ atmel_spi_next_message(master);
+ }
+
++#if defined(CONFIG_SPI_ATMEL_DMA)
++/* Called from IRQ
++ * lock is held
++ *
++ * Must update "current_remaining_bytes" to keep track of data
++ * to transfer.
++ */
++static void
++atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer)
++{
++ u8 *txp;
++ u8 *rxp;
++ unsigned long xfer_pos = xfer->len - as->current_remaining_bytes;
++
++ if (xfer->rx_buf) {
++ rxp = ((u8 *)xfer->rx_buf) + xfer_pos;
++ *rxp = spi_readl(as, RDR);
++ } else {
++ spi_readl(as, RDR);
++ }
++
++ as->current_remaining_bytes--;
++
++ if (as->current_remaining_bytes) {
++ if (xfer->tx_buf) {
++ txp = ((u8 *)xfer->tx_buf) + xfer_pos + 1;
++ spi_writel(as, TDR, *txp);
++ } else {
++ spi_writel(as, TDR, 0);
++ }
++ }
++}
++
++/* Tasklet
++ * Called from DMA callback + pio transfer and overrun IRQ.
++ */
++static void atmel_spi_tasklet_func(unsigned long data)
++{
++ struct spi_master *master = (struct spi_master *)data;
++ struct atmel_spi *as = spi_master_get_devdata(master);
++ struct spi_message *msg;
++ struct spi_transfer *xfer;
++
++ dev_vdbg(master->dev.parent, "atmel_spi_tasklet_func\n");
++
++ atmel_spi_lock(as);
++
++ xfer = as->current_transfer;
++
++ if (xfer == NULL)
++ /* already been there */
++ goto tasklet_out;
++
++ msg = list_entry(as->queue.next, struct spi_message, queue);
++
++ if (as->done_status < 0) {
++ /* error happened (overrun) */
++ if (atmel_spi_use_dma(xfer))
++ atmel_spi_stop_dma(as);
++ } else {
++ /* only update length if no error */
++ msg->actual_length += xfer->len;
++ }
++
++ if (atmel_spi_use_dma(xfer)) {
++ if (!msg->is_dma_mapped)
++ atmel_spi_dma_unmap_xfer(master, xfer);
++ }
++
++ if (xfer->delay_usecs)
++ udelay(xfer->delay_usecs);
++
++ if (atmel_spi_xfer_is_last(msg, xfer) || as->done_status < 0) {
++ /* report completed (or erroneous) message */
++ atmel_spi_msg_done(master, as, msg, xfer->cs_change);
++ } else {
++ if (xfer->cs_change) {
++ cs_deactivate(as, msg->spi);
++ udelay(1);
++ cs_activate(as, msg->spi);
++ }
++
++ /*
++ * Not done yet. Submit the next transfer.
++ *
++ * FIXME handle protocol options for xfer
++ */
++ atmel_spi_next_xfer(master, msg);
++ }
++
++tasklet_out:
++ atmel_spi_unlock(as);
++}
++
++
++/* Interrupt with DMA engine management
++ *
++ * No need for locking in this Interrupt handler: done_status is the
++ * only information modified. What we need is the update of this field
++ * before tasklet runs. This is ensured by using barrier.
++ */
++static irqreturn_t
++atmel_spi_interrupt(int irq, void *dev_id)
++{
++ struct spi_master *master = dev_id;
++ struct atmel_spi *as = spi_master_get_devdata(master);
++ u32 status, pending, imr;
++ struct spi_transfer *xfer;
++ int ret = IRQ_NONE;
++
++ imr = spi_readl(as, IMR);
++ status = spi_readl(as, SR);
++ pending = status & imr;
++
++ if (pending & SPI_BIT(OVRES)) {
++ ret = IRQ_HANDLED;
++ spi_writel(as, IDR, SPI_BIT(OVRES));
++ dev_warn(master->dev.parent, "overrun\n");
++
++ /*
++ * When we get an overrun, we disregard the current
++ * transfer. Data will not be copied back from any
++ * bounce buffer and msg->actual_len will not be
++ * updated with the last xfer.
++ *
++ * We will also not process any remaning transfers in
++ * the message.
++ *
++ * All actions are done in tasklet with done_status indication
++ */
++ as->done_status = -EIO;
++ smp_wmb();
++
++ /* Clear any overrun happening while cleaning up */
++ spi_readl(as, SR);
++
++ tasklet_schedule(&as->tasklet);
++
++ } else if (pending & SPI_BIT(RDRF)) {
++ atmel_spi_lock(as);
++
++ if (as->current_remaining_bytes) {
++ ret = IRQ_HANDLED;
++ xfer = as->current_transfer;
++ atmel_spi_pump_pio_data(as, xfer);
++ if (!as->current_remaining_bytes) {
++ /* no more data to xfer, kick tasklet */
++ spi_writel(as, IDR, pending);
++ tasklet_schedule(&as->tasklet);
++ }
++ }
++
++ atmel_spi_unlock(as);
++ } else {
++ WARN_ONCE(pending, "IRQ not handled, pending = %x\n", pending);
++ ret = IRQ_HANDLED;
++ spi_writel(as, IDR, pending);
++ }
++
++ return ret;
++}
++#else
++static void atmel_spi_tasklet_func(unsigned long data) {}
++
+ static irqreturn_t
+ atmel_spi_interrupt(int irq, void *dev_id)
+ {
+@@ -550,6 +1005,7 @@ atmel_spi_interrupt(int irq, void *dev_id)
+
+ return ret;
+ }
++#endif
+
+ static int atmel_spi_setup(struct spi_device *spi)
+ {
+@@ -709,13 +1165,9 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
+
+ /*
+ * DMA map early, for performance (empties dcache ASAP) and
+- * better fault reporting. This is a DMA-only driver.
+- *
+- * NOTE that if dma_unmap_single() ever starts to do work on
+- * platforms supported by this driver, we would need to clean
+- * up mappings for previously-mapped transfers.
++ * better fault reporting.
+ */
+- if (!msg->is_dma_mapped) {
++ if (!msg->is_dma_mapped && atmel_spi_use_dma(xfer)) {
+ if (atmel_spi_dma_map_xfer(as, xfer) < 0)
+ return -ENOMEM;
+ }
+@@ -816,6 +1268,7 @@ static int __init atmel_spi_probe(struct platform_device *pdev)
+
+ spin_lock_init(&as->lock);
+ INIT_LIST_HEAD(&as->queue);
++ tasklet_init(&as->tasklet, atmel_spi_tasklet_func, (unsigned long)master);
+ as->pdev = pdev;
+ as->regs = ioremap(regs->start, resource_size(regs));
+ if (!as->regs)
+@@ -834,7 +1287,11 @@ static int __init atmel_spi_probe(struct platform_device *pdev)
+ spi_writel(as, CR, SPI_BIT(SWRST));
+ spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
+ spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS));
+- spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
++
++ ret = atmel_spi_configure_dma(master);
++ if (ret)
++ goto out_reset_hw;
++
+ spi_writel(as, CR, SPI_BIT(SPIEN));
+
+ /* go! */
+@@ -843,10 +1300,12 @@ static int __init atmel_spi_probe(struct platform_device *pdev)
+
+ ret = spi_register_master(master);
+ if (ret)
+- goto out_reset_hw;
++ goto out_free_dma;
+
+ return 0;
+
++out_free_dma:
++ atmel_spi_release_dma(as);
+ out_reset_hw:
+ spi_writel(as, CR, SPI_BIT(SWRST));
+ spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
+@@ -855,6 +1314,7 @@ out_reset_hw:
+ out_unmap_regs:
+ iounmap(as->regs);
+ out_free_buffer:
++ tasklet_kill(&as->tasklet);
+ dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
+ as->buffer_dma);
+ out_free:
+@@ -873,6 +1333,8 @@ static int __exit atmel_spi_remove(struct platform_device *pdev)
+ /* reset the hardware and block queue progress */
+ spin_lock_irq(&as->lock);
+ as->stopping = 1;
++ atmel_spi_stop_dma(as);
++ atmel_spi_release_dma(as);
+ spi_writel(as, CR, SPI_BIT(SWRST));
+ spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
+ spi_readl(as, SR);
+@@ -881,13 +1343,14 @@ static int __exit atmel_spi_remove(struct platform_device *pdev)
+ /* Terminate remaining queued transfers */
+ list_for_each_entry(msg, &as->queue, queue) {
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+- if (!msg->is_dma_mapped)
++ if (!msg->is_dma_mapped && atmel_spi_use_dma(xfer))
+ atmel_spi_dma_unmap_xfer(master, xfer);
+ }
+ msg->status = -ESHUTDOWN;
+ msg->complete(msg->context);
+ }
+
++ tasklet_kill(&as->tasklet);
+ dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
+ as->buffer_dma);
+
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0034-net-can-allow-CAN_AT91-on-AT91SAM9X5.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0034-net-can-allow-CAN_AT91-on-AT91SAM9X5.patch
new file mode 100644
index 0000000..3be4cfa
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0034-net-can-allow-CAN_AT91-on-AT91SAM9X5.patch
@@ -0,0 +1,33 @@
+From a84abb9decfb07211601ac972a2d101b83068ea3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
+Date: Tue, 26 Apr 2011 15:05:59 +0200
+Subject: [PATCH 034/107] net/can: allow CAN_AT91 on AT91SAM9X5
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/net/can/Kconfig | 5 +++--
+ 1 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
+index 1d699e3..bbf06f7 100644
+--- a/drivers/net/can/Kconfig
++++ b/drivers/net/can/Kconfig
+@@ -58,9 +58,10 @@ config CAN_CALC_BITTIMING
+
+ config CAN_AT91
+ tristate "Atmel AT91 onchip CAN controller"
+- depends on CAN_DEV && ARCH_AT91SAM9263
++ depends on CAN_DEV && (ARCH_AT91SAM9263 || ARCH_AT91SAM9X5)
+ ---help---
+- This is a driver for the SoC CAN controller in Atmel's AT91SAM9263.
++ This is a driver for the SoC CAN controller in Atmel's AT91SAM9263
++ and AT91SAM9X5 processors.
+
+ config CAN_TI_HECC
+ depends on CAN_DEV && ARCH_OMAP3
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0035-Input-qt1070-Add-MODULE_DEVICE_TABLE.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0035-Input-qt1070-Add-MODULE_DEVICE_TABLE.patch
new file mode 100644
index 0000000..3d9a39e
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0035-Input-qt1070-Add-MODULE_DEVICE_TABLE.patch
@@ -0,0 +1,34 @@
+From ee417d527f59f8d30ea232e142ba02a95bc541f2 Mon Sep 17 00:00:00 2001
+From: Axel Lin <axel.lin@gmail.com>
+Date: Sun, 24 Apr 2011 15:22:45 +0000
+Subject: [PATCH 035/107] Input: qt1070 - Add MODULE_DEVICE_TABLE
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Adding the necessary MODULE_DEVICE_TABLE() information allows the
+driver to be automatically loaded by udev
+
+Signed-off-by: Axel Lin <axel.lin@gmail.com>
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Origin: upstream, commit:94bb530c247a29f75fc728e5f8374a83d59d7e45
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/input/keyboard/qt1070.c | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c
+index fba8404..ca7b891 100644
+--- a/drivers/input/keyboard/qt1070.c
++++ b/drivers/input/keyboard/qt1070.c
+@@ -248,6 +248,7 @@ static const struct i2c_device_id qt1070_id[] = {
+ { "qt1070", 0 },
+ { },
+ };
++MODULE_DEVICE_TABLE(i2c, qt1070_id);
+
+ static struct i2c_driver qt1070_driver = {
+ .driver = {
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0036-Input-qt1070-trivial-fix-CHANGE-line-typo.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0036-Input-qt1070-trivial-fix-CHANGE-line-typo.patch
new file mode 100644
index 0000000..3e5a30d
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0036-Input-qt1070-trivial-fix-CHANGE-line-typo.patch
@@ -0,0 +1,30 @@
+From aef9d83e07df0fd4cc590faf597373cdd05f9e7f Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 25 May 2011 18:33:52 +0200
+Subject: [PATCH 036/107] Input: qt1070: trivial: fix CHANGE line typo
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/input/keyboard/qt1070.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c
+index ca7b891..f2cd759 100644
+--- a/drivers/input/keyboard/qt1070.c
++++ b/drivers/input/keyboard/qt1070.c
+@@ -216,7 +216,7 @@ static int __devinit qt1070_probe(struct i2c_client *client,
+
+ i2c_set_clientdata(client, data);
+
+- /* Read to clear the chang line */
++ /* Read to clear the CHANGE line */
+ qt1070_read(client, DET_STATUS);
+
+ return 0;
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0037-Input-qt1070-add-power-management-suspend-resume.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0037-Input-qt1070-add-power-management-suspend-resume.patch
new file mode 100644
index 0000000..e77a415
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0037-Input-qt1070-add-power-management-suspend-resume.patch
@@ -0,0 +1,166 @@
+From 13daa6596a3b571eb7d46f5e49344fb31833ab8d Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 17 May 2011 15:47:44 +0200
+Subject: [PATCH 037/107] Input: qt1070: add power management suspend/resume
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add the power management suspend/resume functions and enable the wakeup
+capacity of the dedicated IRQ.
+The Low Power Mode of the QT1070 is also positioned on suspend and default
+acquisition frequency is restored on resume. It will allow to save power.
+
+Based on work by Voice Shen.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/input/keyboard/qt1070.c | 85 +++++++++++++++++++++++++++++++++-----
+ 1 files changed, 73 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c
+index f2cd759..7aa0f9e 100644
+--- a/drivers/input/keyboard/qt1070.c
++++ b/drivers/input/keyboard/qt1070.c
+@@ -42,6 +42,9 @@
+ #define QT1070_FW_VERSION 0x15
+
+ #define DET_STATUS 0x02
++#define DET_STATUS_TOUCH 0x01
++#define DET_STATUS_OVER 0x40
++#define DET_STATUS_CALIBR 0x80
+
+ #define KEY_STATUS 0x03
+
+@@ -53,6 +56,10 @@
+ #define RESET 0x39
+ #define QT1070_RESET_TIME 255
+
++/* Low Power Mode */
++#define LP_MODE 0x54
++#define LP_MODE_LOW 255
++
+ /* AT42QT1070 support up to 7 keys */
+ static const unsigned short qt1070_key2code[] = {
+ KEY_0, KEY_1, KEY_2, KEY_3,
+@@ -65,6 +72,7 @@ struct qt1070_data {
+ unsigned int irq;
+ unsigned short keycodes[ARRAY_SIZE(qt1070_key2code)];
+ u8 last_keys;
++ u8 power_mode;
+ };
+
+ static int qt1070_read(struct i2c_client *client, u8 reg)
+@@ -114,29 +122,36 @@ static bool __devinit qt1070_identify(struct i2c_client *client)
+ return true;
+ }
+
+-static irqreturn_t qt1070_interrupt(int irq, void *dev_id)
++static void qt1070_report_key_pressed(struct qt1070_data *data, u8 key)
+ {
+- struct qt1070_data *data = dev_id;
+- struct i2c_client *client = data->client;
+ struct input_dev *input = data->input;
+ int i;
+- u8 new_keys, keyval, mask = 0x01;
+-
+- /* Read the detected status register, thus clearing interrupt */
+- qt1070_read(client, DET_STATUS);
+-
+- /* Read which key changed */
+- new_keys = qt1070_read(client, KEY_STATUS);
++ u8 keyval, mask = 0x01;
+
+ for (i = 0; i < ARRAY_SIZE(qt1070_key2code); i++) {
+- keyval = new_keys & mask;
++ keyval = key & mask;
+ if ((data->last_keys & mask) != keyval)
+ input_report_key(input, data->keycodes[i], keyval);
+ mask <<= 1;
+ }
+ input_sync(input);
+
+- data->last_keys = new_keys;
++ data->last_keys = key;
++}
++
++static irqreturn_t qt1070_interrupt(int irq, void *dev_id)
++{
++ struct qt1070_data *data = dev_id;
++ struct i2c_client *client = data->client;
++ u8 new_keys;
++
++ /* Read the detected status register, thus clearing interrupt */
++ qt1070_read(client, DET_STATUS);
++
++ /* Read which key changed */
++ new_keys = qt1070_read(client, KEY_STATUS);
++
++ qt1070_report_key_pressed(data, new_keys);
+ return IRQ_HANDLED;
+ }
+
+@@ -228,6 +243,51 @@ err_free_mem:
+ kfree(data);
+ return err;
+ }
++#ifdef CONFIG_PM
++static int qt1070_suspend(struct device *dev)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct qt1070_data *data = i2c_get_clientdata(client);
++
++ if (device_may_wakeup(dev)) {
++ enable_irq_wake(client->irq);
++ }
++
++ data->power_mode = qt1070_read(client, LP_MODE);
++ qt1070_write(client, LP_MODE, LP_MODE_LOW);
++
++ return 0;
++}
++
++static int qt1070_resume(struct device *dev)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct qt1070_data *data = i2c_get_clientdata(client);
++ u8 new_keys;
++
++ if (device_may_wakeup(dev)) {
++ disable_irq_wake(client->irq);
++ }
++
++ /* Read the detected status register, thus clearing interrupt */
++ qt1070_read(client, DET_STATUS);
++
++ /* Read which key changed */
++ new_keys = qt1070_read(client, KEY_STATUS);
++
++ qt1070_report_key_pressed(data, new_keys);
++
++ /* Restore power mode */
++ qt1070_write(client, LP_MODE, data->power_mode);
++
++ /* Drain remaining status */
++ while (qt1070_read(client, DET_STATUS) & DET_STATUS_TOUCH)
++ udelay(1);
++
++ return 0;
++}
++#endif
++static SIMPLE_DEV_PM_OPS(qt1070_pm, qt1070_suspend, qt1070_resume);
+
+ static int __devexit qt1070_remove(struct i2c_client *client)
+ {
+@@ -254,6 +314,7 @@ static struct i2c_driver qt1070_driver = {
+ .driver = {
+ .name = "qt1070",
+ .owner = THIS_MODULE,
++ .pm = &qt1070_pm,
+ },
+ .id_table = qt1070_id,
+ .probe = qt1070_probe,
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0038-dmaengine-at_hdmac-clear-channel-status-on-channel-r.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0038-dmaengine-at_hdmac-clear-channel-status-on-channel-r.patch
new file mode 100644
index 0000000..d0a892f
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0038-dmaengine-at_hdmac-clear-channel-status-on-channel-r.patch
@@ -0,0 +1,30 @@
+From 5b10093c7019fe3827d876bf3bfbdbb6ad015463 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 21 Apr 2011 18:36:43 +0200
+Subject: [PATCH 038/107] dmaengine: at_hdmac: clear channel status on channel
+ release
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/dma/at_hdmac.c | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
+index db2c0bd..7fb4b57 100644
+--- a/drivers/dma/at_hdmac.c
++++ b/drivers/dma/at_hdmac.c
+@@ -1107,6 +1107,7 @@ static void atc_free_chan_resources(struct dma_chan *chan)
+ }
+ list_splice_init(&atchan->free_list, &list);
+ atchan->descs_allocated = 0;
++ atchan->status = 0;
+
+ dev_vdbg(chan2dev(chan), "free_chan_resources: done\n");
+ }
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0039-dmaengine-at_hdmac-set-residue-as-total-len-in-atc_t.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0039-dmaengine-at_hdmac-set-residue-as-total-len-in-atc_t.patch
new file mode 100644
index 0000000..0925537
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0039-dmaengine-at_hdmac-set-residue-as-total-len-in-atc_t.patch
@@ -0,0 +1,41 @@
+From 22ed20ae109f8b777b9f3068def49eea74ff7ab4 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 2 May 2011 17:48:30 +0200
+Subject: [PATCH 039/107] dmaengine: at_hdmac: set residue as total len in
+ atc_tx_status
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+If transfer status is !=DMA_SUCCESS, return total transfer len as residue,
+instead of zero.
+
+Idea from dw_dmac patch by Viresh Kumar.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/dma/at_hdmac.c | 7 ++++++-
+ 1 files changed, 6 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
+index 7fb4b57..f2f589c 100644
+--- a/drivers/dma/at_hdmac.c
++++ b/drivers/dma/at_hdmac.c
+@@ -979,7 +979,12 @@ atc_tx_status(struct dma_chan *chan,
+
+ spin_unlock_bh(&atchan->lock);
+
+- dma_set_tx_state(txstate, last_complete, last_used, 0);
++ if (ret != DMA_SUCCESS)
++ dma_set_tx_state(txstate, last_complete, last_used,
++ atc_first_active(atchan)->len);
++ else
++ dma_set_tx_state(txstate, last_complete, last_used, 0);
++
+ dev_vdbg(chan2dev(chan), "tx_status: %d (d%d, u%d)\n",
+ cookie, last_complete ? last_complete : 0,
+ last_used ? last_used : 0);
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0040-dmaengine-at_hdmac-implement-pause-and-resume-in-atc.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0040-dmaengine-at_hdmac-implement-pause-and-resume-in-atc.patch
new file mode 100644
index 0000000..5538423
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0040-dmaengine-at_hdmac-implement-pause-and-resume-in-atc.patch
@@ -0,0 +1,170 @@
+From 662cdace226d8aba7f0fc0931f5099b125609ea8 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Fri, 6 May 2011 19:56:52 +0200
+Subject: [PATCH 040/107] dmaengine: at_hdmac: implement pause and resume in
+ atc_control
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Pause and resume controls are useful for audio devices. This also returns
+correct status from atc_tx_status() in case chan is paused.
+
+Idea from dw_dmac patch by Linus Walleij.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Vinod Koul <vinod.koul@intel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/dma/at_hdmac.c | 98 ++++++++++++++++++++++++++++++------------
+ drivers/dma/at_hdmac_regs.h | 1 +
+ 2 files changed, 71 insertions(+), 28 deletions(-)
+
+diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
+index f2f589c..1999703 100644
+--- a/drivers/dma/at_hdmac.c
++++ b/drivers/dma/at_hdmac.c
+@@ -484,7 +484,8 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id)
+ if (pending & (AT_DMA_BTC(i) | AT_DMA_ERR(i))) {
+ if (pending & AT_DMA_ERR(i)) {
+ /* Disable channel on AHB error */
+- dma_writel(atdma, CHDR, atchan->mask);
++ dma_writel(atdma, CHDR,
++ AT_DMA_RES(i) | atchan->mask);
+ /* Give information to tasklet */
+ set_bit(ATC_IS_ERROR, &atchan->status);
+ }
+@@ -904,40 +905,78 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ {
+ struct at_dma_chan *atchan = to_at_dma_chan(chan);
+ struct at_dma *atdma = to_at_dma(chan->device);
+- struct at_desc *desc, *_desc;
++ int chan_id = atchan->chan_common.chan_id;
++
+ LIST_HEAD(list);
+
+- /* Only supports DMA_TERMINATE_ALL */
+- if (cmd != DMA_TERMINATE_ALL)
+- return -ENXIO;
++ dev_vdbg(chan2dev(chan), "atc_control (%d)\n", cmd);
+
+- /*
+- * This is only called when something went wrong elsewhere, so
+- * we don't really care about the data. Just disable the
+- * channel. We still have to poll the channel enable bit due
+- * to AHB/HSB limitations.
+- */
+- spin_lock_bh(&atchan->lock);
++ if (cmd == DMA_PAUSE) {
++ int pause_timeout = 1000;
+
+- dma_writel(atdma, CHDR, atchan->mask);
++ spin_lock_bh(&atchan->lock);
+
+- /* confirm that this channel is disabled */
+- while (dma_readl(atdma, CHSR) & atchan->mask)
+- cpu_relax();
++ dma_writel(atdma, CHER, AT_DMA_SUSP(chan_id));
++
++ /* wait for FIFO to be empty */
++ while (!(dma_readl(atdma, CHSR) & AT_DMA_EMPT(chan_id))) {
++ if (pause_timeout-- > 0) {
++ /* the FIFO can only drain if the peripheral
++ * is still requesting data:
++ * -> timeout if it is not the case. */
++ dma_writel(atdma, CHDR, AT_DMA_RES(chan_id));
++ spin_unlock_bh(&atchan->lock);
++ return -ETIMEDOUT;
++ }
++ cpu_relax();
++ }
+
+- /* active_list entries will end up before queued entries */
+- list_splice_init(&atchan->queue, &list);
+- list_splice_init(&atchan->active_list, &list);
++ set_bit(ATC_IS_PAUSED, &atchan->status);
+
+- /* Flush all pending and queued descriptors */
+- list_for_each_entry_safe(desc, _desc, &list, desc_node)
+- atc_chain_complete(atchan, desc);
++ spin_unlock_bh(&atchan->lock);
++ } else if (cmd == DMA_RESUME) {
++ if (!test_bit(ATC_IS_PAUSED, &atchan->status))
++ return 0;
+
+- spin_unlock_bh(&atchan->lock);
++ spin_lock_bh(&atchan->lock);
+
+- /* XXX/ukl: should this be done with bh disabled? */
+- /* if channel dedicated to cyclic operations, free it */
+- clear_bit(ATC_IS_CYCLIC, &atchan->status);
++ dma_writel(atdma, CHDR, AT_DMA_RES(chan_id));
++ clear_bit(ATC_IS_PAUSED, &atchan->status);
++
++ spin_unlock_bh(&atchan->lock);
++ } else if (cmd == DMA_TERMINATE_ALL) {
++ struct at_desc *desc, *_desc;
++ /*
++ * This is only called when something went wrong elsewhere, so
++ * we don't really care about the data. Just disable the
++ * channel. We still have to poll the channel enable bit due
++ * to AHB/HSB limitations.
++ */
++ spin_lock_bh(&atchan->lock);
++
++ /* disabling channel: must also remove suspend state */
++ dma_writel(atdma, CHDR, AT_DMA_RES(chan_id) | atchan->mask);
++
++ /* confirm that this channel is disabled */
++ while (dma_readl(atdma, CHSR) & atchan->mask)
++ cpu_relax();
++
++ /* active_list entries will end up before queued entries */
++ list_splice_init(&atchan->queue, &list);
++ list_splice_init(&atchan->active_list, &list);
++
++ /* Flush all pending and queued descriptors */
++ list_for_each_entry_safe(desc, _desc, &list, desc_node)
++ atc_chain_complete(atchan, desc);
++
++ clear_bit(ATC_IS_PAUSED, &atchan->status);
++ /* if channel dedicated to cyclic operations, free it */
++ clear_bit(ATC_IS_CYCLIC, &atchan->status);
++
++ spin_unlock_bh(&atchan->lock);
++ } else {
++ return -ENXIO;
++ }
+
+ return 0;
+ }
+@@ -985,8 +1024,11 @@ atc_tx_status(struct dma_chan *chan,
+ else
+ dma_set_tx_state(txstate, last_complete, last_used, 0);
+
+- dev_vdbg(chan2dev(chan), "tx_status: %d (d%d, u%d)\n",
+- cookie, last_complete ? last_complete : 0,
++ if (test_bit(ATC_IS_PAUSED, &atchan->status))
++ ret = DMA_PAUSED;
++
++ dev_vdbg(chan2dev(chan), "tx_status %d: cookie = %d (d%d, u%d)\n",
++ ret, cookie, last_complete ? last_complete : 0,
+ last_used ? last_used : 0);
+
+ return ret;
+diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h
+index 9afcb8d..629703a 100644
+--- a/drivers/dma/at_hdmac_regs.h
++++ b/drivers/dma/at_hdmac_regs.h
+@@ -189,6 +189,7 @@ txd_to_at_desc(struct dma_async_tx_descriptor *txd)
+ */
+ enum atc_status {
+ ATC_IS_ERROR = 0,
++ ATC_IS_PAUSED = 1,
+ ATC_IS_CYCLIC = 24,
+ };
+
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0041-dmaengine-at_hdmac-pause-no-need-to-wait-for-FIFO-em.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0041-dmaengine-at_hdmac-pause-no-need-to-wait-for-FIFO-em.patch
new file mode 100644
index 0000000..af628d0
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0041-dmaengine-at_hdmac-pause-no-need-to-wait-for-FIFO-em.patch
@@ -0,0 +1,60 @@
+From a8a86b647c212d379d8df079d0c57a3ab26848fc Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 9 May 2011 18:11:37 +0200
+Subject: [PATCH 041/107] dmaengine: at_hdmac: pause: no need to wait for FIFO
+ empty
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+With the addition of the "pause" feature, an active wait was introduced
+to check the "FIFO empty" event. This event was not always happening and
+a timout contition was needed.
+But, in some cases, this event depend on the peripheral connected to the
+channel that is paused: FIFO becomes empty if the peripheral consumes data.
+The timeout is pretty difficult to evaluate. Moreover, this check is not
+needed.
+In conclusion, it seems sensible to entirely remove the checking of
+"FIFO empty" status when pausing.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+[commit msg edited for grammer]
+Signed-off-by: Vinod Koul <vinod.koul@intel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/dma/at_hdmac.c | 16 ----------------
+ 1 files changed, 0 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
+index 1999703..f11f640 100644
+--- a/drivers/dma/at_hdmac.c
++++ b/drivers/dma/at_hdmac.c
+@@ -912,25 +912,9 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ dev_vdbg(chan2dev(chan), "atc_control (%d)\n", cmd);
+
+ if (cmd == DMA_PAUSE) {
+- int pause_timeout = 1000;
+-
+ spin_lock_bh(&atchan->lock);
+
+ dma_writel(atdma, CHER, AT_DMA_SUSP(chan_id));
+-
+- /* wait for FIFO to be empty */
+- while (!(dma_readl(atdma, CHSR) & AT_DMA_EMPT(chan_id))) {
+- if (pause_timeout-- > 0) {
+- /* the FIFO can only drain if the peripheral
+- * is still requesting data:
+- * -> timeout if it is not the case. */
+- dma_writel(atdma, CHDR, AT_DMA_RES(chan_id));
+- spin_unlock_bh(&atchan->lock);
+- return -ETIMEDOUT;
+- }
+- cpu_relax();
+- }
+-
+ set_bit(ATC_IS_PAUSED, &atchan->status);
+
+ spin_unlock_bh(&atchan->lock);
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0042-dmaengine-at_hdmac-replace-spin_lock-with-irqsave-va.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0042-dmaengine-at_hdmac-replace-spin_lock-with-irqsave-va.patch
new file mode 100644
index 0000000..f936c9c
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0042-dmaengine-at_hdmac-replace-spin_lock-with-irqsave-va.patch
@@ -0,0 +1,244 @@
+From 14a52d058779054c81e68a0feda2a2f382ce16c3 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 9 May 2011 18:20:21 +0200
+Subject: [PATCH 042/107] dmaengine: at_hdmac: replace spin_lock* with irqsave
+ variants
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+dmaengine routines can be called from interrupt context and with
+interrupts disabled. Whereas spin_unlock_bh can't be called from
+such contexts. So this patch converts all spin_lock* routines
+to irqsave variants.
+
+Also, spin_lock() used in tasklet is converted to irqsave variants,
+as tasklet can be interrupted, and dma requests from such interruptions
+may also call spin_lock.
+
+Idea from dw_dmac patch by Viresh Kumar.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/dma/at_hdmac.c | 52 +++++++++++++++++++++++++++--------------------
+ 1 files changed, 30 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
+index f11f640..b29942a 100644
+--- a/drivers/dma/at_hdmac.c
++++ b/drivers/dma/at_hdmac.c
+@@ -106,10 +106,11 @@ static struct at_desc *atc_desc_get(struct at_dma_chan *atchan)
+ {
+ struct at_desc *desc, *_desc;
+ struct at_desc *ret = NULL;
++ unsigned long flags;
+ unsigned int i = 0;
+ LIST_HEAD(tmp_list);
+
+- spin_lock_bh(&atchan->lock);
++ spin_lock_irqsave(&atchan->lock, flags);
+ list_for_each_entry_safe(desc, _desc, &atchan->free_list, desc_node) {
+ i++;
+ if (async_tx_test_ack(&desc->txd)) {
+@@ -120,7 +121,7 @@ static struct at_desc *atc_desc_get(struct at_dma_chan *atchan)
+ dev_dbg(chan2dev(&atchan->chan_common),
+ "desc %p not ACKed\n", desc);
+ }
+- spin_unlock_bh(&atchan->lock);
++ spin_unlock_irqrestore(&atchan->lock, flags);
+ dev_vdbg(chan2dev(&atchan->chan_common),
+ "scanned %u descriptors on freelist\n", i);
+
+@@ -128,9 +129,9 @@ static struct at_desc *atc_desc_get(struct at_dma_chan *atchan)
+ if (!ret) {
+ ret = atc_alloc_descriptor(&atchan->chan_common, GFP_ATOMIC);
+ if (ret) {
+- spin_lock_bh(&atchan->lock);
++ spin_lock_irqsave(&atchan->lock, flags);
+ atchan->descs_allocated++;
+- spin_unlock_bh(&atchan->lock);
++ spin_unlock_irqrestore(&atchan->lock, flags);
+ } else {
+ dev_err(chan2dev(&atchan->chan_common),
+ "not enough descriptors available\n");
+@@ -149,8 +150,9 @@ static void atc_desc_put(struct at_dma_chan *atchan, struct at_desc *desc)
+ {
+ if (desc) {
+ struct at_desc *child;
++ unsigned long flags;
+
+- spin_lock_bh(&atchan->lock);
++ spin_lock_irqsave(&atchan->lock, flags);
+ list_for_each_entry(child, &desc->tx_list, desc_node)
+ dev_vdbg(chan2dev(&atchan->chan_common),
+ "moving child desc %p to freelist\n",
+@@ -159,7 +161,7 @@ static void atc_desc_put(struct at_dma_chan *atchan, struct at_desc *desc)
+ dev_vdbg(chan2dev(&atchan->chan_common),
+ "moving desc %p to freelist\n", desc);
+ list_add(&desc->desc_node, &atchan->free_list);
+- spin_unlock_bh(&atchan->lock);
++ spin_unlock_irqrestore(&atchan->lock, flags);
+ }
+ }
+
+@@ -447,8 +449,9 @@ static void atc_handle_cyclic(struct at_dma_chan *atchan)
+ static void atc_tasklet(unsigned long data)
+ {
+ struct at_dma_chan *atchan = (struct at_dma_chan *)data;
++ unsigned long flags;
+
+- spin_lock(&atchan->lock);
++ spin_lock_irqsave(&atchan->lock, flags);
+ if (test_and_clear_bit(ATC_IS_ERROR, &atchan->status))
+ atc_handle_error(atchan);
+ else if (test_bit(ATC_IS_CYCLIC, &atchan->status))
+@@ -456,7 +459,7 @@ static void atc_tasklet(unsigned long data)
+ else
+ atc_advance_work(atchan);
+
+- spin_unlock(&atchan->lock);
++ spin_unlock_irqrestore(&atchan->lock, flags);
+ }
+
+ static irqreturn_t at_dma_interrupt(int irq, void *dev_id)
+@@ -515,8 +518,9 @@ static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx)
+ struct at_desc *desc = txd_to_at_desc(tx);
+ struct at_dma_chan *atchan = to_at_dma_chan(tx->chan);
+ dma_cookie_t cookie;
++ unsigned long flags;
+
+- spin_lock_bh(&atchan->lock);
++ spin_lock_irqsave(&atchan->lock, flags);
+ cookie = atc_assign_cookie(atchan, desc);
+
+ if (list_empty(&atchan->active_list)) {
+@@ -530,7 +534,7 @@ static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx)
+ list_add_tail(&desc->desc_node, &atchan->queue);
+ }
+
+- spin_unlock_bh(&atchan->lock);
++ spin_unlock_irqrestore(&atchan->lock, flags);
+
+ return cookie;
+ }
+@@ -906,28 +910,29 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ struct at_dma_chan *atchan = to_at_dma_chan(chan);
+ struct at_dma *atdma = to_at_dma(chan->device);
+ int chan_id = atchan->chan_common.chan_id;
++ unsigned long flags;
+
+ LIST_HEAD(list);
+
+ dev_vdbg(chan2dev(chan), "atc_control (%d)\n", cmd);
+
+ if (cmd == DMA_PAUSE) {
+- spin_lock_bh(&atchan->lock);
++ spin_lock_irqsave(&atchan->lock, flags);
+
+ dma_writel(atdma, CHER, AT_DMA_SUSP(chan_id));
+ set_bit(ATC_IS_PAUSED, &atchan->status);
+
+- spin_unlock_bh(&atchan->lock);
++ spin_unlock_irqrestore(&atchan->lock, flags);
+ } else if (cmd == DMA_RESUME) {
+ if (!test_bit(ATC_IS_PAUSED, &atchan->status))
+ return 0;
+
+- spin_lock_bh(&atchan->lock);
++ spin_lock_irqsave(&atchan->lock, flags);
+
+ dma_writel(atdma, CHDR, AT_DMA_RES(chan_id));
+ clear_bit(ATC_IS_PAUSED, &atchan->status);
+
+- spin_unlock_bh(&atchan->lock);
++ spin_unlock_irqrestore(&atchan->lock, flags);
+ } else if (cmd == DMA_TERMINATE_ALL) {
+ struct at_desc *desc, *_desc;
+ /*
+@@ -936,7 +941,7 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ * channel. We still have to poll the channel enable bit due
+ * to AHB/HSB limitations.
+ */
+- spin_lock_bh(&atchan->lock);
++ spin_lock_irqsave(&atchan->lock, flags);
+
+ /* disabling channel: must also remove suspend state */
+ dma_writel(atdma, CHDR, AT_DMA_RES(chan_id) | atchan->mask);
+@@ -957,7 +962,7 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ /* if channel dedicated to cyclic operations, free it */
+ clear_bit(ATC_IS_CYCLIC, &atchan->status);
+
+- spin_unlock_bh(&atchan->lock);
++ spin_unlock_irqrestore(&atchan->lock, flags);
+ } else {
+ return -ENXIO;
+ }
+@@ -983,9 +988,10 @@ atc_tx_status(struct dma_chan *chan,
+ struct at_dma_chan *atchan = to_at_dma_chan(chan);
+ dma_cookie_t last_used;
+ dma_cookie_t last_complete;
++ unsigned long flags;
+ enum dma_status ret;
+
+- spin_lock_bh(&atchan->lock);
++ spin_lock_irqsave(&atchan->lock, flags);
+
+ last_complete = atchan->completed_cookie;
+ last_used = chan->cookie;
+@@ -1000,7 +1006,7 @@ atc_tx_status(struct dma_chan *chan,
+ ret = dma_async_is_complete(cookie, last_complete, last_used);
+ }
+
+- spin_unlock_bh(&atchan->lock);
++ spin_unlock_irqrestore(&atchan->lock, flags);
+
+ if (ret != DMA_SUCCESS)
+ dma_set_tx_state(txstate, last_complete, last_used,
+@@ -1025,6 +1031,7 @@ atc_tx_status(struct dma_chan *chan,
+ static void atc_issue_pending(struct dma_chan *chan)
+ {
+ struct at_dma_chan *atchan = to_at_dma_chan(chan);
++ unsigned long flags;
+
+ dev_vdbg(chan2dev(chan), "issue_pending\n");
+
+@@ -1032,11 +1039,11 @@ static void atc_issue_pending(struct dma_chan *chan)
+ if (test_bit(ATC_IS_CYCLIC, &atchan->status))
+ return;
+
+- spin_lock_bh(&atchan->lock);
++ spin_lock_irqsave(&atchan->lock, flags);
+ if (!atc_chan_is_enabled(atchan)) {
+ atc_advance_work(atchan);
+ }
+- spin_unlock_bh(&atchan->lock);
++ spin_unlock_irqrestore(&atchan->lock, flags);
+ }
+
+ /**
+@@ -1052,6 +1059,7 @@ static int atc_alloc_chan_resources(struct dma_chan *chan)
+ struct at_dma *atdma = to_at_dma(chan->device);
+ struct at_desc *desc;
+ struct at_dma_slave *atslave;
++ unsigned long flags;
+ int i;
+ u32 cfg;
+ LIST_HEAD(tmp_list);
+@@ -1095,11 +1103,11 @@ static int atc_alloc_chan_resources(struct dma_chan *chan)
+ list_add_tail(&desc->desc_node, &tmp_list);
+ }
+
+- spin_lock_bh(&atchan->lock);
++ spin_lock_irqsave(&atchan->lock, flags);
+ atchan->descs_allocated = i;
+ list_splice(&tmp_list, &atchan->free_list);
+ atchan->completed_cookie = chan->cookie = 1;
+- spin_unlock_bh(&atchan->lock);
++ spin_unlock_irqrestore(&atchan->lock, flags);
+
+ /* channel parameters */
+ channel_writel(atchan, CFG, cfg);
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0043-dmaengine-at_hdmac-improve-power-management-routines.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0043-dmaengine-at_hdmac-improve-power-management-routines.patch
new file mode 100644
index 0000000..b146b20
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0043-dmaengine-at_hdmac-improve-power-management-routines.patch
@@ -0,0 +1,182 @@
+From 66d750fa5b628797590fe9505137a4409a5badbe Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 19 May 2011 14:08:48 +0200
+Subject: [PATCH 043/107] dmaengine: at_hdmac: improve power management
+ routines
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Save/restore dma controller state across a suspend-resume sequence.
+The prepare() function will wait for the non-cyclic channels to become idle.
+It also deals with cyclic operations with the start at next period while
+resuming.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/dma/at_hdmac.c | 88 ++++++++++++++++++++++++++++++++++++++++++-
+ drivers/dma/at_hdmac_regs.h | 7 +++
+ 2 files changed, 94 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
+index b29942a..42b0e95 100644
+--- a/drivers/dma/at_hdmac.c
++++ b/drivers/dma/at_hdmac.c
+@@ -1364,27 +1364,113 @@ static void at_dma_shutdown(struct platform_device *pdev)
+ clk_disable(atdma->clk);
+ }
+
++static int at_dma_prepare(struct device *dev)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct at_dma *atdma = platform_get_drvdata(pdev);
++ struct dma_chan *chan, *_chan;
++
++ list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels,
++ device_node) {
++ struct at_dma_chan *atchan = to_at_dma_chan(chan);
++ /* wait for transaction completion (except in cyclic case) */
++ if (atc_chan_is_enabled(atchan) &&
++ !test_bit(ATC_IS_CYCLIC, &atchan->status))
++ return -EAGAIN;
++ }
++ return 0;
++}
++
++static void atc_suspend_cyclic(struct at_dma_chan *atchan)
++{
++ struct dma_chan *chan = &atchan->chan_common;
++
++ /* Channel should be paused by user
++ * do it anyway even if it is not done already */
++ if (!test_bit(ATC_IS_PAUSED, &atchan->status)) {
++ dev_warn(chan2dev(chan),
++ "cyclic channel not paused, should be done by channel user\n");
++ atc_control(chan, DMA_PAUSE, 0);
++ }
++
++ /* now preserve additional data for cyclic operations */
++ /* next descriptor address in the cyclic list */
++ atchan->save_dscr = channel_readl(atchan, DSCR);
++
++ vdbg_dump_regs(atchan);
++}
++
+ static int at_dma_suspend_noirq(struct device *dev)
+ {
+ struct platform_device *pdev = to_platform_device(dev);
+ struct at_dma *atdma = platform_get_drvdata(pdev);
++ struct dma_chan *chan, *_chan;
+
+- at_dma_off(platform_get_drvdata(pdev));
++ /* preserve data */
++ list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels,
++ device_node) {
++ struct at_dma_chan *atchan = to_at_dma_chan(chan);
++
++ if (test_bit(ATC_IS_CYCLIC, &atchan->status))
++ atc_suspend_cyclic(atchan);
++ atchan->save_cfg = channel_readl(atchan, CFG);
++ }
++ atdma->save_imr = dma_readl(atdma, EBCIMR);
++
++ /* disable DMA controller */
++ at_dma_off(atdma);
+ clk_disable(atdma->clk);
+ return 0;
+ }
+
++static void atc_resume_cyclic(struct at_dma_chan *atchan)
++{
++ struct at_dma *atdma = to_at_dma(atchan->chan_common.device);
++
++ /* restore channel status for cyclic descriptors list:
++ * next descriptor in the cyclic list at the time of suspend */
++ channel_writel(atchan, SADDR, 0);
++ channel_writel(atchan, DADDR, 0);
++ channel_writel(atchan, CTRLA, 0);
++ channel_writel(atchan, CTRLB, 0);
++ channel_writel(atchan, DSCR, atchan->save_dscr);
++ dma_writel(atdma, CHER, atchan->mask);
++
++ /* channel pause status should be removed by channel user
++ * We cannot take the initiative to do it here */
++
++ vdbg_dump_regs(atchan);
++}
++
+ static int at_dma_resume_noirq(struct device *dev)
+ {
+ struct platform_device *pdev = to_platform_device(dev);
+ struct at_dma *atdma = platform_get_drvdata(pdev);
++ struct dma_chan *chan, *_chan;
+
++ /* bring back DMA controller */
+ clk_enable(atdma->clk);
+ dma_writel(atdma, EN, AT_DMA_ENABLE);
++
++ /* clear any pending interrupt */
++ while (dma_readl(atdma, EBCISR))
++ cpu_relax();
++
++ /* restore saved data */
++ dma_writel(atdma, EBCIER, atdma->save_imr);
++ list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels,
++ device_node) {
++ struct at_dma_chan *atchan = to_at_dma_chan(chan);
++
++ channel_writel(atchan, CFG, atchan->save_cfg);
++ if (test_bit(ATC_IS_CYCLIC, &atchan->status))
++ atc_resume_cyclic(atchan);
++ }
+ return 0;
+ }
+
+ static const struct dev_pm_ops at_dma_dev_pm_ops = {
++ .prepare = at_dma_prepare,
+ .suspend_noirq = at_dma_suspend_noirq,
+ .resume_noirq = at_dma_resume_noirq,
+ };
+diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h
+index 629703a..a29c698 100644
+--- a/drivers/dma/at_hdmac_regs.h
++++ b/drivers/dma/at_hdmac_regs.h
+@@ -202,6 +202,9 @@ enum atc_status {
+ * @status: transmit status information from irq/prep* functions
+ * to tasklet (use atomic operations)
+ * @tasklet: bottom half to finish transaction work
++ * @save_cfg: configuration register that is saved on suspend/resume cycle
++ * @save_dscr: for cyclic operations, preserve next descriptor address in
++ * the cyclic list on suspend/resume cycle
+ * @lock: serializes enqueue/dequeue operations to descriptors lists
+ * @completed_cookie: identifier for the most recently completed operation
+ * @active_list: list of descriptors dmaengine is being running on
+@@ -216,6 +219,8 @@ struct at_dma_chan {
+ u8 mask;
+ unsigned long status;
+ struct tasklet_struct tasklet;
++ u32 save_cfg;
++ u32 save_dscr;
+
+ spinlock_t lock;
+
+@@ -246,6 +251,7 @@ static inline struct at_dma_chan *to_at_dma_chan(struct dma_chan *dchan)
+ * @chan_common: common dmaengine dma_device object members
+ * @ch_regs: memory mapped register base
+ * @clk: dma controller clock
++ * @save_imr: interrupt mask register that is saved on suspend/resume cycle
+ * @all_chan_mask: all channels availlable in a mask
+ * @dma_desc_pool: base of DMA descriptor region (DMA address)
+ * @chan: channels table to store at_dma_chan structures
+@@ -254,6 +260,7 @@ struct at_dma {
+ struct dma_device dma_common;
+ void __iomem *regs;
+ struct clk *clk;
++ u32 save_imr;
+
+ u8 all_chan_mask;
+
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0044-sound-atmel-pcm-trivial-typo-in-debug-comment.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0044-sound-atmel-pcm-trivial-typo-in-debug-comment.patch
new file mode 100644
index 0000000..50cc12d
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0044-sound-atmel-pcm-trivial-typo-in-debug-comment.patch
@@ -0,0 +1,30 @@
+From 6186270eb3654216ff51bd159444b46e83ffc5f2 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 6 Apr 2011 17:27:32 +0200
+Subject: [PATCH 044/107] sound/atmel-pcm: trivial: typo in debug comment
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ sound/soc/atmel/atmel-pcm.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c
+index d0e7532..51dde4e 100644
+--- a/sound/soc/atmel/atmel-pcm.c
++++ b/sound/soc/atmel/atmel-pcm.c
+@@ -382,7 +382,7 @@ static int atmel_pcm_new(struct snd_card *card,
+ }
+
+ if (dai->driver->capture.channels_min) {
+- pr_debug("at32-pcm:"
++ pr_debug("atmel-pcm:"
+ "Allocating PCM capture DMA buffer\n");
+ ret = atmel_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_CAPTURE);
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0045-sound-atmel-pcm-trivial-typo-in-atmel_pcm_dma_params.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0045-sound-atmel-pcm-trivial-typo-in-atmel_pcm_dma_params.patch
new file mode 100644
index 0000000..e0b6354
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0045-sound-atmel-pcm-trivial-typo-in-atmel_pcm_dma_params.patch
@@ -0,0 +1,31 @@
+From 139378503c1344fbad3f65af947b883055b8230d Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 6 Apr 2011 17:29:41 +0200
+Subject: [PATCH 045/107] sound/atmel-pcm: trivial: typo in
+ atmel_pcm_dma_params structure comment
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ sound/soc/atmel/atmel-pcm.h | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h
+index 2597329..5e0a95e 100644
+--- a/sound/soc/atmel/atmel-pcm.h
++++ b/sound/soc/atmel/atmel-pcm.h
+@@ -60,7 +60,7 @@ struct atmel_ssc_mask {
+ * This structure, shared between the PCM driver and the interface,
+ * contains all information required by the PCM driver to perform the
+ * PDC DMA operation. All fields except dma_intr_handler() are initialized
+- * by the interface. The dms_intr_handler() pointer is set by the PCM
++ * by the interface. The dma_intr_handler() pointer is set by the PCM
+ * driver and called by the interface SSC interrupt handler if it is
+ * non-NULL.
+ */
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0046-dmaengine-at_hdmac-add-slave-config-operation.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0046-dmaengine-at_hdmac-add-slave-config-operation.patch
new file mode 100644
index 0000000..f8ccbb3
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0046-dmaengine-at_hdmac-add-slave-config-operation.patch
@@ -0,0 +1,58 @@
+From 7499db30444de85e7cc8e7b0cf1576cb90e041ee Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 19 May 2011 17:09:20 +0200
+Subject: [PATCH 046/107] dmaengine: at_hdmac: add slave config operation
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/dma/at_hdmac.c | 30 ++++++++++++++++++++++++++++++
+ 1 files changed, 30 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
+index 42b0e95..f793804 100644
+--- a/drivers/dma/at_hdmac.c
++++ b/drivers/dma/at_hdmac.c
+@@ -933,6 +933,36 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ clear_bit(ATC_IS_PAUSED, &atchan->status);
+
+ spin_unlock_irqrestore(&atchan->lock, flags);
++ } else if (cmd == DMA_SLAVE_CONFIG) {
++ struct dma_slave_config *dmaengine_cfg = (void *)arg;
++ struct at_dma_slave *atslave = chan->private;
++ enum dma_slave_buswidth sdma_width;
++ enum at_dma_slave_width atdma_width;
++
++ /* only modify transfer size width */
++ if (!atslave)
++ return -ENXIO;
++
++ if (dmaengine_cfg->direction == DMA_FROM_DEVICE) {
++ sdma_width = dmaengine_cfg->src_addr_width;
++ } else {
++ sdma_width = dmaengine_cfg->dst_addr_width;
++ }
++
++ switch (sdma_width) {
++ case DMA_SLAVE_BUSWIDTH_1_BYTE:
++ atdma_width = AT_DMA_SLAVE_WIDTH_8BIT;
++ break;
++ case DMA_SLAVE_BUSWIDTH_2_BYTES:
++ atdma_width = AT_DMA_SLAVE_WIDTH_16BIT;
++ break;
++ case DMA_SLAVE_BUSWIDTH_4_BYTES:
++ atdma_width = AT_DMA_SLAVE_WIDTH_32BIT;
++ break;
++ default:
++ return -EINVAL;
++ }
++ atslave->reg_width = atdma_width;
+ } else if (cmd == DMA_TERMINATE_ALL) {
+ struct at_desc *desc, *_desc;
+ /*
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0047-SPI-m25p80-add-serial-flash-IDs.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0047-SPI-m25p80-add-serial-flash-IDs.patch
new file mode 100644
index 0000000..e6cf93c
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0047-SPI-m25p80-add-serial-flash-IDs.patch
@@ -0,0 +1,29 @@
+From 691890bc172ede0563732ca42bfea930249423bd Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 19 May 2011 17:12:59 +0200
+Subject: [PATCH 047/107] SPI: m25p80: add serial flash IDs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/mtd/devices/m25p80.c | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
+index 3fb981d..1fdc4ab 100644
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -648,6 +648,7 @@ static const struct spi_device_id m25p_ids[] = {
+ { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) },
+
+ { "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8, SECT_4K) },
++ { "at25df321", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) },
+ { "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) },
+
+ { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) },
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0048-sound-wm8731-rework-power-management.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0048-sound-wm8731-rework-power-management.patch
new file mode 100644
index 0000000..e27f502
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0048-sound-wm8731-rework-power-management.patch
@@ -0,0 +1,44 @@
+From e9364a4c457eed43d78f5d4c04f8fa364835fb9f Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 19 May 2011 14:14:34 +0200
+Subject: [PATCH 048/107] sound: wm8731: rework power management
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+- preserve crystal oscillator across suspend/resume sequence:
+ enabled by default,it should be kept enabled on resume.
+- if codec is in active state: set the active bit at resume time.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ sound/soc/codecs/wm8731.c | 5 ++++-
+ 1 files changed, 4 insertions(+), 1 deletions(-)
+
+diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
+index 0a67c31..aa55b84 100644
+--- a/sound/soc/codecs/wm8731.c
++++ b/sound/soc/codecs/wm8731.c
+@@ -492,7 +492,8 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
+ break;
+ case SND_SOC_BIAS_OFF:
+ snd_soc_write(codec, WM8731_ACTIVE, 0x0);
+- snd_soc_write(codec, WM8731_PWR, 0xffff);
++ /* standby: keep crystal oscillator enabled */
++ snd_soc_write(codec, WM8731_PWR, 0x00df);
+ regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies),
+ wm8731->supplies);
+ break;
+@@ -544,6 +545,8 @@ static int wm8731_suspend(struct snd_soc_codec *codec, pm_message_t state)
+ static int wm8731_resume(struct snd_soc_codec *codec)
+ {
+ wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
++ if (codec->active)
++ snd_soc_write(codec, WM8731_ACTIVE, 0x0001);
+
+ return 0;
+ }
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0049-atmel-ssc-add-phybase-in-device-structure.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0049-atmel-ssc-add-phybase-in-device-structure.patch
new file mode 100644
index 0000000..44e26a8
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0049-atmel-ssc-add-phybase-in-device-structure.patch
@@ -0,0 +1,44 @@
+From e5b9dfa6b7a9918cfb961b2ea1b5d3456b320edf Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 19 May 2011 17:41:06 +0200
+Subject: [PATCH 049/107] atmel-ssc: add phybase in device structure
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Useful for dmaengine use.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/misc/atmel-ssc.c | 1 +
+ include/linux/atmel-ssc.h | 1 +
+ 2 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c
+index 4afffe6..27c9ffa 100644
+--- a/drivers/misc/atmel-ssc.c
++++ b/drivers/misc/atmel-ssc.c
+@@ -101,6 +101,7 @@ static int __init ssc_probe(struct platform_device *pdev)
+ retval = -EINVAL;
+ goto out_clk;
+ }
++ ssc->phybase = regs->start;
+
+ /* disable all interrupts */
+ clk_enable(ssc->clk);
+diff --git a/include/linux/atmel-ssc.h b/include/linux/atmel-ssc.h
+index 0602339..2bab4b4 100644
+--- a/include/linux/atmel-ssc.h
++++ b/include/linux/atmel-ssc.h
+@@ -6,6 +6,7 @@
+
+ struct ssc_device {
+ struct list_head list;
++ resource_size_t phybase;
+ void __iomem *regs;
+ struct platform_device *pdev;
+ struct clk *clk;
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0050-atmel-ssc-dmaengine-usage-switch-depending-on-cpu.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0050-atmel-ssc-dmaengine-usage-switch-depending-on-cpu.patch
new file mode 100644
index 0000000..e705923
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0050-atmel-ssc-dmaengine-usage-switch-depending-on-cpu.patch
@@ -0,0 +1,36 @@
+From c0254163515ae4e8fe27cf3ca1cccfaf84173dfc Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 19 May 2011 17:42:01 +0200
+Subject: [PATCH 050/107] atmel-ssc: dmaengine usage switch depending on cpu
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ include/linux/atmel-ssc.h | 3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/include/linux/atmel-ssc.h b/include/linux/atmel-ssc.h
+index 2bab4b4..52b4c20 100644
+--- a/include/linux/atmel-ssc.h
++++ b/include/linux/atmel-ssc.h
+@@ -3,6 +3,7 @@
+
+ #include <linux/platform_device.h>
+ #include <linux/list.h>
++#include <mach/cpu.h>
+
+ struct ssc_device {
+ struct list_head list;
+@@ -310,4 +311,6 @@ void ssc_free(struct ssc_device *ssc);
+ #define ssc_readl(base, reg) __raw_readl(base + SSC_##reg)
+ #define ssc_writel(base, reg, value) __raw_writel((value), base + SSC_##reg)
+
++#define ssc_use_dmaengine() cpu_is_at91sam9x5()
++
+ #endif /* __INCLUDE_ATMEL_SSC_H */
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0051-sound-atmel_ssc_dai-fix-ssc-error-path.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0051-sound-atmel_ssc_dai-fix-ssc-error-path.patch
new file mode 100644
index 0000000..410d4f0
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0051-sound-atmel_ssc_dai-fix-ssc-error-path.patch
@@ -0,0 +1,35 @@
+From 4c6134391085c25e9c59ce2df43d648eeaf4366a Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 26 May 2011 13:25:08 +0200
+Subject: [PATCH 051/107] sound: atmel_ssc_dai: fix ssc error path
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We do not have to free a resource that is not allocated yet.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ sound/soc/atmel/atmel_ssc_dai.c | 4 +---
+ 1 files changed, 1 insertions(+), 3 deletions(-)
+
+diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
+index 7fbfa05..a7a7bbc 100644
+--- a/sound/soc/atmel/atmel_ssc_dai.c
++++ b/sound/soc/atmel/atmel_ssc_dai.c
+@@ -838,10 +838,8 @@ int atmel_ssc_set_audio(int ssc_id)
+ }
+
+ ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id);
+- if (!ssc_pdev) {
+- ssc_free(ssc);
++ if (!ssc_pdev)
+ return -ENOMEM;
+- }
+
+ /* If we can grab the SSC briefly to parent the DAI device off it */
+ ssc = ssc_request(ssc_id);
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0052-sound-atmel_ssc_dai-atmel-pmc-adapt-to-dmaengine-usa.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0052-sound-atmel_ssc_dai-atmel-pmc-adapt-to-dmaengine-usa.patch
new file mode 100644
index 0000000..a701dbb
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0052-sound-atmel_ssc_dai-atmel-pmc-adapt-to-dmaengine-usa.patch
@@ -0,0 +1,706 @@
+From 9feca7e7811843f5a3ca57b3410ee872d2731813 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 19 May 2011 17:52:02 +0200
+Subject: [PATCH 052/107] sound: atmel_ssc_dai/atmel-pmc: adapt to dmaengine
+ usage
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Change xfer_size name to apply to PDC and DMA aswell.
+Specify overrun bit in interrupt mask.
+Add dmaengine specific routines and replace PDC ones in
+pcm_ops if appropriate.
+Uses cyclic DMA API for queuing samples.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ sound/soc/atmel/atmel-pcm.c | 387 +++++++++++++++++++++++++++++++++++---
+ sound/soc/atmel/atmel-pcm.h | 4 +-
+ sound/soc/atmel/atmel_ssc_dai.c | 33 ++--
+ 3 files changed, 378 insertions(+), 46 deletions(-)
+
+diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c
+index 51dde4e..536f325 100644
+--- a/sound/soc/atmel/atmel-pcm.c
++++ b/sound/soc/atmel/atmel-pcm.c
+@@ -37,6 +37,7 @@
+ #include <linux/slab.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/atmel_pdc.h>
++#include <linux/dmaengine.h>
+ #include <linux/atmel-ssc.h>
+
+ #include <sound/core.h>
+@@ -44,6 +45,8 @@
+ #include <sound/pcm_params.h>
+ #include <sound/soc.h>
+
++#include <mach/at_hdmac.h>
++
+ #include "atmel-pcm.h"
+
+
+@@ -53,7 +56,7 @@
+ /* TODO: These values were taken from the AT91 platform driver, check
+ * them against real values for AT32
+ */
+-static const struct snd_pcm_hardware atmel_pcm_hardware = {
++static const struct snd_pcm_hardware atmel_pcm_pdc_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+@@ -66,6 +69,22 @@ static const struct snd_pcm_hardware atmel_pcm_hardware = {
+ .buffer_bytes_max = 32 * 1024,
+ };
+
++static const struct snd_pcm_hardware atmel_pcm_dma_hardware = {
++ .info = SNDRV_PCM_INFO_MMAP |
++ SNDRV_PCM_INFO_MMAP_VALID |
++ SNDRV_PCM_INFO_INTERLEAVED |
++ SNDRV_PCM_INFO_RESUME |
++ SNDRV_PCM_INFO_PAUSE,
++ .formats = SNDRV_PCM_FMTBIT_S16_LE,
++ .period_bytes_min = 256, /* not too low to absorb DMA programming overhead */
++ .period_bytes_max = 2 * 0xffff, /* if 2 bytes format */
++ .periods_min = 8,
++ .periods_max = 1024, /* no limit */
++ .buffer_bytes_max = 64 * 1024, /* 64KiB */
++};
++
++static const struct snd_pcm_hardware *atmel_pcm_hardware;
++
+
+ /*--------------------------------------------------------------------------*\
+ * Data types
+@@ -77,12 +96,19 @@ struct atmel_runtime_data {
+ size_t period_size;
+
+ dma_addr_t period_ptr; /* physical address of next period */
++ int periods; /* period index of period_ptr */
+
+ /* PDC register save */
+ u32 pdc_xpr_save;
+ u32 pdc_xcr_save;
+ u32 pdc_xnpr_save;
+ u32 pdc_xncr_save;
++
++ /* dmaengine data */
++ struct at_dma_slave atslave;
++ struct dma_async_tx_descriptor *desc;
++ dma_cookie_t cookie;
++ struct dma_chan *dma_chan;
+ };
+
+
+@@ -94,7 +120,7 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
+ {
+ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+- size_t size = atmel_pcm_hardware.buffer_bytes_max;
++ size_t size = atmel_pcm_hardware->buffer_bytes_max;
+
+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ buf->dev.dev = pcm->card->dev;
+@@ -116,7 +142,7 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
+ /*--------------------------------------------------------------------------*\
+ * ISR
+ \*--------------------------------------------------------------------------*/
+-static void atmel_pcm_dma_irq(u32 ssc_sr,
++static void atmel_pcm_pdc_irq(u32 ssc_sr,
+ struct snd_pcm_substream *substream)
+ {
+ struct atmel_runtime_data *prtd = substream->runtime->private_data;
+@@ -142,7 +168,7 @@ static void atmel_pcm_dma_irq(u32 ssc_sr,
+ ssc_writex(params->ssc->regs, params->pdc->xpr,
+ prtd->period_ptr);
+ ssc_writex(params->ssc->regs, params->pdc->xcr,
+- prtd->period_size / params->pdc_xfer_size);
++ prtd->period_size / params->data_xfer_size);
+ ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
+ params->mask->pdc_enable);
+ }
+@@ -156,12 +182,165 @@ static void atmel_pcm_dma_irq(u32 ssc_sr,
+ ssc_writex(params->ssc->regs, params->pdc->xnpr,
+ prtd->period_ptr);
+ ssc_writex(params->ssc->regs, params->pdc->xncr,
+- prtd->period_size / params->pdc_xfer_size);
++ prtd->period_size / params->data_xfer_size);
+ }
+
+ snd_pcm_period_elapsed(substream);
+ }
+
++/**
++ * atmel_pcm_dma_irq: SSC interrupt handler for DMAENGINE enabled SSC
++ *
++ * We use DMAENGINE to send/receive data to/from SSC so this ISR is only to
++ * check if any overrun occured.
++ */
++static void atmel_pcm_dma_irq(u32 ssc_sr,
++ struct snd_pcm_substream *substream)
++{
++ struct atmel_runtime_data *prtd = substream->runtime->private_data;
++ struct atmel_pcm_dma_params *params = prtd->params;
++
++ if (ssc_sr & params->mask->ssc_error) {
++ if (snd_pcm_running(substream))
++ pr_warning("atmel-pcm: buffer %s on %s"
++ " (SSC_SR=%#x)\n",
++ substream->stream == SNDRV_PCM_STREAM_PLAYBACK
++ ? "underrun" : "overrun",
++ params->name, ssc_sr);
++
++ /* stop RX and capture stream: will be enabled again at restart */
++ ssc_writex(params->ssc->regs, SSC_CR, params->mask->ssc_disable);
++ snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
++
++ /* now drain RHR and read status to remove xrun condition */
++ ssc_readx(params->ssc->regs, SSC_RHR);
++ ssc_readx(params->ssc->regs, SSC_SR);
++ }
++}
++
++/*--------------------------------------------------------------------------*\
++ * DMAENGINE operations
++\*--------------------------------------------------------------------------*/
++static bool filter(struct dma_chan *chan, void *slave)
++{
++ struct at_dma_slave *sl = slave;
++
++ if (sl->dma_dev == chan->device->dev) {
++ chan->private = sl;
++ return true;
++ } else {
++ return false;
++ }
++}
++
++static int atmel_pcm_dma_alloc(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ struct atmel_runtime_data *prtd = runtime->private_data;
++ struct ssc_device *ssc = prtd->params->ssc;
++ struct at_dma_slave *sdata = NULL;
++
++ if (ssc->pdev)
++ sdata = ssc->pdev->dev.platform_data;
++
++ if (sdata && sdata->dma_dev) {
++ dma_cap_mask_t mask;
++
++ /* setup DMA addresses */
++ sdata->rx_reg = (dma_addr_t)ssc->phybase + SSC_RHR;
++ sdata->tx_reg = (dma_addr_t)ssc->phybase + SSC_THR;
++
++ /* Try to grab a DMA channel */
++ dma_cap_zero(mask);
++ dma_cap_set(DMA_CYCLIC, mask);
++ prtd->dma_chan = dma_request_channel(mask, filter, sdata);
++ }
++ if (!prtd->dma_chan) {
++ pr_err("atmel-pcm: "
++ "DMA channel not available, unable to use SSC-audio\n");
++ return -EBUSY;
++ }
++
++ return 0;
++}
++
++static void audio_dma_irq(void *data)
++{
++ struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ struct atmel_runtime_data *prtd = runtime->private_data;
++
++ prtd->period_ptr += prtd->period_size;
++ if (prtd->period_ptr >= prtd->dma_buffer_end)
++ prtd->period_ptr = prtd->dma_buffer;
++
++ snd_pcm_period_elapsed(substream);
++}
++
++static void atmel_pcm_dma_slave_config(struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ struct atmel_runtime_data *prtd = runtime->private_data;
++ struct dma_chan *chan = prtd->dma_chan;
++ struct dma_slave_config slave_config;
++ enum dma_slave_buswidth buswidth;
++
++ switch (prtd->params->data_xfer_size) {
++ case 1:
++ buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
++ break;
++ case 2:
++ buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
++ break;
++ case 4:
++ buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
++ break;
++ default:
++ return;
++ }
++
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ slave_config.direction = DMA_TO_DEVICE;
++ slave_config.dst_addr_width = buswidth;
++ } else {
++ slave_config.direction = DMA_FROM_DEVICE;
++ slave_config.src_addr_width = buswidth;
++ }
++
++ chan->device->device_control(chan, DMA_SLAVE_CONFIG,
++ (unsigned long)&slave_config);
++
++}
++
++static int atmel_pcm_dma_prep(struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ struct atmel_runtime_data *prtd = runtime->private_data;
++ struct dma_chan *chan = prtd->dma_chan;
++
++ if (prtd->desc)
++ /* already been there: redo the prep job */
++ chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
++
++ /* setup dma configuration */
++ atmel_pcm_dma_slave_config(substream);
++
++ prtd->desc = chan->device->device_prep_dma_cyclic(chan, prtd->dma_buffer,
++ prtd->period_size * prtd->periods,
++ prtd->period_size,
++ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
++ DMA_TO_DEVICE : DMA_FROM_DEVICE);
++ if (!prtd->desc) {
++ dev_err(&chan->dev->device, "cannot prepare slave dma\n");
++ return -EINVAL;
++ }
++
++ prtd->desc->callback = audio_dma_irq;
++ prtd->desc->callback_param = substream;
++
++ return 0;
++}
+
+ /*--------------------------------------------------------------------------*\
+ * PCM operations
+@@ -172,6 +351,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct atmel_runtime_data *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ int ret;
+
+ /* this may get called several times by oss emulation
+ * with different params */
+@@ -180,15 +360,35 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
+ runtime->dma_bytes = params_buffer_bytes(params);
+
+ prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+- prtd->params->dma_intr_handler = atmel_pcm_dma_irq;
+
+ prtd->dma_buffer = runtime->dma_addr;
+ prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes;
+ prtd->period_size = params_period_bytes(params);
++ prtd->periods = params_periods(params);
++
++ if (ssc_use_dmaengine()) {
++ if (prtd->dma_chan == NULL) {
++ ret = atmel_pcm_dma_alloc(substream, params);
++ if (ret)
++ return ret;
++ }
++ ret = atmel_pcm_dma_prep(substream);
++ if (ret) {
++ dma_release_channel(prtd->dma_chan);
++ prtd->dma_chan = NULL;
++ return ret;
++ }
++
++ prtd->params->dma_intr_handler = atmel_pcm_dma_irq;
++ } else {
++ prtd->params->dma_intr_handler = atmel_pcm_pdc_irq;
++ }
+
+ pr_debug("atmel-pcm: "
+- "hw_params: DMA for %s initialized "
++ "hw_params: %s%s for %s initialized "
+ "(dma_bytes=%u, period_size=%u)\n",
++ prtd->dma_chan ? "DMA " : "PDC",
++ prtd->dma_chan ? dma_chan_name(prtd->dma_chan): "",
+ prtd->params->name,
+ runtime->dma_bytes,
+ prtd->period_size);
+@@ -201,15 +401,31 @@ static int atmel_pcm_hw_free(struct snd_pcm_substream *substream)
+ struct atmel_pcm_dma_params *params = prtd->params;
+
+ if (params != NULL) {
+- ssc_writex(params->ssc->regs, SSC_PDC_PTCR,
+- params->mask->pdc_disable);
++ if (ssc_use_dmaengine()) {
++ struct dma_chan *chan = prtd->dma_chan;
++
++ if (chan) {
++ chan->device->device_control(chan,
++ DMA_TERMINATE_ALL, 0);
++ prtd->cookie = 0;
++ prtd->desc = NULL;
++ dma_release_channel(chan);
++ prtd->dma_chan = NULL;
++ }
++ } else {
++ ssc_writex(params->ssc->regs, SSC_PDC_PTCR,
++ params->mask->pdc_disable);
++ }
+ prtd->params->dma_intr_handler = NULL;
+ }
+
+ return 0;
+ }
+
+-static int atmel_pcm_prepare(struct snd_pcm_substream *substream)
++/*--------------------------------------------------------------------------*\
++ * PCM callbacks using PDC
++\*--------------------------------------------------------------------------*/
++static int atmel_pcm_pdc_prepare(struct snd_pcm_substream *substream)
+ {
+ struct atmel_runtime_data *prtd = substream->runtime->private_data;
+ struct atmel_pcm_dma_params *params = prtd->params;
+@@ -221,7 +437,7 @@ static int atmel_pcm_prepare(struct snd_pcm_substream *substream)
+ return 0;
+ }
+
+-static int atmel_pcm_trigger(struct snd_pcm_substream *substream,
++static int atmel_pcm_pdc_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+ {
+ struct snd_pcm_runtime *rtd = substream->runtime;
+@@ -240,13 +456,13 @@ static int atmel_pcm_trigger(struct snd_pcm_substream *substream,
+ ssc_writex(params->ssc->regs, params->pdc->xpr,
+ prtd->period_ptr);
+ ssc_writex(params->ssc->regs, params->pdc->xcr,
+- prtd->period_size / params->pdc_xfer_size);
++ prtd->period_size / params->data_xfer_size);
+
+ prtd->period_ptr += prtd->period_size;
+ ssc_writex(params->ssc->regs, params->pdc->xnpr,
+ prtd->period_ptr);
+ ssc_writex(params->ssc->regs, params->pdc->xncr,
+- prtd->period_size / params->pdc_xfer_size);
++ prtd->period_size / params->data_xfer_size);
+
+ pr_debug("atmel-pcm: trigger: "
+ "period_ptr=%lx, xpr=%u, "
+@@ -264,7 +480,7 @@ static int atmel_pcm_trigger(struct snd_pcm_substream *substream,
+
+ pr_debug("sr=%u imr=%u\n",
+ ssc_readx(params->ssc->regs, SSC_SR),
+- ssc_readx(params->ssc->regs, SSC_IER));
++ ssc_readx(params->ssc->regs, SSC_IMR));
+ break; /* SNDRV_PCM_TRIGGER_START */
+
+ case SNDRV_PCM_TRIGGER_STOP:
+@@ -287,7 +503,7 @@ static int atmel_pcm_trigger(struct snd_pcm_substream *substream,
+ return ret;
+ }
+
+-static snd_pcm_uframes_t atmel_pcm_pointer(
++static snd_pcm_uframes_t atmel_pcm_pdc_pointer(
+ struct snd_pcm_substream *substream)
+ {
+ struct snd_pcm_runtime *runtime = substream->runtime;
+@@ -305,13 +521,109 @@ static snd_pcm_uframes_t atmel_pcm_pointer(
+ return x;
+ }
+
++/*--------------------------------------------------------------------------*\
++ * PCM callbacks using DMAENGINE
++\*--------------------------------------------------------------------------*/
++static int atmel_pcm_dma_prepare(struct snd_pcm_substream *substream)
++{
++ struct atmel_runtime_data *prtd = substream->runtime->private_data;
++ struct atmel_pcm_dma_params *params = prtd->params;
++
++ ssc_writex(params->ssc->regs, SSC_IDR, params->mask->ssc_error);
++ return 0;
++}
++
++static int atmel_pcm_dma_trigger(struct snd_pcm_substream *substream,
++ int cmd)
++{
++ struct snd_pcm_runtime *rtd = substream->runtime;
++ struct atmel_runtime_data *prtd = rtd->private_data;
++ struct atmel_pcm_dma_params *params = prtd->params;
++ dma_cookie_t cookie;
++ int ret = 0;
++
++ pr_debug("atmel-pcm: trigger %d: buffer_size = %ld,"
++ " dma_area = %p, dma_bytes = %u\n",
++ cmd, rtd->buffer_size, rtd->dma_area, rtd->dma_bytes);
++
++ switch (cmd) {
++ case SNDRV_PCM_TRIGGER_START:
++
++ if (prtd->cookie < DMA_MIN_COOKIE) {
++ cookie = prtd->desc->tx_submit(prtd->desc);
++ if (dma_submit_error(cookie)) {
++ ret = -EINVAL;
++ break;
++ }
++ prtd->cookie = cookie;
++ prtd->period_ptr = prtd->dma_buffer;
++ }
++
++
++ pr_debug("atmel-pcm: trigger: start sr=0x%08x imr=0x%08u\n",
++ ssc_readx(params->ssc->regs, SSC_SR),
++ ssc_readx(params->ssc->regs, SSC_IMR));
++
++ /* fallback */
++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
++ case SNDRV_PCM_TRIGGER_RESUME:
++ prtd->dma_chan->device->device_control(prtd->dma_chan,
++ DMA_RESUME, 0);
++
++ /* It not already done or comming from xrun state */
++ ssc_readx(params->ssc->regs, SSC_SR);
++ ssc_writex(params->ssc->regs, SSC_IER, params->mask->ssc_error);
++ ssc_writex(params->ssc->regs, SSC_CR, params->mask->ssc_enable);
++
++ break;
++ case SNDRV_PCM_TRIGGER_STOP:
++ pr_debug("atmel-pcm: trigger: stop cmd = %d\n", cmd);
++
++ ssc_writex(params->ssc->regs, SSC_IDR, params->mask->ssc_error);
++
++ /* fallback */
++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
++ case SNDRV_PCM_TRIGGER_SUSPEND:
++ prtd->dma_chan->device->device_control(prtd->dma_chan,
++ DMA_PAUSE, 0);
++ break;
++ default:
++ ret = -EINVAL;
++ }
++
++ return ret;
++}
++
++static snd_pcm_uframes_t atmel_pcm_dma_pointer(
++ struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ struct atmel_runtime_data *prtd = runtime->private_data;
++ snd_pcm_uframes_t x;
++
++ dev_vdbg(substream->pcm->card->dev, "%s: 0x%08x %ld\n",
++ __func__, prtd->period_ptr,
++ bytes_to_frames(runtime, prtd->period_ptr - prtd->dma_buffer));
++
++ x = bytes_to_frames(runtime, prtd->period_ptr - prtd->dma_buffer);
++
++ if (x >= runtime->buffer_size)
++ x = 0;
++
++ return x;
++}
++
++
++/*--------------------------------------------------------------------------*\
++ * PCM open/close/mmap
++\*--------------------------------------------------------------------------*/
+ static int atmel_pcm_open(struct snd_pcm_substream *substream)
+ {
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct atmel_runtime_data *prtd;
+ int ret = 0;
+
+- snd_soc_set_runtime_hwparams(substream, &atmel_pcm_hardware);
++ snd_soc_set_runtime_hwparams(substream, atmel_pcm_hardware);
+
+ /* ensure that buffer size is a multiple of period size */
+ ret = snd_pcm_hw_constraint_integer(runtime,
+@@ -352,9 +664,9 @@ static struct snd_pcm_ops atmel_pcm_ops = {
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = atmel_pcm_hw_params,
+ .hw_free = atmel_pcm_hw_free,
+- .prepare = atmel_pcm_prepare,
+- .trigger = atmel_pcm_trigger,
+- .pointer = atmel_pcm_pointer,
++ .prepare = atmel_pcm_pdc_prepare,
++ .trigger = atmel_pcm_pdc_trigger,
++ .pointer = atmel_pcm_pdc_pointer,
+ .mmap = atmel_pcm_mmap,
+ };
+
+@@ -426,14 +738,16 @@ static int atmel_pcm_suspend(struct snd_soc_dai *dai)
+ prtd = runtime->private_data;
+ params = prtd->params;
+
+- /* disable the PDC and save the PDC registers */
++ if (!ssc_use_dmaengine()) {
++ /* disable the PDC and save the PDC registers */
+
+- ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable);
++ ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable);
+
+- prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr);
+- prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr);
+- prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr);
+- prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr);
++ prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr);
++ prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr);
++ prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr);
++ prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr);
++ }
+
+ return 0;
+ }
+@@ -450,13 +764,15 @@ static int atmel_pcm_resume(struct snd_soc_dai *dai)
+ prtd = runtime->private_data;
+ params = prtd->params;
+
+- /* restore the PDC registers and enable the PDC */
+- ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save);
+- ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save);
+- ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save);
+- ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save);
++ if (!ssc_use_dmaengine()) {
++ /* restore the PDC registers and enable the PDC */
++ ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save);
++ ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save);
++ ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save);
++ ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save);
+
+- ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable);
++ ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable);
++ }
+ return 0;
+ }
+ #else
+@@ -495,6 +811,15 @@ static struct platform_driver atmel_pcm_driver = {
+
+ static int __init snd_atmel_pcm_init(void)
+ {
++ if (ssc_use_dmaengine()) {
++ atmel_pcm_ops.prepare = atmel_pcm_dma_prepare;
++ atmel_pcm_ops.trigger = atmel_pcm_dma_trigger;
++ atmel_pcm_ops.pointer = atmel_pcm_dma_pointer;
++
++ atmel_pcm_hardware = &atmel_pcm_dma_hardware;
++ } else {
++ atmel_pcm_hardware = &atmel_pcm_pdc_hardware;
++ }
+ return platform_driver_register(&atmel_pcm_driver);
+ }
+ module_init(snd_atmel_pcm_init);
+diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h
+index 5e0a95e..b007376 100644
+--- a/sound/soc/atmel/atmel-pcm.h
++++ b/sound/soc/atmel/atmel-pcm.h
+@@ -50,6 +50,7 @@ struct atmel_pdc_regs {
+ struct atmel_ssc_mask {
+ u32 ssc_enable; /* SSC recv/trans enable */
+ u32 ssc_disable; /* SSC recv/trans disable */
++ u32 ssc_error; /* SSC error conditions */
+ u32 ssc_endx; /* SSC ENDTX or ENDRX */
+ u32 ssc_endbuf; /* SSC TXBUFE or RXBUFF */
+ u32 pdc_enable; /* PDC recv/trans enable */
+@@ -66,7 +67,8 @@ struct atmel_ssc_mask {
+ */
+ struct atmel_pcm_dma_params {
+ char *name; /* stream identifier */
+- int pdc_xfer_size; /* PDC counter increment in bytes */
++ int data_xfer_size; /* PDC counter increment in bytes,
++ DMA data transfer size in bytes */
+ struct ssc_device *ssc; /* SSC device for stream */
+ struct atmel_pdc_regs *pdc; /* PDC receive or transmit registers */
+ struct atmel_ssc_mask *mask; /* SSC & PDC status bits */
+diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
+index a7a7bbc..9412fc3 100644
+--- a/sound/soc/atmel/atmel_ssc_dai.c
++++ b/sound/soc/atmel/atmel_ssc_dai.c
+@@ -48,7 +48,8 @@
+ #include "atmel_ssc_dai.h"
+
+
+-#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20)
++#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20) \
++ || defined(CONFIG_ARCH_AT91SAM9X5)
+ #define NUM_SSC_DEVICES 1
+ #else
+ #define NUM_SSC_DEVICES 3
+@@ -86,6 +87,7 @@ static struct atmel_ssc_mask ssc_tx_mask = {
+ static struct atmel_ssc_mask ssc_rx_mask = {
+ .ssc_enable = SSC_BIT(CR_RXEN),
+ .ssc_disable = SSC_BIT(CR_RXDIS),
++ .ssc_error = SSC_BIT(SR_OVRUN),
+ .ssc_endx = SSC_BIT(SR_ENDRX),
+ .ssc_endbuf = SSC_BIT(SR_RXBUFF),
+ .pdc_enable = ATMEL_PDC_RXTEN,
+@@ -183,7 +185,8 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id)
+ if ((dma_params != NULL) &&
+ (dma_params->dma_intr_handler != NULL)) {
+ ssc_substream_mask = (dma_params->mask->ssc_endx |
+- dma_params->mask->ssc_endbuf);
++ dma_params->mask->ssc_endbuf |
++ dma_params->mask->ssc_error);
+ if (ssc_sr & ssc_substream_mask) {
+ dma_params->dma_intr_handler(ssc_sr,
+ dma_params->
+@@ -376,19 +379,19 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ bits = 8;
+- dma_params->pdc_xfer_size = 1;
++ dma_params->data_xfer_size = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ bits = 16;
+- dma_params->pdc_xfer_size = 2;
++ dma_params->data_xfer_size = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bits = 24;
+- dma_params->pdc_xfer_size = 4;
++ dma_params->data_xfer_size = 4;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ bits = 32;
+- dma_params->pdc_xfer_size = 4;
++ dma_params->data_xfer_size = 4;
+ break;
+ default:
+ printk(KERN_WARNING "atmel_ssc_dai: unsupported PCM format");
+@@ -561,15 +564,17 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
+ /* Reset the SSC and its PDC registers */
+ ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
+
+- ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0);
+- ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0);
+- ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0);
+- ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0);
++ if (!ssc_use_dmaengine()) {
++ ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0);
++ ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0);
++ ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0);
++ ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0);
+
+- ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0);
+- ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0);
+- ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0);
+- ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0);
++ ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0);
++ ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0);
++ ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0);
++ ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0);
++ }
+
+ ret = request_irq(ssc_p->ssc->irq, atmel_ssc_interrupt, 0,
+ ssc_p->name, ssc_p);
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0053-sound-sam9x5_wm8731-machine-driver-for-at91sam9x5-wm.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0053-sound-sam9x5_wm8731-machine-driver-for-at91sam9x5-wm.patch
new file mode 100644
index 0000000..7efbec5
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0053-sound-sam9x5_wm8731-machine-driver-for-at91sam9x5-wm.patch
@@ -0,0 +1,291 @@
+From 0aa157c9e71ccccf3abc30fa37eb5c95b392978d Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 19 May 2011 17:57:48 +0200
+Subject: [PATCH 053/107] sound: sam9x5_wm8731: machine driver for at91sam9x5
+ wm8731 boards
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Description of the Asoc machine driver for an at91sam9x5 based board
+with a wm8731 audio DAC. Wm8731 is clocked by a crystal and used as a
+master on the SSC/I2S interface. Its connections are a headphone jack
+and an Line input jack.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ sound/soc/atmel/Kconfig | 9 ++
+ sound/soc/atmel/Makefile | 2 +
+ sound/soc/atmel/sam9x5_wm8731.c | 222 +++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 233 insertions(+), 0 deletions(-)
+ create mode 100644 sound/soc/atmel/sam9x5_wm8731.c
+
+diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
+index bee3c94..2fdb037 100644
+--- a/sound/soc/atmel/Kconfig
++++ b/sound/soc/atmel/Kconfig
+@@ -24,6 +24,15 @@ config SND_AT91_SOC_SAM9G20_WM8731
+ Say Y if you want to add support for SoC audio on WM8731-based
+ AT91sam9g20 evaluation board.
+
++config SND_AT91_SOC_SAM9X5_WM8731
++ tristate "SoC Audio support for WM8731-based at91sam9x5 board"
++ depends on ATMEL_SSC && SND_ATMEL_SOC && ARCH_AT91SAM9X5
++ select SND_ATMEL_SOC_SSC
++ select SND_SOC_WM8731
++ help
++ Say Y if you want to add support for audio SoC on an
++ at91sam9x5 based board that is using WM8731 codec.
++
+ config SND_AT32_SOC_PLAYPAQ
+ tristate "SoC Audio support for PlayPaq with WM8510"
+ depends on SND_ATMEL_SOC && BOARD_PLAYPAQ && AT91_PROGRAMMABLE_CLOCKS
+diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile
+index e7ea56b..c5f2b62 100644
+--- a/sound/soc/atmel/Makefile
++++ b/sound/soc/atmel/Makefile
+@@ -7,10 +7,12 @@ obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o
+
+ # AT91 Machine Support
+ snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o
++snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o
+
+ # AT32 Machine Support
+ snd-soc-playpaq-objs := playpaq_wm8510.o
+
+ obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
++obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o
+ obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o
+ obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o
+diff --git a/sound/soc/atmel/sam9x5_wm8731.c b/sound/soc/atmel/sam9x5_wm8731.c
+new file mode 100644
+index 0000000..009e033
+--- /dev/null
++++ b/sound/soc/atmel/sam9x5_wm8731.c
+@@ -0,0 +1,222 @@
++/*
++ * sam9x5_wm8731 -- SoC audio for AT91SAM9X5-based boards
++ * that are using WM8731 as codec.
++ *
++ * Copyright (C) 2011 Atmel,
++ * Nicolas Ferre <nicolas.ferre@atmel.com>
++ *
++ * Based on sam9g20_wm8731.c by:
++ * Sedji Gaouaou <sedji.gaouaou@atmel.com>
++ *
++ * GPL
++ */
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/kernel.h>
++#include <linux/clk.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <linux/i2c.h>
++
++#include <linux/atmel-ssc.h>
++
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++
++#include <asm/mach-types.h>
++#include <mach/hardware.h>
++#include <mach/gpio.h>
++
++#include "../codecs/wm8731.h"
++#include "atmel-pcm.h"
++#include "atmel_ssc_dai.h"
++
++#define MCLK_RATE 12288000
++
++static int at91sam9x5ek_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai *codec_dai = rtd->codec_dai;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++ int ret;
++
++ /* set codec DAI configuration */
++ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
++ if (ret < 0)
++ return ret;
++
++ /* set cpu DAI configuration */
++ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
++ if (ret < 0)
++ return ret;
++
++ /* set the codec system clock for DAC and ADC */
++ ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
++ MCLK_RATE, SND_SOC_CLOCK_IN);
++ if (ret < 0) {
++ printk(KERN_ERR "ASoC: Failed to set WM8731 SYSCLK: %d\n", ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static struct snd_soc_ops at91sam9x5ek_ops = {
++ .hw_params = at91sam9x5ek_hw_params,
++};
++
++/*
++ * Audio paths on at91sam9x5ek board:
++ *
++ * |A| ------------> | | ---R----> Headphone Jack
++ * |T| <----\ | WM | ---L--/
++ * |9| ---> CLK <--> | 8751 | <--R----- Line In Jack
++ * |1| <------------ | | <--L--/
++ */
++static const struct snd_soc_dapm_widget at91sam9x5ek_dapm_widgets[] = {
++ SND_SOC_DAPM_HP("Headphone Jack", NULL),
++ SND_SOC_DAPM_LINE("Line In Jack", NULL),
++};
++
++static const struct snd_soc_dapm_route intercon[] = {
++ /* headphone jack connected to HPOUT */
++ {"Headphone Jack", NULL, "RHPOUT"},
++ {"Headphone Jack", NULL, "LHPOUT"},
++
++ /* line in jack connected LINEIN */
++ {"LLINEIN", NULL, "Line In Jack"},
++ {"RLINEIN", NULL, "Line In Jack"},
++};
++
++/*
++ * Logic for a wm8731 as connected on a at91sam9x5 based board.
++ */
++static int at91sam9x5ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_codec *codec = rtd->codec;
++ struct snd_soc_dai *codec_dai = rtd->codec_dai;
++ struct snd_soc_dapm_context *dapm = &codec->dapm;
++
++ printk(KERN_DEBUG
++ "ASoC: at91sam9x5_wm8731"
++ ": at91sam9x5ek_wm8731_init() called\n");
++
++ /* remove some not supported rates in relation with clock
++ * provided to the wm8731 codec */
++ switch (MCLK_RATE) {
++ case 12288000:
++ codec_dai->driver->playback.rates &= SNDRV_PCM_RATE_8000 |
++ SNDRV_PCM_RATE_32000 |
++ SNDRV_PCM_RATE_48000 |
++ SNDRV_PCM_RATE_96000;
++ codec_dai->driver->capture.rates &= SNDRV_PCM_RATE_8000 |
++ SNDRV_PCM_RATE_32000 |
++ SNDRV_PCM_RATE_48000 |
++ SNDRV_PCM_RATE_96000;
++ break;
++ case 12000000:
++ /* all wm8731 rates supported */
++ break;
++ default:
++ printk(KERN_ERR "ASoC: Codec Master clock rate not defined\n");
++ return -EINVAL;
++ }
++
++ /* set not connected pins */
++ snd_soc_dapm_nc_pin(dapm, "Mic Bias");
++ snd_soc_dapm_nc_pin(dapm, "MICIN");
++ snd_soc_dapm_nc_pin(dapm, "LOUT");
++ snd_soc_dapm_nc_pin(dapm, "ROUT");
++
++ /* add specific widgets */
++ snd_soc_dapm_new_controls(dapm, at91sam9x5ek_dapm_widgets,
++ ARRAY_SIZE(at91sam9x5ek_dapm_widgets));
++ /* set up specific audio path interconnects */
++ snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
++
++ /* always connected */
++ snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
++ snd_soc_dapm_enable_pin(dapm, "Line In Jack");
++
++ /* signal a DAPM event */
++ snd_soc_dapm_sync(dapm);
++ return 0;
++}
++
++static struct snd_soc_dai_link at91sam9x5ek_dai = {
++ .name = "WM8731",
++ .stream_name = "WM8731 PCM",
++ .cpu_dai_name = "atmel-ssc-dai.0",
++ .codec_dai_name = "wm8731-hifi",
++ .init = at91sam9x5ek_wm8731_init,
++ .platform_name = "atmel-pcm-audio",
++ .codec_name = "wm8731-codec.0-001a",
++ .ops = &at91sam9x5ek_ops,
++};
++
++static struct snd_soc_card snd_soc_at91sam9x5ek = {
++ .name = "AT91SAM9X5",
++ .dai_link = &at91sam9x5ek_dai,
++ .num_links = 1,
++};
++
++static struct platform_device *at91sam9x5ek_snd_device;
++
++static int __init at91sam9x5ek_init(void)
++{
++ int ret;
++
++ if (!machine_is_at91sam9x5ek())
++ return -ENODEV;
++
++ ret = atmel_ssc_set_audio(0);
++ if (ret != 0) {
++ pr_err("ASoC: Failed to set SSC 0 for audio: %d\n", ret);
++ goto err;
++ }
++
++ at91sam9x5ek_snd_device = platform_device_alloc("soc-audio", -1);
++ if (!at91sam9x5ek_snd_device) {
++ printk(KERN_ERR "ASoC: Platform device allocation failed\n");
++ ret = -ENOMEM;
++ goto err;
++ }
++
++ platform_set_drvdata(at91sam9x5ek_snd_device,
++ &snd_soc_at91sam9x5ek);
++
++ ret = platform_device_add(at91sam9x5ek_snd_device);
++ if (ret) {
++ printk(KERN_ERR "ASoC: Platform device allocation failed\n");
++ goto err_device_add;
++ }
++
++ printk(KERN_INFO "ASoC: at91sam9x5ek_init ok\n");
++
++ return ret;
++
++err_device_add:
++ platform_device_put(at91sam9x5ek_snd_device);
++err:
++ return ret;
++}
++
++static void __exit at91sam9x5ek_exit(void)
++{
++ platform_device_unregister(at91sam9x5ek_snd_device);
++ at91sam9x5ek_snd_device = NULL;
++}
++
++module_init(at91sam9x5ek_init);
++module_exit(at91sam9x5ek_exit);
++
++/* Module information */
++MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com>");
++MODULE_DESCRIPTION("ALSA SoC machine driver for AT91SAM9x5 - WM8731");
++MODULE_LICENSE("GPL");
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0054-mtd-atmel_nand-do-not-scream-while-using-PIO-instead.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0054-mtd-atmel_nand-do-not-scream-while-using-PIO-instead.patch
new file mode 100644
index 0000000..2bbd506
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0054-mtd-atmel_nand-do-not-scream-while-using-PIO-instead.patch
@@ -0,0 +1,33 @@
+From a1b192d1b61c8a67b5e4dfa23ddf58d77b7296bb Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Fri, 20 May 2011 11:35:59 +0200
+Subject: [PATCH 054/107] mtd: atmel_nand: do not scream while using PIO
+ instead of DMA
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/mtd/nand/atmel_nand.c | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index e89c8c7..c4e07be 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -296,8 +296,10 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
+ err_dma:
+ dma_unmap_single(dma_dev->dev, phys_addr, len, dir);
+ err_buf:
++#if 0
+ if (err != 0)
+ dev_warn(host->dev, "Fall back to CPU I/O\n");
++#endif
+ return err;
+ }
+
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0055-MMC-PM-suspend-resume-in-atmel-mci.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0055-MMC-PM-suspend-resume-in-atmel-mci.patch
new file mode 100644
index 0000000..0cb9c71
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0055-MMC-PM-suspend-resume-in-atmel-mci.patch
@@ -0,0 +1,83 @@
+From efa965541f4e6b3a5dd06d65a44d7a85cafd73b8 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 16 May 2011 14:32:07 +0200
+Subject: [PATCH 055/107] MMC: PM: suspend/resume in atmel-mci
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Take care of slots while going to suspend state.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/mmc/host/atmel-mci.c | 51 ++++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 51 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index f6b2552..346f91b 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -1891,8 +1891,59 @@ static int __exit atmci_remove(struct platform_device *pdev)
+ return 0;
+ }
+
++#ifdef CONFIG_PM
++static int atmci_suspend(struct platform_device *pdev, pm_message_t mesg)
++{
++ struct atmel_mci *host = platform_get_drvdata(pdev);
++ struct atmel_mci_slot *slot;
++ int i, ret;
++
++ for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
++ slot = host->slot[i];
++ if (!slot)
++ continue;
++ ret = mmc_suspend_host(slot->mmc);
++ if (ret < 0) {
++ while (--i >= 0) {
++ slot = host->slot[i];
++ if (slot)
++ mmc_resume_host(host->slot[i]->mmc);
++ }
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
++static int atmci_resume(struct platform_device *pdev)
++{
++ struct atmel_mci *host = platform_get_drvdata(pdev);
++ struct atmel_mci_slot *slot;
++ int i, ret;
++
++ for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
++ slot = host->slot[i];
++ if (!slot)
++ continue;
++ ret = mmc_resume_host(slot->mmc);
++ if (ret < 0)
++ return ret;
++ }
++
++ return 0;
++}
++#else
++#define atmci_suspend NULL
++#define atmci_resume NULL
++#endif
++
++
++
+ static struct platform_driver atmci_driver = {
+ .remove = __exit_p(atmci_remove),
++ .suspend = atmci_suspend,
++ .resume = atmci_resume,
+ .driver = {
+ .name = "atmel_mci",
+ },
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0056-ASoc-wm8731-fix-wm8731_check_osc-connected-condition.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0056-ASoc-wm8731-fix-wm8731_check_osc-connected-condition.patch
new file mode 100644
index 0000000..9f0e18d
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0056-ASoc-wm8731-fix-wm8731_check_osc-connected-condition.patch
@@ -0,0 +1,37 @@
+From 676d27f65a64deed4d5f5696774c35cfb01bf44e Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 24 May 2011 11:13:47 +0200
+Subject: [PATCH 056/107] ASoc: wm8731: fix wm8731_check_osc() connected
+ condition
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The crystal oscillator is only enabled if the WM8731_SYSCLK_XTAL master clock
+is specified. Fix the connected() struct snd_soc_dapm_route function to take
+this into account. Oscillator is not enabled on machine that need it otherwise.
+
+Machine drivers have to make sure that they use the proper SYSCLK value.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ sound/soc/codecs/wm8731.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
+index aa55b84..ec176b6 100644
+--- a/sound/soc/codecs/wm8731.c
++++ b/sound/soc/codecs/wm8731.c
+@@ -198,7 +198,7 @@ static int wm8731_check_osc(struct snd_soc_dapm_widget *source,
+ {
+ struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(source->codec);
+
+- return wm8731->sysclk_type == WM8731_SYSCLK_MCLK;
++ return wm8731->sysclk_type == WM8731_SYSCLK_XTAL;
+ }
+
+ static const struct snd_soc_dapm_route intercon[] = {
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0057-ASoc-sam9g20_wm8731-use-the-proper-SYSCKL-value.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0057-ASoc-sam9g20_wm8731-use-the-proper-SYSCKL-value.patch
new file mode 100644
index 0000000..bc7a352
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0057-ASoc-sam9g20_wm8731-use-the-proper-SYSCKL-value.patch
@@ -0,0 +1,34 @@
+From 7cec4ca2653d0f1053635fa47a60127c0e5b6856 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 24 May 2011 11:24:22 +0200
+Subject: [PATCH 057/107] ASoc: sam9g20_wm8731: use the proper SYSCKL value
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+at91sam9g20 is providing master clock to wm8731: not using a crystal but an
+external MCLK. We can avoid conflict and save power using WM8731_SYSCLK_MCLK as
+we do not need oscillator to be powered.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ sound/soc/atmel/sam9g20_wm8731.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c
+index af3c730..91cc80d 100644
+--- a/sound/soc/atmel/sam9g20_wm8731.c
++++ b/sound/soc/atmel/sam9g20_wm8731.c
+@@ -146,7 +146,7 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
+ "at91sam9g20ek_wm8731 "
+ ": at91sam9g20ek_wm8731_init() called\n");
+
+- ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
++ ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_MCLK,
+ MCLK_RATE, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret);
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0058-sound-atmel_ssc_dai-PM-actually-stopping-clock-on-su.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0058-sound-atmel_ssc_dai-PM-actually-stopping-clock-on-su.patch
new file mode 100644
index 0000000..e007def
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0058-sound-atmel_ssc_dai-PM-actually-stopping-clock-on-su.patch
@@ -0,0 +1,73 @@
+From e1ee811e7bbcce6728f7cd28153a894991c2c230 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 25 May 2011 19:36:51 +0200
+Subject: [PATCH 058/107] sound: atmel_ssc_dai: PM: actually stopping clock on
+ suspend/resume
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Stop SSC clock on suspend/resume cycle checking if the controller is actually
+initialized. This will save power while sleeping.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ sound/soc/atmel/atmel_ssc_dai.c | 20 +++++++++++++-------
+ 1 files changed, 13 insertions(+), 7 deletions(-)
+
+diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
+index 9412fc3..43cce80 100644
+--- a/sound/soc/atmel/atmel_ssc_dai.c
++++ b/sound/soc/atmel/atmel_ssc_dai.c
+@@ -631,12 +631,10 @@ static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
+ #ifdef CONFIG_PM
+ static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai)
+ {
+- struct atmel_ssc_info *ssc_p;
++ struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
+
+ if (!cpu_dai->active)
+- return 0;
+-
+- ssc_p = &ssc_info[cpu_dai->id];
++ goto out;
+
+ /* Save the status register before disabling transmit and receive */
+ ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR);
+@@ -652,6 +650,11 @@ static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai)
+ ssc_p->ssc_state.ssc_tcmr = ssc_readl(ssc_p->ssc->regs, TCMR);
+ ssc_p->ssc_state.ssc_tfmr = ssc_readl(ssc_p->ssc->regs, TFMR);
+
++out:
++ if (ssc_p->initialized) {
++ pr_debug("atmel_ssc_dai: suspend - stop clock\n");
++ clk_disable(ssc_p->ssc->clk);
++ }
+ return 0;
+ }
+
+@@ -659,14 +662,17 @@ static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai)
+
+ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
+ {
+- struct atmel_ssc_info *ssc_p;
++ struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
+ u32 cr;
+
++ if (ssc_p->initialized) {
++ pr_debug("atmel_ssc_dai: resume - restart clock\n");
++ clk_enable(ssc_p->ssc->clk);
++ }
++
+ if (!cpu_dai->active)
+ return 0;
+
+- ssc_p = &ssc_info[cpu_dai->id];
+-
+ /* restore SSC register settings */
+ ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr);
+ ssc_writel(ssc_p->ssc->regs, TCMR, ssc_p->ssc_state.ssc_tcmr);
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0059-ARM-at91-sam9x5-increase-CONSISTENT_DMA_SIZE.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0059-ARM-at91-sam9x5-increase-CONSISTENT_DMA_SIZE.patch
new file mode 100644
index 0000000..4c36a8e
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0059-ARM-at91-sam9x5-increase-CONSISTENT_DMA_SIZE.patch
@@ -0,0 +1,29 @@
+From 3cf98b7f7bf07aba4e6292df6e942bfe7e20f735 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
+Date: Fri, 27 May 2011 09:41:44 +0200
+Subject: [PATCH 059/107] ARM: at91/sam9x5: increase CONSISTENT_DMA_SIZE
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ arch/arm/mach-at91/include/mach/at91sam9x5.h | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5.h b/arch/arm/mach-at91/include/mach/at91sam9x5.h
+index c263b46..1219b32 100644
+--- a/arch/arm/mach-at91/include/mach/at91sam9x5.h
++++ b/arch/arm/mach-at91/include/mach/at91sam9x5.h
+@@ -133,7 +133,7 @@
+
+ #define CONFIG_DRAM_BASE AT91_CHIPSELECT_1
+
+-#define CONSISTENT_DMA_SIZE SZ_4M
++#define CONSISTENT_DMA_SIZE (14 * SZ_1M)
+
+ /*
+ * DMA0 peripheral identifiers
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0060-SPI-atmel_spi-add-bit-in-mode-register-to-prevent-ov.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0060-SPI-atmel_spi-add-bit-in-mode-register-to-prevent-ov.patch
new file mode 100644
index 0000000..c9dbc76
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0060-SPI-atmel_spi-add-bit-in-mode-register-to-prevent-ov.patch
@@ -0,0 +1,130 @@
+From c8701994e8c5e940c2b5694e355ff670e0ddf369 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Fri, 27 May 2011 13:32:55 +0200
+Subject: [PATCH 060/107] SPI: atmel_spi: add bit in mode register to prevent
+ overrun
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add the "WDRBT: Wait Data Read Before Transfer" bit in the mode register for
+controllers that support it (v210 and greater).
+This bit will prevent overruns error in reception.
+
+The modification of cs_activate() is need to preserver this initial
+configuration.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/spi/atmel_spi.c | 24 +++++++++++++++++++-----
+ drivers/spi/atmel_spi.h | 9 +++++++++
+ 2 files changed, 28 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
+index 12d8a81..ca9dab5 100644
+--- a/drivers/spi/atmel_spi.c
++++ b/drivers/spi/atmel_spi.c
+@@ -106,6 +106,15 @@ static bool atmel_spi_is_v2(void)
+ return !cpu_is_at91rm9200();
+ }
+
++static bool atmel_spi_v21x(struct atmel_spi *as)
++{
++ u32 v;
++
++ v = SPI_BFEXT(VERS, spi_readl(as, VERSION));
++ v &= 0x0ff0;
++ return (v == 0x210);
++}
++
+ /*
+ * Earlier SPI controllers (e.g. on at91rm9200) have a design bug whereby
+ * they assume that spi slave device state will not change on deselect, so
+@@ -137,6 +146,7 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
+ unsigned active = spi->mode & SPI_CS_HIGH;
+ u32 mr;
+
++ mr = spi_readl(as, MR);
+ if (atmel_spi_is_v2()) {
+ /*
+ * Always use CSR0. This ensures that the clock
+@@ -144,9 +154,9 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
+ * toggle the CS.
+ */
+ spi_writel(as, CSR0, asd->csr);
+- spi_writel(as, MR, SPI_BF(PCS, 0x0e) | SPI_BIT(MODFDIS)
+- | SPI_BIT(MSTR));
+- mr = spi_readl(as, MR);
++ mr &= (SPI_BIT(MODFDIS) | SPI_BIT(MSTR) | SPI_BIT(WDRBT));
++ mr |= SPI_BF(PCS, 0x0e);
++ spi_writel(as, MR, mr);
+ gpio_set_value(asd->npcs_pin, active);
+ } else {
+ u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0;
+@@ -161,7 +171,6 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
+ csr ^ SPI_BIT(CPOL));
+ }
+
+- mr = spi_readl(as, MR);
+ mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr);
+ if (spi->chip_select != 0)
+ gpio_set_value(asd->npcs_pin, active);
+@@ -1224,6 +1233,7 @@ static int __init atmel_spi_probe(struct platform_device *pdev)
+ int irq;
+ struct clk *clk;
+ int ret;
++ u32 mr;
+ struct spi_master *master;
+ struct atmel_spi *as;
+
+@@ -1286,7 +1296,11 @@ static int __init atmel_spi_probe(struct platform_device *pdev)
+ clk_enable(clk);
+ spi_writel(as, CR, SPI_BIT(SWRST));
+ spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
+- spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS));
++ mr = SPI_BIT(MSTR) | SPI_BIT(MODFDIS);
++ if (atmel_spi_v21x(as))
++ mr |= SPI_BIT(WDRBT); /* Prevent overrun errors */
++ spi_writel(as, MR, mr);
++
+
+ ret = atmel_spi_configure_dma(master);
+ if (ret)
+diff --git a/drivers/spi/atmel_spi.h b/drivers/spi/atmel_spi.h
+index 6e06b6a..e3a08ac 100644
+--- a/drivers/spi/atmel_spi.h
++++ b/drivers/spi/atmel_spi.h
+@@ -23,6 +23,7 @@
+ #define SPI_CSR1 0x0034
+ #define SPI_CSR2 0x0038
+ #define SPI_CSR3 0x003c
++#define SPI_VERSION 0x00fc
+ #define SPI_RPR 0x0100
+ #define SPI_RCR 0x0104
+ #define SPI_TPR 0x0108
+@@ -55,6 +56,8 @@
+ #define SPI_FDIV_SIZE 1
+ #define SPI_MODFDIS_OFFSET 4
+ #define SPI_MODFDIS_SIZE 1
++#define SPI_WDRBT_OFFSET 5
++#define SPI_WDRBT_SIZE 1
+ #define SPI_LLB_OFFSET 7
+ #define SPI_LLB_SIZE 1
+ #define SPI_PCS_OFFSET 16
+@@ -110,6 +113,12 @@
+ #define SPI_DLYBCT_OFFSET 24
+ #define SPI_DLYBCT_SIZE 8
+
++/* Bitfields in VERSION */
++#define SPI_VERS_OFFSET 0
++#define SPI_VERS_SIZE 12
++#define SPI_MFN_OFFSET 16
++#define SPI_MFN_SIZE 3
++
+ /* Bitfields in RCR */
+ #define SPI_RXCTR_OFFSET 0
+ #define SPI_RXCTR_SIZE 16
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0061-media-at91sam9x5-video-new-driver-for-the-high-end-o.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0061-media-at91sam9x5-video-new-driver-for-the-high-end-o.patch
new file mode 100644
index 0000000..5d930dc
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0061-media-at91sam9x5-video-new-driver-for-the-high-end-o.patch
@@ -0,0 +1,1530 @@
+From 18e4aead1dcdb0493291049f928d9378082b71bb Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
+Date: Tue, 24 May 2011 23:45:21 +0200
+Subject: [PATCH 061/107] media/at91sam9x5-video: new driver for the high end
+ overlay on at91sam9x5
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/media/video/Kconfig | 8 +
+ drivers/media/video/Makefile | 1 +
+ drivers/media/video/at91sam9x5-video.c | 1440 ++++++++++++++++++++++++++++++++
+ drivers/video/atmel_lcdfb.c | 7 +-
+ 4 files changed, 1453 insertions(+), 3 deletions(-)
+ create mode 100644 drivers/media/video/at91sam9x5-video.c
+
+diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
+index 00f51dd..c937e4d 100644
+--- a/drivers/media/video/Kconfig
++++ b/drivers/media/video/Kconfig
+@@ -81,6 +81,14 @@ menuconfig VIDEO_CAPTURE_DRIVERS
+
+ if VIDEO_CAPTURE_DRIVERS && VIDEO_V4L2
+
++config VIDEO_AT91SAM9X5
++ tristate "Support for AT91SAM9X5 Video"
++ depends on ARCH_AT91SAM9X5
++ depends on VIDEO_V4L2
++ select VIDEOBUF2_DMA_CONTIG
++ help
++ support for the "High End Overlay" found in Atmel's AT91SAM9X5 SoCs.
++
+ config VIDEO_ADV_DEBUG
+ bool "Enable advanced debug functionality"
+ default n
+diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
+index ace5d8b..5a7620d 100644
+--- a/drivers/media/video/Makefile
++++ b/drivers/media/video/Makefile
+@@ -105,6 +105,7 @@ obj-$(CONFIG_VIDEO_MXB) += mxb.o
+ obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
+ obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
+ obj-$(CONFIG_VIDEO_TIMBERDALE) += timblogiw.o
++obj-$(CONFIG_VIDEO_AT91SAM9X5) += at91sam9x5-video.o
+
+ obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
+ obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
+diff --git a/drivers/media/video/at91sam9x5-video.c b/drivers/media/video/at91sam9x5-video.c
+new file mode 100644
+index 0000000..1e5154b
+--- /dev/null
++++ b/drivers/media/video/at91sam9x5-video.c
+@@ -0,0 +1,1440 @@
++/*
++ * Copyright (C) 2011 Pengutronix
++ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.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.
++ */
++
++/*
++ * XXX:
++ * - handle setting of global alpha
++ * - handle more formats
++ * - complete this list :-)
++ */
++
++#include <linux/err.h>
++#include <linux/fb.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#include <media/v4l2-common.h>
++#include <media/v4l2-dev.h>
++#include <media/v4l2-ioctl.h>
++#include <media/videobuf2-dma-contig.h>
++
++#define debug(fmt, ...)
++
++#define DRIVER_NAME "at91sam9x5-video"
++
++#define REG_HEOCHER 0x00
++#define REG_HEOCHER_CHEN 0x00000001
++#define REG_HEOCHER_UPDATEEN 0x00000002
++#define REG_HEOCHER_A2QEN 0x00000004
++
++#define REG_HEOCHDR 0x04
++#define REG_HEOCHDR_CHDIS 0x00000001
++#define REG_HEOCHDR_CHRST 0x00000100
++
++#define REG_HEOCHSR 0x08
++#define REG_HEOCHSR_CHSR 0x00000001
++#define REG_HEOCHSR_UPDATESR 0x00000002
++#define REG_HEOCHSR_A2QSR 0x00000004
++
++#define REG_HEOIER 0x0c
++#define REG_HEOIDR 0x10
++#define REG_HEOIMR 0x14
++#define REG_HEOISR 0x18
++#define REG_HEOIxR_DMA 0x00000004
++#define REG_HEOIxR_DSCR 0x00000008
++#define REG_HEOIxR_ADD 0x00000010
++#define REG_HEOIxR_DONE 0x00000020
++#define REG_HEOIxR_OVR 0x00000040
++#define REG_HEOIxR_UDMA 0x00000400
++#define REG_HEOIxR_UDSCR 0x00000800
++#define REG_HEOIxR_UADD 0x00001000
++#define REG_HEOIxR_UDONE 0x00002000
++#define REG_HEOIxR_UOVR 0x00004000
++#define REG_HEOIxR_VDMA 0x00040000
++#define REG_HEOIxR_VDSCR 0x00080000
++#define REG_HEOIxR_VADD 0x00100000
++#define REG_HEOIxR_VDONE 0x00200000
++#define REG_HEOIxR_VOVR 0x00400000
++
++#define REG_HEOHEAD 0x1c
++#define REG_HEOUHEAD 0x2c
++#define REG_HEOVHEAD 0x3c
++
++#define REG_HEOADDR 0x20
++#define REG_HEOUADDR 0x30
++#define REG_HEOVADDR 0x40
++
++#define REG_HEOCTRL 0x24
++#define REG_HEOUCTRL 0x34
++#define REG_HEOVCTRL 0x44
++#define REG_HEOxCTRL_DFETCH 0x00000001
++#define REG_HEOCTRL_LFETCH 0x00000002
++#define REG_HEOxCTRL_DMAIEN 0x00000004
++#define REG_HEOxCTRL_DSCRIEN 0x00000008
++#define REG_HEOxCTRL_ADDIEN 0x00000010
++#define REG_HEOxCTRL_DONEIEN 0x00000020
++
++#define REG_HEONEXT 0x28
++#define REG_HEOUNEXT 0x38
++#define REG_HEOVNEXT 0x48
++
++#define REG_HEOCFG0 0x4c
++#define REG_HEOCFG0_DLBO 0x00000100
++#define REG_HEOCFG0_BLEN 0x00000030
++#define REG_HEOCFG0_BLEN_INCR1 0x00000000
++#define REG_HEOCFG0_BLEN_INCR4 0x00000010
++#define REG_HEOCFG0_BLEN_INCR8 0x00000020
++#define REG_HEOCFG0_BLEN_INCR16 0x00000030
++#define REG_HEOCFG0_BLENUV 0x000000c0
++#define REG_HEOCFG0_BLENUV_INCR1 0x00000000
++#define REG_HEOCFG0_BLENUV_INCR4 0x00000040
++#define REG_HEOCFG0_BLENUV_INCR8 0x00000080
++#define REG_HEOCFG0_BLENUV_INCR16 0x000000c0
++
++#define REG_HEOCFG1 0x50
++#define REG_HEOCFG1_CLUTEN 0x00000001
++#define REG_HEOCFG1_YUVEN 0x00000002
++#define REG_HEOCFG1_YUVMODE_12YCBCRP 0x00008000
++
++#define REG_HEOCFG2 0x54
++#define REG_HEOCFG2_XPOS 0x000007ff
++#define REG_HEOCFG2_YPOS 0x07ff0000
++
++#define REG_HEOCFG3 0x58
++#define REG_HEOCFG3_XSIZE 0x000007ff
++#define REG_HEOCFG3_YSIZE 0x07ff0000
++
++#define REG_HEOCFG4 0x5c
++#define REG_HEOCFG4_XMEMSIZE 0x000007ff
++#define REG_HEOCFG4_YMEMSIZE 0x07ff0000
++
++#define REG_HEOCFG5 0x60
++#define REG_HEOCFG5_XSTRIDE 0xffffffff
++
++#define REG_HEOCFG6 0x64
++#define REG_HEOCFG6_PSTRIDE 0xffffffff
++
++#define REG_HEOCFG7 0x68
++#define REG_HEOCFG7_UVXSTRIDE 0xffffffff
++
++#define REG_HEOCFG8 0x6c
++#define REG_HEOCFG8_UVPSTRIDE 0xffffffff
++
++#define REG_HEOCFG9 0x70
++#define REG_HEOCFG10 0x74
++#define REG_HEOCFG11 0x78
++
++#define REG_HEOCFG12 0x7c
++#define REG_HEOCFG12_CRKEY 0x00000001
++#define REG_HEOCFG12_INV 0x00000002
++#define REG_HEOCFG12_ITER2BL 0x00000004
++#define REG_HEOCFG12_ITER 0x00000008
++#define REG_HEOCFG12_REVALPHA 0x00000010
++#define REG_HEOCFG12_GAEN 0x00000020
++#define REG_HEOCFG12_LAEN 0x00000040
++#define REG_HEOCFG12_OVR 0x00000080
++#define REG_HEOCFG12_DMA 0x00000100
++#define REG_HEOCFG12_REP 0x00000200
++#define REG_HEOCFG12_DSTKEY 0x00000400
++#define REG_HEOCFG12_VIDPRI 0x00001000
++#define REG_HEOCFG12_GA 0x00ff0000
++
++#define REG_HEOCFG13 0x80
++#define REG_HEOCFG13_XFACTOR 0x00001fff
++#define REG_HEOCFG13_YFACTOR 0x1fff0000
++#define REG_HEOCFG13_SCALEN 0x80000000
++
++#define REG_HEOCFG14 0x84
++#define REG_HEOCFG15 0x88
++#define REG_HEOCFG16 0x8c
++
++#define valtomask(val, mask) (((val) << __ffs((mask))) & (mask))
++#define valfrommask(val, mask) (((val) & (mask)) >> __ffs((mask)))
++
++struct at91sam9x5_video_pdata {
++ u16 base_width;
++ u16 base_height;
++};
++
++struct at91sam9x5_video_bufinfo {
++ struct vb2_buffer *vb;
++ unsigned u_planeno, v_planeno;
++ unsigned long plane_size[3];
++};
++
++struct at91sam9x5_video_priv {
++ struct platform_device *pdev;
++
++ /* framebuffer stuff */
++ struct notifier_block fb_notifier;
++ struct fb_info *fbinfo;
++
++ struct video_device *video_dev;
++
++ void __iomem *regbase;
++ unsigned int irq;
++
++ struct vb2_queue queue;
++ void *alloc_ctx;
++
++ struct at91sam9x5_video_bufinfo cur, next;
++
++ /* protects the members after lock and hardware access */
++ spinlock_t lock;
++
++ enum {
++ /* DMA not running */
++ at91sam9x5_video_HW_IDLE,
++ /* DMA running, unless cfgstate is BAD */
++ at91sam9x5_video_HW_RUNNING,
++ } hwstate;
++
++ enum {
++ at91sam9x5_video_CFG_GOOD,
++ /* the shadow registers need an update */
++ at91sam9x5_video_CFG_GOOD_LATCH,
++ at91sam9x5_video_CFG_BAD,
++ } cfgstate;
++
++ /* if true the vid_out config in hardware doesn't match sw config */
++ int cfgupdate;
++
++ int valid_config;
++
++ struct v4l2_pix_format fmt_vid_out_cur, fmt_vid_out_next;
++
++ int rotation;
++
++ struct v4l2_window fmt_vid_overlay;
++
++ /*
++ * For YUV formats Y data is always in plane 0. U, V are either both in
++ * 0, both in 1, or U in 1 or V in 2. -1 for formats that don't use U
++ * and V.
++ */
++ int u_planeno, v_planeno;
++
++ unsigned long plane_size[3];
++
++ /*
++ * These are the offsets into the buffers to start the hardware for.
++ * Depending on rotation and overlay position this is more or less ugly
++ * to calculate. (y_offset is used for rgb data, too.)
++ */
++ u32 y_offset, u_offset, v_offset;
++
++ u32 irqstat;
++};
++
++static u32 at91sam9x5_video_read32(struct at91sam9x5_video_priv *priv,
++ size_t offset)
++{
++ /* XXX: really use the __raw variants? */
++ return __raw_readl(priv->regbase + offset);
++}
++
++static void at91sam9x5_video_write32(struct at91sam9x5_video_priv *priv,
++ size_t offset, u32 val)
++{
++ debug("$%x := %08x, $08 == %08x\n", offset, val,
++ at91sam9x5_video_read32(priv, REG_HEOCHSR));
++ __raw_writel(val, priv->regbase + offset);
++ debug("$08 == %08x\n", at91sam9x5_video_read32(priv, REG_HEOCHSR));
++}
++
++static int __at91sam9x5_video_buf_in_use(struct at91sam9x5_video_priv *priv,
++ struct at91sam9x5_video_bufinfo *bi,
++ size_t heoaddr_offset, unsigned planeno)
++{
++ if (planeno >= 0) {
++ u32 heoaddr = at91sam9x5_video_read32(priv, heoaddr_offset);
++ dma_addr_t plane_paddr =
++ vb2_dma_contig_plane_paddr(bi->vb, planeno);
++
++ if (heoaddr - plane_paddr <= bi->plane_size[planeno])
++ return 1;
++ }
++
++ return 0;
++}
++
++
++static int at91sam9x5_video_buf_in_use(struct at91sam9x5_video_priv *priv,
++ struct at91sam9x5_video_bufinfo *bi)
++{
++ if (__at91sam9x5_video_buf_in_use(priv, bi, REG_HEOADDR, 0))
++ return 1;
++ if (__at91sam9x5_video_buf_in_use(priv, bi,
++ REG_HEOUADDR, bi->u_planeno))
++ return 1;
++ if (__at91sam9x5_video_buf_in_use(priv, bi,
++ REG_HEOVADDR, bi->v_planeno))
++ return 1;
++
++ return 0;
++}
++
++static u32 at91sam9x5_video_handle_irqstat(struct at91sam9x5_video_priv *priv)
++{
++ u32 heoisr = at91sam9x5_video_read32(priv, REG_HEOISR);
++
++ debug("cur=%p, next=%p, heoisr=%08x\n", priv->cur.vb,
++ priv->next.vb, heoisr);
++ debug("cfgupdate=%d hwstate=%d cfgstate=%d\n",
++ priv->cfgupdate, priv->hwstate, priv->cfgstate);
++
++ if (!priv->cur.vb) {
++ priv->cur = priv->next;
++ priv->next.vb = NULL;
++ }
++
++ if (priv->hwstate == at91sam9x5_video_HW_IDLE &&
++ !(at91sam9x5_video_read32(priv, REG_HEOCHSR) &
++ REG_HEOCHSR_CHSR)) {
++ if (priv->cur.vb) {
++ vb2_buffer_done(priv->cur.vb, VB2_BUF_STATE_DONE);
++ priv->cur.vb = NULL;
++ }
++
++ if (priv->next.vb) {
++ vb2_buffer_done(priv->next.vb, VB2_BUF_STATE_DONE);
++ priv->next.vb = NULL;
++ }
++
++ at91sam9x5_video_write32(priv, REG_HEOIDR,
++ REG_HEOIxR_ADD | REG_HEOIxR_DMA |
++ REG_HEOIxR_UADD | REG_HEOIxR_UDMA |
++ REG_HEOIxR_VADD | REG_HEOIxR_VDMA);
++
++ } else if (priv->cur.vb && priv->next.vb) {
++ int hwrunning = 1;
++ if (priv->cfgstate == at91sam9x5_video_CFG_BAD &&
++ !(at91sam9x5_video_read32(priv, REG_HEOCHSR) &
++ REG_HEOCHSR_CHSR))
++ hwrunning = 0;
++
++ if (!hwrunning || !at91sam9x5_video_buf_in_use(priv,
++ &priv->cur)) {
++ vb2_buffer_done(priv->cur.vb, VB2_BUF_STATE_DONE);
++ priv->cur = priv->next;
++ priv->next.vb = NULL;
++ }
++ } else if (priv->next.vb) {
++ priv->cur = priv->next;
++ priv->next.vb = NULL;
++ }
++
++ return heoisr;
++}
++
++static irqreturn_t at91sam9x5_video_irq(int irq, void *data)
++{
++ struct at91sam9x5_video_priv *priv = data;
++ unsigned long flags;
++ u32 handled, heoimr;
++
++ spin_lock_irqsave(&priv->lock, flags);
++
++ heoimr = at91sam9x5_video_read32(priv, REG_HEOIMR);
++ handled = at91sam9x5_video_handle_irqstat(priv);
++
++ debug("%x, HEOCHSR = %08x\n", handled,
++ at91sam9x5_video_read32(priv, REG_HEOCHSR));
++
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ if (handled & heoimr)
++ return IRQ_HANDLED;
++ else
++ return IRQ_NONE;
++}
++
++static inline int sign(int x)
++{
++ if (x > 0)
++ return 1;
++ else if (x < 0)
++ return -1;
++ else
++ return 0;
++}
++
++static void at91sam9x5_video_show_buf(struct at91sam9x5_video_priv *priv,
++ struct vb2_buffer *vb)
++{
++ dma_addr_t buffer = vb2_dma_contig_plane_paddr(vb, 0);
++ void *vaddr = vb2_plane_vaddr(vb, 0);
++ struct v4l2_pix_format *pix = &priv->fmt_vid_out_cur;
++ /* XXX: format dependant */
++ size_t offset_dmadesc = ALIGN(pix->width * pix->height +
++ ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2, 32);
++ u32 *dmadesc = vaddr + offset_dmadesc;
++ u32 heocher;
++
++ if (priv->cfgstate == at91sam9x5_video_CFG_GOOD_LATCH) {
++ heocher = REG_HEOCHER_UPDATEEN;
++ priv->cfgstate = at91sam9x5_video_CFG_GOOD;
++ } else {
++ BUG_ON(priv->cfgstate != at91sam9x5_video_CFG_GOOD);
++ heocher = 0;
++ }
++
++ debug("vout=%ux%u, heocher=%08x\n", pix->width, pix->height, heocher);
++
++ dmadesc[0] = buffer + priv->y_offset;
++ dmadesc[1] = REG_HEOxCTRL_DFETCH;
++ dmadesc[2] = buffer + offset_dmadesc;
++
++ if (priv->u_planeno >= 0) {
++ dmadesc[3] = vb2_dma_contig_plane_paddr(vb, priv->u_planeno) +
++ priv->u_offset;
++ dmadesc[4] = REG_HEOxCTRL_DFETCH;
++ dmadesc[5] = buffer + offset_dmadesc + 3 * 4;
++ }
++
++ if (priv->v_planeno >= 0) {
++ dmadesc[6] = vb2_dma_contig_plane_paddr(vb, priv->v_planeno) +
++ priv->v_offset;
++ dmadesc[7] = REG_HEOxCTRL_DFETCH;
++ dmadesc[8] = buffer + offset_dmadesc + 6 * 4;
++ }
++
++
++ debug("HEOCHSR = %08x\n", at91sam9x5_video_read32(priv, REG_HEOCHSR));
++ if (likely(priv->hwstate == at91sam9x5_video_HW_RUNNING)) {
++
++ at91sam9x5_video_write32(priv, REG_HEOHEAD, dmadesc[2]);
++
++ if (priv->u_planeno >= 0)
++ at91sam9x5_video_write32(priv,
++ REG_HEOUHEAD, dmadesc[5]);
++
++ if (priv->v_planeno >= 0)
++ at91sam9x5_video_write32(priv,
++ REG_HEOVHEAD, dmadesc[8]);
++
++ at91sam9x5_video_write32(priv,
++ REG_HEOCHER, heocher | REG_HEOCHER_A2QEN);
++
++ } else {
++
++ at91sam9x5_video_write32(priv, REG_HEOADDR, dmadesc[0]);
++ at91sam9x5_video_write32(priv, REG_HEOCTRL, dmadesc[1]);
++ at91sam9x5_video_write32(priv, REG_HEONEXT, dmadesc[2]);
++
++ if (priv->u_planeno >= 0) {
++ at91sam9x5_video_write32(priv,
++ REG_HEOUADDR, dmadesc[3]);
++ at91sam9x5_video_write32(priv,
++ REG_HEOUCTRL, dmadesc[4]);
++ at91sam9x5_video_write32(priv,
++ REG_HEOUNEXT, dmadesc[5]);
++ }
++
++ if (priv->v_planeno >= 0) {
++ at91sam9x5_video_write32(priv,
++ REG_HEOVADDR, dmadesc[6]);
++ at91sam9x5_video_write32(priv,
++ REG_HEOVCTRL, dmadesc[7]);
++ at91sam9x5_video_write32(priv,
++ REG_HEOVNEXT, dmadesc[8]);
++ }
++
++ at91sam9x5_video_write32(priv, REG_HEOCHER,
++ heocher | REG_HEOCHER_CHEN);
++
++ priv->hwstate = at91sam9x5_video_HW_RUNNING;
++ }
++
++ if (priv->cur.vb && at91sam9x5_video_buf_in_use(priv, &priv->cur)) {
++ if (priv->next.vb) {
++ /* drop next; XXX: is this an error? */
++ debug("drop %p\n", priv->next.vb);
++ vb2_buffer_done(priv->next.vb, VB2_BUF_STATE_ERROR);
++ }
++ } else {
++ if (priv->cur.vb)
++ vb2_buffer_done(priv->cur.vb, VB2_BUF_STATE_DONE);
++
++ priv->cur = priv->next;
++ }
++ priv->next.vb = vb;
++ priv->next.u_planeno = priv->u_planeno;
++ priv->next.v_planeno = priv->v_planeno;
++ priv->next.plane_size[0] = priv->plane_size[0];
++ priv->next.plane_size[1] = priv->plane_size[1];
++ priv->next.plane_size[2] = priv->plane_size[2];
++}
++
++static int experimental;
++module_param(experimental, bool, 0644);
++MODULE_PARM_DESC(experimental, "enable experimental features");
++
++static void at91sam9x5_video_params(unsigned width, unsigned height,
++ int rotation, u32 *xstride, u32 *pstride, u32 *tloffset)
++{
++/* offset of pixel at (x, y) in the buffer */
++#define po(x, y) ((x) + width * (y))
++
++ /* offsets of the edges in counter-clockwise order */
++ const unsigned e[] = {
++ po(0, 0),
++ po(0, height - 1),
++ po(width - 1, height - 1),
++ po(width - 1, 0),
++ };
++
++ /*
++ * offsets of the pixels next to the corresponding edges
++ * If edge[i] goes to the top left corner, edge_neighbour[i] is
++ * located just below of edge[i].
++ */
++ const unsigned en[] = {
++ po(0, 1),
++ po(1, height - 1),
++ po(width - 1, height - 2),
++ po(width - 2, 0),
++ };
++
++#define ro(r) ((rotation + (r)) % 4)
++
++ *xstride = en[ro(0)] - e[ro(3)];
++ *pstride = e[ro(3)] - en[ro(3)];
++ *tloffset = e[ro(0)];
++}
++
++static void at91sam9x5_video_update_config_real(
++ struct at91sam9x5_video_priv *priv)
++{
++ struct v4l2_pix_format *pix = &priv->fmt_vid_out_cur;
++ struct v4l2_window *win = &priv->fmt_vid_overlay;
++ struct v4l2_rect *rect = &win->w;
++ /* XXX: check for overflow? */
++ s32 right = rect->left + rect->width, bottom = rect->top + rect->height;
++
++ unsigned hwxpos, hwypos, hwxsize, hwysize;
++ unsigned hwxmem_size, hwymem_size;
++ s32 hwxstride, hwpstride;
++ s32 hwuvxstride, hwuvpstride;
++ s32 rotated_pixwidth, rotated_pixheight;
++
++ debug("vout=%ux%u, ovl=(%d,%d)+(%d,%d)\n", pix->width, pix->height,
++ rect->left, rect->top, rect->width, rect->height);
++
++ if (!experimental && priv->rotation) {
++ dev_info(&priv->video_dev->dev, "disable rotation\n");
++ priv->rotation = 0;
++ }
++
++ if (rect->left < 0)
++ hwxpos = 0;
++ else
++ hwxpos = rect->left;
++
++ if (rect->top < 0)
++ hwypos = 0;
++ else
++ hwypos = rect->top;
++
++ if (right > priv->fbinfo->var.xres)
++ hwxsize = priv->fbinfo->var.xres - hwxpos;
++ else
++ hwxsize = right - hwxpos;
++
++ if (bottom > priv->fbinfo->var.yres)
++ hwysize = priv->fbinfo->var.yres - hwypos;
++ else
++ hwysize = bottom - hwypos;
++
++ at91sam9x5_video_write32(priv, REG_HEOCFG2,
++ valtomask(hwxpos, REG_HEOCFG2_XPOS) |
++ valtomask(hwypos, REG_HEOCFG2_YPOS));
++
++ at91sam9x5_video_write32(priv, REG_HEOCFG3,
++ valtomask(hwxsize - 1, REG_HEOCFG3_XSIZE) |
++ valtomask(hwysize - 1, REG_HEOCFG3_YSIZE));
++
++ /* XXX:
++ * - clipping
++ */
++ at91sam9x5_video_write32(priv, REG_HEOCFG1,
++ REG_HEOCFG1_YUVMODE_12YCBCRP |
++ REG_HEOCFG1_YUVEN);
++ at91sam9x5_video_write32(priv, REG_HEOCFG12,
++ REG_HEOCFG12_GAEN |
++ REG_HEOCFG12_OVR |
++ REG_HEOCFG12_DMA |
++ REG_HEOCFG12_REP |
++ REG_HEOCFG12_GA);
++
++#define vx(pos) xedge[(priv->rotation + pos) % 4]
++#define vy(pos) yedge[(priv->rotation + pos) % 4]
++
++ if (priv->rotation & 1) {
++ rotated_pixwidth = pix->height;
++ rotated_pixheight = pix->width;
++ } else {
++ rotated_pixwidth = pix->width;
++ rotated_pixheight = pix->height;
++ }
++
++ hwxmem_size = rotated_pixwidth * hwxsize / rect->width;
++ hwymem_size = rotated_pixheight * hwysize / rect->height;
++
++ at91sam9x5_video_write32(priv, REG_HEOCFG4,
++ valtomask(hwxmem_size - 1, REG_HEOCFG4_XMEMSIZE) |
++ valtomask(hwymem_size - 1, REG_HEOCFG4_YMEMSIZE));
++
++ at91sam9x5_video_write32(priv, REG_HEOCFG13,
++ REG_HEOCFG13_SCALEN |
++ valtomask(1024 * hwxmem_size / hwxsize,
++ REG_HEOCFG13_XFACTOR) |
++ valtomask(1024 * hwymem_size / hwysize,
++ REG_HEOCFG13_YFACTOR));
++
++ at91sam9x5_video_params(pix->width, pix->height, priv->rotation,
++ &hwxstride, &hwpstride, &priv->y_offset);
++
++ /* XXX: format-dependant */
++ at91sam9x5_video_params(DIV_ROUND_UP(pix->width, 2),
++ DIV_ROUND_UP(pix->height, 2), priv->rotation,
++ &hwuvxstride, &hwuvpstride, &priv->u_offset);
++
++ at91sam9x5_video_write32(priv, REG_HEOCFG5,
++ valtomask(hwxstride - 1, REG_HEOCFG5_XSTRIDE));
++ at91sam9x5_video_write32(priv, REG_HEOCFG6,
++ valtomask(hwpstride - 1, REG_HEOCFG6_PSTRIDE));
++
++ at91sam9x5_video_write32(priv, REG_HEOCFG7,
++ valtomask(hwuvxstride - 1, REG_HEOCFG7_UVXSTRIDE));
++ at91sam9x5_video_write32(priv, REG_HEOCFG8,
++ valtomask(hwuvpstride - 1, REG_HEOCFG8_UVPSTRIDE));
++
++ /* XXX: format dependant */
++ priv->u_planeno = 0;
++ priv->v_planeno = 0;
++ priv->u_offset += pix->width * pix->height;
++ priv->v_offset = priv->u_offset +
++ DIV_ROUND_UP(pix->width, 2) * DIV_ROUND_UP(pix->height, 2);
++
++ /* XXX: evaluate pix->colorspace */
++ at91sam9x5_video_write32(priv, REG_HEOCFG14, 0x4c900091);
++ at91sam9x5_video_write32(priv, REG_HEOCFG15, 0x7a5f5090);
++ at91sam9x5_video_write32(priv, REG_HEOCFG16, 0x40040890);
++}
++
++static void at91sam9x5_video_update_config(struct at91sam9x5_video_priv *priv,
++ int overlay_only)
++{
++ debug("cfgupdate=%d overlay_only=%d\n", priv->cfgupdate, overlay_only);
++
++ at91sam9x5_video_handle_irqstat(priv);
++
++ if (priv->cfgupdate || overlay_only) {
++ struct v4l2_pix_format *pix = &priv->fmt_vid_out_cur;
++ struct v4l2_window *win = &priv->fmt_vid_overlay;
++ struct v4l2_rect *rect = &win->w;
++
++ if (!overlay_only) {
++ *pix = priv->fmt_vid_out_next;
++ priv->cfgupdate = 0;
++ }
++
++ /* XXX: handle clipping */
++ if (rect->width <= 0 || rect->height <= 0 ||
++ /* vid_out is set */
++ pix->width <= 0 ||
++ pix->height <= 0 ||
++ /* window is partly invisible or too small */
++ rect->left < 0 ||
++ rect->top < 0 ||
++ rect->left >= (int)priv->fbinfo->var.xres - 5 ||
++ rect->top >= (int)priv->fbinfo->var.yres - 5 ||
++ rect->left + rect->width >
++ (int)priv->fbinfo->var.xres ||
++ rect->top + rect->height >
++ (int)priv->fbinfo->var.yres) {
++
++ if (priv->cfgstate == at91sam9x5_video_CFG_GOOD ||
++ priv->cfgstate ==
++ at91sam9x5_video_CFG_GOOD_LATCH)
++ at91sam9x5_video_write32(priv,
++ REG_HEOCHDR, REG_HEOCHDR_CHDIS);
++
++ priv->cfgstate = at91sam9x5_video_CFG_BAD;
++ } else {
++ at91sam9x5_video_update_config_real(priv);
++
++ debug("hwstate=%d cfgstate=%d\n",
++ priv->hwstate, priv->cfgstate);
++ if (overlay_only && priv->hwstate ==
++ at91sam9x5_video_HW_RUNNING) {
++ if (priv->cfgstate ==
++ at91sam9x5_video_CFG_BAD) {
++ priv->cfgstate =
++ at91sam9x5_video_CFG_GOOD_LATCH;
++ priv->hwstate =
++ at91sam9x5_video_HW_IDLE;
++
++ at91sam9x5_video_show_buf(priv,
++ priv->cur.vb);
++ } else
++ at91sam9x5_video_write32(priv,
++ REG_HEOCHER,
++ REG_HEOCHER_UPDATEEN);
++ } else
++ priv->cfgstate =
++ at91sam9x5_video_CFG_GOOD_LATCH;
++ }
++
++ }
++}
++
++static int at91sam9x5_video_vb_queue_setup(struct vb2_queue *q,
++ unsigned int *num_buffers, unsigned int *num_planes,
++ unsigned long sizes[], void *alloc_ctxs[])
++{
++ struct at91sam9x5_video_priv *priv =
++ container_of(q, struct at91sam9x5_video_priv, queue);
++ struct v4l2_pix_format *pix = &priv->fmt_vid_out_next;
++
++ debug("vout=%ux%u\n", pix->width, pix->height);
++
++ /* XXX */
++ *num_planes = 1;
++
++ /*
++ * The last 9 (aligned) words are used for the 3 dma descriptors (3
++ * 32-bit words each). The additional 32 bits are for alignment.
++ * XXX: is that allowed and done right?
++ * XXX: format-dependant
++ */
++ sizes[0] = pix->width * pix->height +
++ ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2 +
++ 10 * 32;
++ priv->plane_size[0] = sizes[0];
++
++ alloc_ctxs[0] = priv->alloc_ctx;
++
++ return 0;
++}
++
++static void at91sam9x5_video_vb_wait_prepare(struct vb2_queue *q)
++{
++ struct at91sam9x5_video_priv *priv =
++ container_of(q, struct at91sam9x5_video_priv, queue);
++ unsigned long flags;
++
++ debug("cfgupdate=%d hwstate=%d cfgstate=%d\n",
++ priv->cfgupdate, priv->hwstate, priv->cfgstate);
++ debug("bufs=%p,%p\n", priv->cur.vb, priv->next.vb);
++ spin_lock_irqsave(&priv->lock, flags);
++
++ at91sam9x5_video_handle_irqstat(priv);
++
++ at91sam9x5_video_write32(priv, REG_HEOIER,
++ REG_HEOIxR_ADD | REG_HEOIxR_DMA |
++ REG_HEOIxR_UADD | REG_HEOIxR_UDMA |
++ REG_HEOIxR_VADD | REG_HEOIxR_VDMA);
++
++ spin_unlock_irqrestore(&priv->lock, flags);
++}
++
++static void at91sam9x5_video_vb_wait_finish(struct vb2_queue *q)
++{
++ struct at91sam9x5_video_priv *priv =
++ container_of(q, struct at91sam9x5_video_priv, queue);
++ unsigned long flags;
++
++ debug("cfgupdate=%d hwstate=%d cfgstate=%d\n",
++ priv->cfgupdate, priv->hwstate, priv->cfgstate);
++ debug("bufs=%p,%p\n", priv->cur.vb, priv->next.vb);
++ spin_lock_irqsave(&priv->lock, flags);
++
++ at91sam9x5_video_write32(priv, REG_HEOIDR,
++ REG_HEOIxR_ADD | REG_HEOIxR_DMA |
++ REG_HEOIxR_UADD | REG_HEOIxR_UDMA |
++ REG_HEOIxR_VADD | REG_HEOIxR_VDMA);
++
++ spin_unlock_irqrestore(&priv->lock, flags);
++}
++
++static int at91sam9x5_video_vb_buf_prepare(struct vb2_buffer *vb)
++{
++ struct vb2_queue *q = vb->vb2_queue;
++ struct at91sam9x5_video_priv *priv =
++ container_of(q, struct at91sam9x5_video_priv, queue);
++ struct v4l2_pix_format *pix = &priv->fmt_vid_out_cur;
++ unsigned long flags;
++
++ spin_lock_irqsave(&priv->lock, flags);
++ if (priv->cfgupdate)
++ pix = &priv->fmt_vid_out_next;
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ debug("vout=%ux%u\n", pix->width, pix->height);
++ debug("buflen=%u\n", vb->v4l2_planes[0].length);
++
++ /* XXX: format-dependant */
++ if (vb->v4l2_planes[0].length < pix->width * pix->height +
++ ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2 +
++ 10 * 32)
++ return -EINVAL;
++
++ return 0;
++}
++
++static void at91sam9x5_video_vb_buf_queue(struct vb2_buffer *vb)
++{
++ struct vb2_queue *q = vb->vb2_queue;
++ struct at91sam9x5_video_priv *priv =
++ container_of(q, struct at91sam9x5_video_priv, queue);
++ unsigned long flags;
++
++ spin_lock_irqsave(&priv->lock, flags);
++
++ at91sam9x5_video_update_config(priv, 0);
++
++ switch (priv->cfgstate) {
++ case at91sam9x5_video_CFG_GOOD:
++ case at91sam9x5_video_CFG_GOOD_LATCH:
++ /* show_buf takes care of the eventual hwstate update */
++ at91sam9x5_video_show_buf(priv, vb);
++ break;
++
++ case at91sam9x5_video_CFG_BAD:
++ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
++ priv->hwstate = at91sam9x5_video_HW_RUNNING;
++ break;
++ }
++
++ spin_unlock_irqrestore(&priv->lock, flags);
++}
++
++const struct vb2_ops at91sam9x5_video_vb_ops = {
++ .queue_setup = at91sam9x5_video_vb_queue_setup,
++
++ .wait_prepare = at91sam9x5_video_vb_wait_prepare,
++ .wait_finish = at91sam9x5_video_vb_wait_finish,
++
++ .buf_prepare = at91sam9x5_video_vb_buf_prepare,
++ .buf_queue = at91sam9x5_video_vb_buf_queue,
++};
++
++static int at91sam9x5_video_vidioc_querycap(struct file *filp,
++ void *fh, struct v4l2_capability *cap)
++{
++ strcpy(cap->driver, DRIVER_NAME);
++ cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING |
++ V4L2_CAP_VIDEO_OVERLAY;
++
++ /* XXX */
++ cap->version = 0;
++ cap->card[0] = '\0';
++ cap->bus_info[0] = '\0';
++
++ return 0;
++}
++
++static int at91sam9x5_video_vidioc_g_fmt_vid_out(struct file *filp,
++ void *fh, struct v4l2_format *f)
++{
++ struct video_device *vdev = filp->private_data;
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++ unsigned long flags;
++
++ if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
++ return -EINVAL;
++
++ spin_lock_irqsave(&priv->lock, flags);
++
++ f->fmt.pix = priv->fmt_vid_out_next;
++
++ spin_unlock_irqrestore(&priv->lock, flags);
++ return 0;
++}
++
++static int at91sam9x5_video_vidioc_s_fmt_vid_out(struct file *filp,
++ void *fh, struct v4l2_format *f)
++{
++ struct video_device *vdev = filp->private_data;
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++ struct v4l2_pix_format *pix = &f->fmt.pix;
++ unsigned long flags;
++
++ if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
++ return -EINVAL;
++
++ if (pix->pixelformat != V4L2_PIX_FMT_YUV420)
++ return -EINVAL;
++
++ debug("vout=%ux%u\n", pix->width, pix->height);
++
++ spin_lock_irqsave(&priv->lock, flags);
++
++ priv->fmt_vid_out_next = *pix;
++
++ priv->cfgupdate = 1;
++
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ return 0;
++}
++
++static int at91sam9x5_video_vidioc_g_fmt_vid_overlay(struct file *filp,
++ void *fh, struct v4l2_format *f)
++{
++ struct video_device *vdev = filp->private_data;
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++ unsigned long flags;
++
++ if (f->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
++ return -EINVAL;
++
++ spin_lock_irqsave(&priv->lock, flags);
++
++ f->fmt.win = priv->fmt_vid_overlay;
++
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ return 0;
++}
++
++static int at91sam9x5_video_vidioc_s_fmt_vid_overlay(struct file *filp,
++ void *fh, struct v4l2_format *f)
++{
++ struct video_device *vdev = filp->private_data;
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++ struct v4l2_window *win = &f->fmt.win;
++ unsigned long flags;
++
++ if (f->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
++ return -EINVAL;
++
++ debug("rect=(%d,%d)+(%d,%d)\n",
++ win->w.left, win->w.top, win->w.width, win->w.height);
++
++ spin_lock_irqsave(&priv->lock, flags);
++
++ priv->fmt_vid_overlay = *win;
++
++ at91sam9x5_video_update_config(priv, 1);
++
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ return 0;
++}
++
++static int at91sam9x5_video_vidioc_enum_fmt_vid_out(struct file *filp,
++ void *fh, struct v4l2_fmtdesc *f)
++{
++ /* XXX: support more formats */
++ if (f->index > 0)
++ return -EINVAL;
++
++ f->pixelformat = V4L2_PIX_FMT_YUV420;
++ return 0;
++}
++
++static int at91sam9x5_video_vidioc_reqbufs(struct file *filp,
++ void *fh, struct v4l2_requestbuffers *b)
++{
++ struct video_device *vdev = filp->private_data;
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++ struct vb2_queue *q = &priv->queue;
++
++ if (b->type != q->type) {
++ dev_err(&priv->pdev->dev, "invalid buffer type (%d != %d)\n",
++ b->type, q->type);
++ return -EINVAL;
++ }
++
++ return vb2_reqbufs(q, b);
++}
++
++static int at91sam9x5_video_vidioc_querybuf(struct file *filp,
++ void *fh, struct v4l2_buffer *b)
++{
++ struct video_device *vdev = filp->private_data;
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++
++ return vb2_querybuf(&priv->queue, b);
++}
++
++static int at91sam9x5_video_vidioc_qbuf(struct file *filp,
++ void *fh, struct v4l2_buffer *b)
++{
++ struct video_device *vdev = filp->private_data;
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++
++ return vb2_qbuf(&priv->queue, b);
++}
++
++static int at91sam9x5_video_vidioc_dqbuf(struct file *filp,
++ void *fh, struct v4l2_buffer *b)
++{
++ struct video_device *vdev = filp->private_data;
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++
++ return vb2_dqbuf(&priv->queue, b, filp->f_flags & O_NONBLOCK);
++}
++
++static int at91sam9x5_video_vidioc_streamon(struct file *filp,
++ void *fh, enum v4l2_buf_type type)
++{
++ struct video_device *vdev = video_devdata(filp);
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++
++ return vb2_streamon(&priv->queue, type);
++}
++
++static int at91sam9x5_video_vidioc_streamoff(struct file *filp,
++ void *fh, enum v4l2_buf_type type)
++{
++ struct video_device *vdev = video_devdata(filp);
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++ unsigned long flags;
++
++ spin_lock_irqsave(&priv->lock, flags);
++
++ /* disable channel */
++ at91sam9x5_video_write32(priv, REG_HEOCHDR, REG_HEOCHDR_CHDIS);
++
++ at91sam9x5_video_handle_irqstat(priv);
++
++ if (priv->cur.vb)
++ at91sam9x5_video_write32(priv, REG_HEOIER,
++ REG_HEOIxR_ADD | REG_HEOIxR_DMA |
++ REG_HEOIxR_UADD | REG_HEOIxR_UDMA |
++ REG_HEOIxR_VADD | REG_HEOIxR_VDMA);
++
++ priv->hwstate = at91sam9x5_video_HW_IDLE;
++
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ return vb2_streamoff(&priv->queue, type);
++}
++
++static int at91sam9x5_video_vidioc_queryctrl(struct file *filp, void *fh,
++ struct v4l2_queryctrl *a)
++{
++ int ret;
++
++ switch (a->id) {
++ case V4L2_CID_ROTATE:
++ ret = v4l2_ctrl_query_fill(a, 0, 270, 90, 0);
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ return ret;
++}
++
++static int at91sam9x5_video_vidioc_g_ctrl(struct file *filp, void *fh,
++ struct v4l2_control *a)
++{
++ struct video_device *vdev = video_devdata(filp);
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++ int ret = 0;
++
++ switch (a->id) {
++ case V4L2_CID_ROTATE:
++ a->value = 90 * priv->rotation;
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ return ret;
++}
++
++static int at91sam9x5_video_vidioc_s_ctrl(struct file *filp, void *fh,
++ struct v4l2_control *a)
++{
++ struct video_device *vdev = video_devdata(filp);
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++ int ret;
++ unsigned long flags;
++
++ switch (a->id) {
++ case V4L2_CID_ROTATE:
++ if (a->value / 90 * 90 != a->value ||
++ (a->value / 90) % 4 != a->value / 90) {
++ ret = -EINVAL;
++ } else {
++ debug("rotation: %d\n", a->value);
++ spin_lock_irqsave(&priv->lock, flags);
++ priv->rotation = a->value / 90;
++ at91sam9x5_video_update_config(priv, 1);
++ spin_unlock_irqrestore(&priv->lock, flags);
++ }
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ return ret;
++}
++
++static const struct v4l2_ioctl_ops at91sam9x5_video_ioctl_ops = {
++ .vidioc_querycap = at91sam9x5_video_vidioc_querycap,
++ .vidioc_g_fmt_vid_out = at91sam9x5_video_vidioc_g_fmt_vid_out,
++ .vidioc_s_fmt_vid_out = at91sam9x5_video_vidioc_s_fmt_vid_out,
++ .vidioc_g_fmt_vid_overlay = at91sam9x5_video_vidioc_g_fmt_vid_overlay,
++ .vidioc_s_fmt_vid_overlay = at91sam9x5_video_vidioc_s_fmt_vid_overlay,
++ .vidioc_enum_fmt_vid_out = at91sam9x5_video_vidioc_enum_fmt_vid_out,
++ .vidioc_reqbufs = at91sam9x5_video_vidioc_reqbufs,
++ .vidioc_querybuf = at91sam9x5_video_vidioc_querybuf,
++ .vidioc_qbuf = at91sam9x5_video_vidioc_qbuf,
++ .vidioc_dqbuf = at91sam9x5_video_vidioc_dqbuf,
++ .vidioc_streamon = at91sam9x5_video_vidioc_streamon,
++ .vidioc_streamoff = at91sam9x5_video_vidioc_streamoff,
++ .vidioc_queryctrl = at91sam9x5_video_vidioc_queryctrl,
++ .vidioc_g_ctrl = at91sam9x5_video_vidioc_g_ctrl,
++ .vidioc_s_ctrl = at91sam9x5_video_vidioc_s_ctrl,
++};
++
++static int at91sam9x5_video_open(struct file *filp)
++{
++ struct video_device *vdev = video_devdata(filp);
++
++ /*
++ * XXX: allow only one open? Or is that already enforced by the
++ * framework?
++ */
++ filp->private_data = vdev;
++
++ return 0;
++}
++
++static int at91sam9x5_video_release(struct file *filp)
++{
++ struct video_device *vdev = video_devdata(filp);
++
++ dev_dbg(&vdev->dev, "%s\n", __func__);
++
++ return 0;
++}
++
++static int at91sam9x5_video_mmap(struct file *filp, struct vm_area_struct *vma)
++{
++ struct video_device *vdev = video_devdata(filp);
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++
++ dev_dbg(&vdev->dev, "%s\n", __func__);
++
++ /* returning -EIO here makes gst-launch segfault */
++ return vb2_mmap(&priv->queue, vma);
++}
++
++static struct v4l2_file_operations at91sam9x5_video_fops = {
++ .owner = THIS_MODULE,
++ .open = at91sam9x5_video_open,
++ .release = at91sam9x5_video_release,
++ .ioctl = video_ioctl2,
++ .mmap = at91sam9x5_video_mmap,
++};
++
++static int at91sam9x5_video_register(struct at91sam9x5_video_priv *priv,
++ struct fb_info *fbinfo)
++{
++ int ret = -ENOMEM;
++ struct platform_device *pdev = priv->pdev;
++ struct resource *res;
++ const struct at91sam9x5_video_pdata *pdata =
++ dev_get_platdata(&pdev->dev);
++ struct vb2_queue *q = &priv->queue;
++ unsigned long flags;
++
++ spin_lock_irqsave(&priv->lock, flags);
++ if (priv->fbinfo) {
++ spin_unlock_irqrestore(&priv->lock, flags);
++ return -EBUSY;
++ }
++ priv->fbinfo = fbinfo;
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ /* XXX: this doesn't belong here, does it? */
++ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
++
++ if (!pdata) {
++ dev_err(&pdev->dev, "failed to get platform data\n");
++ goto err_get_pdata;
++ }
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ dev_err(&pdev->dev, "failed to get register base\n");
++ goto err_get_regbase;
++ }
++
++ priv->regbase = ioremap(res->start, resource_size(res));
++ if (!priv->regbase) {
++ dev_err(&pdev->dev, "failed to remap register base\n");
++ goto err_ioremap;
++ }
++
++ /*
++ * XXX: video_device_alloc is just a kzalloc, so embedding struct
++ * video_device into struct at91sam9x5_video_priv would work, too.
++ * Is that allowed?
++ */
++ priv->video_dev = video_device_alloc();
++ if (!priv->video_dev) {
++ dev_err(&pdev->dev, "failed to alloc video device for %p\n",
++ fbinfo);
++ goto err_video_device_alloc;
++ }
++
++ priv->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
++ if (IS_ERR(priv->alloc_ctx)) {
++ ret = PTR_ERR(priv->alloc_ctx);
++ dev_err(&pdev->dev, "failed to init alloc_ctx (%d)\n", ret);
++ goto err_init_ctx;
++ }
++
++ q->ops = &at91sam9x5_video_vb_ops;
++ q->mem_ops = &vb2_dma_contig_memops;
++ q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
++ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_WRITE;
++
++ ret = vb2_queue_init(q);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to init queue (%d)\n", ret);
++ goto err_queue_init;
++ }
++
++ priv->video_dev->fops = &at91sam9x5_video_fops;
++ priv->video_dev->ioctl_ops = &at91sam9x5_video_ioctl_ops;
++ priv->video_dev->release = video_device_release;
++
++ video_set_drvdata(priv->video_dev, priv);
++
++ /* reset channel and clear status */
++ at91sam9x5_video_write32(priv, REG_HEOCHDR, REG_HEOCHDR_CHRST);
++ (void)at91sam9x5_video_read32(priv, REG_HEOISR);
++
++ /* set maximal bursting */
++ at91sam9x5_video_write32(priv, REG_HEOCFG0,
++ REG_HEOCFG0_BLEN_INCR16 |
++ REG_HEOCFG0_BLENUV_INCR16);
++
++ ret = platform_get_irq(pdev, 0);
++ if (ret <= 0) {
++ dev_err(&pdev->dev, "failed to get irq from resources (%d)\n",
++ ret);
++ if (!ret)
++ ret = -ENXIO;
++ goto err_get_irq;
++ }
++ priv->irq = ret;
++
++ ret = request_irq(priv->irq, at91sam9x5_video_irq, IRQF_SHARED,
++ DRIVER_NAME, priv);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to request irq (%d)\n", ret);
++ goto err_request_irq;
++ }
++
++ ret = video_register_device(priv->video_dev,
++ /* XXX: really grabber? */ VFL_TYPE_GRABBER, -1);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to register video device (%d)\n",
++ ret);
++
++ free_irq(priv->irq, priv);
++ err_request_irq:
++ err_get_irq:
++
++ vb2_queue_release(q);
++err_queue_init:
++
++ vb2_dma_contig_cleanup_ctx(priv->alloc_ctx);
++ err_init_ctx:
++
++ video_device_release(priv->video_dev);
++ err_video_device_alloc:
++
++ iounmap(priv->regbase);
++
++ priv->fbinfo = NULL;
++ }
++ err_ioremap:
++ err_get_regbase:
++ err_get_pdata:
++
++ return ret;
++}
++
++static void at91sam9x5_video_unregister(struct at91sam9x5_video_priv *priv)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&priv->lock, flags);
++
++ if (!priv->fbinfo) {
++ spin_unlock_irqrestore(&priv->lock, flags);
++ return;
++ }
++ /* XXX: handle fbinfo being NULL in various callbacks */
++ priv->fbinfo = NULL;
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ /* silence DMA */
++ at91sam9x5_video_write32(priv, REG_HEOIDR,
++ REG_HEOIxR_ADD | REG_HEOIxR_DMA | REG_HEOIxR_UADD |
++ REG_HEOIxR_UDMA | REG_HEOIxR_VADD | REG_HEOIxR_VDMA);
++
++ video_unregister_device(priv->video_dev);
++ free_irq(priv->irq, priv);
++ vb2_queue_release(&priv->queue);
++ vb2_dma_contig_cleanup_ctx(priv->alloc_ctx);
++ video_device_release(priv->video_dev);
++ iounmap(priv->regbase);
++}
++
++static int at91sam9x5_video_fb_event_notify(struct notifier_block *self,
++ unsigned long action, void *data)
++{
++ struct at91sam9x5_video_priv *priv =
++ container_of(self, struct at91sam9x5_video_priv, fb_notifier);
++ struct fb_event *event = data;
++ struct fb_info *fbinfo = event->info;
++
++ /* XXX: only do this for atmel_lcdfb devices! */
++ switch (action) {
++ case FB_EVENT_FB_REGISTERED:
++ at91sam9x5_video_register(priv, fbinfo);
++ break;
++
++ case FB_EVENT_FB_UNREGISTERED:
++ at91sam9x5_video_unregister(priv);
++ break;
++ }
++ return 0;
++}
++
++static int __devinit at91sam9x5_video_probe(struct platform_device *pdev)
++{
++ int ret = -ENOMEM;
++ size_t i;
++ struct at91sam9x5_video_priv *priv = kzalloc(sizeof(*priv), GFP_KERNEL);
++
++ if (!priv) {
++ dev_err(&pdev->dev, "failed to allocate driver private data\n");
++ goto err_alloc_priv;
++ }
++
++ priv->pdev = pdev;
++ priv->fb_notifier.notifier_call = at91sam9x5_video_fb_event_notify;
++
++ platform_set_drvdata(pdev, priv);
++
++ spin_lock_init(&priv->lock);
++
++ ret = fb_register_client(&priv->fb_notifier);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to register fb client (%d)\n", ret);
++
++ kfree(priv);
++err_alloc_priv:
++
++ return ret;
++ }
++
++ /* XXX: This is racy. If a new fb is registered then
++ * at91sam9x5_video_register is called twice. This should be solved
++ * somewhere in drivers/fb. priv->fbinfo is used to prevent multiple
++ * registration.
++ */
++
++ for (i = 0; i < ARRAY_SIZE(registered_fb); ++i)
++ if (registered_fb[i])
++ at91sam9x5_video_register(priv, registered_fb[i]);
++
++ return 0;
++}
++
++int __devexit at91sam9x5_video_remove(struct platform_device *pdev)
++{
++ struct at91sam9x5_video_priv *priv = platform_get_drvdata(pdev);
++
++ fb_unregister_client(&priv->fb_notifier);
++ at91sam9x5_video_unregister(priv);
++ kfree(priv);
++
++ return 0;
++}
++
++static struct platform_driver at91sam9x5_video_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = at91sam9x5_video_probe,
++ .remove = at91sam9x5_video_remove,
++};
++
++static struct platform_device *at91sam9x5_video_device;
++static int __init at91sam9x5_video_init(void)
++{
++ /* XXX: register the device in arch/arm/mach-at91 */
++ int ret;
++ const struct resource res[] = {
++ {
++ .start = 0xf8038280,
++ .end = 0xf803833f,
++ .flags = IORESOURCE_MEM,
++ }, {
++ .start = 25,
++ .end = 25,
++ .flags = IORESOURCE_IRQ,
++ },
++ };
++ const struct at91sam9x5_video_pdata pdata = {
++ .base_width = 800,
++ .base_height = 480,
++ };
++
++ ret = platform_driver_register(&at91sam9x5_video_driver);
++ if (ret) {
++ pr_err("failed to register driver (%d)", ret);
++ goto err_driver_register;
++ }
++
++ at91sam9x5_video_device = platform_device_register_resndata(NULL,
++ DRIVER_NAME, -1,
++ res, ARRAY_SIZE(res), &pdata, sizeof(pdata));
++ if (IS_ERR(at91sam9x5_video_device)) {
++ ret = PTR_ERR(at91sam9x5_video_device);
++ pr_err("failed to register device (%d)", ret);
++ platform_driver_unregister(&at91sam9x5_video_driver);
++ }
++
++ err_driver_register:
++ return ret;
++}
++module_init(at91sam9x5_video_init);
++
++static void __exit at91sam9x5_video_exit(void)
++{
++ platform_device_unregister(at91sam9x5_video_device);
++ platform_driver_unregister(&at91sam9x5_video_driver);
++}
++module_exit(at91sam9x5_video_exit);
++
++MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 7ba17cb..2a943ae 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -734,7 +734,7 @@ static int atmel_lcdfb_setup_9x5_core(struct fb_info *info)
+ lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL);
+ /* Enable BASE LAYER overflow interrupts, if want to enable DMA interrupt, also need set it at LCDC_BASECTRL reg */
+ lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | LCDC_LCDIER_BASEIE);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | LCDC_LCDIER_BASEIE | LCDC_LCDIER_HEOIE);
+
+ return 0;
+ }
+@@ -1066,7 +1066,8 @@ static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
+ dev_warn(info->device, "base layer overflow %#x\n",
+ baselayer_status);
+
+- }
++ } else
++ return IRQ_NONE;
+ } else {
+ status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
+ if (status & ATMEL_LCDC_UFLWI) {
+@@ -1266,7 +1267,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+ init_contrast(sinfo);
+
+ /* interrupt */
+- ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
++ ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, IRQF_SHARED, pdev->name, info);
+ if (ret) {
+ dev_err(dev, "request_irq failed: %d\n", ret);
+ goto unmap_mmio;
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0062-can-at91_can-don-t-align-struct-definitions.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0062-can-at91_can-don-t-align-struct-definitions.patch
new file mode 100644
index 0000000..d958172
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0062-can-at91_can-don-t-align-struct-definitions.patch
@@ -0,0 +1,81 @@
+From 05f0ec4badc2fa76dae2785cba53df2ed500895c Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Sun, 30 Jan 2011 22:14:49 +0100
+Subject: [PATCH 062/107] can: at91_can: don't align struct definitions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Applied-Upstream: v3.1, commit:44d8566
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/net/can/at91_can.c | 34 +++++++++++++++++-----------------
+ 1 files changed, 17 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
+index 74efb5a..8f15ae4 100644
+--- a/drivers/net/can/at91_can.c
++++ b/drivers/net/can/at91_can.c
+@@ -157,21 +157,21 @@ enum at91_mb_mode {
+ #define AT91_IRQ_ALL (0x1fffffff)
+
+ struct at91_priv {
+- struct can_priv can; /* must be the first member! */
+- struct net_device *dev;
+- struct napi_struct napi;
++ struct can_priv can; /* must be the first member! */
++ struct net_device *dev;
++ struct napi_struct napi;
+
+- void __iomem *reg_base;
++ void __iomem *reg_base;
+
+- u32 reg_sr;
+- unsigned int tx_next;
+- unsigned int tx_echo;
+- unsigned int rx_next;
++ u32 reg_sr;
++ unsigned int tx_next;
++ unsigned int tx_echo;
++ unsigned int rx_next;
+
+- struct clk *clk;
+- struct at91_can_data *pdata;
++ struct clk *clk;
++ struct at91_can_data *pdata;
+
+- canid_t mb0_id;
++ canid_t mb0_id;
+ };
+
+ static struct can_bittiming_const at91_bittiming_const = {
+@@ -271,7 +271,7 @@ static void at91_setup_mailboxes(struct net_device *dev)
+
+ /* reset acceptance mask and id register */
+ for (i = AT91_MB_RX_FIRST; i <= AT91_MB_RX_LAST; i++) {
+- at91_write(priv, AT91_MAM(i), 0x0 );
++ at91_write(priv, AT91_MAM(i), 0x0);
+ at91_write(priv, AT91_MID(i), AT91_MID_MIDE);
+ }
+
+@@ -1231,11 +1231,11 @@ static int __devexit at91_can_remove(struct platform_device *pdev)
+ }
+
+ static struct platform_driver at91_can_driver = {
+- .probe = at91_can_probe,
+- .remove = __devexit_p(at91_can_remove),
+- .driver = {
+- .name = KBUILD_MODNAME,
+- .owner = THIS_MODULE,
++ .probe = at91_can_probe,
++ .remove = __devexit_p(at91_can_remove),
++ .driver = {
++ .name = KBUILD_MODNAME,
++ .owner = THIS_MODULE,
+ },
+ };
+
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0063-can-at91_can-fix-comment-about-priv-tx_next.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0063-can-at91_can-fix-comment-about-priv-tx_next.patch
new file mode 100644
index 0000000..a7a99f7
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0063-can-at91_can-fix-comment-about-priv-tx_next.patch
@@ -0,0 +1,31 @@
+From bfb1a854ef000d59a9af5957540dde72c75d875b Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Sat, 16 Apr 2011 13:25:15 +0200
+Subject: [PATCH 063/107] can: at91_can: fix comment about priv->tx_next
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Applied-Upstream: v3.1, commit:5613fff
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/net/can/at91_can.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
+index 8f15ae4..afd0f5d 100644
+--- a/drivers/net/can/at91_can.c
++++ b/drivers/net/can/at91_can.c
+@@ -375,7 +375,7 @@ static void at91_chip_stop(struct net_device *dev, enum can_state state)
+ * mailbox, but without the offset AT91_MB_TX_FIRST. The lower bits
+ * encode the mailbox number, the upper 4 bits the mailbox priority:
+ *
+- * priv->tx_next = (prio << AT91_NEXT_PRIO_SHIFT) ||
++ * priv->tx_next = (prio << AT91_NEXT_PRIO_SHIFT) |
+ * (mb - AT91_MB_TX_FIRST);
+ *
+ */
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0064-can-at91_can-don-t-copy-data-to-rx-ed-RTR-frames.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0064-can-at91_can-don-t-copy-data-to-rx-ed-RTR-frames.patch
new file mode 100644
index 0000000..cb7287c
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0064-can-at91_can-don-t-copy-data-to-rx-ed-RTR-frames.patch
@@ -0,0 +1,42 @@
+From e98b3a1a9cf098bd77e0a75d223c0ec466a6f8f2 Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Thu, 21 Oct 2010 18:39:26 +0200
+Subject: [PATCH 064/107] can: at91_can: don't copy data to rx'ed RTR frames
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Acked-by: Wolfgang Grandegger <wg@grandegger.com>
+Applied-Upstream: v3.1, commit:e14ee40
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/net/can/at91_can.c | 10 ++++++----
+ 1 files changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
+index afd0f5d..5358d70 100644
+--- a/drivers/net/can/at91_can.c
++++ b/drivers/net/can/at91_can.c
+@@ -513,12 +513,14 @@ static void at91_read_mb(struct net_device *dev, unsigned int mb,
+ cf->can_id = (reg_mid >> 18) & CAN_SFF_MASK;
+
+ reg_msr = at91_read(priv, AT91_MSR(mb));
+- if (reg_msr & AT91_MSR_MRTR)
+- cf->can_id |= CAN_RTR_FLAG;
+ cf->can_dlc = get_can_dlc((reg_msr >> 16) & 0xf);
+
+- *(u32 *)(cf->data + 0) = at91_read(priv, AT91_MDL(mb));
+- *(u32 *)(cf->data + 4) = at91_read(priv, AT91_MDH(mb));
++ if (reg_msr & AT91_MSR_MRTR)
++ cf->can_id |= CAN_RTR_FLAG;
++ else {
++ *(u32 *)(cf->data + 0) = at91_read(priv, AT91_MDL(mb));
++ *(u32 *)(cf->data + 4) = at91_read(priv, AT91_MDH(mb));
++ }
+
+ /* allow RX of extended frames */
+ at91_write(priv, AT91_MID(mb), AT91_MID_MIDE);
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0065-can-at91_can-let-get_tx_-functions-return-unsigned-i.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0065-can-at91_can-let-get_tx_-functions-return-unsigned-i.patch
new file mode 100644
index 0000000..0709071
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0065-can-at91_can-let-get_tx_-functions-return-unsigned-i.patch
@@ -0,0 +1,44 @@
+From faca8b47ba90bf3ab89a467afdac0ce2659ee3d5 Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Tue, 3 May 2011 17:47:55 +0200
+Subject: [PATCH 065/107] can: at91_can: let get_tx_* functions return
+ unsigned int
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Applied-Upstream: v3.1, commit:9c2e0a6
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/net/can/at91_can.c | 6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
+index 5358d70..716f22b 100644
+--- a/drivers/net/can/at91_can.c
++++ b/drivers/net/can/at91_can.c
+@@ -186,17 +186,17 @@ static struct can_bittiming_const at91_bittiming_const = {
+ .brp_inc = 1,
+ };
+
+-static inline int get_tx_next_mb(const struct at91_priv *priv)
++static inline unsigned int get_tx_next_mb(const struct at91_priv *priv)
+ {
+ return (priv->tx_next & AT91_NEXT_MB_MASK) + AT91_MB_TX_FIRST;
+ }
+
+-static inline int get_tx_next_prio(const struct at91_priv *priv)
++static inline unsigned int get_tx_next_prio(const struct at91_priv *priv)
+ {
+ return (priv->tx_next >> AT91_NEXT_PRIO_SHIFT) & 0xf;
+ }
+
+-static inline int get_tx_echo_mb(const struct at91_priv *priv)
++static inline unsigned int get_tx_echo_mb(const struct at91_priv *priv)
+ {
+ return (priv->tx_echo & AT91_NEXT_MB_MASK) + AT91_MB_TX_FIRST;
+ }
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0066-can-at91_can-directly-define-AT91_MB_RX_LAST.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0066-can-at91_can-directly-define-AT91_MB_RX_LAST.patch
new file mode 100644
index 0000000..5acfa3d
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0066-can-at91_can-directly-define-AT91_MB_RX_LAST.patch
@@ -0,0 +1,39 @@
+From 83f3681bb95d906f176355187b5bada0229999d1 Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Sat, 30 Apr 2011 20:46:12 +0200
+Subject: [PATCH 066/107] can: at91_can: directly define AT91_MB_RX_LAST
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+...instead of deriving it from AT91_MB_RX_FIRST and AT91_MB_RX_NUM.
+This removes a level of computation, when switching the driver from
+compile time constants to runtime values.
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Applied-Upstream: v3.1, commit:267cbe04
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/net/can/at91_can.c | 3 +--
+ 1 files changed, 1 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
+index 716f22b..9ce00fa 100644
+--- a/drivers/net/can/at91_can.c
++++ b/drivers/net/can/at91_can.c
+@@ -47,11 +47,10 @@
+ * RX/TX Mailbox split
+ * don't dare to touch
+ */
+-#define AT91_MB_RX_NUM 11
+ #define AT91_MB_TX_SHIFT 2
+
+ #define AT91_MB_RX_FIRST 1
+-#define AT91_MB_RX_LAST (AT91_MB_RX_FIRST + AT91_MB_RX_NUM - 1)
++#define AT91_MB_RX_LAST 11
+
+ #define AT91_MB_RX_MASK(i) ((1 << (i)) - 1)
+ #define AT91_MB_RX_SPLIT 8
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0067-can-at91_can-rename-AT91_MB_RX_MASK-to-AT91_IRQ_MB_R.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0067-can-at91_can-rename-AT91_MB_RX_MASK-to-AT91_IRQ_MB_R.patch
new file mode 100644
index 0000000..47af3eb
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0067-can-at91_can-rename-AT91_MB_RX_MASK-to-AT91_IRQ_MB_R.patch
@@ -0,0 +1,74 @@
+From 4467291b29f43ba2db20412149f68b33e32ac5a2 Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Tue, 3 May 2011 16:37:16 +0200
+Subject: [PATCH 067/107] can: at91_can: rename AT91_MB_RX_MASK to
+ AT91_IRQ_MB_RX
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+... and use it for AT91_NEXT_MB_MASK,
+AT91_IRQ_MB_RX and AT91_IRQ_MB_RX, too.
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Applied-Upstream: v3.1, commit:b049994
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/net/can/at91_can.c | 18 +++++++++---------
+ 1 files changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
+index 9ce00fa..8699484 100644
+--- a/drivers/net/can/at91_can.c
++++ b/drivers/net/can/at91_can.c
+@@ -52,11 +52,11 @@
+ #define AT91_MB_RX_FIRST 1
+ #define AT91_MB_RX_LAST 11
+
+-#define AT91_MB_RX_MASK(i) ((1 << (i)) - 1)
++#define AT91_MB_MASK(i) ((1 << (i)) - 1)
+ #define AT91_MB_RX_SPLIT 8
+ #define AT91_MB_RX_LOW_LAST (AT91_MB_RX_SPLIT - 1)
+-#define AT91_MB_RX_LOW_MASK (AT91_MB_RX_MASK(AT91_MB_RX_SPLIT) & \
+- ~AT91_MB_RX_MASK(AT91_MB_RX_FIRST))
++#define AT91_MB_RX_LOW_MASK (AT91_MB_MASK(AT91_MB_RX_SPLIT) & \
++ ~AT91_MB_MASK(AT91_MB_RX_FIRST))
+
+ #define AT91_MB_TX_NUM (1 << AT91_MB_TX_SHIFT)
+ #define AT91_MB_TX_FIRST (AT91_MB_RX_LAST + 1)
+@@ -64,7 +64,7 @@
+
+ #define AT91_NEXT_PRIO_SHIFT (AT91_MB_TX_SHIFT)
+ #define AT91_NEXT_PRIO_MASK (0xf << AT91_MB_TX_SHIFT)
+-#define AT91_NEXT_MB_MASK (AT91_MB_TX_NUM - 1)
++#define AT91_NEXT_MB_MASK (AT91_MB_MASK(AT91_MB_TX_SHIFT))
+ #define AT91_NEXT_MASK ((AT91_MB_TX_NUM - 1) | AT91_NEXT_PRIO_MASK)
+
+ /* Common registers */
+@@ -127,10 +127,10 @@ enum at91_mb_mode {
+ };
+
+ /* Interrupt mask bits */
+-#define AT91_IRQ_MB_RX ((1 << (AT91_MB_RX_LAST + 1)) \
+- - (1 << AT91_MB_RX_FIRST))
+-#define AT91_IRQ_MB_TX ((1 << (AT91_MB_TX_LAST + 1)) \
+- - (1 << AT91_MB_TX_FIRST))
++#define AT91_IRQ_MB_RX (AT91_MB_MASK(AT91_MB_RX_LAST + 1) & \
++ ~AT91_MB_MASK(AT91_MB_RX_FIRST))
++#define AT91_IRQ_MB_TX (AT91_MB_MASK(AT91_MB_TX_LAST + 1) & \
++ ~AT91_MB_MASK(AT91_MB_TX_FIRST))
+ #define AT91_IRQ_MB_ALL (AT91_IRQ_MB_RX | AT91_IRQ_MB_TX)
+
+ #define AT91_IRQ_ERRA (1 << 16)
+@@ -735,7 +735,7 @@ static int at91_poll(struct napi_struct *napi, int quota)
+ if (work_done < quota) {
+ /* enable IRQs for frame errors and all mailboxes >= rx_next */
+ u32 reg_ier = AT91_IRQ_ERR_FRAME;
+- reg_ier |= AT91_IRQ_MB_RX & ~AT91_MB_RX_MASK(priv->rx_next);
++ reg_ier |= AT91_IRQ_MB_RX & ~AT91_MB_MASK(priv->rx_next);
+
+ napi_complete(napi);
+ at91_write(priv, AT91_IER, reg_ier);
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0068-can-at91_can-convert-derived-mailbox-constants-into-.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0068-can-at91_can-convert-derived-mailbox-constants-into-.patch
new file mode 100644
index 0000000..e757c8b
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0068-can-at91_can-convert-derived-mailbox-constants-into-.patch
@@ -0,0 +1,296 @@
+From 7ed5674423392303ccc14045b0595a72e5d25aed Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Tue, 3 May 2011 17:31:40 +0200
+Subject: [PATCH 068/107] can: at91_can: convert derived mailbox constants
+ into functions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This is the first of two patches converting the at91_can driver from a
+compile time mailbox setup to a dynamic one.
+
+This patch converts all derived mailbox constants to functions.
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Applied-Upstream: v3.1, commit:7900899
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/net/can/at91_can.c | 125 +++++++++++++++++++++++++++++---------------
+ 1 files changed, 83 insertions(+), 42 deletions(-)
+
+diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
+index 8699484..900ff67 100644
+--- a/drivers/net/can/at91_can.c
++++ b/drivers/net/can/at91_can.c
+@@ -54,18 +54,7 @@
+
+ #define AT91_MB_MASK(i) ((1 << (i)) - 1)
+ #define AT91_MB_RX_SPLIT 8
+-#define AT91_MB_RX_LOW_LAST (AT91_MB_RX_SPLIT - 1)
+-#define AT91_MB_RX_LOW_MASK (AT91_MB_MASK(AT91_MB_RX_SPLIT) & \
+- ~AT91_MB_MASK(AT91_MB_RX_FIRST))
+
+-#define AT91_MB_TX_NUM (1 << AT91_MB_TX_SHIFT)
+-#define AT91_MB_TX_FIRST (AT91_MB_RX_LAST + 1)
+-#define AT91_MB_TX_LAST (AT91_MB_TX_FIRST + AT91_MB_TX_NUM - 1)
+-
+-#define AT91_NEXT_PRIO_SHIFT (AT91_MB_TX_SHIFT)
+-#define AT91_NEXT_PRIO_MASK (0xf << AT91_MB_TX_SHIFT)
+-#define AT91_NEXT_MB_MASK (AT91_MB_MASK(AT91_MB_TX_SHIFT))
+-#define AT91_NEXT_MASK ((AT91_MB_TX_NUM - 1) | AT91_NEXT_PRIO_MASK)
+
+ /* Common registers */
+ enum at91_reg {
+@@ -127,12 +116,6 @@ enum at91_mb_mode {
+ };
+
+ /* Interrupt mask bits */
+-#define AT91_IRQ_MB_RX (AT91_MB_MASK(AT91_MB_RX_LAST + 1) & \
+- ~AT91_MB_MASK(AT91_MB_RX_FIRST))
+-#define AT91_IRQ_MB_TX (AT91_MB_MASK(AT91_MB_TX_LAST + 1) & \
+- ~AT91_MB_MASK(AT91_MB_TX_FIRST))
+-#define AT91_IRQ_MB_ALL (AT91_IRQ_MB_RX | AT91_IRQ_MB_TX)
+-
+ #define AT91_IRQ_ERRA (1 << 16)
+ #define AT91_IRQ_WARN (1 << 17)
+ #define AT91_IRQ_ERRP (1 << 18)
+@@ -185,19 +168,77 @@ static struct can_bittiming_const at91_bittiming_const = {
+ .brp_inc = 1,
+ };
+
++static inline unsigned int get_mb_rx_low_last(const struct at91_priv *priv)
++{
++ return AT91_MB_RX_SPLIT - 1;
++}
++
++static inline unsigned int get_mb_rx_low_mask(const struct at91_priv *priv)
++{
++ return AT91_MB_MASK(AT91_MB_RX_SPLIT) &
++ ~AT91_MB_MASK(AT91_MB_RX_FIRST);
++}
++
++static inline unsigned int get_mb_tx_num(const struct at91_priv *priv)
++{
++ return 1 << AT91_MB_TX_SHIFT;
++}
++
++static inline unsigned int get_mb_tx_first(const struct at91_priv *priv)
++{
++ return AT91_MB_RX_LAST + 1;
++}
++
++static inline unsigned int get_mb_tx_last(const struct at91_priv *priv)
++{
++ return get_mb_tx_first(priv) + get_mb_tx_num(priv) - 1;
++}
++
++static inline unsigned int get_next_prio_shift(const struct at91_priv *priv)
++{
++ return AT91_MB_TX_SHIFT;
++}
++
++static inline unsigned int get_next_prio_mask(const struct at91_priv *priv)
++{
++ return 0xf << AT91_MB_TX_SHIFT;
++}
++
++static inline unsigned int get_next_mb_mask(const struct at91_priv *priv)
++{
++ return AT91_MB_MASK(AT91_MB_TX_SHIFT);
++}
++
++static inline unsigned int get_next_mask(const struct at91_priv *priv)
++{
++ return get_next_mb_mask(priv) | get_next_prio_mask(priv);
++}
++
++static inline unsigned int get_irq_mb_rx(const struct at91_priv *priv)
++{
++ return AT91_MB_MASK(AT91_MB_RX_LAST + 1) &
++ ~AT91_MB_MASK(AT91_MB_RX_FIRST);
++}
++
++static inline unsigned int get_irq_mb_tx(const struct at91_priv *priv)
++{
++ return AT91_MB_MASK(get_mb_tx_last(priv) + 1) &
++ ~AT91_MB_MASK(get_mb_tx_first(priv));
++}
++
+ static inline unsigned int get_tx_next_mb(const struct at91_priv *priv)
+ {
+- return (priv->tx_next & AT91_NEXT_MB_MASK) + AT91_MB_TX_FIRST;
++ return (priv->tx_next & get_next_mb_mask(priv)) + get_mb_tx_first(priv);
+ }
+
+ static inline unsigned int get_tx_next_prio(const struct at91_priv *priv)
+ {
+- return (priv->tx_next >> AT91_NEXT_PRIO_SHIFT) & 0xf;
++ return (priv->tx_next >> get_next_prio_shift(priv)) & 0xf;
+ }
+
+ static inline unsigned int get_tx_echo_mb(const struct at91_priv *priv)
+ {
+- return (priv->tx_echo & AT91_NEXT_MB_MASK) + AT91_MB_TX_FIRST;
++ return (priv->tx_echo & get_next_mb_mask(priv)) + get_mb_tx_first(priv);
+ }
+
+ static inline u32 at91_read(const struct at91_priv *priv, enum at91_reg reg)
+@@ -275,7 +316,7 @@ static void at91_setup_mailboxes(struct net_device *dev)
+ }
+
+ /* The last 4 mailboxes are used for transmitting. */
+- for (i = AT91_MB_TX_FIRST; i <= AT91_MB_TX_LAST; i++)
++ for (i = get_mb_tx_first(priv); i <= get_mb_tx_last(priv); i++)
+ set_mb_mode_prio(priv, i, AT91_MB_MODE_TX, 0);
+
+ /* Reset tx and rx helper pointers */
+@@ -335,7 +376,7 @@ static void at91_chip_start(struct net_device *dev)
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ /* Enable interrupts */
+- reg_ier = AT91_IRQ_MB_RX | AT91_IRQ_ERRP | AT91_IRQ_ERR_FRAME;
++ reg_ier = get_irq_mb_rx(priv) | AT91_IRQ_ERRP | AT91_IRQ_ERR_FRAME;
+ at91_write(priv, AT91_IDR, AT91_IRQ_ALL);
+ at91_write(priv, AT91_IER, reg_ier);
+ }
+@@ -416,7 +457,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ stats->tx_bytes += cf->can_dlc;
+
+ /* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */
+- can_put_echo_skb(skb, dev, mb - AT91_MB_TX_FIRST);
++ can_put_echo_skb(skb, dev, mb - get_mb_tx_first(priv));
+
+ /*
+ * we have to stop the queue and deliver all messages in case
+@@ -429,7 +470,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ priv->tx_next++;
+ if (!(at91_read(priv, AT91_MSR(get_tx_next_mb(priv))) &
+ AT91_MSR_MRDY) ||
+- (priv->tx_next & AT91_NEXT_MASK) == 0)
++ (priv->tx_next & get_next_mask(priv)) == 0)
+ netif_stop_queue(dev);
+
+ /* Enable interrupt for this mailbox */
+@@ -446,7 +487,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ */
+ static inline void at91_activate_rx_low(const struct at91_priv *priv)
+ {
+- u32 mask = AT91_MB_RX_LOW_MASK;
++ u32 mask = get_mb_rx_low_mask(priv);
+ at91_write(priv, AT91_TCR, mask);
+ }
+
+@@ -611,23 +652,23 @@ static int at91_poll_rx(struct net_device *dev, int quota)
+ unsigned int mb;
+ int received = 0;
+
+- if (priv->rx_next > AT91_MB_RX_LOW_LAST &&
+- reg_sr & AT91_MB_RX_LOW_MASK)
++ if (priv->rx_next > get_mb_rx_low_last(priv) &&
++ reg_sr & get_mb_rx_low_mask(priv))
+ netdev_info(dev,
+ "order of incoming frames cannot be guaranteed\n");
+
+ again:
+- for (mb = find_next_bit(addr, AT91_MB_RX_LAST + 1, priv->rx_next);
+- mb < AT91_MB_RX_LAST + 1 && quota > 0;
++ for (mb = find_next_bit(addr, get_mb_tx_first(priv), priv->rx_next);
++ mb < get_mb_tx_first(priv) && quota > 0;
+ reg_sr = at91_read(priv, AT91_SR),
+- mb = find_next_bit(addr, AT91_MB_RX_LAST + 1, ++priv->rx_next)) {
++ mb = find_next_bit(addr, get_mb_tx_first(priv), ++priv->rx_next)) {
+ at91_read_msg(dev, mb);
+
+ /* reactivate mailboxes */
+- if (mb == AT91_MB_RX_LOW_LAST)
++ if (mb == get_mb_rx_low_last(priv))
+ /* all lower mailboxed, if just finished it */
+ at91_activate_rx_low(priv);
+- else if (mb > AT91_MB_RX_LOW_LAST)
++ else if (mb > get_mb_rx_low_last(priv))
+ /* only the mailbox we read */
+ at91_activate_rx_mb(priv, mb);
+
+@@ -636,7 +677,7 @@ static int at91_poll_rx(struct net_device *dev, int quota)
+ }
+
+ /* upper group completed, look again in lower */
+- if (priv->rx_next > AT91_MB_RX_LOW_LAST &&
++ if (priv->rx_next > get_mb_rx_low_last(priv) &&
+ quota > 0 && mb > AT91_MB_RX_LAST) {
+ priv->rx_next = AT91_MB_RX_FIRST;
+ goto again;
+@@ -721,7 +762,7 @@ static int at91_poll(struct napi_struct *napi, int quota)
+ u32 reg_sr = at91_read(priv, AT91_SR);
+ int work_done = 0;
+
+- if (reg_sr & AT91_IRQ_MB_RX)
++ if (reg_sr & get_irq_mb_rx(priv))
+ work_done += at91_poll_rx(dev, quota - work_done);
+
+ /*
+@@ -735,7 +776,7 @@ static int at91_poll(struct napi_struct *napi, int quota)
+ if (work_done < quota) {
+ /* enable IRQs for frame errors and all mailboxes >= rx_next */
+ u32 reg_ier = AT91_IRQ_ERR_FRAME;
+- reg_ier |= AT91_IRQ_MB_RX & ~AT91_MB_MASK(priv->rx_next);
++ reg_ier |= get_irq_mb_rx(priv) & ~AT91_MB_MASK(priv->rx_next);
+
+ napi_complete(napi);
+ at91_write(priv, AT91_IER, reg_ier);
+@@ -784,7 +825,7 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr)
+ if (likely(reg_msr & AT91_MSR_MRDY &&
+ ~reg_msr & AT91_MSR_MABT)) {
+ /* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */
+- can_get_echo_skb(dev, mb - AT91_MB_TX_FIRST);
++ can_get_echo_skb(dev, mb - get_mb_tx_first(priv));
+ dev->stats.tx_packets++;
+ }
+ }
+@@ -794,8 +835,8 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr)
+ * we get a TX int for the last can frame directly before a
+ * wrap around.
+ */
+- if ((priv->tx_next & AT91_NEXT_MASK) != 0 ||
+- (priv->tx_echo & AT91_NEXT_MASK) == 0)
++ if ((priv->tx_next & get_next_mask(priv)) != 0 ||
++ (priv->tx_echo & get_next_mask(priv)) == 0)
+ netif_wake_queue(dev);
+ }
+
+@@ -969,19 +1010,19 @@ static irqreturn_t at91_irq(int irq, void *dev_id)
+ handled = IRQ_HANDLED;
+
+ /* Receive or error interrupt? -> napi */
+- if (reg_sr & (AT91_IRQ_MB_RX | AT91_IRQ_ERR_FRAME)) {
++ if (reg_sr & (get_irq_mb_rx(priv) | AT91_IRQ_ERR_FRAME)) {
+ /*
+ * The error bits are clear on read,
+ * save for later use.
+ */
+ priv->reg_sr = reg_sr;
+ at91_write(priv, AT91_IDR,
+- AT91_IRQ_MB_RX | AT91_IRQ_ERR_FRAME);
++ get_irq_mb_rx(priv) | AT91_IRQ_ERR_FRAME);
+ napi_schedule(&priv->napi);
+ }
+
+ /* Transmission complete interrupt */
+- if (reg_sr & AT91_IRQ_MB_TX)
++ if (reg_sr & get_irq_mb_tx(priv))
+ at91_irq_tx(dev, reg_sr);
+
+ at91_irq_err(dev);
+@@ -1158,7 +1199,7 @@ static int __devinit at91_can_probe(struct platform_device *pdev)
+ goto exit_release;
+ }
+
+- dev = alloc_candev(sizeof(struct at91_priv), AT91_MB_TX_NUM);
++ dev = alloc_candev(sizeof(struct at91_priv), 1 << AT91_MB_TX_SHIFT);
+ if (!dev) {
+ err = -ENOMEM;
+ goto exit_iounmap;
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0069-can-at91_can-add-id_table-and-convert-prime-mailbox-.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0069-can-at91_can-add-id_table-and-convert-prime-mailbox-.patch
new file mode 100644
index 0000000..d9cee95
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0069-can-at91_can-add-id_table-and-convert-prime-mailbox-.patch
@@ -0,0 +1,337 @@
+From ba269f591624cb00895324940c224d8ba8f6af95 Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Tue, 3 May 2011 17:41:09 +0200
+Subject: [PATCH 069/107] can: at91_can: add id_table and convert prime
+ mailbox constats to functions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This is the second of two patches converting the at91_can driver from a
+compile time mailbox setup to a dynamic one.
+
+This patch first adds a id_table to the platform driver. Depending on the
+driver_data the constants for the mailbox setup is selected. Then all
+remaining prime mailbox constants are converted to functions, using the
+run time selected mailbox constants.
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Applied-Upstream: v3.1, commit:d3d4726
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/net/can/at91_can.c | 137 +++++++++++++++++++++++++++++++------------
+ 1 files changed, 99 insertions(+), 38 deletions(-)
+
+diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
+index 900ff67..248e03f 100644
+--- a/drivers/net/can/at91_can.c
++++ b/drivers/net/can/at91_can.c
+@@ -41,20 +41,7 @@
+
+ #include <mach/board.h>
+
+-#define AT91_NAPI_WEIGHT 11
+-
+-/*
+- * RX/TX Mailbox split
+- * don't dare to touch
+- */
+-#define AT91_MB_TX_SHIFT 2
+-
+-#define AT91_MB_RX_FIRST 1
+-#define AT91_MB_RX_LAST 11
+-
+ #define AT91_MB_MASK(i) ((1 << (i)) - 1)
+-#define AT91_MB_RX_SPLIT 8
+-
+
+ /* Common registers */
+ enum at91_reg {
+@@ -138,6 +125,18 @@ enum at91_mb_mode {
+
+ #define AT91_IRQ_ALL (0x1fffffff)
+
++enum at91_devtype {
++ AT91_DEVTYPE_SAM9263,
++};
++
++struct at91_devtype_data {
++ unsigned int rx_first;
++ unsigned int rx_split;
++ unsigned int rx_last;
++ unsigned int tx_shift;
++ enum at91_devtype type;
++};
++
+ struct at91_priv {
+ struct can_priv can; /* must be the first member! */
+ struct net_device *dev;
+@@ -149,6 +148,7 @@ struct at91_priv {
+ unsigned int tx_next;
+ unsigned int tx_echo;
+ unsigned int rx_next;
++ struct at91_devtype_data devtype_data;
+
+ struct clk *clk;
+ struct at91_can_data *pdata;
+@@ -156,6 +156,15 @@ struct at91_priv {
+ canid_t mb0_id;
+ };
+
++static const struct at91_devtype_data at91_devtype_data[] __devinitconst = {
++ [AT91_DEVTYPE_SAM9263] = {
++ .rx_first = 1,
++ .rx_split = 8,
++ .rx_last = 11,
++ .tx_shift = 2,
++ },
++};
++
+ static struct can_bittiming_const at91_bittiming_const = {
+ .name = KBUILD_MODNAME,
+ .tseg1_min = 4,
+@@ -168,25 +177,58 @@ static struct can_bittiming_const at91_bittiming_const = {
+ .brp_inc = 1,
+ };
+
++#define AT91_IS(_model) \
++static inline int at91_is_sam##_model(const struct at91_priv *priv) \
++{ \
++ return priv->devtype_data.type == AT91_DEVTYPE_SAM##_model; \
++}
++
++AT91_IS(9263);
++
++static inline unsigned int get_mb_rx_first(const struct at91_priv *priv)
++{
++ return priv->devtype_data.rx_first;
++}
++
++static inline unsigned int get_mb_rx_last(const struct at91_priv *priv)
++{
++ return priv->devtype_data.rx_last;
++}
++
++static inline unsigned int get_mb_rx_split(const struct at91_priv *priv)
++{
++ return priv->devtype_data.rx_split;
++}
++
++static inline unsigned int get_mb_rx_num(const struct at91_priv *priv)
++{
++ return get_mb_rx_last(priv) - get_mb_rx_first(priv) + 1;
++}
++
+ static inline unsigned int get_mb_rx_low_last(const struct at91_priv *priv)
+ {
+- return AT91_MB_RX_SPLIT - 1;
++ return get_mb_rx_split(priv) - 1;
+ }
+
+ static inline unsigned int get_mb_rx_low_mask(const struct at91_priv *priv)
+ {
+- return AT91_MB_MASK(AT91_MB_RX_SPLIT) &
+- ~AT91_MB_MASK(AT91_MB_RX_FIRST);
++ return AT91_MB_MASK(get_mb_rx_split(priv)) &
++ ~AT91_MB_MASK(get_mb_rx_first(priv));
++}
++
++static inline unsigned int get_mb_tx_shift(const struct at91_priv *priv)
++{
++ return priv->devtype_data.tx_shift;
+ }
+
+ static inline unsigned int get_mb_tx_num(const struct at91_priv *priv)
+ {
+- return 1 << AT91_MB_TX_SHIFT;
++ return 1 << get_mb_tx_shift(priv);
+ }
+
+ static inline unsigned int get_mb_tx_first(const struct at91_priv *priv)
+ {
+- return AT91_MB_RX_LAST + 1;
++ return get_mb_rx_last(priv) + 1;
+ }
+
+ static inline unsigned int get_mb_tx_last(const struct at91_priv *priv)
+@@ -196,17 +238,17 @@ static inline unsigned int get_mb_tx_last(const struct at91_priv *priv)
+
+ static inline unsigned int get_next_prio_shift(const struct at91_priv *priv)
+ {
+- return AT91_MB_TX_SHIFT;
++ return get_mb_tx_shift(priv);
+ }
+
+ static inline unsigned int get_next_prio_mask(const struct at91_priv *priv)
+ {
+- return 0xf << AT91_MB_TX_SHIFT;
++ return 0xf << get_mb_tx_shift(priv);
+ }
+
+ static inline unsigned int get_next_mb_mask(const struct at91_priv *priv)
+ {
+- return AT91_MB_MASK(AT91_MB_TX_SHIFT);
++ return AT91_MB_MASK(get_mb_tx_shift(priv));
+ }
+
+ static inline unsigned int get_next_mask(const struct at91_priv *priv)
+@@ -216,8 +258,8 @@ static inline unsigned int get_next_mask(const struct at91_priv *priv)
+
+ static inline unsigned int get_irq_mb_rx(const struct at91_priv *priv)
+ {
+- return AT91_MB_MASK(AT91_MB_RX_LAST + 1) &
+- ~AT91_MB_MASK(AT91_MB_RX_FIRST);
++ return AT91_MB_MASK(get_mb_rx_last(priv) + 1) &
++ ~AT91_MB_MASK(get_mb_rx_first(priv));
+ }
+
+ static inline unsigned int get_irq_mb_tx(const struct at91_priv *priv)
+@@ -299,18 +341,18 @@ static void at91_setup_mailboxes(struct net_device *dev)
+ * overflow.
+ */
+ reg_mid = at91_can_id_to_reg_mid(priv->mb0_id);
+- for (i = 0; i < AT91_MB_RX_FIRST; i++) {
++ for (i = 0; i < get_mb_rx_first(priv); i++) {
+ set_mb_mode(priv, i, AT91_MB_MODE_DISABLED);
+ at91_write(priv, AT91_MID(i), reg_mid);
+ at91_write(priv, AT91_MCR(i), 0x0); /* clear dlc */
+ }
+
+- for (i = AT91_MB_RX_FIRST; i < AT91_MB_RX_LAST; i++)
++ for (i = get_mb_rx_first(priv); i < get_mb_rx_last(priv); i++)
+ set_mb_mode(priv, i, AT91_MB_MODE_RX);
+- set_mb_mode(priv, AT91_MB_RX_LAST, AT91_MB_MODE_RX_OVRWR);
++ set_mb_mode(priv, get_mb_rx_last(priv), AT91_MB_MODE_RX_OVRWR);
+
+ /* reset acceptance mask and id register */
+- for (i = AT91_MB_RX_FIRST; i <= AT91_MB_RX_LAST; i++) {
++ for (i = get_mb_rx_first(priv); i <= get_mb_rx_last(priv); i++) {
+ at91_write(priv, AT91_MAM(i), 0x0);
+ at91_write(priv, AT91_MID(i), AT91_MID_MIDE);
+ }
+@@ -321,7 +363,7 @@ static void at91_setup_mailboxes(struct net_device *dev)
+
+ /* Reset tx and rx helper pointers */
+ priv->tx_next = priv->tx_echo = 0;
+- priv->rx_next = AT91_MB_RX_FIRST;
++ priv->rx_next = get_mb_rx_first(priv);
+ }
+
+ static int at91_set_bittiming(struct net_device *dev)
+@@ -415,8 +457,8 @@ static void at91_chip_stop(struct net_device *dev, enum can_state state)
+ * mailbox, but without the offset AT91_MB_TX_FIRST. The lower bits
+ * encode the mailbox number, the upper 4 bits the mailbox priority:
+ *
+- * priv->tx_next = (prio << AT91_NEXT_PRIO_SHIFT) |
+- * (mb - AT91_MB_TX_FIRST);
++ * priv->tx_next = (prio << get_next_prio_shift(priv)) |
++ * (mb - get_mb_tx_first(priv));
+ *
+ */
+ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -565,7 +607,7 @@ static void at91_read_mb(struct net_device *dev, unsigned int mb,
+ /* allow RX of extended frames */
+ at91_write(priv, AT91_MID(mb), AT91_MID_MIDE);
+
+- if (unlikely(mb == AT91_MB_RX_LAST && reg_msr & AT91_MSR_MMI))
++ if (unlikely(mb == get_mb_rx_last(priv) && reg_msr & AT91_MSR_MMI))
+ at91_rx_overflow_err(dev);
+ }
+
+@@ -603,8 +645,9 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb)
+ *
+ * Theory of Operation:
+ *
+- * 11 of the 16 mailboxes on the chip are reserved for RX. we split
+- * them into 2 groups. The lower group holds 7 and upper 4 mailboxes.
++ * About 3/4 of the mailboxes (get_mb_rx_first()...get_mb_rx_last())
++ * on the chip are reserved for RX. We split them into 2 groups. The
++ * lower group ranges from get_mb_rx_first() to get_mb_rx_low_last().
+ *
+ * Like it or not, but the chip always saves a received CAN message
+ * into the first free mailbox it finds (starting with the
+@@ -678,8 +721,8 @@ static int at91_poll_rx(struct net_device *dev, int quota)
+
+ /* upper group completed, look again in lower */
+ if (priv->rx_next > get_mb_rx_low_last(priv) &&
+- quota > 0 && mb > AT91_MB_RX_LAST) {
+- priv->rx_next = AT91_MB_RX_FIRST;
++ quota > 0 && mb > get_mb_rx_last(priv)) {
++ priv->rx_next = get_mb_rx_first(priv);
+ goto again;
+ }
+
+@@ -1165,6 +1208,8 @@ static struct attribute_group at91_sysfs_attr_group = {
+
+ static int __devinit at91_can_probe(struct platform_device *pdev)
+ {
++ const struct at91_devtype_data *devtype_data;
++ enum at91_devtype devtype;
+ struct net_device *dev;
+ struct at91_priv *priv;
+ struct resource *res;
+@@ -1172,6 +1217,9 @@ static int __devinit at91_can_probe(struct platform_device *pdev)
+ void __iomem *addr;
+ int err, irq;
+
++ devtype = pdev->id_entry->driver_data;
++ devtype_data = &at91_devtype_data[devtype];
++
+ clk = clk_get(&pdev->dev, "can_clk");
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "no clock defined\n");
+@@ -1199,7 +1247,8 @@ static int __devinit at91_can_probe(struct platform_device *pdev)
+ goto exit_release;
+ }
+
+- dev = alloc_candev(sizeof(struct at91_priv), 1 << AT91_MB_TX_SHIFT);
++ dev = alloc_candev(sizeof(struct at91_priv),
++ 1 << devtype_data->tx_shift);
+ if (!dev) {
+ err = -ENOMEM;
+ goto exit_iounmap;
+@@ -1216,13 +1265,15 @@ static int __devinit at91_can_probe(struct platform_device *pdev)
+ priv->can.do_set_mode = at91_set_mode;
+ priv->can.do_get_berr_counter = at91_get_berr_counter;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
+- priv->reg_base = addr;
+ priv->dev = dev;
++ priv->reg_base = addr;
++ priv->devtype_data = *devtype_data;
++ priv->devtype_data.type = devtype;
+ priv->clk = clk;
+ priv->pdata = pdev->dev.platform_data;
+ priv->mb0_id = 0x7ff;
+
+- netif_napi_add(dev, &priv->napi, at91_poll, AT91_NAPI_WEIGHT);
++ netif_napi_add(dev, &priv->napi, at91_poll, get_mb_rx_num(priv));
+
+ dev_set_drvdata(&pdev->dev, dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+@@ -1272,6 +1323,15 @@ static int __devexit at91_can_remove(struct platform_device *pdev)
+ return 0;
+ }
+
++static const struct platform_device_id at91_can_id_table[] = {
++ {
++ .name = "at91_can",
++ .driver_data = AT91_DEVTYPE_SAM9263,
++ }, {
++ /* sentinel */
++ }
++};
++
+ static struct platform_driver at91_can_driver = {
+ .probe = at91_can_probe,
+ .remove = __devexit_p(at91_can_remove),
+@@ -1279,6 +1339,7 @@ static struct platform_driver at91_can_driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ },
++ .id_table = at91_can_id_table,
+ };
+
+ static int __init at91_can_module_init(void)
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0070-can-at91_can-register-mb0-sysfs-entry-only-on-at91sa.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0070-can-at91_can-register-mb0-sysfs-entry-only-on-at91sa.patch
new file mode 100644
index 0000000..dcf155a
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0070-can-at91_can-register-mb0-sysfs-entry-only-on-at91sa.patch
@@ -0,0 +1,45 @@
+From d2c865e1724b16dcdd5156d8c1d2d2cf6f4129dc Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Wed, 1 Jun 2011 00:20:17 +0200
+Subject: [PATCH 070/107] can: at91_can: register mb0 sysfs entry only on
+ at91sam9263
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch prepares the driver for the at91sam9X5 processors,
+which don't have the mb0 bug.
+(See commit 3a5655a5b545e9647c3437473ee3d815fe1b9050 for more details.)
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Applied-Upstream: v3.1, commit:07a648e
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/net/can/at91_can.c | 4 +++-
+ 1 files changed, 3 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
+index 248e03f..2b97281 100644
+--- a/drivers/net/can/at91_can.c
++++ b/drivers/net/can/at91_can.c
+@@ -1257,7 +1257,6 @@ static int __devinit at91_can_probe(struct platform_device *pdev)
+ dev->netdev_ops = &at91_netdev_ops;
+ dev->irq = irq;
+ dev->flags |= IFF_ECHO;
+- dev->sysfs_groups[0] = &at91_sysfs_attr_group;
+
+ priv = netdev_priv(dev);
+ priv->can.clock.freq = clk_get_rate(clk);
+@@ -1275,6 +1274,9 @@ static int __devinit at91_can_probe(struct platform_device *pdev)
+
+ netif_napi_add(dev, &priv->napi, at91_poll, get_mb_rx_num(priv));
+
++ if (at91_is_sam9263(priv))
++ dev->sysfs_groups[0] = &at91_sysfs_attr_group;
++
+ dev_set_drvdata(&pdev->dev, dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0071-can-at91_can-add-support-for-the-AT91SAM9X5-SOCs.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0071-can-at91_can-add-support-for-the-AT91SAM9X5-SOCs.patch
new file mode 100644
index 0000000..dc96db0
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0071-can-at91_can-add-support-for-the-AT91SAM9X5-SOCs.patch
@@ -0,0 +1,139 @@
+From a46409cbd2b3141e654b30d8a987ef4a09c7d40a Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl@pengutronix.de>
+Date: Sun, 17 Apr 2011 00:08:45 +0200
+Subject: [PATCH 071/107] can: at91_can: add support for the AT91SAM9X5 SOCs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The AT91SAM9X5 SOCs have a similar CAN core, but they only have 8 compared
+to 16 mailboxes on the AT91SAM9263 SOC. Another difference is that the bits
+defining the state of the CAN core are cleared on read, thus the driver
+has to derive the state by looking at the error counters.
+
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Applied-Upstream: v3.1, commit:6388b39
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/net/can/at91_can.c | 69 +++++++++++++++++++++++++++++++++++---------
+ 1 files changed, 55 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
+index 2b97281..121ede6 100644
+--- a/drivers/net/can/at91_can.c
++++ b/drivers/net/can/at91_can.c
+@@ -127,6 +127,7 @@ enum at91_mb_mode {
+
+ enum at91_devtype {
+ AT91_DEVTYPE_SAM9263,
++ AT91_DEVTYPE_SAM9X5,
+ };
+
+ struct at91_devtype_data {
+@@ -163,6 +164,12 @@ static const struct at91_devtype_data at91_devtype_data[] __devinitconst = {
+ .rx_last = 11,
+ .tx_shift = 2,
+ },
++ [AT91_DEVTYPE_SAM9X5] = {
++ .rx_first = 0,
++ .rx_split = 4,
++ .rx_last = 5,
++ .tx_shift = 1,
++ },
+ };
+
+ static struct can_bittiming_const at91_bittiming_const = {
+@@ -184,6 +191,7 @@ static inline int at91_is_sam##_model(const struct at91_priv *priv) \
+ }
+
+ AT91_IS(9263);
++AT91_IS(9X5);
+
+ static inline unsigned int get_mb_rx_first(const struct at91_priv *priv)
+ {
+@@ -991,6 +999,29 @@ static void at91_irq_err_state(struct net_device *dev,
+ at91_write(priv, AT91_IER, reg_ier);
+ }
+
++static int at91_get_state_by_bec(const struct net_device *dev,
++ enum can_state *state)
++{
++ struct can_berr_counter bec;
++ int err;
++
++ err = at91_get_berr_counter(dev, &bec);
++ if (err)
++ return err;
++
++ if (bec.txerr < 96 && bec.rxerr < 96)
++ *state = CAN_STATE_ERROR_ACTIVE;
++ else if (bec.txerr < 128 && bec.rxerr < 128)
++ *state = CAN_STATE_ERROR_WARNING;
++ else if (bec.txerr < 256 && bec.rxerr < 256)
++ *state = CAN_STATE_ERROR_PASSIVE;
++ else
++ *state = CAN_STATE_BUS_OFF;
++
++ return 0;
++}
++
++
+ static void at91_irq_err(struct net_device *dev)
+ {
+ struct at91_priv *priv = netdev_priv(dev);
+@@ -998,21 +1029,28 @@ static void at91_irq_err(struct net_device *dev)
+ struct can_frame *cf;
+ enum can_state new_state;
+ u32 reg_sr;
++ int err;
+
+- reg_sr = at91_read(priv, AT91_SR);
+-
+- /* we need to look at the unmasked reg_sr */
+- if (unlikely(reg_sr & AT91_IRQ_BOFF))
+- new_state = CAN_STATE_BUS_OFF;
+- else if (unlikely(reg_sr & AT91_IRQ_ERRP))
+- new_state = CAN_STATE_ERROR_PASSIVE;
+- else if (unlikely(reg_sr & AT91_IRQ_WARN))
+- new_state = CAN_STATE_ERROR_WARNING;
+- else if (likely(reg_sr & AT91_IRQ_ERRA))
+- new_state = CAN_STATE_ERROR_ACTIVE;
+- else {
+- netdev_err(dev, "BUG! hardware in undefined state\n");
+- return;
++ if (at91_is_sam9263(priv)) {
++ reg_sr = at91_read(priv, AT91_SR);
++
++ /* we need to look at the unmasked reg_sr */
++ if (unlikely(reg_sr & AT91_IRQ_BOFF))
++ new_state = CAN_STATE_BUS_OFF;
++ else if (unlikely(reg_sr & AT91_IRQ_ERRP))
++ new_state = CAN_STATE_ERROR_PASSIVE;
++ else if (unlikely(reg_sr & AT91_IRQ_WARN))
++ new_state = CAN_STATE_ERROR_WARNING;
++ else if (likely(reg_sr & AT91_IRQ_ERRA))
++ new_state = CAN_STATE_ERROR_ACTIVE;
++ else {
++ netdev_err(dev, "BUG! hardware in undefined state\n");
++ return;
++ }
++ } else {
++ err = at91_get_state_by_bec(dev, &new_state);
++ if (err)
++ return;
+ }
+
+ /* state hasn't changed */
+@@ -1330,6 +1368,9 @@ static const struct platform_device_id at91_can_id_table[] = {
+ .name = "at91_can",
+ .driver_data = AT91_DEVTYPE_SAM9263,
+ }, {
++ .name = "at91sam9x5_can",
++ .driver_data = AT91_DEVTYPE_SAM9X5,
++ }, {
+ /* sentinel */
+ }
+ };
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0072-media-V4L-videobuf2-memops-use-pr_debug-for-debug-me.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0072-media-V4L-videobuf2-memops-use-pr_debug-for-debug-me.patch
new file mode 100644
index 0000000..19a8529
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0072-media-V4L-videobuf2-memops-use-pr_debug-for-debug-me.patch
@@ -0,0 +1,51 @@
+From fe4fd5253bfef5de174fd5c4ca69de6f9b91ddaa Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
+Date: Wed, 1 Jun 2011 22:13:59 +0200
+Subject: [PATCH 072/107] [media] V4L/videobuf2-memops: use pr_debug for debug
+ messages
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Otherwise they clutter the dmesg buffer even on a production kernel.
+
+Forwarded: 1306959563-7108-1-git-send-email-u.kleine-koenig@pengutronix.de
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/media/video/videobuf2-memops.c | 6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/media/video/videobuf2-memops.c b/drivers/media/video/videobuf2-memops.c
+index 5370a3a..1987e1b1 100644
+--- a/drivers/media/video/videobuf2-memops.c
++++ b/drivers/media/video/videobuf2-memops.c
+@@ -177,7 +177,7 @@ int vb2_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr,
+
+ vma->vm_ops->open(vma);
+
+- printk(KERN_DEBUG "%s: mapped paddr 0x%08lx at 0x%08lx, size %ld\n",
++ pr_debug("%s: mapped paddr 0x%08lx at 0x%08lx, size %ld\n",
+ __func__, paddr, vma->vm_start, size);
+
+ return 0;
+@@ -195,7 +195,7 @@ static void vb2_common_vm_open(struct vm_area_struct *vma)
+ {
+ struct vb2_vmarea_handler *h = vma->vm_private_data;
+
+- printk(KERN_DEBUG "%s: %p, refcount: %d, vma: %08lx-%08lx\n",
++ pr_debug("%s: %p, refcount: %d, vma: %08lx-%08lx\n",
+ __func__, h, atomic_read(h->refcount), vma->vm_start,
+ vma->vm_end);
+
+@@ -213,7 +213,7 @@ static void vb2_common_vm_close(struct vm_area_struct *vma)
+ {
+ struct vb2_vmarea_handler *h = vma->vm_private_data;
+
+- printk(KERN_DEBUG "%s: %p, refcount: %d, vma: %08lx-%08lx\n",
++ pr_debug("%s: %p, refcount: %d, vma: %08lx-%08lx\n",
+ __func__, h, atomic_read(h->refcount), vma->vm_start,
+ vma->vm_end);
+
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0073-video-atmelfb-initially-split-atmelfb-into-a-driver-.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0073-video-atmelfb-initially-split-atmelfb-into-a-driver-.patch
new file mode 100644
index 0000000..4ff9d16
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0073-video-atmelfb-initially-split-atmelfb-into-a-driver-.patch
@@ -0,0 +1,2622 @@
+From f6a5d666df5107051f4b716b8ed7e8e9a8a2d06a Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Thu, 19 May 2011 09:42:55 +0200
+Subject: [PATCH 073/107] video: atmelfb: initially split atmelfb into a
+ driver and library part
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/Makefile | 2 +-
+ drivers/video/atmel_lcdfb.c | 1410 +-------------------------------------
+ drivers/video/atmel_lcdfb_core.c | 1077 +++++++++++++++++++++++++++++
+ include/video/atmel_lcdc.h | 17 +-
+ 4 files changed, 1104 insertions(+), 1402 deletions(-)
+ create mode 100644 drivers/video/atmel_lcdfb_core.c
+
+diff --git a/drivers/video/Makefile b/drivers/video/Makefile
+index 2ea44b6..e963559 100644
+--- a/drivers/video/Makefile
++++ b/drivers/video/Makefile
+@@ -91,7 +91,7 @@ obj-$(CONFIG_FB_EP93XX) += ep93xx-fb.o
+ obj-$(CONFIG_FB_SA1100) += sa1100fb.o
+ obj-$(CONFIG_FB_HIT) += hitfb.o
+ obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o
+-obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o
++obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o atmel_lcdfb_core.o
+ obj-$(CONFIG_FB_PVR2) += pvr2fb.o
+ obj-$(CONFIG_FB_VOODOO1) += sstfb.o
+ obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 2a943ae..4e1454c 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -10,1384 +10,12 @@
+
+ #include <linux/kernel.h>
+ #include <linux/platform_device.h>
+-#include <linux/dma-mapping.h>
+ #include <linux/interrupt.h>
+-#include <linux/clk.h>
+ #include <linux/fb.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+-#include <linux/backlight.h>
+-#include <linux/gfp.h>
+-
+-#include <mach/board.h>
+-#include <mach/cpu.h>
+-#include <mach/gpio.h>
+
+ #include <video/atmel_lcdc.h>
+-#include <mach/atmel_hlcdfb.h>
+-
+-#define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg))
+-#define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg))
+-
+-/* configurable parameters */
+-#define ATMEL_LCDC_CVAL_DEFAULT 0xc8
+-#define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
+-#define ATMEL_LCDC_FIFO_SIZE 512 /* words */
+-
+-#if defined(CONFIG_ARCH_AT91)
+-#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
+- | FBINFO_PARTIAL_PAN_OK \
+- | FBINFO_HWACCEL_YPAN)
+-
+-static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+- struct fb_var_screeninfo *var)
+-{
+-
+-}
+-#elif defined(CONFIG_AVR32)
+-#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
+- | FBINFO_PARTIAL_PAN_OK \
+- | FBINFO_HWACCEL_XPAN \
+- | FBINFO_HWACCEL_YPAN)
+-
+-static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+- struct fb_var_screeninfo *var)
+-{
+- u32 dma2dcfg;
+- u32 pixeloff;
+-
+- pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f;
+-
+- dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8;
+- dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
+- lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
+-
+- /* Update configuration */
+- lcdc_writel(sinfo, ATMEL_LCDC_DMACON,
+- lcdc_readl(sinfo, ATMEL_LCDC_DMACON)
+- | ATMEL_LCDC_DMAUPDT);
+-}
+-#endif
+-
+-static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
+- | ATMEL_LCDC_POL_POSITIVE
+- | ATMEL_LCDC_ENA_PWMENABLE;
+-
+-static const u32 contrast_pwm_ctr = LCDC_LCDCFG6_PWMPOL
+- | (ATMEL_LCDC_CVAL_DEFAULT << LCDC_LCDCFG6_PWMCVAL_OFFSET);
+-
+-#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+-
+-/* some bl->props field just changed */
+-static int atmel_bl_update_status(struct backlight_device *bl)
+-{
+- struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+- int power = sinfo->bl_power;
+- int brightness = bl->props.brightness;
+- u32 reg;
+-
+- /* REVISIT there may be a meaningful difference between
+- * fb_blank and power ... there seem to be some cases
+- * this doesn't handle correctly.
+- */
+- if (bl->props.fb_blank != sinfo->bl_power)
+- power = bl->props.fb_blank;
+- else if (bl->props.power != sinfo->bl_power)
+- power = bl->props.power;
+-
+- if (brightness < 0 && power == FB_BLANK_UNBLANK) {
+- if (cpu_is_at91sam9x5())
+- brightness = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6)
+- >> LCDC_LCDCFG6_PWMCVAL_OFFSET;
+- else
+- brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+- } else if (power != FB_BLANK_UNBLANK) {
+- brightness = 0;
+- }
+-
+- if (cpu_is_at91sam9x5()) {
+- reg = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) & ~LCDC_LCDCFG6_PWMCVAL;
+- reg |= brightness << LCDC_LCDCFG6_PWMCVAL_OFFSET;
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, reg);
+- } else {
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
+- brightness ? contrast_ctr : 0);
+- }
+-
+- bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
+-
+- return 0;
+-}
+-
+-static int atmel_bl_get_brightness(struct backlight_device *bl)
+-{
+- struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+-
+- if (cpu_is_at91sam9x5())
+- return lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) >> LCDC_LCDCFG6_PWMCVAL_OFFSET;
+- else
+- return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+-}
+-
+-static const struct backlight_ops atmel_lcdc_bl_ops = {
+- .update_status = atmel_bl_update_status,
+- .get_brightness = atmel_bl_get_brightness,
+-};
+-
+-static void init_backlight(struct atmel_lcdfb_info *sinfo)
+-{
+- struct backlight_properties props;
+- struct backlight_device *bl;
+-
+- sinfo->bl_power = FB_BLANK_UNBLANK;
+-
+- if (sinfo->backlight)
+- return;
+-
+- memset(&props, 0, sizeof(struct backlight_properties));
+- props.type = BACKLIGHT_RAW;
+- props.max_brightness = 0xff;
+- bl = backlight_device_register("backlight", &sinfo->pdev->dev, sinfo,
+- &atmel_lcdc_bl_ops, &props);
+- if (IS_ERR(bl)) {
+- dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n",
+- PTR_ERR(bl));
+- return;
+- }
+- sinfo->backlight = bl;
+-
+- bl->props.power = FB_BLANK_UNBLANK;
+- bl->props.fb_blank = FB_BLANK_UNBLANK;
+- bl->props.brightness = atmel_bl_get_brightness(bl);
+-}
+-
+-static void exit_backlight(struct atmel_lcdfb_info *sinfo)
+-{
+- if (sinfo->backlight)
+- backlight_device_unregister(sinfo->backlight);
+-}
+-
+-#else
+-
+-static void init_backlight(struct atmel_lcdfb_info *sinfo)
+-{
+- dev_warn(&sinfo->pdev->dev, "backlight control is not available\n");
+-}
+-
+-static void exit_backlight(struct atmel_lcdfb_info *sinfo)
+-{
+-}
+-
+-#endif
+-
+-static void init_contrast(struct atmel_lcdfb_info *sinfo)
+-{
+- if (cpu_is_at91sam9x5()) {
+- /* have some default contrast/backlight settings */
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, contrast_pwm_ctr);
+- } else {
+- /* contrast pwm can be 'inverted' */
+- if (sinfo->lcdcon_pol_negative)
+- contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
+- /* have some default contrast/backlight settings */
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+- }
+- if (sinfo->lcdcon_is_backlight)
+- init_backlight(sinfo);
+-}
+-
+-
+-static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
+- .type = FB_TYPE_PACKED_PIXELS,
+- .visual = FB_VISUAL_TRUECOLOR,
+- .xpanstep = 0,
+- .ypanstep = 1,
+- .ywrapstep = 0,
+- .accel = FB_ACCEL_NONE,
+-};
+-
+-static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
+-{
+- unsigned long value;
+-
+- if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10()
+- || cpu_is_at32ap7000()))
+- return xres;
+-
+- value = xres;
+- if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
+- /* STN display */
+- if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) {
+- value *= 3;
+- }
+- if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4
+- || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8
+- && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL ))
+- value = DIV_ROUND_UP(value, 4);
+- else
+- value = DIV_ROUND_UP(value, 8);
+- }
+-
+- return value;
+-}
+-
+-static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
+-{
+- if (cpu_is_at91sam9x5()) {
+- /* Disable DISP signal */
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_DISPDIS);
+- while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS))
+- msleep(1);
+- /* Disable synchronization */
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_SYNCDIS);
+- while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS))
+- msleep(1);
+- /* Disable pixel clock */
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_CLKDIS);
+- while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS))
+- msleep(1);
+- /* Disable PWM */
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_PWMDIS);
+- while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS))
+- msleep(1);
+- } else {
+- /* Turn off the LCD controller and the DMA controller */
+- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+- sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
+-
+- /* Wait for the LCDC core to become idle */
+- while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
+- msleep(10);
+-
+- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
+- }
+-}
+-
+-static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo)
+-{
+- atmel_lcdfb_stop_nowait(sinfo);
+-
+- if (cpu_is_at91sam9x5()) {
+- /* Wait for the end of DMA transfer */
+- while (!(lcdc_readl(sinfo, ATMEL_LCDC_BASEISR) & LCDC_BASEISR_DMA))
+- msleep(10);
+- } else {
+- /* Wait for DMA engine to become idle... */
+- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+- msleep(10);
+- }
+-}
+-
+-static void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
+-{
+- u32 value;
+-
+- if (cpu_is_at91sam9x5()) {
+- value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_CLKEN);
+- while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS))
+- msleep(1);
+- value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_SYNCEN);
+- while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS))
+- msleep(1);
+- value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_DISPEN);
+- while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS))
+- msleep(1);
+- value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_PWMEN);
+- while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS))
+- msleep(1);
+- } else {
+- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
+- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+- (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
+- | ATMEL_LCDC_PWR);
+- }
+-}
+-
+-static void atmel_lcdfb_update_dma(struct fb_info *info,
+- struct fb_var_screeninfo *var)
+-{
+- struct atmel_lcdfb_info *sinfo = info->par;
+- struct fb_fix_screeninfo *fix = &info->fix;
+- unsigned long dma_addr;
+- struct lcd_dma_desc *desc;
+-
+- dma_addr = (fix->smem_start + var->yoffset * fix->line_length
+- + var->xoffset * var->bits_per_pixel / 8);
+-
+- dma_addr &= ~3UL;
+-
+- if (cpu_is_at91sam9x5()) {
+- /* Setup the DMA descriptor, this descriptor will loop to itself */
+- desc = (struct lcd_dma_desc *)sinfo->p_dma_desc;
+-
+- desc->address = dma_addr;
+- /* Disable DMA transfer interrupt & descriptor loaded interrupt. */
+- desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN
+- | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH;
+- desc->next = sinfo->dma_desc_phys;
+-
+- lcdc_writel(sinfo, ATMEL_LCDC_BASEADDR, dma_addr);
+- lcdc_writel(sinfo, ATMEL_LCDC_BASECTRL, desc->control);
+- lcdc_writel(sinfo, ATMEL_LCDC_BASENEXT, sinfo->dma_desc_phys);
+- lcdc_writel(sinfo, ATMEL_LCDC_BASECHER, LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN);
+- } else {
+- /* Set framebuffer DMA base address and pixel offset */
+- lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
+- }
+-
+- atmel_lcdfb_update_dma2d(sinfo, var);
+-}
+-
+-static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
+-{
+- struct fb_info *info = sinfo->info;
+-
+- dma_free_writecombine(info->device, info->fix.smem_len,
+- info->screen_base, info->fix.smem_start);
+-
+- if (cpu_is_at91sam9x5()) {
+- if (sinfo->p_dma_desc)
+- dma_free_writecombine(info->device, sizeof(struct lcd_dma_desc),
+- sinfo->p_dma_desc, sinfo->dma_desc_phys);
+- }
+-}
+-
+-/**
+- * atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory
+- * @sinfo: the frame buffer to allocate memory for
+- *
+- * This function is called only from the atmel_lcdfb_probe()
+- * so no locking by fb_info->mm_lock around smem_len setting is needed.
+- */
+-static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
+-{
+- struct fb_info *info = sinfo->info;
+- struct fb_var_screeninfo *var = &info->var;
+- unsigned int smem_len;
+-
+- smem_len = (var->xres_virtual * var->yres_virtual
+- * ((var->bits_per_pixel + 7) / 8));
+- info->fix.smem_len = max(smem_len, sinfo->smem_len);
+-
+- info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len,
+- (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL);
+-
+- if (!info->screen_base) {
+- return -ENOMEM;
+- }
+-
+- memset(info->screen_base, 0, info->fix.smem_len);
+-
+- if (cpu_is_at91sam9x5()) {
+- sinfo->p_dma_desc = dma_alloc_writecombine(info->device,
+- sizeof(struct lcd_dma_desc),
+- (dma_addr_t *)&(sinfo->dma_desc_phys),
+- GFP_KERNEL);
+-
+- if (!sinfo->p_dma_desc) {
+- dma_free_writecombine(info->device, info->fix.smem_len,
+- info->screen_base, info->fix.smem_start);
+- return -ENOMEM;
+- }
+- }
+-
+- return 0;
+-}
+-
+-static const struct fb_videomode *atmel_lcdfb_choose_mode(struct fb_var_screeninfo *var,
+- struct fb_info *info)
+-{
+- struct fb_videomode varfbmode;
+- const struct fb_videomode *fbmode = NULL;
+-
+- fb_var_to_videomode(&varfbmode, var);
+- fbmode = fb_find_nearest_mode(&varfbmode, &info->modelist);
+- if (fbmode)
+- fb_videomode_to_var(var, fbmode);
+- return fbmode;
+-}
+-
+-
+-/**
+- * atmel_lcdfb_check_var - Validates a var passed in.
+- * @var: frame buffer variable screen structure
+- * @info: frame buffer structure that represents a single frame buffer
+- *
+- * Checks to see if the hardware supports the state requested by
+- * var passed in. This function does not alter the hardware
+- * state!!! This means the data stored in struct fb_info and
+- * struct atmel_lcdfb_info do not change. This includes the var
+- * inside of struct fb_info. Do NOT change these. This function
+- * can be called on its own if we intent to only test a mode and
+- * not actually set it. The stuff in modedb.c is a example of
+- * this. If the var passed in is slightly off by what the
+- * hardware can support then we alter the var PASSED in to what
+- * we can do. If the hardware doesn't support mode change a
+- * -EINVAL will be returned by the upper layers. You don't need
+- * to implement this function then. If you hardware doesn't
+- * support changing the resolution then this function is not
+- * needed. In this case the driver would just provide a var that
+- * represents the static state the screen is in.
+- *
+- * Returns negative errno on error, or zero on success.
+- */
+-static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
+- struct fb_info *info)
+-{
+- struct device *dev = info->device;
+- struct atmel_lcdfb_info *sinfo = info->par;
+- unsigned long clk_value_khz;
+-
+- clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+-
+- dev_dbg(dev, "%s:\n", __func__);
+-
+- if (!(var->pixclock && var->bits_per_pixel)) {
+- /* choose a suitable mode if possible */
+- if (!atmel_lcdfb_choose_mode(var, info)) {
+- dev_err(dev, "needed value not specified\n");
+- return -EINVAL;
+- }
+- }
+-
+- dev_dbg(dev, " resolution: %ux%u\n", var->xres, var->yres);
+- dev_dbg(dev, " pixclk: %lu KHz\n", PICOS2KHZ(var->pixclock));
+- dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel);
+- dev_dbg(dev, " clk: %lu KHz\n", clk_value_khz);
+-
+- if (PICOS2KHZ(var->pixclock) > clk_value_khz) {
+- dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock));
+- return -EINVAL;
+- }
+-
+- /* Do not allow to have real resoulution larger than virtual */
+- if (var->xres > var->xres_virtual)
+- var->xres_virtual = var->xres;
+-
+- if (var->yres > var->yres_virtual)
+- var->yres_virtual = var->yres;
+-
+- /* Force same alignment for each line */
+- var->xres = (var->xres + 3) & ~3UL;
+- var->xres_virtual = (var->xres_virtual + 3) & ~3UL;
+-
+- var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
+- var->transp.msb_right = 0;
+- var->transp.offset = var->transp.length = 0;
+- var->xoffset = var->yoffset = 0;
+-
+- if (info->fix.smem_len) {
+- unsigned int smem_len = (var->xres_virtual * var->yres_virtual
+- * ((var->bits_per_pixel + 7) / 8));
+- if (smem_len > info->fix.smem_len)
+- return -EINVAL;
+- }
+-
+- /* Saturate vertical and horizontal timings at maximum values */
+- if (cpu_is_at91sam9x5()) {
+- var->vsync_len = min_t(u32, var->vsync_len,
+- (LCDC_LCDCFG1_VSPW >> LCDC_LCDCFG1_VSPW_OFFSET) + 1);
+- var->upper_margin = min_t(u32, var->upper_margin,
+- (LCDC_LCDCFG2_VFPW >> LCDC_LCDCFG2_VFPW_OFFSET) + 1);
+- var->lower_margin = min_t(u32, var->lower_margin,
+- LCDC_LCDCFG2_VBPW >> LCDC_LCDCFG2_VBPW_OFFSET);
+- var->right_margin = min_t(u32, var->right_margin,
+- (LCDC_LCDCFG3_HBPW >> LCDC_LCDCFG3_HBPW_OFFSET) + 1);
+- var->hsync_len = min_t(u32, var->hsync_len,
+- (LCDC_LCDCFG1_HSPW >> LCDC_LCDCFG1_HSPW_OFFSET) + 1);
+- var->left_margin = min_t(u32, var->left_margin,
+- (LCDC_LCDCFG3_HFPW >> LCDC_LCDCFG3_HFPW_OFFSET) + 1);
+- } else {
+- var->vsync_len = min_t(u32, var->vsync_len,
+- (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
+- var->upper_margin = min_t(u32, var->upper_margin,
+- ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
+- var->lower_margin = min_t(u32, var->lower_margin,
+- ATMEL_LCDC_VFP);
+- var->right_margin = min_t(u32, var->right_margin,
+- (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
+- var->hsync_len = min_t(u32, var->hsync_len,
+- (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
+- var->left_margin = min_t(u32, var->left_margin,
+- ATMEL_LCDC_HBP + 1);
+- }
+-
+- /* Some parameters can't be zero */
+- var->vsync_len = max_t(u32, var->vsync_len, 1);
+- var->right_margin = max_t(u32, var->right_margin, 1);
+- var->hsync_len = max_t(u32, var->hsync_len, 1);
+- var->left_margin = max_t(u32, var->left_margin, 1);
+-
+- switch (var->bits_per_pixel) {
+- case 1:
+- case 2:
+- case 4:
+- case 8:
+- var->red.offset = var->green.offset = var->blue.offset = 0;
+- var->red.length = var->green.length = var->blue.length
+- = var->bits_per_pixel;
+- break;
+- case 12:
+- if (cpu_is_at91sam9x5()) {
+- /* RGB:444 mode */
+- var->red.offset = 8;
+- var->blue.offset = 0;
+- var->green.offset = 4;
+- var->red.length = var->green.length = var->blue.length = 4;
+- } else {
+- /*TODO: rework*/
+- BUG();
+- }
+- break;
+- case 15:
+- if (cpu_is_at91sam9x5()) {
+- /* RGB:555 mode */
+- var->red.offset = 10;
+- var->blue.offset = 0;
+- var->green.length = 5;
+- var->red.length = var->green.length = var->blue.length = 5;
+- } else {
+- /*TODO: rework*/
+- BUG();
+- }
+- break;
+- case 16:
+- if (cpu_is_at91sam9x5()) {
+- if (sinfo->alpha_enabled) {
+- /* ARGB:4444 mode */
+- var->red.offset = 8;
+- var->blue.offset = 0;
+- var->green.offset = 4;
+- var->transp.offset = 12;
+- var->red.length = var->green.length
+- = var->blue.length
+- = var->transp.length = 4;
+- } else {
+- /* RGB:565 mode */
+- var->red.offset = 11;
+- var->blue.offset = 0;
+- var->green.offset = 5;
+- var->green.length = 6;
+- var->red.length = var->blue.length = 5;
+- }
+- break;
+- }
+- if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
+- /* RGB:565 mode */
+- var->red.offset = 11;
+- var->blue.offset = 0;
+- var->green.length = 6;
+- } else if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB555) {
+- var->red.offset = 10;
+- var->blue.offset = 0;
+- var->green.length = 5;
+- } else {
+- /* BGR:555 mode */
+- var->red.offset = 0;
+- var->blue.offset = 10;
+- var->green.length = 5;
+- }
+- var->green.offset = 5;
+- var->red.length = var->blue.length = 5;
+- break;
+- case 32:
+- /* TODO 32 & 24 modes */
+- var->transp.offset = 24;
+- var->transp.length = 8;
+- /* fall through */
+- case 24:
+- if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
+- /* RGB:888 mode */
+- var->red.offset = 16;
+- var->blue.offset = 0;
+- } else {
+- /* BGR:888 mode */
+- var->red.offset = 0;
+- var->blue.offset = 16;
+- }
+- var->green.offset = 8;
+- var->red.length = var->green.length = var->blue.length = 8;
+- break;
+- default:
+- dev_err(dev, "color depth %d not supported\n",
+- var->bits_per_pixel);
+- return -EINVAL;
+- }
+-
+- return 0;
+-}
+-
+-/*
+- * LCD reset sequence
+- */
+-static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
+-{
+- might_sleep();
+-
+- atmel_lcdfb_stop(sinfo);
+- atmel_lcdfb_start(sinfo);
+-}
+-
+-static int atmel_lcdfb_setup_9x5_core(struct fb_info *info)
+-{
+- struct atmel_lcdfb_info *sinfo = info->par;
+- unsigned long value;
+- unsigned long clk_value_khz;
+-
+- dev_dbg(info->device, "%s:\n", __func__);
+- /* Set pixel clock */
+- clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+-
+- value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
+-
+- if (value < 1) {
+- dev_notice(info->device, "using system clock as pixel clock\n");
+- value = LCDC_LCDCFG0_CLKPOL | LCDC_LCDCFG0_CLKPWMSEL | LCDC_LCDCFG0_CGDISBASE;
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value);
+- } else {
+- info->var.pixclock = KHZ2PICOS(clk_value_khz / value);
+- dev_dbg(info->device, " updated pixclk: %lu KHz\n",
+- PICOS2KHZ(info->var.pixclock));
+- value = value - 2;
+- dev_dbg(info->device, " * programming CLKDIV = 0x%08lx\n",
+- value);
+- value = (value << LCDC_LCDCFG0_CLKDIV_OFFSET)
+- | LCDC_LCDCFG0_CLKPOL
+- | LCDC_LCDCFG0_CGDISBASE;
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value);
+- }
+-
+- /* Initialize control register 5 */
+- /* In 9x5, the default_lcdcon2 will use for LCDCFG5 */
+- value = sinfo->default_lcdcon2;
+- value |= (sinfo->guard_time << LCDC_LCDCFG5_GUARDTIME_OFFSET)
+- | LCDC_LCDCFG5_DISPDLY
+- | LCDC_LCDCFG5_VSPDLYS;
+-
+- if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
+- value |= LCDC_LCDCFG5_HSPOL;
+- if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+- value |= LCDC_LCDCFG5_VSPOL;
+-
+- dev_dbg(info->device, " * LCDC_LCDCFG5 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG5, value);
+-
+- /* Vertical & Horizontal Timing */
+- value = (info->var.vsync_len - 1) << LCDC_LCDCFG1_VSPW_OFFSET;
+- value |= (info->var.hsync_len - 1) << LCDC_LCDCFG1_HSPW_OFFSET;
+- dev_dbg(info->device, " * LCDC_LCDCFG1 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG1, value);
+-
+- value = (info->var.lower_margin) << LCDC_LCDCFG2_VBPW_OFFSET;
+- value |= (info->var.upper_margin - 1) << LCDC_LCDCFG2_VFPW_OFFSET;
+- dev_dbg(info->device, " * LCDC_LCDCFG2 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG2, value);
+-
+- value = (info->var.right_margin - 1) << LCDC_LCDCFG3_HBPW_OFFSET;
+- value |= (info->var.left_margin - 1) << LCDC_LCDCFG3_HFPW_OFFSET;
+- dev_dbg(info->device, " * LCDC_LCDCFG3 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG3, value);
+-
+- /* Display size */
+- value = (info->var.yres - 1) << LCDC_LCDCFG4_RPF_OFFSET;
+- value |= (info->var.xres - 1) << LCDC_LCDCFG4_PPL_OFFSET;
+- dev_dbg(info->device, " * LCDC_LCDCFG4 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG4, value);
+-
+- lcdc_writel(sinfo, ATMEL_LCDC_BASECFG0, LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO);
+- switch (info->var.bits_per_pixel) {
+- case 12:
+- value = LCDC_BASECFG1_RGBMODE_12BPP_RGB_444;
+- break;
+- case 16:
+- if (info->var.transp.offset != 0)
+- value = LCDC_BASECFG1_RGBMODE_16BPP_ARGB_4444;
+- else
+- value = LCDC_BASECFG1_RGBMODE_16BPP_RGB_565;
+- break;
+- case 18:
+- value = LCDC_BASECFG1_RGBMODE_18BPP_RGB_666_PACKED;
+- break;
+- case 24:
+- value = LCDC_BASECFG1_RGBMODE_24BPP_RGB_888_PACKED;
+- break;
+- case 32:
+- value = LCDC_BASECFG1_RGBMODE_32BPP_ARGB_8888;
+- break;
+- default:
+- BUG();
+- break;
+- }
+- lcdc_writel(sinfo, ATMEL_LCDC_BASECFG1, value);
+- lcdc_writel(sinfo, ATMEL_LCDC_BASECFG2, 0);
+- lcdc_writel(sinfo, ATMEL_LCDC_BASECFG3, 0); /* Default color */
+- lcdc_writel(sinfo, ATMEL_LCDC_BASECFG4, LCDC_BASECFG4_DMA);
+-
+- /* Disable all interrupts */
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL);
+- lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL);
+- /* Enable BASE LAYER overflow interrupts, if want to enable DMA interrupt, also need set it at LCDC_BASECTRL reg */
+- lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | LCDC_LCDIER_BASEIE | LCDC_LCDIER_HEOIE);
+-
+- return 0;
+-}
+-
+-static int atmel_lcdfb_setup_core(struct fb_info *info)
+-{
+- struct atmel_lcdfb_info *sinfo = info->par;
+- unsigned long hozval_linesz;
+- unsigned long value;
+- unsigned long clk_value_khz;
+- unsigned long pix_factor = 2;
+-
+- if (cpu_is_at91sam9x5()) {
+- return atmel_lcdfb_setup_9x5_core(info);
+- } else {
+- /* ...set frame size and burst length = 8 words (?) */
+- value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
+- value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
+- lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
+-
+- /* Set pixel clock */
+- if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
+- pix_factor = 1;
+-
+- clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+-
+- value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
+-
+- if (value < pix_factor) {
+- dev_notice(info->device, "Bypassing pixel clock divider\n");
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
+- } else {
+- value = (value / pix_factor) - 1;
+- dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n",
+- value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
+- value << ATMEL_LCDC_CLKVAL_OFFSET);
+- info->var.pixclock =
+- KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
+- dev_dbg(info->device, " updated pixclk: %lu KHz\n",
+- PICOS2KHZ(info->var.pixclock));
+- }
+-
+-
+- /* Initialize control register 2 */
+- value = sinfo->default_lcdcon2;
+-
+- if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
+- value |= ATMEL_LCDC_INVLINE_INVERTED;
+- if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+- value |= ATMEL_LCDC_INVFRAME_INVERTED;
+-
+- switch (info->var.bits_per_pixel) {
+- case 1:
+- value |= ATMEL_LCDC_PIXELSIZE_1;
+- break;
+- case 2:
+- value |= ATMEL_LCDC_PIXELSIZE_2;
+- break;
+- case 4:
+- value |= ATMEL_LCDC_PIXELSIZE_4;
+- break;
+- case 8:
+- value |= ATMEL_LCDC_PIXELSIZE_8;
+- break;
+- case 15: /* fall through */
+- case 16:
+- value |= ATMEL_LCDC_PIXELSIZE_16;
+- break;
+- case 24:
+- value |= ATMEL_LCDC_PIXELSIZE_24;
+- break;
+- case 32:
+- value |= ATMEL_LCDC_PIXELSIZE_32;
+- break;
+- default:
+- BUG();
+- break;
+- }
+- dev_dbg(info->device, " * LCDCON2 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
+-
+- /* Vertical timing */
+- value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
+- value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
+- value |= info->var.lower_margin;
+- dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
+-
+- /* Horizontal timing */
+- value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
+- value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
+- value |= (info->var.left_margin - 1);
+- dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
+-
+- /* Horizontal value (aka line size) */
+- hozval_linesz = compute_hozval(info->var.xres,
+- lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
+-
+- /* Display size */
+- value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
+- value |= info->var.yres - 1;
+- dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
+-
+- /* FIFO Threshold: Use formula from data sheet */
+- value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
+- lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
+-
+- /* Toggle LCD_MODE every frame */
+- lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
+-
+- /* Disable all interrupts */
+- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
+- /* Enable FIFO & DMA errors */
+- lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
+-
+- /* ...wait for DMA engine to become idle... */
+- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+- msleep(10);
+-
+- return 0;
+- }
+-}
+-
+-/**
+- * atmel_lcdfb_set_par - Alters the hardware state.
+- * @info: frame buffer structure that represents a single frame buffer
+- *
+- * Using the fb_var_screeninfo in fb_info we set the resolution
+- * of the this particular framebuffer. This function alters the
+- * par AND the fb_fix_screeninfo stored in fb_info. It doesn't
+- * not alter var in fb_info since we are using that data. This
+- * means we depend on the data in var inside fb_info to be
+- * supported by the hardware. atmel_lcdfb_check_var is always called
+- * before atmel_lcdfb_set_par to ensure this. Again if you can't
+- * change the resolution you don't need this function.
+- *
+- */
+-static int atmel_lcdfb_set_par(struct fb_info *info)
+-{
+- struct atmel_lcdfb_info *sinfo = info->par;
+- unsigned long bits_per_line;
+-
+- might_sleep();
+-
+- dev_dbg(info->device, "%s:\n", __func__);
+- dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n",
+- info->var.xres, info->var.yres,
+- info->var.xres_virtual, info->var.yres_virtual);
+-
+- atmel_lcdfb_stop_nowait(sinfo);
+-
+- if (info->var.bits_per_pixel == 1)
+- info->fix.visual = FB_VISUAL_MONO01;
+- else if (info->var.bits_per_pixel <= 8)
+- info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+- else
+- info->fix.visual = FB_VISUAL_TRUECOLOR;
+-
+- bits_per_line = info->var.xres_virtual * info->var.bits_per_pixel;
+- info->fix.line_length = DIV_ROUND_UP(bits_per_line, 8);
+-
+- /* Re-initialize the DMA engine... */
+- dev_dbg(info->device, " * update DMA engine\n");
+- atmel_lcdfb_update_dma(info, &info->var);
+-
+- /* Now, the LCDC core... */
+- atmel_lcdfb_setup_core(info);
+-
+- atmel_lcdfb_start(sinfo);
+-
+- dev_dbg(info->device, " * DONE\n");
+-
+- return 0;
+-}
+-
+-static inline unsigned int chan_to_field(unsigned int chan, const struct fb_bitfield *bf)
+-{
+- chan &= 0xffff;
+- chan >>= 16 - bf->length;
+- return chan << bf->offset;
+-}
+-
+-/**
+- * atmel_lcdfb_setcolreg - Optional function. Sets a color register.
+- * @regno: Which register in the CLUT we are programming
+- * @red: The red value which can be up to 16 bits wide
+- * @green: The green value which can be up to 16 bits wide
+- * @blue: The blue value which can be up to 16 bits wide.
+- * @transp: If supported the alpha value which can be up to 16 bits wide.
+- * @info: frame buffer info structure
+- *
+- * Set a single color register. The values supplied have a 16 bit
+- * magnitude which needs to be scaled in this function for the hardware.
+- * Things to take into consideration are how many color registers, if
+- * any, are supported with the current color visual. With truecolor mode
+- * no color palettes are supported. Here a pseudo palette is created
+- * which we store the value in pseudo_palette in struct fb_info. For
+- * pseudocolor mode we have a limited color palette. To deal with this
+- * we can program what color is displayed for a particular pixel value.
+- * DirectColor is similar in that we can program each color field. If
+- * we have a static colormap we don't need to implement this function.
+- *
+- * Returns negative errno on error, or zero on success. In an
+- * ideal world, this would have been the case, but as it turns
+- * out, the other drivers return 1 on failure, so that's what
+- * we're going to do.
+- */
+-static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
+- unsigned int green, unsigned int blue,
+- unsigned int transp, struct fb_info *info)
+-{
+- struct atmel_lcdfb_info *sinfo = info->par;
+- unsigned int val;
+- u32 *pal;
+- int ret = 1;
+-
+- if (info->var.grayscale)
+- red = green = blue = (19595 * red + 38470 * green
+- + 7471 * blue) >> 16;
+-
+- switch (info->fix.visual) {
+- case FB_VISUAL_TRUECOLOR:
+- if (regno < 16) {
+- pal = info->pseudo_palette;
+-
+- val = chan_to_field(red, &info->var.red);
+- val |= chan_to_field(green, &info->var.green);
+- val |= chan_to_field(blue, &info->var.blue);
+-
+- pal[regno] = val;
+- ret = 0;
+- }
+- break;
+-
+- case FB_VISUAL_PSEUDOCOLOR:
+- if (regno < 256) {
+- val = ((red >> 11) & 0x001f);
+- val |= ((green >> 6) & 0x03e0);
+- val |= ((blue >> 1) & 0x7c00);
+-
+- /*
+- * TODO: intensity bit. Maybe something like
+- * ~(red[10] ^ green[10] ^ blue[10]) & 1
+- */
+-
+- lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
+- ret = 0;
+- }
+- break;
+-
+- case FB_VISUAL_MONO01:
+- if (regno < 2) {
+- val = (regno == 0) ? 0x00 : 0x1F;
+- lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
+- ret = 0;
+- }
+- break;
+-
+- }
+-
+- return ret;
+-}
+-
+-static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var,
+- struct fb_info *info)
+-{
+- dev_dbg(info->device, "%s\n", __func__);
+-
+- atmel_lcdfb_update_dma(info, var);
+-
+- return 0;
+-}
+-
+-static int atmel_lcdfb_blank(int blank_mode, struct fb_info *info)
+-{
+- struct atmel_lcdfb_info *sinfo = info->par;
+-
+- switch (blank_mode) {
+- case FB_BLANK_UNBLANK:
+- case FB_BLANK_NORMAL:
+- atmel_lcdfb_start(sinfo);
+- break;
+- case FB_BLANK_VSYNC_SUSPEND:
+- case FB_BLANK_HSYNC_SUSPEND:
+- break;
+- case FB_BLANK_POWERDOWN:
+- atmel_lcdfb_stop(sinfo);
+- break;
+- default:
+- return -EINVAL;
+- }
+-
+- /* let fbcon do a soft blank for us */
+- return ((blank_mode == FB_BLANK_NORMAL) ? 1 : 0);
+-}
+-
+-static struct fb_ops atmel_lcdfb_ops = {
+- .owner = THIS_MODULE,
+- .fb_check_var = atmel_lcdfb_check_var,
+- .fb_set_par = atmel_lcdfb_set_par,
+- .fb_setcolreg = atmel_lcdfb_setcolreg,
+- .fb_blank = atmel_lcdfb_blank,
+- .fb_pan_display = atmel_lcdfb_pan_display,
+- .fb_fillrect = cfb_fillrect,
+- .fb_copyarea = cfb_copyarea,
+- .fb_imageblit = cfb_imageblit,
+-};
+-
+-static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
+-{
+- struct fb_info *info = dev_id;
+- struct atmel_lcdfb_info *sinfo = info->par;
+- u32 status;
+- u32 baselayer_status;
+-
+- if (cpu_is_at91sam9x5()) {
+- /* Check for error status via interrupt.*/
+- status = lcdc_readl(sinfo, ATMEL_LCDC_LCDISR);
+- if (status & LCDC_LCDISR_FIFOERR) {
+- dev_warn(info->device, "FIFO underflow %#x\n", status);
+- } else if (status & LCDC_LCDISR_BASE) {
+- /* Check base layer's overflow error. */
+- baselayer_status = lcdc_readl(sinfo, ATMEL_LCDC_BASEISR);
+-
+- if (baselayer_status & LCDC_BASEISR_OVR)
+- dev_warn(info->device, "base layer overflow %#x\n",
+- baselayer_status);
+-
+- } else
+- return IRQ_NONE;
+- } else {
+- status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
+- if (status & ATMEL_LCDC_UFLWI) {
+- dev_warn(info->device, "FIFO underflow %#x\n", status);
+- /* reset DMA and FIFO to avoid screen shifting */
+- schedule_work(&sinfo->task);
+- }
+- lcdc_writel(sinfo, ATMEL_LCDC_ICR, status);
+- }
+-
+- return IRQ_HANDLED;
+-}
+-
+-/*
+- * LCD controller task (to reset the LCD)
+- */
+-static void atmel_lcdfb_task(struct work_struct *work)
+-{
+- struct atmel_lcdfb_info *sinfo =
+- container_of(work, struct atmel_lcdfb_info, task);
+-
+- atmel_lcdfb_reset(sinfo);
+-}
+-
+-static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo)
+-{
+- struct fb_info *info = sinfo->info;
+- int ret = 0;
+-
+- info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
+-
+- dev_info(info->device,
+- "%luKiB frame buffer at %08lx (mapped at %p)\n",
+- (unsigned long)info->fix.smem_len / 1024,
+- (unsigned long)info->fix.smem_start,
+- info->screen_base);
+-
+- /* Allocate colormap */
+- ret = fb_alloc_cmap(&info->cmap, 256, 0);
+- if (ret < 0)
+- dev_err(info->device, "Alloc color map failed\n");
+-
+- return ret;
+-}
+-
+-static void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo)
+-{
+- if (sinfo->bus_clk)
+- clk_enable(sinfo->bus_clk);
+- clk_enable(sinfo->lcdc_clk);
+-}
+-
+-static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
+-{
+- if (sinfo->bus_clk)
+- clk_disable(sinfo->bus_clk);
+- clk_disable(sinfo->lcdc_clk);
+-}
+-
+-
+-static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+-{
+- struct device *dev = &pdev->dev;
+- struct fb_info *info;
+- struct atmel_lcdfb_info *sinfo;
+- struct atmel_lcdfb_info *pdata_sinfo;
+- struct fb_videomode fbmode;
+- struct resource *regs = NULL;
+- struct resource *map = NULL;
+- int ret;
+-
+- dev_dbg(dev, "%s BEGIN\n", __func__);
+-
+- ret = -ENOMEM;
+- info = framebuffer_alloc(sizeof(struct atmel_lcdfb_info), dev);
+- if (!info) {
+- dev_err(dev, "cannot allocate memory\n");
+- goto out;
+- }
+-
+- sinfo = info->par;
+-
+- if (dev->platform_data) {
+- pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data;
+- sinfo->default_bpp = pdata_sinfo->default_bpp;
+- sinfo->default_dmacon = pdata_sinfo->default_dmacon;
+- sinfo->default_lcdcon2 = pdata_sinfo->default_lcdcon2;
+- sinfo->default_monspecs = pdata_sinfo->default_monspecs;
+- sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
+- sinfo->guard_time = pdata_sinfo->guard_time;
+- sinfo->smem_len = pdata_sinfo->smem_len;
+- sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
+- sinfo->lcdcon_pol_negative = pdata_sinfo->lcdcon_pol_negative;
+- sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode;
+- } else {
+- dev_err(dev, "cannot get default configuration\n");
+- goto free_info;
+- }
+- sinfo->info = info;
+- sinfo->pdev = pdev;
+-
+- strcpy(info->fix.id, sinfo->pdev->name);
+- info->flags = ATMEL_LCDFB_FBINFO_DEFAULT;
+- info->pseudo_palette = sinfo->pseudo_palette;
+- info->fbops = &atmel_lcdfb_ops;
+-
+- memcpy(&info->monspecs, sinfo->default_monspecs, sizeof(info->monspecs));
+- info->fix = atmel_lcdfb_fix;
+-
+- /* Enable LCDC Clocks */
+- if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()
+- || cpu_is_at32ap7000()) {
+- sinfo->bus_clk = clk_get(dev, "hck1");
+- if (IS_ERR(sinfo->bus_clk)) {
+- ret = PTR_ERR(sinfo->bus_clk);
+- goto free_info;
+- }
+- }
+- sinfo->lcdc_clk = clk_get(dev, "lcdc_clk");
+- if (IS_ERR(sinfo->lcdc_clk)) {
+- ret = PTR_ERR(sinfo->lcdc_clk);
+- goto put_bus_clk;
+- }
+- atmel_lcdfb_start_clock(sinfo);
+-
+- ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb,
+- info->monspecs.modedb_len, info->monspecs.modedb,
+- sinfo->default_bpp);
+- if (!ret) {
+- dev_err(dev, "no suitable video mode found\n");
+- goto stop_clk;
+- }
+-
+-
+- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- if (!regs) {
+- dev_err(dev, "resources unusable\n");
+- ret = -ENXIO;
+- goto stop_clk;
+- }
+-
+- sinfo->irq_base = platform_get_irq(pdev, 0);
+- if (sinfo->irq_base < 0) {
+- dev_err(dev, "unable to get irq\n");
+- ret = sinfo->irq_base;
+- goto stop_clk;
+- }
+-
+- /* Initialize video memory */
+- map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+- sinfo->p_dma_desc = NULL;
+- sinfo->dma_desc_phys = 0;
+- if (map) {
+- /* use a pre-allocated memory buffer */
+- info->fix.smem_start = map->start;
+- info->fix.smem_len = map->end - map->start + 1;
+- if (!request_mem_region(info->fix.smem_start,
+- info->fix.smem_len, pdev->name)) {
+- ret = -EBUSY;
+- goto stop_clk;
+- }
+-
+- info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+- if (!info->screen_base)
+- goto release_intmem;
+-
+- /*
+- * Don't clear the framebuffer -- someone may have set
+- * up a splash image.
+- */
+- } else {
+- /* alocate memory buffer */
+- ret = atmel_lcdfb_alloc_video_memory(sinfo);
+- if (ret < 0) {
+- dev_err(dev, "cannot allocate framebuffer: %d\n", ret);
+- goto stop_clk;
+- }
+- }
+-
+- /* LCDC registers */
+- info->fix.mmio_start = regs->start;
+- info->fix.mmio_len = regs->end - regs->start + 1;
+-
+- if (!request_mem_region(info->fix.mmio_start,
+- info->fix.mmio_len, pdev->name)) {
+- ret = -EBUSY;
+- goto free_fb;
+- }
+-
+- sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len);
+- if (!sinfo->mmio) {
+- dev_err(dev, "cannot map LCDC registers\n");
+- goto release_mem;
+- }
+-
+- /* Initialize PWM for contrast or backlight ("off") */
+- init_contrast(sinfo);
+-
+- /* interrupt */
+- ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, IRQF_SHARED, pdev->name, info);
+- if (ret) {
+- dev_err(dev, "request_irq failed: %d\n", ret);
+- goto unmap_mmio;
+- }
+-
+- /* Some operations on the LCDC might sleep and
+- * require a preemptible task context */
+- INIT_WORK(&sinfo->task, atmel_lcdfb_task);
+-
+- ret = atmel_lcdfb_init_fbinfo(sinfo);
+- if (ret < 0) {
+- dev_err(dev, "init fbinfo failed: %d\n", ret);
+- goto unregister_irqs;
+- }
+-
+- /*
+- * This makes sure that our colour bitfield
+- * descriptors are correctly initialised.
+- */
+- atmel_lcdfb_check_var(&info->var, info);
+-
+- ret = fb_set_var(info, &info->var);
+- if (ret) {
+- dev_warn(dev, "unable to set display parameters\n");
+- goto free_cmap;
+- }
+-
+- dev_set_drvdata(dev, info);
+-
+- /*
+- * Tell the world that we're ready to go
+- */
+- ret = register_framebuffer(info);
+- if (ret < 0) {
+- dev_err(dev, "failed to register framebuffer device: %d\n", ret);
+- goto reset_drvdata;
+- }
+-
+- /* add selected videomode to modelist */
+- fb_var_to_videomode(&fbmode, &info->var);
+- fb_add_videomode(&fbmode, &info->modelist);
+-
+- /* Power up the LCDC screen */
+- if (sinfo->atmel_lcdfb_power_control)
+- sinfo->atmel_lcdfb_power_control(1);
+-
+- dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %d\n",
+- info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base);
+-
+- return 0;
+-
+-reset_drvdata:
+- dev_set_drvdata(dev, NULL);
+-free_cmap:
+- fb_dealloc_cmap(&info->cmap);
+-unregister_irqs:
+- cancel_work_sync(&sinfo->task);
+- free_irq(sinfo->irq_base, info);
+-unmap_mmio:
+- exit_backlight(sinfo);
+- iounmap(sinfo->mmio);
+-release_mem:
+- release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+-free_fb:
+- if (map)
+- iounmap(info->screen_base);
+- else
+- atmel_lcdfb_free_video_memory(sinfo);
+-
+-release_intmem:
+- if (map)
+- release_mem_region(info->fix.smem_start, info->fix.smem_len);
+-stop_clk:
+- atmel_lcdfb_stop_clock(sinfo);
+- clk_put(sinfo->lcdc_clk);
+-put_bus_clk:
+- if (sinfo->bus_clk)
+- clk_put(sinfo->bus_clk);
+-free_info:
+- framebuffer_release(info);
+-out:
+- dev_dbg(dev, "%s FAILED\n", __func__);
+- return ret;
+-}
+-
+-static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
+-{
+- struct device *dev = &pdev->dev;
+- struct fb_info *info = dev_get_drvdata(dev);
+- struct atmel_lcdfb_info *sinfo;
+-
+- if (!info || !info->par)
+- return 0;
+- sinfo = info->par;
+-
+- cancel_work_sync(&sinfo->task);
+- exit_backlight(sinfo);
+- if (sinfo->atmel_lcdfb_power_control)
+- sinfo->atmel_lcdfb_power_control(0);
+- unregister_framebuffer(info);
+- atmel_lcdfb_stop_clock(sinfo);
+- clk_put(sinfo->lcdc_clk);
+- if (sinfo->bus_clk)
+- clk_put(sinfo->bus_clk);
+- fb_dealloc_cmap(&info->cmap);
+- free_irq(sinfo->irq_base, info);
+- iounmap(sinfo->mmio);
+- release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+- if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) {
+- iounmap(info->screen_base);
+- release_mem_region(info->fix.smem_start, info->fix.smem_len);
+- } else {
+- atmel_lcdfb_free_video_memory(sinfo);
+- }
+-
+- dev_set_drvdata(dev, NULL);
+- framebuffer_release(info);
+-
+- return 0;
+-}
+
+ #ifdef CONFIG_PM
+
+@@ -1400,16 +28,10 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
+ * We don't want to handle interrupts while the clock is
+ * stopped. It may take forever.
+ */
+- if (cpu_is_at91sam9x5()) {
+- /* Disable all interrupts */
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL);
+- lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL);
+- } else {
+- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
++ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
+
+- sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
+- }
++ sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
+
+ if (sinfo->atmel_lcdfb_power_control)
+ sinfo->atmel_lcdfb_power_control(0);
+@@ -1430,17 +52,11 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
+ if (sinfo->atmel_lcdfb_power_control)
+ sinfo->atmel_lcdfb_power_control(1);
+
+- if (cpu_is_at91sam9x5()) {
+- /* Enable fifo error & BASE LAYER overflow interrupts */
+- lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | LCDC_LCDIER_BASEIE);
+- } else {
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon);
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon);
+
+- /* Enable FIFO & DMA errors */
+- lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI
+- | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
+- }
++ /* Enable FIFO & DMA errors */
++ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI
++ | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
+
+ return 0;
+ }
+@@ -1450,6 +66,15 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
+ #define atmel_lcdfb_resume NULL
+ #endif
+
++static int __init atmel_lcdfb_probe(struct platform_device *pdev)
++{
++ return __atmel_lcdfb_probe(pdev);
++}
++static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
++{
++ return __atmel_lcdfb_remove(pdev);
++}
++
+ static struct platform_driver atmel_lcdfb_driver = {
+ .remove = __exit_p(atmel_lcdfb_remove),
+ .suspend = atmel_lcdfb_suspend,
+@@ -1465,13 +90,12 @@ static int __init atmel_lcdfb_init(void)
+ {
+ return platform_driver_probe(&atmel_lcdfb_driver, atmel_lcdfb_probe);
+ }
++module_init(atmel_lcdfb_init);
+
+ static void __exit atmel_lcdfb_exit(void)
+ {
+ platform_driver_unregister(&atmel_lcdfb_driver);
+ }
+-
+-module_init(atmel_lcdfb_init);
+ module_exit(atmel_lcdfb_exit);
+
+ MODULE_DESCRIPTION("AT91/AT32 LCD Controller framebuffer driver");
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+new file mode 100644
+index 0000000..54bdbcb
+--- /dev/null
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -0,0 +1,1077 @@
++/*
++ * Driver for AT91/AT32 LCD Controller
++ *
++ * Copyright (C) 2007 Atmel Corporation
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive for
++ * more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/interrupt.h>
++#include <linux/clk.h>
++#include <linux/fb.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/backlight.h>
++#include <linux/gfp.h>
++
++#include <mach/board.h>
++#include <mach/cpu.h>
++#include <mach/gpio.h>
++
++#include <video/atmel_lcdc.h>
++
++/* configurable parameters */
++#define ATMEL_LCDC_CVAL_DEFAULT 0xc8
++#define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
++#define ATMEL_LCDC_FIFO_SIZE 512 /* words */
++
++#if defined(CONFIG_ARCH_AT91)
++#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
++ | FBINFO_PARTIAL_PAN_OK \
++ | FBINFO_HWACCEL_YPAN)
++
++static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
++ struct fb_var_screeninfo *var)
++{
++
++}
++#elif defined(CONFIG_AVR32)
++#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
++ | FBINFO_PARTIAL_PAN_OK \
++ | FBINFO_HWACCEL_XPAN \
++ | FBINFO_HWACCEL_YPAN)
++
++static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
++ struct fb_var_screeninfo *var)
++{
++ u32 dma2dcfg;
++ u32 pixeloff;
++
++ pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f;
++
++ dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8;
++ dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
++ lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
++
++ /* Update configuration */
++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON,
++ lcdc_readl(sinfo, ATMEL_LCDC_DMACON)
++ | ATMEL_LCDC_DMAUPDT);
++}
++#endif
++
++static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
++ | ATMEL_LCDC_POL_POSITIVE
++ | ATMEL_LCDC_ENA_PWMENABLE;
++
++#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
++
++/* some bl->props field just changed */
++static int atmel_bl_update_status(struct backlight_device *bl)
++{
++ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
++ int power = sinfo->bl_power;
++ int brightness = bl->props.brightness;
++
++ /* REVISIT there may be a meaningful difference between
++ * fb_blank and power ... there seem to be some cases
++ * this doesn't handle correctly.
++ */
++ if (bl->props.fb_blank != sinfo->bl_power)
++ power = bl->props.fb_blank;
++ else if (bl->props.power != sinfo->bl_power)
++ power = bl->props.power;
++
++ if (brightness < 0 && power == FB_BLANK_UNBLANK)
++ brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
++ else if (power != FB_BLANK_UNBLANK)
++ brightness = 0;
++
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
++ brightness ? contrast_ctr : 0);
++
++ bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
++
++ return 0;
++}
++
++static int atmel_bl_get_brightness(struct backlight_device *bl)
++{
++ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
++
++ return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
++}
++
++static const struct backlight_ops atmel_lcdc_bl_ops = {
++ .update_status = atmel_bl_update_status,
++ .get_brightness = atmel_bl_get_brightness,
++};
++
++static void init_backlight(struct atmel_lcdfb_info *sinfo)
++{
++ struct backlight_properties props;
++ struct backlight_device *bl;
++
++ sinfo->bl_power = FB_BLANK_UNBLANK;
++
++ if (sinfo->backlight)
++ return;
++
++ memset(&props, 0, sizeof(struct backlight_properties));
++ props.type = BACKLIGHT_RAW;
++ props.max_brightness = 0xff;
++ bl = backlight_device_register("backlight", &sinfo->pdev->dev, sinfo,
++ &atmel_lcdc_bl_ops, &props);
++ if (IS_ERR(bl)) {
++ dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n",
++ PTR_ERR(bl));
++ return;
++ }
++ sinfo->backlight = bl;
++
++ bl->props.power = FB_BLANK_UNBLANK;
++ bl->props.fb_blank = FB_BLANK_UNBLANK;
++ bl->props.brightness = atmel_bl_get_brightness(bl);
++}
++
++static void exit_backlight(struct atmel_lcdfb_info *sinfo)
++{
++ if (sinfo->backlight)
++ backlight_device_unregister(sinfo->backlight);
++}
++
++#else
++
++static void init_backlight(struct atmel_lcdfb_info *sinfo)
++{
++ dev_warn(&sinfo->pdev->dev, "backlight control is not available\n");
++}
++
++static void exit_backlight(struct atmel_lcdfb_info *sinfo)
++{
++}
++
++#endif
++
++static void init_contrast(struct atmel_lcdfb_info *sinfo)
++{
++ /* contrast pwm can be 'inverted' */
++ if (sinfo->lcdcon_pol_negative)
++ contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
++
++ /* have some default contrast/backlight settings */
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
++
++ if (sinfo->lcdcon_is_backlight)
++ init_backlight(sinfo);
++}
++
++
++static struct fb_fix_screeninfo atmel_lcdfb_fix = {
++ .type = FB_TYPE_PACKED_PIXELS,
++ .visual = FB_VISUAL_TRUECOLOR,
++ .xpanstep = 0,
++ .ypanstep = 1,
++ .ywrapstep = 0,
++ .accel = FB_ACCEL_NONE,
++};
++
++static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
++{
++ unsigned long value;
++
++ if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10()
++ || cpu_is_at32ap7000()))
++ return xres;
++
++ value = xres;
++ if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
++ /* STN display */
++ if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) {
++ value *= 3;
++ }
++ if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4
++ || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8
++ && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL ))
++ value = DIV_ROUND_UP(value, 4);
++ else
++ value = DIV_ROUND_UP(value, 8);
++ }
++
++ return value;
++}
++
++static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
++{
++ /* Turn off the LCD controller and the DMA controller */
++ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
++ sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
++
++ /* Wait for the LCDC core to become idle */
++ while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
++ msleep(10);
++
++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
++}
++
++void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo)
++{
++ atmel_lcdfb_stop_nowait(sinfo);
++
++ /* Wait for DMA engine to become idle... */
++ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
++ msleep(10);
++}
++EXPORT_SYMBOL_GPL(atmel_lcdfb_stop);
++
++void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
++{
++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
++ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
++ (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
++ | ATMEL_LCDC_PWR);
++}
++EXPORT_SYMBOL_GPL(atmel_lcdfb_start);
++
++static void atmel_lcdfb_update_dma(struct fb_info *info,
++ struct fb_var_screeninfo *var)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ struct fb_fix_screeninfo *fix = &info->fix;
++ unsigned long dma_addr;
++
++ dma_addr = (fix->smem_start + var->yoffset * fix->line_length
++ + var->xoffset * var->bits_per_pixel / 8);
++
++ dma_addr &= ~3UL;
++
++ /* Set framebuffer DMA base address and pixel offset */
++ lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
++
++ atmel_lcdfb_update_dma2d(sinfo, var);
++}
++
++static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
++{
++ struct fb_info *info = sinfo->info;
++
++ dma_free_writecombine(info->device, info->fix.smem_len,
++ info->screen_base, info->fix.smem_start);
++}
++
++/**
++ * atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory
++ * @sinfo: the frame buffer to allocate memory for
++ *
++ * This function is called only from the atmel_lcdfb_probe()
++ * so no locking by fb_info->mm_lock around smem_len setting is needed.
++ */
++static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
++{
++ struct fb_info *info = sinfo->info;
++ struct fb_var_screeninfo *var = &info->var;
++ unsigned int smem_len;
++
++ smem_len = (var->xres_virtual * var->yres_virtual
++ * ((var->bits_per_pixel + 7) / 8));
++ info->fix.smem_len = max(smem_len, sinfo->smem_len);
++
++ info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len,
++ (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL);
++
++ if (!info->screen_base) {
++ return -ENOMEM;
++ }
++
++ memset(info->screen_base, 0, info->fix.smem_len);
++
++ return 0;
++}
++
++static const struct fb_videomode *atmel_lcdfb_choose_mode(struct fb_var_screeninfo *var,
++ struct fb_info *info)
++{
++ struct fb_videomode varfbmode;
++ const struct fb_videomode *fbmode = NULL;
++
++ fb_var_to_videomode(&varfbmode, var);
++ fbmode = fb_find_nearest_mode(&varfbmode, &info->modelist);
++ if (fbmode)
++ fb_videomode_to_var(var, fbmode);
++ return fbmode;
++}
++
++
++/**
++ * atmel_lcdfb_check_var - Validates a var passed in.
++ * @var: frame buffer variable screen structure
++ * @info: frame buffer structure that represents a single frame buffer
++ *
++ * Checks to see if the hardware supports the state requested by
++ * var passed in. This function does not alter the hardware
++ * state!!! This means the data stored in struct fb_info and
++ * struct atmel_lcdfb_info do not change. This includes the var
++ * inside of struct fb_info. Do NOT change these. This function
++ * can be called on its own if we intent to only test a mode and
++ * not actually set it. The stuff in modedb.c is a example of
++ * this. If the var passed in is slightly off by what the
++ * hardware can support then we alter the var PASSED in to what
++ * we can do. If the hardware doesn't support mode change a
++ * -EINVAL will be returned by the upper layers. You don't need
++ * to implement this function then. If you hardware doesn't
++ * support changing the resolution then this function is not
++ * needed. In this case the driver would just provide a var that
++ * represents the static state the screen is in.
++ *
++ * Returns negative errno on error, or zero on success.
++ */
++static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
++ struct fb_info *info)
++{
++ struct device *dev = info->device;
++ struct atmel_lcdfb_info *sinfo = info->par;
++ unsigned long clk_value_khz;
++
++ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
++
++ dev_dbg(dev, "%s:\n", __func__);
++
++ if (!(var->pixclock && var->bits_per_pixel)) {
++ /* choose a suitable mode if possible */
++ if (!atmel_lcdfb_choose_mode(var, info)) {
++ dev_err(dev, "needed value not specified\n");
++ return -EINVAL;
++ }
++ }
++
++ dev_dbg(dev, " resolution: %ux%u\n", var->xres, var->yres);
++ dev_dbg(dev, " pixclk: %lu KHz\n", PICOS2KHZ(var->pixclock));
++ dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel);
++ dev_dbg(dev, " clk: %lu KHz\n", clk_value_khz);
++
++ if (PICOS2KHZ(var->pixclock) > clk_value_khz) {
++ dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock));
++ return -EINVAL;
++ }
++
++ /* Do not allow to have real resoulution larger than virtual */
++ if (var->xres > var->xres_virtual)
++ var->xres_virtual = var->xres;
++
++ if (var->yres > var->yres_virtual)
++ var->yres_virtual = var->yres;
++
++ /* Force same alignment for each line */
++ var->xres = (var->xres + 3) & ~3UL;
++ var->xres_virtual = (var->xres_virtual + 3) & ~3UL;
++
++ var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
++ var->transp.msb_right = 0;
++ var->transp.offset = var->transp.length = 0;
++ var->xoffset = var->yoffset = 0;
++
++ if (info->fix.smem_len) {
++ unsigned int smem_len = (var->xres_virtual * var->yres_virtual
++ * ((var->bits_per_pixel + 7) / 8));
++ if (smem_len > info->fix.smem_len)
++ return -EINVAL;
++ }
++
++ /* Saturate vertical and horizontal timings at maximum values */
++ var->vsync_len = min_t(u32, var->vsync_len,
++ (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
++ var->upper_margin = min_t(u32, var->upper_margin,
++ ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
++ var->lower_margin = min_t(u32, var->lower_margin,
++ ATMEL_LCDC_VFP);
++ var->right_margin = min_t(u32, var->right_margin,
++ (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
++ var->hsync_len = min_t(u32, var->hsync_len,
++ (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
++ var->left_margin = min_t(u32, var->left_margin,
++ ATMEL_LCDC_HBP + 1);
++
++ /* Some parameters can't be zero */
++ var->vsync_len = max_t(u32, var->vsync_len, 1);
++ var->right_margin = max_t(u32, var->right_margin, 1);
++ var->hsync_len = max_t(u32, var->hsync_len, 1);
++ var->left_margin = max_t(u32, var->left_margin, 1);
++
++ switch (var->bits_per_pixel) {
++ case 1:
++ case 2:
++ case 4:
++ case 8:
++ var->red.offset = var->green.offset = var->blue.offset = 0;
++ var->red.length = var->green.length = var->blue.length
++ = var->bits_per_pixel;
++ break;
++ case 15:
++ case 16:
++ if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
++ /* RGB:565 mode */
++ var->red.offset = 11;
++ var->blue.offset = 0;
++ var->green.length = 6;
++ } else if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB555) {
++ var->red.offset = 10;
++ var->blue.offset = 0;
++ var->green.length = 5;
++ } else {
++ /* BGR:555 mode */
++ var->red.offset = 0;
++ var->blue.offset = 10;
++ var->green.length = 5;
++ }
++ var->green.offset = 5;
++ var->red.length = var->blue.length = 5;
++ break;
++ case 32:
++ var->transp.offset = 24;
++ var->transp.length = 8;
++ /* fall through */
++ case 24:
++ if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
++ /* RGB:888 mode */
++ var->red.offset = 16;
++ var->blue.offset = 0;
++ } else {
++ /* BGR:888 mode */
++ var->red.offset = 0;
++ var->blue.offset = 16;
++ }
++ var->green.offset = 8;
++ var->red.length = var->green.length = var->blue.length = 8;
++ break;
++ default:
++ dev_err(dev, "color depth %d not supported\n",
++ var->bits_per_pixel);
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++/*
++ * LCD reset sequence
++ */
++static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
++{
++ might_sleep();
++
++ atmel_lcdfb_stop(sinfo);
++ atmel_lcdfb_start(sinfo);
++}
++
++/**
++ * atmel_lcdfb_set_par - Alters the hardware state.
++ * @info: frame buffer structure that represents a single frame buffer
++ *
++ * Using the fb_var_screeninfo in fb_info we set the resolution
++ * of the this particular framebuffer. This function alters the
++ * par AND the fb_fix_screeninfo stored in fb_info. It doesn't
++ * not alter var in fb_info since we are using that data. This
++ * means we depend on the data in var inside fb_info to be
++ * supported by the hardware. atmel_lcdfb_check_var is always called
++ * before atmel_lcdfb_set_par to ensure this. Again if you can't
++ * change the resolution you don't need this function.
++ *
++ */
++static int atmel_lcdfb_set_par(struct fb_info *info)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ unsigned long hozval_linesz;
++ unsigned long value;
++ unsigned long clk_value_khz;
++ unsigned long bits_per_line;
++ unsigned long pix_factor = 2;
++
++ might_sleep();
++
++ dev_dbg(info->device, "%s:\n", __func__);
++ dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n",
++ info->var.xres, info->var.yres,
++ info->var.xres_virtual, info->var.yres_virtual);
++
++ atmel_lcdfb_stop_nowait(sinfo);
++
++ if (info->var.bits_per_pixel == 1)
++ info->fix.visual = FB_VISUAL_MONO01;
++ else if (info->var.bits_per_pixel <= 8)
++ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
++ else
++ info->fix.visual = FB_VISUAL_TRUECOLOR;
++
++ bits_per_line = info->var.xres_virtual * info->var.bits_per_pixel;
++ info->fix.line_length = DIV_ROUND_UP(bits_per_line, 8);
++
++ /* Re-initialize the DMA engine... */
++ dev_dbg(info->device, " * update DMA engine\n");
++ atmel_lcdfb_update_dma(info, &info->var);
++
++ /* ...set frame size and burst length = 8 words (?) */
++ value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
++ value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
++ lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
++
++ /* Now, the LCDC core... */
++
++ /* Set pixel clock */
++ if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
++ pix_factor = 1;
++
++ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
++
++ value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
++
++ if (value < pix_factor) {
++ dev_notice(info->device, "Bypassing pixel clock divider\n");
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
++ } else {
++ value = (value / pix_factor) - 1;
++ dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n",
++ value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
++ value << ATMEL_LCDC_CLKVAL_OFFSET);
++ info->var.pixclock =
++ KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
++ dev_dbg(info->device, " updated pixclk: %lu KHz\n",
++ PICOS2KHZ(info->var.pixclock));
++ }
++
++
++ /* Initialize control register 2 */
++ value = sinfo->default_lcdcon2;
++
++ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
++ value |= ATMEL_LCDC_INVLINE_INVERTED;
++ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
++ value |= ATMEL_LCDC_INVFRAME_INVERTED;
++
++ switch (info->var.bits_per_pixel) {
++ case 1: value |= ATMEL_LCDC_PIXELSIZE_1; break;
++ case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
++ case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
++ case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
++ case 15: /* fall through */
++ case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
++ case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
++ case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
++ default: BUG(); break;
++ }
++ dev_dbg(info->device, " * LCDCON2 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
++
++ /* Vertical timing */
++ value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
++ value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
++ value |= info->var.lower_margin;
++ dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
++
++ /* Horizontal timing */
++ value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
++ value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
++ value |= (info->var.left_margin - 1);
++ dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
++
++ /* Horizontal value (aka line size) */
++ hozval_linesz = compute_hozval(info->var.xres,
++ lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
++
++ /* Display size */
++ value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
++ value |= info->var.yres - 1;
++ dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
++
++ /* FIFO Threshold: Use formula from data sheet */
++ value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
++ lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
++
++ /* Toggle LCD_MODE every frame */
++ lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
++
++ /* Disable all interrupts */
++ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
++ /* Enable FIFO & DMA errors */
++ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
++
++ /* ...wait for DMA engine to become idle... */
++ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
++ msleep(10);
++
++ atmel_lcdfb_start(sinfo);
++
++ dev_dbg(info->device, " * DONE\n");
++
++ return 0;
++}
++
++static inline unsigned int chan_to_field(unsigned int chan, const struct fb_bitfield *bf)
++{
++ chan &= 0xffff;
++ chan >>= 16 - bf->length;
++ return chan << bf->offset;
++}
++
++/**
++ * atmel_lcdfb_setcolreg - Optional function. Sets a color register.
++ * @regno: Which register in the CLUT we are programming
++ * @red: The red value which can be up to 16 bits wide
++ * @green: The green value which can be up to 16 bits wide
++ * @blue: The blue value which can be up to 16 bits wide.
++ * @transp: If supported the alpha value which can be up to 16 bits wide.
++ * @info: frame buffer info structure
++ *
++ * Set a single color register. The values supplied have a 16 bit
++ * magnitude which needs to be scaled in this function for the hardware.
++ * Things to take into consideration are how many color registers, if
++ * any, are supported with the current color visual. With truecolor mode
++ * no color palettes are supported. Here a pseudo palette is created
++ * which we store the value in pseudo_palette in struct fb_info. For
++ * pseudocolor mode we have a limited color palette. To deal with this
++ * we can program what color is displayed for a particular pixel value.
++ * DirectColor is similar in that we can program each color field. If
++ * we have a static colormap we don't need to implement this function.
++ *
++ * Returns negative errno on error, or zero on success. In an
++ * ideal world, this would have been the case, but as it turns
++ * out, the other drivers return 1 on failure, so that's what
++ * we're going to do.
++ */
++static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
++ unsigned int green, unsigned int blue,
++ unsigned int transp, struct fb_info *info)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ unsigned int val;
++ u32 *pal;
++ int ret = 1;
++
++ if (info->var.grayscale)
++ red = green = blue = (19595 * red + 38470 * green
++ + 7471 * blue) >> 16;
++
++ switch (info->fix.visual) {
++ case FB_VISUAL_TRUECOLOR:
++ if (regno < 16) {
++ pal = info->pseudo_palette;
++
++ val = chan_to_field(red, &info->var.red);
++ val |= chan_to_field(green, &info->var.green);
++ val |= chan_to_field(blue, &info->var.blue);
++
++ pal[regno] = val;
++ ret = 0;
++ }
++ break;
++
++ case FB_VISUAL_PSEUDOCOLOR:
++ if (regno < 256) {
++ val = ((red >> 11) & 0x001f);
++ val |= ((green >> 6) & 0x03e0);
++ val |= ((blue >> 1) & 0x7c00);
++
++ /*
++ * TODO: intensity bit. Maybe something like
++ * ~(red[10] ^ green[10] ^ blue[10]) & 1
++ */
++
++ lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
++ ret = 0;
++ }
++ break;
++
++ case FB_VISUAL_MONO01:
++ if (regno < 2) {
++ val = (regno == 0) ? 0x00 : 0x1F;
++ lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
++ ret = 0;
++ }
++ break;
++
++ }
++
++ return ret;
++}
++
++static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var,
++ struct fb_info *info)
++{
++ dev_dbg(info->device, "%s\n", __func__);
++
++ atmel_lcdfb_update_dma(info, var);
++
++ return 0;
++}
++
++static int atmel_lcdfb_blank(int blank_mode, struct fb_info *info)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++
++ switch (blank_mode) {
++ case FB_BLANK_UNBLANK:
++ case FB_BLANK_NORMAL:
++ atmel_lcdfb_start(sinfo);
++ break;
++ case FB_BLANK_VSYNC_SUSPEND:
++ case FB_BLANK_HSYNC_SUSPEND:
++ break;
++ case FB_BLANK_POWERDOWN:
++ atmel_lcdfb_stop(sinfo);
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ /* let fbcon do a soft blank for us */
++ return ((blank_mode == FB_BLANK_NORMAL) ? 1 : 0);
++}
++
++static struct fb_ops atmel_lcdfb_ops = {
++ .owner = THIS_MODULE,
++ .fb_check_var = atmel_lcdfb_check_var,
++ .fb_set_par = atmel_lcdfb_set_par,
++ .fb_setcolreg = atmel_lcdfb_setcolreg,
++ .fb_blank = atmel_lcdfb_blank,
++ .fb_pan_display = atmel_lcdfb_pan_display,
++ .fb_fillrect = cfb_fillrect,
++ .fb_copyarea = cfb_copyarea,
++ .fb_imageblit = cfb_imageblit,
++};
++
++static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
++{
++ struct fb_info *info = dev_id;
++ struct atmel_lcdfb_info *sinfo = info->par;
++ u32 status;
++
++ status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
++ if (status & ATMEL_LCDC_UFLWI) {
++ dev_warn(info->device, "FIFO underflow %#x\n", status);
++ /* reset DMA and FIFO to avoid screen shifting */
++ schedule_work(&sinfo->task);
++ }
++ lcdc_writel(sinfo, ATMEL_LCDC_ICR, status);
++ return IRQ_HANDLED;
++}
++
++/*
++ * LCD controller task (to reset the LCD)
++ */
++static void atmel_lcdfb_task(struct work_struct *work)
++{
++ struct atmel_lcdfb_info *sinfo =
++ container_of(work, struct atmel_lcdfb_info, task);
++
++ atmel_lcdfb_reset(sinfo);
++}
++
++static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo)
++{
++ struct fb_info *info = sinfo->info;
++ int ret = 0;
++
++ info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
++
++ dev_info(info->device,
++ "%luKiB frame buffer at %08lx (mapped at %p)\n",
++ (unsigned long)info->fix.smem_len / 1024,
++ (unsigned long)info->fix.smem_start,
++ info->screen_base);
++
++ /* Allocate colormap */
++ ret = fb_alloc_cmap(&info->cmap, 256, 0);
++ if (ret < 0)
++ dev_err(info->device, "Alloc color map failed\n");
++
++ return ret;
++}
++
++void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo)
++{
++ if (sinfo->bus_clk)
++ clk_enable(sinfo->bus_clk);
++ clk_enable(sinfo->lcdc_clk);
++}
++EXPORT_SYMBOL_GPL(atmel_lcdfb_start_clock);
++
++void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
++{
++ if (sinfo->bus_clk)
++ clk_disable(sinfo->bus_clk);
++ clk_disable(sinfo->lcdc_clk);
++}
++EXPORT_SYMBOL_GPL(atmel_lcdfb_stop_clock);
++
++
++int __atmel_lcdfb_probe(struct platform_device *pdev,
++ struct atmel_lcdfb_devdata *dev_data)
++{
++ struct device *dev = &pdev->dev;
++ struct fb_info *info;
++ struct atmel_lcdfb_info *sinfo;
++ struct atmel_lcdfb_info *pdata_sinfo;
++ struct fb_videomode fbmode;
++ struct resource *regs = NULL;
++ struct resource *map = NULL;
++ int ret;
++
++ dev_dbg(dev, "%s BEGIN\n", __func__);
++
++ ret = -ENOMEM;
++ info = framebuffer_alloc(sizeof(struct atmel_lcdfb_info), dev);
++ if (!info) {
++ dev_err(dev, "cannot allocate memory\n");
++ goto out;
++ }
++
++ sinfo = info->par;
++
++ if (dev->platform_data) {
++ pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data;
++ sinfo->default_bpp = pdata_sinfo->default_bpp;
++ sinfo->default_dmacon = pdata_sinfo->default_dmacon;
++ sinfo->default_lcdcon2 = pdata_sinfo->default_lcdcon2;
++ sinfo->default_monspecs = pdata_sinfo->default_monspecs;
++ sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
++ sinfo->guard_time = pdata_sinfo->guard_time;
++ sinfo->smem_len = pdata_sinfo->smem_len;
++ sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
++ sinfo->lcdcon_pol_negative = pdata_sinfo->lcdcon_pol_negative;
++ sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode;
++ } else {
++ dev_err(dev, "cannot get default configuration\n");
++ goto free_info;
++ }
++ sinfo->info = info;
++ sinfo->pdev = pdev;
++
++ strcpy(info->fix.id, sinfo->pdev->name);
++ info->flags = ATMEL_LCDFB_FBINFO_DEFAULT;
++ info->pseudo_palette = sinfo->pseudo_palette;
++ info->fbops = &atmel_lcdfb_ops;
++
++ memcpy(&info->monspecs, sinfo->default_monspecs, sizeof(info->monspecs));
++ info->fix = atmel_lcdfb_fix;
++
++ /* Enable LCDC Clocks */
++ if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()
++ || cpu_is_at32ap7000()) {
++ sinfo->bus_clk = clk_get(dev, "hck1");
++ if (IS_ERR(sinfo->bus_clk)) {
++ ret = PTR_ERR(sinfo->bus_clk);
++ goto free_info;
++ }
++ }
++ sinfo->lcdc_clk = clk_get(dev, "lcdc_clk");
++ if (IS_ERR(sinfo->lcdc_clk)) {
++ ret = PTR_ERR(sinfo->lcdc_clk);
++ goto put_bus_clk;
++ }
++ atmel_lcdfb_start_clock(sinfo);
++
++ ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb,
++ info->monspecs.modedb_len, info->monspecs.modedb,
++ sinfo->default_bpp);
++ if (!ret) {
++ dev_err(dev, "no suitable video mode found\n");
++ goto stop_clk;
++ }
++
++
++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!regs) {
++ dev_err(dev, "resources unusable\n");
++ ret = -ENXIO;
++ goto stop_clk;
++ }
++
++ sinfo->irq_base = platform_get_irq(pdev, 0);
++ if (sinfo->irq_base < 0) {
++ dev_err(dev, "unable to get irq\n");
++ ret = sinfo->irq_base;
++ goto stop_clk;
++ }
++
++ /* Initialize video memory */
++ map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ if (map) {
++ /* use a pre-allocated memory buffer */
++ info->fix.smem_start = map->start;
++ info->fix.smem_len = map->end - map->start + 1;
++ if (!request_mem_region(info->fix.smem_start,
++ info->fix.smem_len, pdev->name)) {
++ ret = -EBUSY;
++ goto stop_clk;
++ }
++
++ info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
++ if (!info->screen_base)
++ goto release_intmem;
++
++ /*
++ * Don't clear the framebuffer -- someone may have set
++ * up a splash image.
++ */
++ } else {
++ /* alocate memory buffer */
++ ret = atmel_lcdfb_alloc_video_memory(sinfo);
++ if (ret < 0) {
++ dev_err(dev, "cannot allocate framebuffer: %d\n", ret);
++ goto stop_clk;
++ }
++ }
++
++ /* LCDC registers */
++ info->fix.mmio_start = regs->start;
++ info->fix.mmio_len = regs->end - regs->start + 1;
++
++ if (!request_mem_region(info->fix.mmio_start,
++ info->fix.mmio_len, pdev->name)) {
++ ret = -EBUSY;
++ goto free_fb;
++ }
++
++ sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len);
++ if (!sinfo->mmio) {
++ dev_err(dev, "cannot map LCDC registers\n");
++ goto release_mem;
++ }
++
++ /* Initialize PWM for contrast or backlight ("off") */
++ init_contrast(sinfo);
++
++ /* interrupt */
++ ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
++ if (ret) {
++ dev_err(dev, "request_irq failed: %d\n", ret);
++ goto unmap_mmio;
++ }
++
++ /* Some operations on the LCDC might sleep and
++ * require a preemptible task context */
++ INIT_WORK(&sinfo->task, atmel_lcdfb_task);
++
++ ret = atmel_lcdfb_init_fbinfo(sinfo);
++ if (ret < 0) {
++ dev_err(dev, "init fbinfo failed: %d\n", ret);
++ goto unregister_irqs;
++ }
++
++ /*
++ * This makes sure that our colour bitfield
++ * descriptors are correctly initialised.
++ */
++ atmel_lcdfb_check_var(&info->var, info);
++
++ ret = fb_set_var(info, &info->var);
++ if (ret) {
++ dev_warn(dev, "unable to set display parameters\n");
++ goto free_cmap;
++ }
++
++ dev_set_drvdata(dev, info);
++
++ /*
++ * Tell the world that we're ready to go
++ */
++ ret = register_framebuffer(info);
++ if (ret < 0) {
++ dev_err(dev, "failed to register framebuffer device: %d\n", ret);
++ goto reset_drvdata;
++ }
++
++ /* add selected videomode to modelist */
++ fb_var_to_videomode(&fbmode, &info->var);
++ fb_add_videomode(&fbmode, &info->modelist);
++
++ /* Power up the LCDC screen */
++ if (sinfo->atmel_lcdfb_power_control)
++ sinfo->atmel_lcdfb_power_control(1);
++
++ dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %d\n",
++ info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base);
++
++ return 0;
++
++reset_drvdata:
++ dev_set_drvdata(dev, NULL);
++free_cmap:
++ fb_dealloc_cmap(&info->cmap);
++unregister_irqs:
++ cancel_work_sync(&sinfo->task);
++ free_irq(sinfo->irq_base, info);
++unmap_mmio:
++ exit_backlight(sinfo);
++ iounmap(sinfo->mmio);
++release_mem:
++ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
++free_fb:
++ if (map)
++ iounmap(info->screen_base);
++ else
++ atmel_lcdfb_free_video_memory(sinfo);
++
++release_intmem:
++ if (map)
++ release_mem_region(info->fix.smem_start, info->fix.smem_len);
++stop_clk:
++ atmel_lcdfb_stop_clock(sinfo);
++ clk_put(sinfo->lcdc_clk);
++put_bus_clk:
++ if (sinfo->bus_clk)
++ clk_put(sinfo->bus_clk);
++free_info:
++ framebuffer_release(info);
++out:
++ dev_dbg(dev, "%s FAILED\n", __func__);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(__atmel_lcdfb_probe);
++
++int __atmel_lcdfb_remove(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct fb_info *info = dev_get_drvdata(dev);
++ struct atmel_lcdfb_info *sinfo;
++
++ if (!info || !info->par)
++ return 0;
++ sinfo = info->par;
++
++ cancel_work_sync(&sinfo->task);
++ exit_backlight(sinfo);
++ if (sinfo->atmel_lcdfb_power_control)
++ sinfo->atmel_lcdfb_power_control(0);
++ unregister_framebuffer(info);
++ atmel_lcdfb_stop_clock(sinfo);
++ clk_put(sinfo->lcdc_clk);
++ if (sinfo->bus_clk)
++ clk_put(sinfo->bus_clk);
++ fb_dealloc_cmap(&info->cmap);
++ free_irq(sinfo->irq_base, info);
++ iounmap(sinfo->mmio);
++ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
++ if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) {
++ iounmap(info->screen_base);
++ release_mem_region(info->fix.smem_start, info->fix.smem_len);
++ } else {
++ atmel_lcdfb_free_video_memory(sinfo);
++ }
++
++ dev_set_drvdata(dev, NULL);
++ framebuffer_release(info);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(__atmel_lcdfb_remove);
+diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
+index 5183ab7..4fa084b 100644
+--- a/include/video/atmel_lcdc.h
++++ b/include/video/atmel_lcdc.h
+@@ -32,6 +32,13 @@
+ #define ATMEL_LCDC_WIRING_RGB 1
+ #define ATMEL_LCDC_WIRING_RGB555 2
+
++extern void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo);
++extern void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo);
++extern void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo);
++extern void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo);
++
++extern int __atmel_lcdfb_probe(struct platform_device *pdev);
++extern int __atmel_lcdfb_remove(struct platform_device *pdev);
+
+ /* LCD Controller info data structure, stored in device platform_data */
+ struct atmel_lcdfb_info {
+@@ -47,9 +54,6 @@ struct atmel_lcdfb_info {
+ struct clk *bus_clk;
+ struct clk *lcdc_clk;
+
+- struct lcd_dma_desc *p_dma_desc;
+- dma_addr_t dma_desc_phys;
+-
+ #ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+ struct backlight_device *backlight;
+ u8 bl_power;
+@@ -68,11 +72,8 @@ struct atmel_lcdfb_info {
+ u32 pseudo_palette[16];
+ };
+
+-struct lcd_dma_desc {
+- u32 address;
+- u32 control;
+- u32 next;
+-};
++#define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg))
++#define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg))
+
+ #define ATMEL_LCDC_DMABADDR1 0x00
+ #define ATMEL_LCDC_DMABADDR2 0x04
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0074-video-atmelfb-refactor-core-setup.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0074-video-atmelfb-refactor-core-setup.patch
new file mode 100644
index 0000000..045683f
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0074-video-atmelfb-refactor-core-setup.patch
@@ -0,0 +1,403 @@
+From 9bcc93b07d7b2465b9cce20bcd86bef247a880e8 Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Thu, 19 May 2011 14:29:36 +0200
+Subject: [PATCH 074/107] video: atmelfb: refactor core setup
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/atmel_lcdfb.c | 158 +++++++++++++++++++++++++++++++++++++-
+ drivers/video/atmel_lcdfb_core.c | 126 +-----------------------------
+ include/video/atmel_lcdc.h | 8 ++-
+ 3 files changed, 166 insertions(+), 126 deletions(-)
+
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 4e1454c..85063d6 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -12,12 +12,162 @@
+ #include <linux/platform_device.h>
+ #include <linux/interrupt.h>
+ #include <linux/fb.h>
++#include <linux/clk.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+
++#include <mach/board.h>
++#include <mach/cpu.h>
++
+ #include <video/atmel_lcdc.h>
+
+-#ifdef CONFIG_PM
++/* configurable parameters */
++#define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
++#define ATMEL_LCDC_FIFO_SIZE 512 /* words */
++
++static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
++{
++ unsigned long value;
++
++ if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10()
++ || cpu_is_at32ap7000()))
++ return xres;
++
++ value = xres;
++ if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
++ /* STN display */
++ if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) {
++ value *= 3;
++ }
++ if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4
++ || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8
++ && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL ))
++ value = DIV_ROUND_UP(value, 4);
++ else
++ value = DIV_ROUND_UP(value, 8);
++ }
++
++ return value;
++}
++
++static int atmel_lcdfb_setup_core(struct fb_info *info)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ unsigned long hozval_linesz;
++ unsigned long value;
++ unsigned long clk_value_khz;
++ unsigned long pix_factor = 2;
++
++ /* ...set frame size and burst length = 8 words (?) */
++ value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
++ value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
++ lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
++
++ /* Set pixel clock */
++ if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
++ pix_factor = 1;
++
++ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
++
++ value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
++
++ if (value < pix_factor) {
++ dev_notice(info->device, "Bypassing pixel clock divider\n");
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
++ } else {
++ value = (value / pix_factor) - 1;
++ dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n",
++ value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
++ value << ATMEL_LCDC_CLKVAL_OFFSET);
++ info->var.pixclock =
++ KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
++ dev_dbg(info->device, " updated pixclk: %lu KHz\n",
++ PICOS2KHZ(info->var.pixclock));
++ }
++
++
++ /* Initialize control register 2 */
++ value = sinfo->default_lcdcon2;
++
++ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
++ value |= ATMEL_LCDC_INVLINE_INVERTED;
++ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
++ value |= ATMEL_LCDC_INVFRAME_INVERTED;
++
++ switch (info->var.bits_per_pixel) {
++ case 1:
++ value |= ATMEL_LCDC_PIXELSIZE_1;
++ break;
++ case 2:
++ value |= ATMEL_LCDC_PIXELSIZE_2;
++ break;
++ case 4:
++ value |= ATMEL_LCDC_PIXELSIZE_4;
++ break;
++ case 8:
++ value |= ATMEL_LCDC_PIXELSIZE_8;
++ break;
++ case 15: /* fall through */
++ case 16:
++ value |= ATMEL_LCDC_PIXELSIZE_16;
++ break;
++ case 24:
++ value |= ATMEL_LCDC_PIXELSIZE_24;
++ break;
++ case 32:
++ value |= ATMEL_LCDC_PIXELSIZE_32;
++ break;
++ default:
++ BUG();
++ break;
++ }
++ dev_dbg(info->device, " * LCDCON2 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
++
++ /* Vertical timing */
++ value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
++ value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
++ value |= info->var.lower_margin;
++ dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
++
++ /* Horizontal timing */
++ value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
++ value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
++ value |= (info->var.left_margin - 1);
++ dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
++
++ /* Horizontal value (aka line size) */
++ hozval_linesz = compute_hozval(info->var.xres,
++ lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
++
++ /* Display size */
++ value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
++ value |= info->var.yres - 1;
++ dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
++
++ /* FIFO Threshold: Use formula from data sheet */
++ value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
++ lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
++
++ /* Toggle LCD_MODE every frame */
++ lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
++
++ /* Disable all interrupts */
++ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
++ /* Enable FIFO & DMA errors */
++ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
++
++ /* ...wait for DMA engine to become idle... */
++ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
++ msleep(10);
++
++ return 0;
++}
++
+
+ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
+ {
+@@ -66,9 +216,13 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
+ #define atmel_lcdfb_resume NULL
+ #endif
+
++static struct atmel_lcdfb_devdata dev_data = {
++ .setup_core = atmel_lcdfb_setup_core,
++};
++
+ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+ {
+- return __atmel_lcdfb_probe(pdev);
++ return __atmel_lcdfb_probe(pdev, &dev_data);
+ }
+ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
+ {
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index 54bdbcb..9a7c5eb 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -27,8 +27,6 @@
+
+ /* configurable parameters */
+ #define ATMEL_LCDC_CVAL_DEFAULT 0xc8
+-#define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
+-#define ATMEL_LCDC_FIFO_SIZE 512 /* words */
+
+ #if defined(CONFIG_ARCH_AT91)
+ #define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
+@@ -183,31 +181,6 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix = {
+ .accel = FB_ACCEL_NONE,
+ };
+
+-static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
+-{
+- unsigned long value;
+-
+- if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10()
+- || cpu_is_at32ap7000()))
+- return xres;
+-
+- value = xres;
+- if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
+- /* STN display */
+- if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) {
+- value *= 3;
+- }
+- if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4
+- || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8
+- && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL ))
+- value = DIV_ROUND_UP(value, 4);
+- else
+- value = DIV_ROUND_UP(value, 8);
+- }
+-
+- return value;
+-}
+-
+ static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
+ {
+ /* Turn off the LCD controller and the DMA controller */
+@@ -487,11 +460,7 @@ static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
+ static int atmel_lcdfb_set_par(struct fb_info *info)
+ {
+ struct atmel_lcdfb_info *sinfo = info->par;
+- unsigned long hozval_linesz;
+- unsigned long value;
+- unsigned long clk_value_khz;
+ unsigned long bits_per_line;
+- unsigned long pix_factor = 2;
+
+ might_sleep();
+
+@@ -516,98 +485,8 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
+ dev_dbg(info->device, " * update DMA engine\n");
+ atmel_lcdfb_update_dma(info, &info->var);
+
+- /* ...set frame size and burst length = 8 words (?) */
+- value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
+- value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
+- lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
+-
+ /* Now, the LCDC core... */
+-
+- /* Set pixel clock */
+- if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
+- pix_factor = 1;
+-
+- clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+-
+- value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
+-
+- if (value < pix_factor) {
+- dev_notice(info->device, "Bypassing pixel clock divider\n");
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
+- } else {
+- value = (value / pix_factor) - 1;
+- dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n",
+- value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
+- value << ATMEL_LCDC_CLKVAL_OFFSET);
+- info->var.pixclock =
+- KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
+- dev_dbg(info->device, " updated pixclk: %lu KHz\n",
+- PICOS2KHZ(info->var.pixclock));
+- }
+-
+-
+- /* Initialize control register 2 */
+- value = sinfo->default_lcdcon2;
+-
+- if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
+- value |= ATMEL_LCDC_INVLINE_INVERTED;
+- if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+- value |= ATMEL_LCDC_INVFRAME_INVERTED;
+-
+- switch (info->var.bits_per_pixel) {
+- case 1: value |= ATMEL_LCDC_PIXELSIZE_1; break;
+- case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
+- case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
+- case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
+- case 15: /* fall through */
+- case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
+- case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
+- case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
+- default: BUG(); break;
+- }
+- dev_dbg(info->device, " * LCDCON2 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
+-
+- /* Vertical timing */
+- value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
+- value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
+- value |= info->var.lower_margin;
+- dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
+-
+- /* Horizontal timing */
+- value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
+- value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
+- value |= (info->var.left_margin - 1);
+- dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
+-
+- /* Horizontal value (aka line size) */
+- hozval_linesz = compute_hozval(info->var.xres,
+- lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
+-
+- /* Display size */
+- value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
+- value |= info->var.yres - 1;
+- dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
+-
+- /* FIFO Threshold: Use formula from data sheet */
+- value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
+- lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
+-
+- /* Toggle LCD_MODE every frame */
+- lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
+-
+- /* Disable all interrupts */
+- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
+- /* Enable FIFO & DMA errors */
+- lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
+-
+- /* ...wait for DMA engine to become idle... */
+- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+- msleep(10);
++ sinfo->dev_data->setup_core(info);
+
+ atmel_lcdfb_start(sinfo);
+
+@@ -837,7 +716,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+
+ sinfo = info->par;
+
+- if (dev->platform_data) {
++ if (dev->platform_data && dev_data) {
+ pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data;
+ sinfo->default_bpp = pdata_sinfo->default_bpp;
+ sinfo->default_dmacon = pdata_sinfo->default_dmacon;
+@@ -849,6 +728,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
+ sinfo->lcdcon_pol_negative = pdata_sinfo->lcdcon_pol_negative;
+ sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode;
++ sinfo->dev_data = dev_data;
+ } else {
+ dev_err(dev, "cannot get default configuration\n");
+ goto free_info;
+diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
+index 4fa084b..b1a5fad1 100644
+--- a/include/video/atmel_lcdc.h
++++ b/include/video/atmel_lcdc.h
+@@ -37,15 +37,21 @@ extern void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo);
+ extern void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo);
+ extern void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo);
+
+-extern int __atmel_lcdfb_probe(struct platform_device *pdev);
++extern int __atmel_lcdfb_probe(struct platform_device *pdev,
++ struct atmel_lcdfb_devdata *devdata);
+ extern int __atmel_lcdfb_remove(struct platform_device *pdev);
+
++struct atmel_lcdfb_devdata {
++ int (*setup_core)(struct fb_info *info);
++};
++
+ /* LCD Controller info data structure, stored in device platform_data */
+ struct atmel_lcdfb_info {
+ spinlock_t lock;
+ struct fb_info *info;
+ void __iomem *mmio;
+ int irq_base;
++ struct atmel_lcdfb_devdata *dev_data;
+ struct work_struct task;
+
+ unsigned int guard_time;
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0075-video-atmelfb-refactor-start-stop.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0075-video-atmelfb-refactor-start-stop.patch
new file mode 100644
index 0000000..7a6c7ca
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0075-video-atmelfb-refactor-start-stop.patch
@@ -0,0 +1,196 @@
+From 129f891e93a10824f98ba2533744a6e0488c2afb Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Thu, 19 May 2011 15:12:30 +0200
+Subject: [PATCH 075/107] video: atmelfb: refactor start/stop
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/atmel_lcdfb.c | 30 ++++++++++++++++++++++-
+ drivers/video/atmel_lcdfb_core.c | 50 +++++++++----------------------------
+ include/video/atmel_lcdc.h | 9 ++++--
+ 3 files changed, 47 insertions(+), 42 deletions(-)
+
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 85063d6..422be1a 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -25,6 +25,32 @@
+ #define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
+ #define ATMEL_LCDC_FIFO_SIZE 512 /* words */
+
++void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
++{
++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
++ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
++ (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
++ | ATMEL_LCDC_PWR);
++}
++
++static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo, u32 flags)
++{
++ /* Turn off the LCD controller and the DMA controller */
++ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
++ sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
++
++ /* Wait for the LCDC core to become idle */
++ while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
++ msleep(10);
++
++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
++
++ if (!(flags & ATMEL_LCDC_STOP_NOWAIT))
++ /* Wait for DMA engine to become idle... */
++ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
++ msleep(10);
++}
++
+ static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
+ {
+ unsigned long value;
+@@ -186,7 +212,7 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
+ if (sinfo->atmel_lcdfb_power_control)
+ sinfo->atmel_lcdfb_power_control(0);
+
+- atmel_lcdfb_stop(sinfo);
++ atmel_lcdfb_stop(sinfo, 0);
+ atmel_lcdfb_stop_clock(sinfo);
+
+ return 0;
+@@ -218,6 +244,8 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
+
+ static struct atmel_lcdfb_devdata dev_data = {
+ .setup_core = atmel_lcdfb_setup_core,
++ .start = atmel_lcdfb_start,
++ .stop = atmel_lcdfb_stop,
+ };
+
+ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index 9a7c5eb..8413b76 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -181,38 +181,6 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix = {
+ .accel = FB_ACCEL_NONE,
+ };
+
+-static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
+-{
+- /* Turn off the LCD controller and the DMA controller */
+- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+- sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
+-
+- /* Wait for the LCDC core to become idle */
+- while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
+- msleep(10);
+-
+- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
+-}
+-
+-void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo)
+-{
+- atmel_lcdfb_stop_nowait(sinfo);
+-
+- /* Wait for DMA engine to become idle... */
+- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+- msleep(10);
+-}
+-EXPORT_SYMBOL_GPL(atmel_lcdfb_stop);
+-
+-void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
+-{
+- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
+- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+- (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
+- | ATMEL_LCDC_PWR);
+-}
+-EXPORT_SYMBOL_GPL(atmel_lcdfb_start);
+-
+ static void atmel_lcdfb_update_dma(struct fb_info *info,
+ struct fb_var_screeninfo *var)
+ {
+@@ -439,8 +407,10 @@ static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
+ {
+ might_sleep();
+
+- atmel_lcdfb_stop(sinfo);
+- atmel_lcdfb_start(sinfo);
++ if (sinfo->dev_data->stop)
++ sinfo->dev_data->stop(sinfo, 0);
++ if (sinfo->dev_data->start)
++ sinfo->dev_data->start(sinfo);
+ }
+
+ /**
+@@ -469,7 +439,8 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
+ info->var.xres, info->var.yres,
+ info->var.xres_virtual, info->var.yres_virtual);
+
+- atmel_lcdfb_stop_nowait(sinfo);
++ if (sinfo->dev_data->stop)
++ sinfo->dev_data->stop(sinfo, ATMEL_LCDC_STOP_NOWAIT);
+
+ if (info->var.bits_per_pixel == 1)
+ info->fix.visual = FB_VISUAL_MONO01;
+@@ -488,7 +459,8 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
+ /* Now, the LCDC core... */
+ sinfo->dev_data->setup_core(info);
+
+- atmel_lcdfb_start(sinfo);
++ if (sinfo->dev_data->start)
++ sinfo->dev_data->start(sinfo);
+
+ dev_dbg(info->device, " * DONE\n");
+
+@@ -600,13 +572,15 @@ static int atmel_lcdfb_blank(int blank_mode, struct fb_info *info)
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ case FB_BLANK_NORMAL:
+- atmel_lcdfb_start(sinfo);
++ if (sinfo->dev_data->start)
++ sinfo->dev_data->start(sinfo);
+ break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ break;
+ case FB_BLANK_POWERDOWN:
+- atmel_lcdfb_stop(sinfo);
++ if (sinfo->dev_data->stop)
++ sinfo->dev_data->stop(sinfo, 0);
+ break;
+ default:
+ return -EINVAL;
+diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
+index b1a5fad1..ea7ce31 100644
+--- a/include/video/atmel_lcdc.h
++++ b/include/video/atmel_lcdc.h
+@@ -32,17 +32,20 @@
+ #define ATMEL_LCDC_WIRING_RGB 1
+ #define ATMEL_LCDC_WIRING_RGB555 2
+
+-extern void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo);
+-extern void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo);
++#define ATMEL_LCDC_STOP_NOWAIT (1 << 0)
++
+ extern void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo);
+ extern void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo);
+-
+ extern int __atmel_lcdfb_probe(struct platform_device *pdev,
+ struct atmel_lcdfb_devdata *devdata);
+ extern int __atmel_lcdfb_remove(struct platform_device *pdev);
+
++struct atmel_lcdfb_info;
++
+ struct atmel_lcdfb_devdata {
+ int (*setup_core)(struct fb_info *info);
++ void (*start)(struct atmel_lcdfb_info *sinfo);
++ void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags);
+ };
+
+ /* LCD Controller info data structure, stored in device platform_data */
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0076-video-atmelfb-refactor-isr.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0076-video-atmelfb-refactor-isr.patch
new file mode 100644
index 0000000..86ae469
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0076-video-atmelfb-refactor-isr.patch
@@ -0,0 +1,154 @@
+From 8e18c2a07ac0e90f347bbb66aa83b8a7ea008152 Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Thu, 19 May 2011 15:37:12 +0200
+Subject: [PATCH 076/107] video: atmelfb: refactor isr
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/atmel_lcdfb.c | 18 +++++++++++++++++
+ drivers/video/atmel_lcdfb_core.c | 39 +++++++++++--------------------------
+ include/video/atmel_lcdc.h | 2 +
+ 3 files changed, 32 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 422be1a..3653e2a 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -194,6 +194,23 @@ static int atmel_lcdfb_setup_core(struct fb_info *info)
+ return 0;
+ }
+
++static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
++{
++ struct fb_info *info = dev_id;
++ struct atmel_lcdfb_info *sinfo = info->par;
++ u32 status;
++
++ status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
++ if (status & ATMEL_LCDC_UFLWI) {
++ dev_warn(info->device, "FIFO underflow %#x\n", status);
++ /* reset DMA and FIFO to avoid screen shifting */
++ schedule_work(&sinfo->task);
++ }
++ lcdc_writel(sinfo, ATMEL_LCDC_ICR, status);
++ return IRQ_HANDLED;
++}
++
++#ifdef CONFIG_PM
+
+ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
+ {
+@@ -246,6 +263,7 @@ static struct atmel_lcdfb_devdata dev_data = {
+ .setup_core = atmel_lcdfb_setup_core,
+ .start = atmel_lcdfb_start,
+ .stop = atmel_lcdfb_stop,
++ .isr = atmel_lcdfb_interrupt,
+ };
+
+ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index 8413b76..eab4d88 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -602,22 +602,6 @@ static struct fb_ops atmel_lcdfb_ops = {
+ .fb_imageblit = cfb_imageblit,
+ };
+
+-static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
+-{
+- struct fb_info *info = dev_id;
+- struct atmel_lcdfb_info *sinfo = info->par;
+- u32 status;
+-
+- status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
+- if (status & ATMEL_LCDC_UFLWI) {
+- dev_warn(info->device, "FIFO underflow %#x\n", status);
+- /* reset DMA and FIFO to avoid screen shifting */
+- schedule_work(&sinfo->task);
+- }
+- lcdc_writel(sinfo, ATMEL_LCDC_ICR, status);
+- return IRQ_HANDLED;
+-}
+-
+ /*
+ * LCD controller task (to reset the LCD)
+ */
+@@ -750,12 +734,8 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ goto stop_clk;
+ }
+
++ /* No error checking, some devices can do without IRQ */
+ sinfo->irq_base = platform_get_irq(pdev, 0);
+- if (sinfo->irq_base < 0) {
+- dev_err(dev, "unable to get irq\n");
+- ret = sinfo->irq_base;
+- goto stop_clk;
+- }
+
+ /* Initialize video memory */
+ map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+@@ -806,10 +786,13 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ init_contrast(sinfo);
+
+ /* interrupt */
+- ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
+- if (ret) {
+- dev_err(dev, "request_irq failed: %d\n", ret);
+- goto unmap_mmio;
++ if (sinfo->irq_base >= 0) {
++ ret = request_irq(sinfo->irq_base, sinfo->dev_data->isr,
++ IRQF_SHARED, pdev->name, info);
++ if (ret) {
++ dev_err(dev, "request_irq failed: %d\n", ret);
++ goto unmap_mmio;
++ }
+ }
+
+ /* Some operations on the LCDC might sleep and
+@@ -864,7 +847,8 @@ free_cmap:
+ fb_dealloc_cmap(&info->cmap);
+ unregister_irqs:
+ cancel_work_sync(&sinfo->task);
+- free_irq(sinfo->irq_base, info);
++ if (sinfo->irq_base >= 0)
++ free_irq(sinfo->irq_base, info);
+ unmap_mmio:
+ exit_backlight(sinfo);
+ iounmap(sinfo->mmio);
+@@ -913,7 +897,8 @@ int __atmel_lcdfb_remove(struct platform_device *pdev)
+ if (sinfo->bus_clk)
+ clk_put(sinfo->bus_clk);
+ fb_dealloc_cmap(&info->cmap);
+- free_irq(sinfo->irq_base, info);
++ if (sinfo->irq_base >= 0)
++ free_irq(sinfo->irq_base, info);
+ iounmap(sinfo->mmio);
+ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+ if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) {
+diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
+index ea7ce31..14b5664 100644
+--- a/include/video/atmel_lcdc.h
++++ b/include/video/atmel_lcdc.h
+@@ -23,6 +23,7 @@
+ #define __ATMEL_LCDC_H__
+
+ #include <linux/workqueue.h>
++#include <linux/interrupt.h>
+
+ /* Way LCD wires are connected to the chip:
+ * Some Atmel chips use BGR color mode (instead of standard RGB)
+@@ -46,6 +47,7 @@ struct atmel_lcdfb_devdata {
+ int (*setup_core)(struct fb_info *info);
+ void (*start)(struct atmel_lcdfb_info *sinfo);
+ void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags);
++ irqreturn_t (*isr)(int irq, void *dev_id);
+ };
+
+ /* LCD Controller info data structure, stored in device platform_data */
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0077-video-atmelfb-refactor-backlight-routines.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0077-video-atmelfb-refactor-backlight-routines.patch
new file mode 100644
index 0000000..d49197a
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0077-video-atmelfb-refactor-backlight-routines.patch
@@ -0,0 +1,256 @@
+From cdde3f0de6b5fb035fd79751d93f30f7420fa246 Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Thu, 19 May 2011 16:40:13 +0200
+Subject: [PATCH 077/107] video: atmelfb: refactor backlight routines
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/atmel_lcdfb.c | 61 +++++++++++++++++++++++++++++++
+ drivers/video/atmel_lcdfb_core.c | 73 ++++----------------------------------
+ include/video/atmel_lcdc.h | 3 ++
+ 3 files changed, 71 insertions(+), 66 deletions(-)
+
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 3653e2a..046e6c5 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -11,6 +11,7 @@
+ #include <linux/kernel.h>
+ #include <linux/platform_device.h>
+ #include <linux/interrupt.h>
++#include <linux/backlight.h>
+ #include <linux/fb.h>
+ #include <linux/clk.h>
+ #include <linux/init.h>
+@@ -22,9 +23,67 @@
+ #include <video/atmel_lcdc.h>
+
+ /* configurable parameters */
++#define ATMEL_LCDC_CVAL_DEFAULT 0xc8
+ #define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
+ #define ATMEL_LCDC_FIFO_SIZE 512 /* words */
+
++static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
++ | ATMEL_LCDC_POL_POSITIVE
++ | ATMEL_LCDC_ENA_PWMENABLE;
++
++/* some bl->props field just changed */
++static int atmel_bl_update_status(struct backlight_device *bl)
++{
++ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
++ int power = sinfo->bl_power;
++ int brightness = bl->props.brightness;
++
++ /* REVISIT there may be a meaningful difference between
++ * fb_blank and power ... there seem to be some cases
++ * this doesn't handle correctly.
++ */
++ if (bl->props.fb_blank != sinfo->bl_power)
++ power = bl->props.fb_blank;
++ else if (bl->props.power != sinfo->bl_power)
++ power = bl->props.power;
++
++ if (brightness < 0 && power == FB_BLANK_UNBLANK)
++ brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
++ else if (power != FB_BLANK_UNBLANK)
++ brightness = 0;
++
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
++ brightness ? contrast_ctr : 0);
++
++ bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
++
++ return 0;
++}
++
++static int atmel_bl_get_brightness(struct backlight_device *bl)
++{
++ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
++
++ return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
++}
++
++static const struct backlight_ops atmel_lcdc_bl_ops = {
++ .update_status = atmel_bl_update_status,
++ .get_brightness = atmel_bl_get_brightness,
++};
++
++static void atmel_lcdfb_init_contrast(struct atmel_lcdfb_info *sinfo)
++{
++ /* contrast pwm can be 'inverted' */
++ if (sinfo->lcdcon_pol_negative)
++ contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
++
++ /* have some default contrast/backlight settings */
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
++}
++
+ void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
+ {
+ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
+@@ -264,6 +323,8 @@ static struct atmel_lcdfb_devdata dev_data = {
+ .start = atmel_lcdfb_start,
+ .stop = atmel_lcdfb_stop,
+ .isr = atmel_lcdfb_interrupt,
++ .bl_ops = &atmel_lcdc_bl_ops,
++ .init_contrast = atmel_lcdfb_init_contrast,
+ };
+
+ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index eab4d88..ef63996 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -16,7 +16,6 @@
+ #include <linux/fb.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+-#include <linux/backlight.h>
+ #include <linux/gfp.h>
+
+ #include <mach/board.h>
+@@ -63,54 +62,8 @@ static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+ }
+ #endif
+
+-static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
+- | ATMEL_LCDC_POL_POSITIVE
+- | ATMEL_LCDC_ENA_PWMENABLE;
+-
+ #ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+
+-/* some bl->props field just changed */
+-static int atmel_bl_update_status(struct backlight_device *bl)
+-{
+- struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+- int power = sinfo->bl_power;
+- int brightness = bl->props.brightness;
+-
+- /* REVISIT there may be a meaningful difference between
+- * fb_blank and power ... there seem to be some cases
+- * this doesn't handle correctly.
+- */
+- if (bl->props.fb_blank != sinfo->bl_power)
+- power = bl->props.fb_blank;
+- else if (bl->props.power != sinfo->bl_power)
+- power = bl->props.power;
+-
+- if (brightness < 0 && power == FB_BLANK_UNBLANK)
+- brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+- else if (power != FB_BLANK_UNBLANK)
+- brightness = 0;
+-
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
+- brightness ? contrast_ctr : 0);
+-
+- bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
+-
+- return 0;
+-}
+-
+-static int atmel_bl_get_brightness(struct backlight_device *bl)
+-{
+- struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+-
+- return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+-}
+-
+-static const struct backlight_ops atmel_lcdc_bl_ops = {
+- .update_status = atmel_bl_update_status,
+- .get_brightness = atmel_bl_get_brightness,
+-};
+-
+ static void init_backlight(struct atmel_lcdfb_info *sinfo)
+ {
+ struct backlight_properties props;
+@@ -118,14 +71,14 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo)
+
+ sinfo->bl_power = FB_BLANK_UNBLANK;
+
+- if (sinfo->backlight)
++ if (sinfo->backlight || !sinfo->dev_data->bl_ops)
+ return;
+
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.type = BACKLIGHT_RAW;
+ props.max_brightness = 0xff;
+ bl = backlight_device_register("backlight", &sinfo->pdev->dev, sinfo,
+- &atmel_lcdc_bl_ops, &props);
++ sinfo->dev_data->bl_ops, &props);
+ if (IS_ERR(bl)) {
+ dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n",
+ PTR_ERR(bl));
+@@ -135,7 +88,7 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo)
+
+ bl->props.power = FB_BLANK_UNBLANK;
+ bl->props.fb_blank = FB_BLANK_UNBLANK;
+- bl->props.brightness = atmel_bl_get_brightness(bl);
++ bl->props.brightness = sinfo->dev_data->bl_ops->get_brightness(bl);
+ }
+
+ static void exit_backlight(struct atmel_lcdfb_info *sinfo)
+@@ -157,21 +110,6 @@ static void exit_backlight(struct atmel_lcdfb_info *sinfo)
+
+ #endif
+
+-static void init_contrast(struct atmel_lcdfb_info *sinfo)
+-{
+- /* contrast pwm can be 'inverted' */
+- if (sinfo->lcdcon_pol_negative)
+- contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
+-
+- /* have some default contrast/backlight settings */
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+-
+- if (sinfo->lcdcon_is_backlight)
+- init_backlight(sinfo);
+-}
+-
+-
+ static struct fb_fix_screeninfo atmel_lcdfb_fix = {
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
+@@ -783,7 +721,10 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ }
+
+ /* Initialize PWM for contrast or backlight ("off") */
+- init_contrast(sinfo);
++ if (sinfo->dev_data->init_contrast)
++ sinfo->dev_data->init_contrast(sinfo);
++ if (sinfo->lcdcon_is_backlight)
++ init_backlight(sinfo);
+
+ /* interrupt */
+ if (sinfo->irq_base >= 0) {
+diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
+index 14b5664..e7c0a3f 100644
+--- a/include/video/atmel_lcdc.h
++++ b/include/video/atmel_lcdc.h
+@@ -24,6 +24,7 @@
+
+ #include <linux/workqueue.h>
+ #include <linux/interrupt.h>
++#include <linux/backlight.h>
+
+ /* Way LCD wires are connected to the chip:
+ * Some Atmel chips use BGR color mode (instead of standard RGB)
+@@ -48,6 +49,8 @@ struct atmel_lcdfb_devdata {
+ void (*start)(struct atmel_lcdfb_info *sinfo);
+ void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags);
+ irqreturn_t (*isr)(int irq, void *dev_id);
++ void (*init_contrast)(struct atmel_lcdfb_info *sinfo);
++ const struct backlight_ops *bl_ops;
+ };
+
+ /* LCD Controller info data structure, stored in device platform_data */
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0078-video-atmelfb-refactor-dma_update.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0078-video-atmelfb-refactor-dma_update.patch
new file mode 100644
index 0000000..5af1159
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0078-video-atmelfb-refactor-dma_update.patch
@@ -0,0 +1,211 @@
+From f1495d8f9cdd7d7c142776f83568b145533884ef Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Fri, 20 May 2011 14:31:29 +0200
+Subject: [PATCH 078/107] video: atmelfb: refactor dma_update
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/atmel_lcdfb.c | 55 ++++++++++++++++++++++++++++++++++
+ drivers/video/atmel_lcdfb_core.c | 61 +++----------------------------------
+ include/video/atmel_lcdc.h | 2 +
+ 3 files changed, 62 insertions(+), 56 deletions(-)
+
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 046e6c5..cd6d22e 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -31,6 +31,59 @@ static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
+ | ATMEL_LCDC_POL_POSITIVE
+ | ATMEL_LCDC_ENA_PWMENABLE;
+
++#if defined(CONFIG_ARCH_AT91)
++#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
++ | FBINFO_PARTIAL_PAN_OK \
++ | FBINFO_HWACCEL_YPAN)
++
++static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
++ struct fb_var_screeninfo *var)
++{
++
++}
++#elif defined(CONFIG_AVR32)
++#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
++ | FBINFO_PARTIAL_PAN_OK \
++ | FBINFO_HWACCEL_XPAN \
++ | FBINFO_HWACCEL_YPAN)
++
++static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
++ struct fb_var_screeninfo *var)
++{
++ u32 dma2dcfg;
++ u32 pixeloff;
++
++ pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f;
++
++ dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8;
++ dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
++ lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
++
++ /* Update configuration */
++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON,
++ lcdc_readl(sinfo, ATMEL_LCDC_DMACON)
++ | ATMEL_LCDC_DMAUPDT);
++}
++#endif
++
++static void atmel_lcdfb_update_dma(struct fb_info *info,
++ struct fb_var_screeninfo *var)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ struct fb_fix_screeninfo *fix = &info->fix;
++ unsigned long dma_addr;
++
++ dma_addr = (fix->smem_start + var->yoffset * fix->line_length
++ + var->xoffset * var->bits_per_pixel / 8);
++
++ dma_addr &= ~3UL;
++
++ /* Set framebuffer DMA base address and pixel offset */
++ lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
++
++ atmel_lcdfb_update_dma2d(sinfo, var);
++}
++
+ /* some bl->props field just changed */
+ static int atmel_bl_update_status(struct backlight_device *bl)
+ {
+@@ -323,8 +376,10 @@ static struct atmel_lcdfb_devdata dev_data = {
+ .start = atmel_lcdfb_start,
+ .stop = atmel_lcdfb_stop,
+ .isr = atmel_lcdfb_interrupt,
++ .update_dma = atmel_lcdfb_update_dma,
+ .bl_ops = &atmel_lcdc_bl_ops,
+ .init_contrast = atmel_lcdfb_init_contrast,
++ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
+ };
+
+ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index ef63996..4146e9b 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -27,41 +27,6 @@
+ /* configurable parameters */
+ #define ATMEL_LCDC_CVAL_DEFAULT 0xc8
+
+-#if defined(CONFIG_ARCH_AT91)
+-#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
+- | FBINFO_PARTIAL_PAN_OK \
+- | FBINFO_HWACCEL_YPAN)
+-
+-static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+- struct fb_var_screeninfo *var)
+-{
+-
+-}
+-#elif defined(CONFIG_AVR32)
+-#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
+- | FBINFO_PARTIAL_PAN_OK \
+- | FBINFO_HWACCEL_XPAN \
+- | FBINFO_HWACCEL_YPAN)
+-
+-static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+- struct fb_var_screeninfo *var)
+-{
+- u32 dma2dcfg;
+- u32 pixeloff;
+-
+- pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f;
+-
+- dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8;
+- dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
+- lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
+-
+- /* Update configuration */
+- lcdc_writel(sinfo, ATMEL_LCDC_DMACON,
+- lcdc_readl(sinfo, ATMEL_LCDC_DMACON)
+- | ATMEL_LCDC_DMAUPDT);
+-}
+-#endif
+-
+ #ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+
+ static void init_backlight(struct atmel_lcdfb_info *sinfo)
+@@ -119,24 +84,6 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix = {
+ .accel = FB_ACCEL_NONE,
+ };
+
+-static void atmel_lcdfb_update_dma(struct fb_info *info,
+- struct fb_var_screeninfo *var)
+-{
+- struct atmel_lcdfb_info *sinfo = info->par;
+- struct fb_fix_screeninfo *fix = &info->fix;
+- unsigned long dma_addr;
+-
+- dma_addr = (fix->smem_start + var->yoffset * fix->line_length
+- + var->xoffset * var->bits_per_pixel / 8);
+-
+- dma_addr &= ~3UL;
+-
+- /* Set framebuffer DMA base address and pixel offset */
+- lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
+-
+- atmel_lcdfb_update_dma2d(sinfo, var);
+-}
+-
+ static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
+ {
+ struct fb_info *info = sinfo->info;
+@@ -392,7 +339,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
+
+ /* Re-initialize the DMA engine... */
+ dev_dbg(info->device, " * update DMA engine\n");
+- atmel_lcdfb_update_dma(info, &info->var);
++ sinfo->dev_data->update_dma(info, &info->var);
+
+ /* Now, the LCDC core... */
+ sinfo->dev_data->setup_core(info);
+@@ -496,9 +443,11 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
+ static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+ {
++ struct atmel_lcdfb_info *sinfo = info->par;
++
+ dev_dbg(info->device, "%s\n", __func__);
+
+- atmel_lcdfb_update_dma(info, var);
++ sinfo->dev_data->update_dma(info, var);
+
+ return 0;
+ }
+@@ -633,7 +582,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ sinfo->pdev = pdev;
+
+ strcpy(info->fix.id, sinfo->pdev->name);
+- info->flags = ATMEL_LCDFB_FBINFO_DEFAULT;
++ info->flags = dev_data->fbinfo_flags;
+ info->pseudo_palette = sinfo->pseudo_palette;
+ info->fbops = &atmel_lcdfb_ops;
+
+diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
+index e7c0a3f..866ab47 100644
+--- a/include/video/atmel_lcdc.h
++++ b/include/video/atmel_lcdc.h
+@@ -49,8 +49,10 @@ struct atmel_lcdfb_devdata {
+ void (*start)(struct atmel_lcdfb_info *sinfo);
+ void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags);
+ irqreturn_t (*isr)(int irq, void *dev_id);
++ void (*update_dma)(struct fb_info *info, struct fb_var_screeninfo *var);
+ void (*init_contrast)(struct atmel_lcdfb_info *sinfo);
+ const struct backlight_ops *bl_ops;
++ int fbinfo_flags;
+ };
+
+ /* LCD Controller info data structure, stored in device platform_data */
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0079-video-atmelfb-refactor-LUT.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0079-video-atmelfb-refactor-LUT.patch
new file mode 100644
index 0000000..ab76f70
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0079-video-atmelfb-refactor-LUT.patch
@@ -0,0 +1,80 @@
+From e765be3c1f14cafb2c8c9ffcd0dd6504c37a20d1 Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Fri, 20 May 2011 14:51:45 +0200
+Subject: [PATCH 079/107] video: atmelfb: refactor LUT
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/atmel_lcdfb.c | 1 +
+ drivers/video/atmel_lcdfb_core.c | 6 ++++--
+ include/video/atmel_lcdc.h | 8 ++------
+ 3 files changed, 7 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index cd6d22e..f8993cd 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -380,6 +380,7 @@ static struct atmel_lcdfb_devdata dev_data = {
+ .bl_ops = &atmel_lcdc_bl_ops,
+ .init_contrast = atmel_lcdfb_init_contrast,
+ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
++ .lut_base = ATMEL_LCDC_LUT,
+ };
+
+ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index 4146e9b..0edafb6 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -422,7 +422,8 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
+ * ~(red[10] ^ green[10] ^ blue[10]) & 1
+ */
+
+- lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
++ lcdc_writel(sinfo, sinfo->dev_data->lut_base + regno * 4,
++ val);
+ ret = 0;
+ }
+ break;
+@@ -430,7 +431,8 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
+ case FB_VISUAL_MONO01:
+ if (regno < 2) {
+ val = (regno == 0) ? 0x00 : 0x1F;
+- lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
++ lcdc_writel(sinfo, sinfo->dev_data->lut_base + regno * 4,
++ val);
+ ret = 0;
+ }
+ break;
+diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
+index 866ab47..6c470c4 100644
+--- a/include/video/atmel_lcdc.h
++++ b/include/video/atmel_lcdc.h
+@@ -53,6 +53,7 @@ struct atmel_lcdfb_devdata {
+ void (*init_contrast)(struct atmel_lcdfb_info *sinfo);
+ const struct backlight_ops *bl_ops;
+ int fbinfo_flags;
++ u32 lut_base;
+ };
+
+ /* LCD Controller info data structure, stored in device platform_data */
+@@ -241,11 +242,6 @@ struct atmel_lcdfb_info {
+ #define ATMEL_LCDC_OWRI (1 << 5)
+ #define ATMEL_LCDC_MERI (1 << 6)
+
+-#if !defined(CONFIG_ARCH_AT91SAM9X5)
+-#define ATMEL_LCDC_LUT(n) (0x0c00 + ((n)*4))
+-#else
+-/* Base layer CLUT */
+-#define ATMEL_LCDC_LUT(n) (0x0400 + ((n)*4))
+-#endif
++#define ATMEL_LCDC_LUT 0x0c00
+
+ #endif /* __ATMEL_LCDC_H__ */
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0080-video-atmelfb-refactor-limit_screeninfo.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0080-video-atmelfb-refactor-limit_screeninfo.patch
new file mode 100644
index 0000000..d115da5
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0080-video-atmelfb-refactor-limit_screeninfo.patch
@@ -0,0 +1,92 @@
+From 41af945f4205a245cbb3a4227a4b8407df628e03 Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Fri, 20 May 2011 15:04:10 +0200
+Subject: [PATCH 080/107] video: atmelfb: refactor limit_screeninfo
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/atmel_lcdfb.c | 18 ++++++++++++++++++
+ drivers/video/atmel_lcdfb_core.c | 14 ++------------
+ include/video/atmel_lcdc.h | 1 +
+ 3 files changed, 21 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index f8993cd..7a48e9c 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -306,6 +306,23 @@ static int atmel_lcdfb_setup_core(struct fb_info *info)
+ return 0;
+ }
+
++static void atmelfb_limit_screeninfo(struct fb_var_screeninfo *var)
++{
++ /* Saturate vertical and horizontal timings at maximum values */
++ var->vsync_len = min_t(u32, var->vsync_len,
++ (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
++ var->upper_margin = min_t(u32, var->upper_margin,
++ ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
++ var->lower_margin = min_t(u32, var->lower_margin,
++ ATMEL_LCDC_VFP);
++ var->right_margin = min_t(u32, var->right_margin,
++ (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
++ var->hsync_len = min_t(u32, var->hsync_len,
++ (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
++ var->left_margin = min_t(u32, var->left_margin,
++ ATMEL_LCDC_HBP + 1);
++}
++
+ static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
+ {
+ struct fb_info *info = dev_id;
+@@ -379,6 +396,7 @@ static struct atmel_lcdfb_devdata dev_data = {
+ .update_dma = atmel_lcdfb_update_dma,
+ .bl_ops = &atmel_lcdc_bl_ops,
+ .init_contrast = atmel_lcdfb_init_contrast,
++ .limit_screeninfo = atmelfb_limit_screeninfo,
+ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
+ .lut_base = ATMEL_LCDC_LUT,
+ };
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index 0edafb6..20a4e4f 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -211,18 +211,8 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
+ }
+
+ /* Saturate vertical and horizontal timings at maximum values */
+- var->vsync_len = min_t(u32, var->vsync_len,
+- (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
+- var->upper_margin = min_t(u32, var->upper_margin,
+- ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
+- var->lower_margin = min_t(u32, var->lower_margin,
+- ATMEL_LCDC_VFP);
+- var->right_margin = min_t(u32, var->right_margin,
+- (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
+- var->hsync_len = min_t(u32, var->hsync_len,
+- (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
+- var->left_margin = min_t(u32, var->left_margin,
+- ATMEL_LCDC_HBP + 1);
++ if (sinfo->dev_data->limit_screeninfo)
++ sinfo->dev_data->limit_screeninfo(var);
+
+ /* Some parameters can't be zero */
+ var->vsync_len = max_t(u32, var->vsync_len, 1);
+diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
+index 6c470c4..6031b5a 100644
+--- a/include/video/atmel_lcdc.h
++++ b/include/video/atmel_lcdc.h
+@@ -51,6 +51,7 @@ struct atmel_lcdfb_devdata {
+ irqreturn_t (*isr)(int irq, void *dev_id);
+ void (*update_dma)(struct fb_info *info, struct fb_var_screeninfo *var);
+ void (*init_contrast)(struct atmel_lcdfb_info *sinfo);
++ void (*limit_screeninfo)(struct fb_var_screeninfo *var);
+ const struct backlight_ops *bl_ops;
+ int fbinfo_flags;
+ u32 lut_base;
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0081-arm-at91-refactor-lcdc-includes.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0081-arm-at91-refactor-lcdc-includes.patch
new file mode 100644
index 0000000..61135dd
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0081-arm-at91-refactor-lcdc-includes.patch
@@ -0,0 +1,2648 @@
+From 49526d6bdc4a61e24b8d68fa68cb3718ab936353 Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Wed, 25 May 2011 15:38:50 +0200
+Subject: [PATCH 081/107] arm: at91: refactor lcdc-includes
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Among others the HEO-ISR bit is fixed.
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ arch/arm/mach-at91/at91cap9_devices.c | 3 +-
+ arch/arm/mach-at91/at91sam9261_devices.c | 3 +-
+ arch/arm/mach-at91/at91sam9263_devices.c | 3 +-
+ arch/arm/mach-at91/at91sam9g45_devices.c | 3 +-
+ arch/arm/mach-at91/at91sam9rl_devices.c | 3 +-
+ arch/arm/mach-at91/at91sam9x5_devices.c | 6 +-
+ arch/arm/mach-at91/board-cap9adk.c | 3 +-
+ arch/arm/mach-at91/board-neocore926.c | 3 +-
+ arch/arm/mach-at91/board-sam9261ek.c | 3 +-
+ arch/arm/mach-at91/board-sam9263ek.c | 3 +-
+ arch/arm/mach-at91/board-sam9m10g45ek.c | 3 +-
+ arch/arm/mach-at91/board-sam9rlek.c | 3 +-
+ arch/arm/mach-at91/board-sam9x5cm.c | 2 +-
+ arch/arm/mach-at91/board-sam9x5ek.c | 4 +-
+ arch/arm/mach-at91/include/mach/atmel_hlcdc.h | 721 +++++++++++++++++
+ arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h | 156 ++++
+ arch/arm/mach-at91/include/mach/atmel_hlcdfb.h | 868 ---------------------
+ arch/arm/mach-at91/include/mach/atmel_lcdc.h | 177 +++++
+ drivers/video/atmel_lcdfb.c | 3 +-
+ drivers/video/atmel_lcdfb_core.c | 2 +-
+ include/video/atmel_lcdc.h | 248 ------
+ include/video/atmel_lcdfb.h | 100 +++
+ 22 files changed, 1185 insertions(+), 1135 deletions(-)
+ create mode 100644 arch/arm/mach-at91/include/mach/atmel_hlcdc.h
+ create mode 100644 arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h
+ delete mode 100644 arch/arm/mach-at91/include/mach/atmel_hlcdfb.h
+ create mode 100644 arch/arm/mach-at91/include/mach/atmel_lcdc.h
+ delete mode 100644 include/video/atmel_lcdc.h
+ create mode 100644 include/video/atmel_lcdfb.h
+
+diff --git a/arch/arm/mach-at91/at91cap9_devices.c b/arch/arm/mach-at91/at91cap9_devices.c
+index 9ffbf3a..3398087 100644
+--- a/arch/arm/mach-at91/at91cap9_devices.c
++++ b/arch/arm/mach-at91/at91cap9_devices.c
+@@ -19,11 +19,12 @@
+ #include <linux/platform_device.h>
+ #include <linux/i2c-gpio.h>
+
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ #include <mach/board.h>
+ #include <mach/cpu.h>
+ #include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91cap9.h>
+ #include <mach/at91cap9_matrix.h>
+ #include <mach/at91sam9_smc.h>
+diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
+index 59fc483..24301b2 100644
+--- a/arch/arm/mach-at91/at91sam9261_devices.c
++++ b/arch/arm/mach-at91/at91sam9261_devices.c
+@@ -18,10 +18,11 @@
+ #include <linux/i2c-gpio.h>
+
+ #include <linux/fb.h>
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ #include <mach/board.h>
+ #include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91sam9261.h>
+ #include <mach/at91sam9261_matrix.h>
+ #include <mach/at91sam9_smc.h>
+diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
+index fb5c23a..9bb45ae 100644
+--- a/arch/arm/mach-at91/at91sam9263_devices.c
++++ b/arch/arm/mach-at91/at91sam9263_devices.c
+@@ -17,10 +17,11 @@
+ #include <linux/i2c-gpio.h>
+
+ #include <linux/fb.h>
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ #include <mach/board.h>
+ #include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91sam9263.h>
+ #include <mach/at91sam9263_matrix.h>
+ #include <mach/at91sam9_smc.h>
+diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
+index 1e8f275..f40b254 100644
+--- a/arch/arm/mach-at91/at91sam9g45_devices.c
++++ b/arch/arm/mach-at91/at91sam9g45_devices.c
+@@ -18,10 +18,11 @@
+ #include <linux/atmel-mci.h>
+
+ #include <linux/fb.h>
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ #include <mach/board.h>
+ #include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91sam9g45.h>
+ #include <mach/at91sam9g45_matrix.h>
+ #include <mach/at91sam9_smc.h>
+diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
+index 53aaa94..7ca92f1 100644
+--- a/arch/arm/mach-at91/at91sam9rl_devices.c
++++ b/arch/arm/mach-at91/at91sam9rl_devices.c
+@@ -14,10 +14,11 @@
+ #include <linux/i2c-gpio.h>
+
+ #include <linux/fb.h>
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ #include <mach/board.h>
+ #include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91sam9rl.h>
+ #include <mach/at91sam9rl_matrix.h>
+ #include <mach/at91sam9_smc.h>
+diff --git a/arch/arm/mach-at91/at91sam9x5_devices.c b/arch/arm/mach-at91/at91sam9x5_devices.c
+index e601ae4..36a192a 100644
+--- a/arch/arm/mach-at91/at91sam9x5_devices.c
++++ b/arch/arm/mach-at91/at91sam9x5_devices.c
+@@ -16,13 +16,13 @@
+ #include <linux/platform_device.h>
+ #include <linux/i2c-gpio.h>
+ #include <linux/atmel-mci.h>
+-
+ #include <linux/fb.h>
+-#include <video/atmel_lcdc.h>
+-#include <mach/atmel_hlcdfb.h>
++
++#include <video/atmel_lcdfb.h>
+
+ #include <mach/board.h>
+ #include <mach/gpio.h>
++#include <mach/atmel_hlcdc.h>
+ #include <mach/cpu.h>
+ #include <mach/at91sam9x5.h>
+ #include <mach/at91sam9x5_matrix.h>
+diff --git a/arch/arm/mach-at91/board-cap9adk.c b/arch/arm/mach-at91/board-cap9adk.c
+index e727444..017c7f4 100644
+--- a/arch/arm/mach-at91/board-cap9adk.c
++++ b/arch/arm/mach-at91/board-cap9adk.c
+@@ -31,7 +31,7 @@
+ #include <linux/fb.h>
+ #include <linux/mtd/physmap.h>
+
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ #include <mach/hardware.h>
+ #include <asm/setup.h>
+@@ -42,6 +42,7 @@
+
+ #include <mach/board.h>
+ #include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91cap9_matrix.h>
+ #include <mach/at91sam9_smc.h>
+
+diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
+index fe5f1d4..7dd7f18 100644
+--- a/arch/arm/mach-at91/board-neocore926.c
++++ b/arch/arm/mach-at91/board-neocore926.c
+@@ -31,7 +31,7 @@
+ #include <linux/gpio_keys.h>
+ #include <linux/input.h>
+
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ #include <asm/setup.h>
+ #include <asm/mach-types.h>
+@@ -45,6 +45,7 @@
+ #include <mach/hardware.h>
+ #include <mach/board.h>
+ #include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91sam9_smc.h>
+
+ #include "sam9_smc.h"
+diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
+index 14acc90..b737e59 100644
+--- a/arch/arm/mach-at91/board-sam9261ek.c
++++ b/arch/arm/mach-at91/board-sam9261ek.c
+@@ -33,7 +33,7 @@
+ #include <linux/gpio_keys.h>
+ #include <linux/input.h>
+
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ #include <asm/setup.h>
+ #include <asm/mach-types.h>
+@@ -46,6 +46,7 @@
+ #include <mach/hardware.h>
+ #include <mach/board.h>
+ #include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+
+diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
+index bfe490d..3640554 100644
+--- a/arch/arm/mach-at91/board-sam9263ek.c
++++ b/arch/arm/mach-at91/board-sam9263ek.c
+@@ -32,7 +32,7 @@
+ #include <linux/input.h>
+ #include <linux/leds.h>
+
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ #include <asm/setup.h>
+ #include <asm/mach-types.h>
+@@ -45,6 +45,7 @@
+ #include <mach/hardware.h>
+ #include <mach/board.h>
+ #include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+
+diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
+index 6c999db..b2b1a8b 100644
+--- a/arch/arm/mach-at91/board-sam9m10g45ek.c
++++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
+@@ -27,7 +27,7 @@
+ #include <linux/atmel-mci.h>
+
+ #include <mach/hardware.h>
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ #include <asm/setup.h>
+ #include <asm/mach-types.h>
+@@ -39,6 +39,7 @@
+
+ #include <mach/board.h>
+ #include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+
+diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
+index 3bf3408..721186f 100644
+--- a/arch/arm/mach-at91/board-sam9rlek.c
++++ b/arch/arm/mach-at91/board-sam9rlek.c
+@@ -18,7 +18,7 @@
+ #include <linux/input.h>
+ #include <linux/gpio_keys.h>
+
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ #include <asm/setup.h>
+ #include <asm/mach-types.h>
+@@ -31,6 +31,7 @@
+ #include <mach/hardware.h>
+ #include <mach/board.h>
+ #include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+
+diff --git a/arch/arm/mach-at91/board-sam9x5cm.c b/arch/arm/mach-at91/board-sam9x5cm.c
+index 4fcc150..53d8046 100644
+--- a/arch/arm/mach-at91/board-sam9x5cm.c
++++ b/arch/arm/mach-at91/board-sam9x5cm.c
+@@ -24,7 +24,7 @@
+ #include <linux/clk.h>
+ #include <mach/cpu.h>
+
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ #include <asm/setup.h>
+ #include <asm/mach-types.h>
+diff --git a/arch/arm/mach-at91/board-sam9x5ek.c b/arch/arm/mach-at91/board-sam9x5ek.c
+index d86124c..a005b69 100644
+--- a/arch/arm/mach-at91/board-sam9x5ek.c
++++ b/arch/arm/mach-at91/board-sam9x5ek.c
+@@ -24,8 +24,7 @@
+ #include <linux/clk.h>
+ #include <mach/cpu.h>
+
+-#include <video/atmel_lcdc.h>
+-#include <mach/atmel_hlcdfb.h>
++#include <video/atmel_lcdfb.h>
+
+ #include <asm/setup.h>
+ #include <asm/mach-types.h>
+@@ -38,6 +37,7 @@
+ #include <mach/hardware.h>
+ #include <mach/board.h>
+ #include <mach/gpio.h>
++#include <mach/atmel_hlcdc.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+
+diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdc.h b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
+new file mode 100644
+index 0000000..0b26f27
+--- /dev/null
++++ b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
+@@ -0,0 +1,721 @@
++/*
++ * Header file for AT91 High end LCD Controller
++ *
++ * Data structure and register user interface
++ *
++ * Copyright (C) 2010 Atmel Corporation
++ *
++ * 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.
++ *
++ * 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 PUROFFSETE. 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 __MACH_ATMEL_HLCD_H__
++#define __MACH_ATMEL_HLCD_H__
++
++/* Lcdc hardware registers */
++#define ATMEL_LCDC_LCDCFG0 0x0000
++#define LCDC_LCDCFG0_CLKPOL (0x1 << 0)
++#define LCDC_LCDCFG0_CLKSEL (0x1 << 2)
++#define LCDC_LCDCFG0_CLKPWMSEL (0x1 << 3)
++#define LCDC_LCDCFG0_CGDISBASE (0x1 << 8)
++#define LCDC_LCDCFG0_CGDISOVR1 (0x1 << 9)
++/* XXX: maybe this is 1 << 10? At least the LCD Interrupt registers
++ * use 10 while the documentation specifies 11.
++ */
++#define LCDC_LCDCFG0_CGDISHEO (0x1 << 11)
++#define LCDC_LCDCFG0_CGDISHCR (0x1 << 12)
++#define LCDC_LCDCFG0_CLKDIV_OFFSET 16
++#define LCDC_LCDCFG0_CLKDIV (0xff << LCDC_LCDCFG0_CLKDIV_OFFSET)
++
++#define ATMEL_LCDC_LCDCFG1 0x0004
++#define LCDC_LCDCFG1_HSPW_OFFSET 0
++#define LCDC_LCDCFG1_HSPW (0x3f << LCDC_LCDCFG1_HSPW_OFFSET)
++#define LCDC_LCDCFG1_VSPW_OFFSET 16
++#define LCDC_LCDCFG1_VSPW (0x3f << LCDC_LCDCFG1_VSPW_OFFSET)
++
++#define ATMEL_LCDC_LCDCFG2 0x0008
++#define LCDC_LCDCFG2_VFPW_OFFSET 0
++#define LCDC_LCDCFG2_VFPW (0x3f << LCDC_LCDCFG2_VFPW_OFFSET)
++#define LCDC_LCDCFG2_VBPW_OFFSET 16
++#define LCDC_LCDCFG2_VBPW (0x3f << LCDC_LCDCFG2_VBPW_OFFSET)
++
++#define ATMEL_LCDC_LCDCFG3 0x000C
++#define LCDC_LCDCFG3_HFPW_OFFSET 0
++#define LCDC_LCDCFG3_HFPW (0xff << LCDC_LCDCFG3_HFPW_OFFSET)
++#define LCDC_LCDCFG3_HBPW_OFFSET 16
++#define LCDC_LCDCFG3_HBPW (0xff << LCDC_LCDCFG3_HBPW_OFFSET)
++
++#define ATMEL_LCDC_LCDCFG4 0x0010
++#define LCDC_LCDCFG4_PPL_OFFSET 0
++#define LCDC_LCDCFG4_PPL (0x7ff << LCDC_LCDCFG4_PPL_OFFSET)
++#define LCDC_LCDCFG4_RPF_OFFSET 16
++#define LCDC_LCDCFG4_RPF (0x7ff << LCDC_LCDCFG4_RPF_OFFSET)
++
++#define ATMEL_LCDC_LCDCFG5 0x0014
++#define LCDC_LCDCFG5_HSPOL (0x1 << 0)
++#define LCDC_LCDCFG5_VSPOL (0x1 << 1)
++#define LCDC_LCDCFG5_VSPDLYS (0x1 << 2)
++#define LCDC_LCDCFG5_VSPDLYE (0x1 << 3)
++#define LCDC_LCDCFG5_DISPPOL (0x1 << 4)
++#define LCDC_LCDCFG5_SERIAL (0x1 << 5)
++#define LCDC_LCDCFG5_DITHER (0x1 << 6)
++#define LCDC_LCDCFG5_DISPDLY (0x1 << 7)
++#define LCDC_LCDCFG5_MODE_OFFSET 8
++#define LCDC_LCDCFG5_MODE (0x3 << LCDC_LCDCFG5_MODE_OFFSET)
++#define LCDC_LCDCFG5_MODE_OUTPUT_12BPP (0x0 << 8)
++#define LCDC_LCDCFG5_MODE_OUTPUT_16BPP (0x1 << 8)
++#define LCDC_LCDCFG5_MODE_OUTPUT_18BPP (0x2 << 8)
++#define LCDC_LCDCFG5_MODE_OUTPUT_24BPP (0x3 << 8)
++#define LCDC_LCDCFG5_VSPSU (0x1 << 12)
++#define LCDC_LCDCFG5_VSPHO (0x1 << 13)
++#define LCDC_LCDCFG5_GUARDTIME_OFFSET 16
++#define LCDC_LCDCFG5_GUARDTIME (0x1f << LCDC_LCDCFG5_GUARDTIME_OFFSET)
++
++#define ATMEL_LCDC_LCDCFG6 0x0018
++#define LCDC_LCDCFG6_PWMPS_OFFSET 0
++#define LCDC_LCDCFG6_PWMPS (0x7 << LCDC_LCDCFG6_PWMPS_OFFSET)
++#define LCDC_LCDCFG6_PWMPOL (0x1 << 4)
++#define LCDC_LCDCFG6_PWMCVAL_OFFSET 8
++#define LCDC_LCDCFG6_PWMCVAL (0xff << LCDC_LCDCFG6_PWMCVAL_OFFSET)
++
++#define ATMEL_LCDC_LCDEN 0x0020
++#define LCDC_LCDEN_CLKEN (0x1 << 0)
++#define LCDC_LCDEN_SYNCEN (0x1 << 1)
++#define LCDC_LCDEN_DISPEN (0x1 << 2)
++#define LCDC_LCDEN_PWMEN (0x1 << 3)
++
++#define ATMEL_LCDC_LCDDIS 0x0024
++#define LCDC_LCDDIS_CLKDIS (0x1 << 0)
++#define LCDC_LCDDIS_SYNCDIS (0x1 << 1)
++#define LCDC_LCDDIS_DISPDIS (0x1 << 2)
++#define LCDC_LCDDIS_PWMDIS (0x1 << 3)
++#define LCDC_LCDDIS_CLKRST (0x1 << 8)
++#define LCDC_LCDDIS_SYNCRST (0x1 << 9)
++#define LCDC_LCDDIS_DISPRST (0x1 << 10)
++#define LCDC_LCDDIS_PWMRST (0x1 << 11)
++
++#define ATMEL_LCDC_LCDSR 0x0028
++#define LCDC_LCDSR_CLKSTS (0x1 << 0)
++#define LCDC_LCDSR_LCDSTS (0x1 << 1)
++#define LCDC_LCDSR_DISPSTS (0x1 << 2)
++#define LCDC_LCDSR_PWMSTS (0x1 << 3)
++#define LCDC_LCDSR_SIPSTS (0x1 << 4)
++
++#define ATMEL_LCDC_LCDIER 0x002C
++#define LCDC_LCDIER_SOFIE (0x1 << 0)
++#define LCDC_LCDIER_DISIE (0x1 << 1)
++#define LCDC_LCDIER_DISPIE (0x1 << 2)
++#define LCDC_LCDIER_FIFOERRIE (0x1 << 4)
++#define LCDC_LCDIER_BASEIE (0x1 << 8)
++#define LCDC_LCDIER_OVR1IE (0x1 << 9)
++#define LCDC_LCDIER_HEOIE (0x1 << 10)
++#define LCDC_LCDIER_HCRIE (0x1 << 12)
++
++#define ATMEL_LCDC_LCDIDR 0x0030
++#define LCDC_LCDIDR_SOFID (0x1 << 0)
++#define LCDC_LCDIDR_DISID (0x1 << 1)
++#define LCDC_LCDIDR_DISPID (0x1 << 2)
++#define LCDC_LCDIDR_FIFOERRID (0x1 << 4)
++#define LCDC_LCDIDR_BASEID (0x1 << 8)
++#define LCDC_LCDIDR_OVR1ID (0x1 << 9)
++#define LCDC_LCDIDR_HEOID (0x1 << 10)
++#define LCDC_LCDIDR_HCRID (0x1 << 12)
++
++#define ATMEL_LCDC_LCDIMR 0x0034
++#define LCDC_LCDIMR_SOFIM (0x1 << 0)
++#define LCDC_LCDIMR_DISIM (0x1 << 1)
++#define LCDC_LCDIMR_DISPIM (0x1 << 2)
++#define LCDC_LCDIMR_FIFOERRIM (0x1 << 4)
++#define LCDC_LCDIMR_BASEIM (0x1 << 8)
++#define LCDC_LCDIMR_OVR1IM (0x1 << 9)
++#define LCDC_LCDIMR_HEOIM (0x1 << 10)
++#define LCDC_LCDIMR_HCRIM (0x1 << 12)
++
++#define ATMEL_LCDC_LCDISR 0x0038
++#define LCDC_LCDISR_SOF (0x1 << 0)
++#define LCDC_LCDISR_DIS (0x1 << 1)
++#define LCDC_LCDISR_DISP (0x1 << 2)
++#define LCDC_LCDISR_FIFOERR (0x1 << 4)
++#define LCDC_LCDISR_BASE (0x1 << 8)
++#define LCDC_LCDISR_OVR1 (0x1 << 9)
++#define LCDC_LCDISR_HEO (0x1 << 10)
++#define LCDC_LCDISR_HCR (0x1 << 12)
++
++#define ATMEL_LCDC_BASECHER 0x0040
++#define LCDC_BASECHER_CHEN (0x1 << 0)
++#define LCDC_BASECHER_UPDATEEN (0x1 << 1)
++#define LCDC_BASECHER_A2QEN (0x1 << 2)
++
++#define ATMEL_LCDC_BASECHDR 0x0044
++#define LCDC_BASECHDR_CHDIS (0x1 << 0)
++#define LCDC_BASECHDR_CHRST (0x1 << 8)
++
++#define ATMEL_LCDC_BASECHSR 0x0048
++#define LCDC_BASECHSR_CHSR (0x1 << 0)
++#define LCDC_BASECHSR_UPDATESR (0x1 << 1)
++#define LCDC_BASECHSR_A2QSR (0x1 << 2)
++
++#define ATMEL_LCDC_BASEIER 0x004C
++#define LCDC_BASEIER_DMA (0x1 << 2)
++#define LCDC_BASEIER_DSCR (0x1 << 3)
++#define LCDC_BASEIER_ADD (0x1 << 4)
++#define LCDC_BASEIER_DONE (0x1 << 5)
++#define LCDC_BASEIER_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_BASEIDR 0x0050
++#define LCDC_BASEIDR_DMA (0x1 << 2)
++#define LCDC_BASEIDR_DSCR (0x1 << 3)
++#define LCDC_BASEIDR_ADD (0x1 << 4)
++#define LCDC_BASEIDR_DONE (0x1 << 5)
++#define LCDC_BASEIDR_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_BASEIMR 0x0054
++#define LCDC_BASEIMR_DMA (0x1 << 2)
++#define LCDC_BASEIMR_DSCR (0x1 << 3)
++#define LCDC_BASEIMR_ADD (0x1 << 4)
++#define LCDC_BASEIMR_DONE (0x1 << 5)
++#define LCDC_BASEIMR_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_BASEISR 0x0058
++#define LCDC_BASEISR_DMA (0x1 << 2)
++#define LCDC_BASEISR_DSCR (0x1 << 3)
++#define LCDC_BASEISR_ADD (0x1 << 4)
++#define LCDC_BASEISR_DONE (0x1 << 5)
++#define LCDC_BASEISR_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_BASEHEAD 0x005C
++
++#define ATMEL_LCDC_BASEADDR 0x0060
++
++#define ATMEL_LCDC_BASECTRL 0x0064
++#define LCDC_BASECTRL_DFETCH (0x1 << 0)
++#define LCDC_BASECTRL_LFETCH (0x1 << 1)
++#define LCDC_BASECTRL_DMAIEN (0x1 << 2)
++#define LCDC_BASECTRL_DSCRIEN (0x1 << 3)
++#define LCDC_BASECTRL_ADDIEN (0x1 << 4)
++#define LCDC_BASECTRL_DONEIEN (0x1 << 5)
++
++#define ATMEL_LCDC_BASENEXT 0x0068
++
++#define ATMEL_LCDC_BASECFG0 0x006C
++#define LCDC_BASECFG0_BLEN_OFFSET 4
++#define LCDC_BASECFG0_BLEN (0x3 << LCDC_BASECFG0_BLEN_OFFSET)
++#define LCDC_BASECFG0_BLEN_AHB_SINGLE (0x0 << 4)
++#define LCDC_BASECFG0_BLEN_AHB_INCR4 (0x1 << 4)
++#define LCDC_BASECFG0_BLEN_AHB_INCR8 (0x2 << 4)
++#define LCDC_BASECFG0_BLEN_AHB_INCR16 (0x3 << 4)
++#define LCDC_BASECFG0_DLBO (0x1 << 8)
++
++#define ATMEL_LCDC_BASECFG1 0x0070
++#define LCDC_BASECFG1_CLUTEN (0x1 << 0)
++#define LCDC_BASECFG1_RGBMODE_OFFSET 4
++#define LCDC_BASECFG1_RGBMODE (0xf << LCDC_BASECFG1_RGBMODE_OFFSET)
++#define LCDC_BASECFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
++#define LCDC_BASECFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
++#define LCDC_BASECFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
++#define LCDC_BASECFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
++#define LCDC_BASECFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
++#define LCDC_BASECFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
++#define LCDC_BASECFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
++#define LCDC_BASECFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
++#define LCDC_BASECFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
++#define LCDC_BASECFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
++#define LCDC_BASECFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
++#define LCDC_BASECFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
++#define LCDC_BASECFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
++#define LCDC_BASECFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
++#define LCDC_BASECFG1_CLUTMODE_OFFSET 8
++#define LCDC_BASECFG1_CLUTMODE (0x3 << LCDC_BASECFG1_CLUTMODE_OFFSET)
++#define LCDC_BASECFG1_CLUTMODE_1BPP (0x0 << 8)
++#define LCDC_BASECFG1_CLUTMODE_2BPP (0x1 << 8)
++#define LCDC_BASECFG1_CLUTMODE_4BPP (0x2 << 8)
++#define LCDC_BASECFG1_CLUTMODE_8BPP (0x3 << 8)
++
++#define ATMEL_LCDC_BASECFG2 0x0074
++
++#define ATMEL_LCDC_BASECFG3 0x0078
++#define LCDC_BASECFG3_BDEF_OFFSET 0
++#define LCDC_BASECFG3_BDEF (0xff << LCDC_BASECFG3_BDEF_OFFSET)
++#define LCDC_BASECFG3_GDEF_OFFSET 8
++#define LCDC_BASECFG3_GDEF (0xff << LCDC_BASECFG3_GDEF_OFFSET)
++#define LCDC_BASECFG3_RDEF_OFFSET 16
++#define LCDC_BASECFG3_RDEF (0xff << LCDC_BASECFG3_RDEF_OFFSET)
++
++#define ATMEL_LCDC_BASECFG4 0x007C
++#define LCDC_BASECFG4_DMA (0x1 << 8)
++#define LCDC_BASECFG4_REP (0x1 << 9)
++
++#define ATMEL_LCDC_HEOCHER 0x0280
++#define LCDC_HEOCHER_CHEN (0x1 << 0)
++#define LCDC_HEOCHER_UPDATEEN (0x1 << 1)
++#define LCDC_HEOCHER_A2QEN (0x1 << 2)
++
++#define ATMEL_LCDC_HEOCHDR 0x0284
++#define LCDC_HEOCHDR_CHDIS (0x1 << 0)
++#define LCDC_HEOCHDR_CHRST (0x1 << 8)
++
++#define ATMEL_LCDC_HEOCHSR 0x0288
++#define LCDC_HEOCHSR_CHSR (0x1 << 0)
++#define LCDC_HEOCHSR_UPDATESR (0x1 << 1)
++#define LCDC_HEOCHSR_A2QSR (0x1 << 2)
++
++#define ATMEL_LCDC_HEOIER 0x028C
++#define LCDC_HEOIER_DMA (0x1 << 2)
++#define LCDC_HEOIER_DSCR (0x1 << 3)
++#define LCDC_HEOIER_ADD (0x1 << 4)
++#define LCDC_HEOIER_DONE (0x1 << 5)
++#define LCDC_HEOIER_OVR (0x1 << 6)
++#define LCDC_HEOIER_UDMA (0x1 << 10)
++#define LCDC_HEOIER_UDSCR (0x1 << 11)
++#define LCDC_HEOIER_UADD (0x1 << 12)
++#define LCDC_HEOIER_UDONE (0x1 << 13)
++#define LCDC_HEOIER_UOVR (0x1 << 14)
++#define LCDC_HEOIER_VDMA (0x1 << 18)
++#define LCDC_HEOIER_VDSCR (0x1 << 19)
++#define LCDC_HEOIER_VADD (0x1 << 20)
++#define LCDC_HEOIER_VDONE (0x1 << 21)
++#define LCDC_HEOIER_VOVR (0x1 << 22)
++
++#define ATMEL_LCDC_HEOIDR 0x0290
++#define LCDC_HEOIDR_DMA (0x1 << 2)
++#define LCDC_HEOIDR_DSCR (0x1 << 3)
++#define LCDC_HEOIDR_ADD (0x1 << 4)
++#define LCDC_HEOIDR_DONE (0x1 << 5)
++#define LCDC_HEOIDR_OVR (0x1 << 6)
++#define LCDC_HEOIDR_UDMA (0x1 << 10)
++#define LCDC_HEOIDR_UDSCR (0x1 << 11)
++#define LCDC_HEOIDR_UADD (0x1 << 12)
++#define LCDC_HEOIDR_UDONE (0x1 << 13)
++#define LCDC_HEOIDR_UOVR (0x1 << 14)
++#define LCDC_HEOIDR_VDMA (0x1 << 18)
++#define LCDC_HEOIDR_VDSCR (0x1 << 19)
++#define LCDC_HEOIDR_VADD (0x1 << 20)
++#define LCDC_HEOIDR_VDONE (0x1 << 21)
++#define LCDC_HEOIDR_VOVR (0x1 << 22)
++
++#define ATMEL_LCDC_HEOIMR 0x0294
++#define LCDC_HEOIMR_DMA (0x1 << 2)
++#define LCDC_HEOIMR_DSCR (0x1 << 3)
++#define LCDC_HEOIMR_ADD (0x1 << 4)
++#define LCDC_HEOIMR_DONE (0x1 << 5)
++#define LCDC_HEOIMR_OVR (0x1 << 6)
++#define LCDC_HEOIMR_UDMA (0x1 << 10)
++#define LCDC_HEOIMR_UDSCR (0x1 << 11)
++#define LCDC_HEOIMR_UADD (0x1 << 12)
++#define LCDC_HEOIMR_UDONE (0x1 << 13)
++#define LCDC_HEOIMR_UOVR (0x1 << 14)
++#define LCDC_HEOIMR_VDMA (0x1 << 18)
++#define LCDC_HEOIMR_VDSCR (0x1 << 19)
++#define LCDC_HEOIMR_VADD (0x1 << 20)
++#define LCDC_HEOIMR_VDONE (0x1 << 21)
++#define LCDC_HEOIMR_VOVR (0x1 << 22)
++
++#define ATMEL_LCDC_HEOISR 0x0298
++#define LCDC_HEOISR_DMA (0x1 << 2)
++#define LCDC_HEOISR_DSCR (0x1 << 3)
++#define LCDC_HEOISR_ADD (0x1 << 4)
++#define LCDC_HEOISR_DONE (0x1 << 5)
++#define LCDC_HEOISR_OVR (0x1 << 6)
++#define LCDC_HEOISR_UDMA (0x1 << 10)
++#define LCDC_HEOISR_UDSCR (0x1 << 11)
++#define LCDC_HEOISR_UADD (0x1 << 12)
++#define LCDC_HEOISR_UDONE (0x1 << 13)
++#define LCDC_HEOISR_UOVR (0x1 << 14)
++#define LCDC_HEOISR_VDMA (0x1 << 18)
++#define LCDC_HEOISR_VDSCR (0x1 << 19)
++#define LCDC_HEOISR_VADD (0x1 << 20)
++#define LCDC_HEOISR_VDONE (0x1 << 21)
++#define LCDC_HEOISR_VOVR (0x1 << 22)
++
++#define ATMEL_LCDC_HEOHEAD 0x029C
++
++#define ATMEL_LCDC_HEOADDR 0x02A0
++
++#define ATMEL_LCDC_HEOCTRL 0x02A4
++#define LCDC_HEOCTRL_DFETCH (0x1 << 0)
++#define LCDC_HEOCTRL_LFETCH (0x1 << 1)
++#define LCDC_HEOCTRL_DMAIEN (0x1 << 2)
++#define LCDC_HEOCTRL_DSCRIEN (0x1 << 3)
++#define LCDC_HEOCTRL_ADDIEN (0x1 << 4)
++#define LCDC_HEOCTRL_DONEIEN (0x1 << 5)
++
++#define ATMEL_LCDC_HEONEXT 0x02A8
++
++#define ATMEL_LCDC_HEOUHEAD 0x02AC
++
++#define ATMEL_LCDC_HEOUADDR 0x02B0
++
++#define ATMEL_LCDC_HEOUCTRL 0x02B4
++#define LCDC_HEOUCTRL_UDFETCH (0x1 << 0)
++#define LCDC_HEOUCTRL_UDMAIEN (0x1 << 2)
++#define LCDC_HEOUCTRL_UDSCRIEN (0x1 << 3)
++#define LCDC_HEOUCTRL_UADDIEN (0x1 << 4)
++#define LCDC_HEOUCTRL_UDONEIEN (0x1 << 5)
++
++#define ATMEL_LCDC_HEOUNEXT 0x02B8
++
++#define ATMEL_LCDC_HEOVHEAD 0x02BC
++
++#define ATMEL_LCDC_HEOVADDR 0x02C0
++
++#define ATMEL_LCDC_HEOVCTRL 0x02C4
++#define LCDC_HEOVCTRL_VDFETCH (0x1 << 0)
++#define LCDC_HEOVCTRL_VDMAIEN (0x1 << 2)
++#define LCDC_HEOVCTRL_VDSCRIEN (0x1 << 3)
++#define LCDC_HEOVCTRL_VADDIEN (0x1 << 4)
++#define LCDC_HEOVCTRL_VDONEIEN (0x1 << 5)
++
++#define ATMEL_LCDC_HEOVNEXT 0x02C8
++
++#define ATMEL_LCDC_HEOCFG0 0x02CC
++#define LCDC_HEOCFG0_BLEN_OFFSET 4
++#define LCDC_HEOCFG0_BLEN (0x3 << LCDC_HEOCFG0_BLEN_OFFSET)
++#define LCDC_HEOCFG0_BLEN_AHB_SINGLE (0x0 << 4)
++#define LCDC_HEOCFG0_BLEN_AHB_INCR4 (0x1 << 4)
++#define LCDC_HEOCFG0_BLEN_AHB_INCR8 (0x2 << 4)
++#define LCDC_HEOCFG0_BLEN_AHB_INCR16 (0x3 << 4)
++#define LCDC_HEOCFG0_BLENUV_OFFSET 6
++#define LCDC_HEOCFG0_BLENUV (0x3 << LCDC_HEOCFG0_BLENUV_OFFSET)
++#define LCDC_HEOCFG0_BLENUV_AHB_SINGLE (0x0 << 6)
++#define LCDC_HEOCFG0_BLENUV_AHB_INCR4 (0x1 << 6)
++#define LCDC_HEOCFG0_BLENUV_AHB_INCR8 (0x2 << 6)
++#define LCDC_HEOCFG0_BLENUV_AHB_INCR16 (0x3 << 6)
++#define LCDC_HEOCFG0_DLBO (0x1 << 8)
++#define LCDC_HEOCFG0_ROTDIS (0x1 << 12)
++#define LCDC_HEOCFG0_LOCKDIS (0x1 << 13)
++
++#define ATMEL_LCDC_HEOCFG1 0x02D0
++#define LCDC_HEOCFG1_CLUTEN (0x1 << 0)
++#define LCDC_HEOCFG1_YUVEN (0x1 << 1)
++#define LCDC_HEOCFG1_RGBMODE_OFFSET 4
++#define LCDC_HEOCFG1_RGBMODE (0xf << LCDC_HEOCFG1_RGBMODE_OFFSET)
++#define LCDC_HEOCFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
++#define LCDC_HEOCFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
++#define LCDC_HEOCFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
++#define LCDC_HEOCFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
++#define LCDC_HEOCFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
++#define LCDC_HEOCFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
++#define LCDC_HEOCFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
++#define LCDC_HEOCFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
++#define LCDC_HEOCFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
++#define LCDC_HEOCFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
++#define LCDC_HEOCFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
++#define LCDC_HEOCFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
++#define LCDC_HEOCFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
++#define LCDC_HEOCFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
++#define LCDC_HEOCFG1_CLUTMODE_OFFSET 8
++#define LCDC_HEOCFG1_CLUTMODE (0x3 << LCDC_HEOCFG1_CLUTMODE_OFFSET)
++#define LCDC_HEOCFG1_CLUTMODE_1BPP (0x0 << 8)
++#define LCDC_HEOCFG1_CLUTMODE_2BPP (0x1 << 8)
++#define LCDC_HEOCFG1_CLUTMODE_4BPP (0x2 << 8)
++#define LCDC_HEOCFG1_CLUTMODE_8BPP (0x3 << 8)
++#define LCDC_HEOCFG1_YUVMODE_OFFSET 12
++#define LCDC_HEOCFG1_YUVMODE (0xf << LCDC_HEOCFG1_YUVMODE_OFFSET)
++#define LCDC_HEOCFG1_YUVMODE_32BPP_AYCBCR (0x0 << 12)
++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE0 (0x1 << 12)
++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE1 (0x2 << 12)
++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE2 (0x3 << 12)
++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE3 (0x4 << 12)
++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_SEMIPLANAR (0x5 << 12)
++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_PLANAR (0x6 << 12)
++#define LCDC_HEOCFG1_YUVMODE_12BPP_YCBCR_SEMIPLANAR (0x7 << 12)
++#define LCDC_HEOCFG1_YUVMODE_12BPP_YCBCR_PLANAR (0x8 << 12)
++#define LCDC_HEOCFG1_YUV422ROT (0x1 << 16)
++#define LCDC_HEOCFG1_YUV422SWP (0x1 << 17)
++
++#define ATMEL_LCDC_HEOCFG2 0x02D4
++#define LCDC_HEOCFG2_XOFFSET_OFFSET 0
++#define LCDC_HEOCFG2_XOFFSET (0x7ff << LCDC_HEOCFG2_XOFFSET_OFFSET)
++#define LCDC_HEOCFG2_YOFFSET_OFFSET 16
++#define LCDC_HEOCFG2_YOFFSET (0x7ff << LCDC_HEOCFG2_YOFFSET_OFFSET)
++
++#define ATMEL_LCDC_HEOCFG3 0x02D8
++#define LCDC_HEOCFG3_XSIZE_OFFSET 0
++#define LCDC_HEOCFG3_XSIZE (0x7ff << LCDC_HEOCFG3_XSIZE_OFFSET)
++#define LCDC_HEOCFG3_YSIZE_OFFSET 16
++#define LCDC_HEOCFG3_YSIZE (0x7ff << LCDC_HEOCFG3_YSIZE_OFFSET)
++
++#define ATMEL_LCDC_HEOCFG4 0x02DC
++#define LCDC_HEOCFG4_XMEM_SIZE_OFFSET 0
++#define LCDC_HEOCFG4_XMEM_SIZE (0x7ff << LCDC_HEOCFG4_XMEM_SIZE_OFFSET)
++#define LCDC_HEOCFG4_YMEM_SIZE_OFFSET 16
++#define LCDC_HEOCFG4_YMEM_SIZE (0x7ff << LCDC_HEOCFG4_YMEM_SIZE_OFFSET)
++
++#define ATMEL_LCDC_HEOCFG5 0x02E0
++
++#define ATMEL_LCDC_HEOCFG6 0x02E4
++
++#define ATMEL_LCDC_HEOCFG7 0x02E8
++
++#define ATMEL_LCDC_HEOCFG8 0x02EC
++
++#define ATMEL_LCDC_HEOCFG9 0x02F0
++#define LCDC_HEOCFG9_BDEF_OFFSET 0
++#define LCDC_HEOCFG9_BDEF (0xff << LCDC_HEOCFG9_BDEF_OFFSET)
++#define LCDC_HEOCFG9_GDEF_OFFSET 8
++#define LCDC_HEOCFG9_GDEF (0xff << LCDC_HEOCFG9_GDEF_OFFSET)
++#define LCDC_HEOCFG9_RDEF_OFFSET 16
++#define LCDC_HEOCFG9_RDEF (0xff << LCDC_HEOCFG9_RDEF_OFFSET)
++
++#define ATMEL_LCDC_HEOCFG10 0x02F4
++#define LCDC_HEOCFG10_BKEY_OFFSET 0
++#define LCDC_HEOCFG10_BKEY (0xff << LCDC_HEOCFG10_BKEY_OFFSET)
++#define LCDC_HEOCFG10_GKEY_OFFSET 8
++#define LCDC_HEOCFG10_GKEY (0xff << LCDC_HEOCFG10_GKEY_OFFSET)
++#define LCDC_HEOCFG10_RKEY_OFFSET 16
++#define LCDC_HEOCFG10_RKEY (0xff << LCDC_HEOCFG10_RKEY_OFFSET)
++
++#define ATMEL_LCDC_HEOCFG11 0x02F8
++#define LCDC_HEOCFG11_BMASK_OFFSET 0
++#define LCDC_HEOCFG11_BMASK (0xff << LCDC_HEOCFG11_BMASK_OFFSET)
++#define LCDC_HEOCFG11_GMASK_OFFSET 8
++#define LCDC_HEOCFG11_GMASK (0xff << LCDC_HEOCFG11_GMASK_OFFSET)
++#define LCDC_HEOCFG11_RMASK_OFFSET 16
++#define LCDC_HEOCFG11_RMASK (0xff << LCDC_HEOCFG11_RMASK_OFFSET)
++
++#define ATMEL_LCDC_HEOCFG12 0x02FC
++#define LCDC_HEOCFG12_CRKEY (0x1 << 0)
++#define LCDC_HEOCFG12_INV (0x1 << 1)
++#define LCDC_HEOCFG12_ITER2BL (0x1 << 2)
++#define LCDC_HEOCFG12_ITER (0x1 << 3)
++#define LCDC_HEOCFG12_REVALPHA (0x1 << 4)
++#define LCDC_HEOCFG12_GAEN (0x1 << 5)
++#define LCDC_HEOCFG12_LAEN (0x1 << 6)
++#define LCDC_HEOCFG12_OVR (0x1 << 7)
++#define LCDC_HEOCFG12_DMA (0x1 << 8)
++#define LCDC_HEOCFG12_REP (0x1 << 9)
++#define LCDC_HEOCFG12_DSTKEY (0x1 << 10)
++#define LCDC_HEOCFG12_VIDPRI (0x1 << 12)
++#define LCDC_HEOCFG12_GA_OFFSET 16
++#define LCDC_HEOCFG12_GA (0xff << LCDC_HEOCFG12_GA_OFFSET)
++
++#define ATMEL_LCDC_HEOCFG13 0x0300
++#define LCDC_HEOCFG13_XFACTOR_OFFSET 0
++#define LCDC_HEOCFG13_XFACTOR (0x1fff << LCDC_HEOCFG13_XFACTOR_OFFSET)
++#define LCDC_HEOCFG13_YFACTOR_OFFSET 16
++#define LCDC_HEOCFG13_YFACTOR (0x1fff << LCDC_HEOCFG13_YFACTOR_OFFSET)
++#define LCDC_HEOCFG13_SCALEN (0x1 << 31)
++
++#define ATMEL_LCDC_HEOCFG14 0x0304
++#define LCDC_HEOCFG14_CSCRY_OFFSET 0
++#define LCDC_HEOCFG14_CSCRY (0x3ff << LCDC_HEOCFG14_CSCRY_OFFSET)
++#define LCDC_HEOCFG14_CSCRU_OFFSET 10
++#define LCDC_HEOCFG14_CSCRU (0x3ff << LCDC_HEOCFG14_CSCRU_OFFSET)
++#define LCDC_HEOCFG14_CSCRV_OFFSET 20
++#define LCDC_HEOCFG14_CSCRV (0x3ff << LCDC_HEOCFG14_CSCRV_OFFSET)
++#define LCDC_HEOCFG14_CSCYOFF (0x1 << 30)
++
++#define ATMEL_LCDC_HEOCFG15 0x0308
++#define LCDC_HEOCFG15_CSCGY_OFFSET 0
++#define LCDC_HEOCFG15_CSCGY (0x3ff << LCDC_HEOCFG15_CSCGY_OFFSET)
++#define LCDC_HEOCFG15_CSCGU_OFFSET 10
++#define LCDC_HEOCFG15_CSCGU (0x3ff << LCDC_HEOCFG15_CSCGU_OFFSET)
++#define LCDC_HEOCFG15_CSCGV_OFFSET 20
++#define LCDC_HEOCFG15_CSCGV (0x3ff << LCDC_HEOCFG15_CSCGV_OFFSET)
++#define LCDC_HEOCFG15_CSCUOFF (0x1 << 30)
++
++#define ATMEL_LCDC_HEOCFG16 0x030C
++#define LCDC_HEOCFG16_CSCBY_OFFSET 0
++#define LCDC_HEOCFG16_CSCBY (0x3ff << LCDC_HEOCFG16_CSCBY_OFFSET)
++#define LCDC_HEOCFG16_CSCBU_OFFSET 10
++#define LCDC_HEOCFG16_CSCBU (0x3ff << LCDC_HEOCFG16_CSCBU_OFFSET)
++#define LCDC_HEOCFG16_CSCBV_OFFSET 20
++#define LCDC_HEOCFG16_CSCBV (0x3ff << LCDC_HEOCFG16_CSCBV_OFFSET)
++#define LCDC_HEOCFG16_CSCVOFF (0x1 << 30)
++
++#define ATMEL_LCDC_HCRCHER 0x0340
++#define LCDC_HCRCHER_CHEN (0x1 << 0)
++#define LCDC_HCRCHER_UPDATEEN (0x1 << 1)
++#define LCDC_HCRCHER_A2QEN (0x1 << 2)
++
++#define ATMEL_LCDC_HCRCHDR 0x0344
++#define LCDC_HCRCHDR_CHDIS (0x1 << 0)
++#define LCDC_HCRCHDR_CHRST (0x1 << 8)
++
++#define ATMEL_LCDC_HCRCHSR 0x0348
++#define LCDC_HCRCHSR_CHSR (0x1 << 0)
++#define LCDC_HCRCHSR_UPDATESR (0x1 << 1)
++#define LCDC_HCRCHSR_A2QSR (0x1 << 2)
++
++#define ATMEL_LCDC_HCRIER 0x034C
++#define LCDC_HCRIER_DMA (0x1 << 2)
++#define LCDC_HCRIER_DSCR (0x1 << 3)
++#define LCDC_HCRIER_ADD (0x1 << 4)
++#define LCDC_HCRIER_DONE (0x1 << 5)
++#define LCDC_HCRIER_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_HCRIDR 0x0350
++#define LCDC_HCRIDR_DMA (0x1 << 2)
++#define LCDC_HCRIDR_DSCR (0x1 << 3)
++#define LCDC_HCRIDR_ADD (0x1 << 4)
++#define LCDC_HCRIDR_DONE (0x1 << 5)
++#define LCDC_HCRIDR_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_HCRIMR 0x0354
++#define LCDC_HCRIMR_DMA (0x1 << 2)
++#define LCDC_HCRIMR_DSCR (0x1 << 3)
++#define LCDC_HCRIMR_ADD (0x1 << 4)
++#define LCDC_HCRIMR_DONE (0x1 << 5)
++#define LCDC_HCRIMR_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_HCRISR 0x0358
++#define LCDC_HCRISR_DMA (0x1 << 2)
++#define LCDC_HCRISR_DSCR (0x1 << 3)
++#define LCDC_HCRISR_ADD (0x1 << 4)
++#define LCDC_HCRISR_DONE (0x1 << 5)
++#define LCDC_HCRISR_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_HCRHEAD 0x035C
++
++#define ATMEL_LCDC_HCRADDR 0x0360
++
++#define ATMEL_LCDC_HCRCTRL 0x0364
++#define LCDC_HCRCTRL_DFETCH (0x1 << 0)
++#define LCDC_HCRCTRL_LFETCH (0x1 << 1)
++#define LCDC_HCRCTRL_DMAIEN (0x1 << 2)
++#define LCDC_HCRCTRL_DSCRIEN (0x1 << 3)
++#define LCDC_HCRCTRL_ADDIEN (0x1 << 4)
++#define LCDC_HCRCTRL_DONEIEN (0x1 << 5)
++
++#define ATMEL_LCDC_HCRNEXT 0x0368
++
++#define ATMEL_LCDC_HCRCFG0 0x036C
++#define LCDC_HCRCFG0_BLEN_OFFSET 4
++#define LCDC_HCRCFG0_BLEN (0x3 << LCDC_HCRCFG0_BLEN_OFFSET)
++#define LCDC_HCRCFG0_BLEN_AHB_SINGLE (0x0 << 4)
++#define LCDC_HCRCFG0_BLEN_AHB_INCR4 (0x1 << 4)
++#define LCDC_HCRCFG0_BLEN_AHB_INCR8 (0x2 << 4)
++#define LCDC_HCRCFG0_BLEN_AHB_INCR16 (0x3 << 4)
++#define LCDC_HCRCFG0_DLBO (0x1 << 8)
++
++#define ATMEL_LCDC_HCRCFG1 0x0370
++#define LCDC_HCRCFG1_CLUTEN (0x1 << 0)
++#define LCDC_HCRCFG1_RGBMODE_OFFSET 4
++#define LCDC_HCRCFG1_RGBMODE (0xf << LCDC_HCRCFG1_RGBMODE_OFFSET)
++#define LCDC_HCRCFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
++#define LCDC_HCRCFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
++#define LCDC_HCRCFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
++#define LCDC_HCRCFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
++#define LCDC_HCRCFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
++#define LCDC_HCRCFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
++#define LCDC_HCRCFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
++#define LCDC_HCRCFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
++#define LCDC_HCRCFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
++#define LCDC_HCRCFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
++#define LCDC_HCRCFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
++#define LCDC_HCRCFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
++#define LCDC_HCRCFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
++#define LCDC_HCRCFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
++#define LCDC_HCRCFG1_CLUTMODE_OFFSET 8
++#define LCDC_HCRCFG1_CLUTMODE (0x3 << LCDC_HCRCFG1_CLUTMODE_OFFSET)
++#define LCDC_HCRCFG1_CLUTMODE_1BPP (0x0 << 8)
++#define LCDC_HCRCFG1_CLUTMODE_2BPP (0x1 << 8)
++#define LCDC_HCRCFG1_CLUTMODE_4BPP (0x2 << 8)
++#define LCDC_HCRCFG1_CLUTMODE_8BPP (0x3 << 8)
++
++#define ATMEL_LCDC_HCRCFG2 0x0374
++#define LCDC_HCRCFG2_XOFFSET_OFFSET 0
++#define LCDC_HCRCFG2_XOFFSET (0x7ff << LCDC_HCRCFG2_XOFFSET_OFFSET)
++#define LCDC_HCRCFG2_YOFFSET_OFFSET 16
++#define LCDC_HCRCFG2_YOFFSET (0x7ff << LCDC_HCRCFG2_YOFFSET_OFFSET)
++
++#define ATMEL_LCDC_HCRCFG3 0x0378
++#define LCDC_HCRCFG3_XSIZE_OFFSET 0
++#define LCDC_HCRCFG3_XSIZE (0x7f << LCDC_HCRCFG3_XSIZE_OFFSET)
++#define LCDC_HCRCFG3_YSIZE_OFFSET 16
++#define LCDC_HCRCFG3_YSIZE (0x7f << LCDC_HCRCFG3_YSIZE_OFFSET)
++
++#define ATMEL_LCDC_HCRCFG4 0x037C
++
++#define ATMEL_LCDC_HCRCFG6 0x0384
++#define LCDC_HCRCFG6_BDEF_OFFSET 0
++#define LCDC_HCRCFG6_BDEF (0xff << LCDC_HCRCFG6_BDEF_OFFSET)
++#define LCDC_HCRCFG6_GDEF_OFFSET 8
++#define LCDC_HCRCFG6_GDEF (0xff << LCDC_HCRCFG6_GDEF_OFFSET)
++#define LCDC_HCRCFG6_RDEF_OFFSET 16
++#define LCDC_HCRCFG6_RDEF (0xff << LCDC_HCRCFG6_RDEF_OFFSET)
++
++#define ATMEL_LCDC_HCRCFG7 0x0388
++#define LCDC_HCRCFG7_BKEY_OFFSET 0
++#define LCDC_HCRCFG7_BKEY (0xff << LCDC_HCRCFG7_BKEY_OFFSET)
++#define LCDC_HCRCFG7_GKEY_OFFSET 8
++#define LCDC_HCRCFG7_GKEY (0xff << LCDC_HCRCFG7_GKEY_OFFSET)
++#define LCDC_HCRCFG7_RKEY_OFFSET 16
++#define LCDC_HCRCFG7_RKEY (0xff << LCDC_HCRCFG7_RKEY_OFFSET)
++
++#define ATMEL_LCDC_HCRCFG8 0x038C
++#define LCDC_HCRCFG8_BMASK_OFFSET 0
++#define LCDC_HCRCFG8_BMASK (0xff << LCDC_HCRCFG8_BMASK_OFFSET)
++#define LCDC_HCRCFG8_GMASK_OFFSET 8
++#define LCDC_HCRCFG8_GMASK (0xff << LCDC_HCRCFG8_GMASK_OFFSET)
++#define LCDC_HCRCFG8_RMASK_OFFSET 16
++#define LCDC_HCRCFG8_RMASK (0xff << LCDC_HCRCFG8_RMASK_OFFSET)
++
++#define ATMEL_LCDC_HCRCFG9 0x0390
++#define LCDC_HCRCFG9_CRKEY (0x1 << 0)
++#define LCDC_HCRCFG9_INV (0x1 << 1)
++#define LCDC_HCRCFG9_ITER2BL (0x1 << 2)
++#define LCDC_HCRCFG9_ITER (0x1 << 3)
++#define LCDC_HCRCFG9_REVALPHA (0x1 << 4)
++#define LCDC_HCRCFG9_GAEN (0x1 << 5)
++#define LCDC_HCRCFG9_LAEN (0x1 << 6)
++#define LCDC_HCRCFG9_OVR (0x1 << 7)
++#define LCDC_HCRCFG9_DMA (0x1 << 8)
++#define LCDC_HCRCFG9_REP (0x1 << 9)
++#define LCDC_HCRCFG9_DSTKEY (0x1 << 10)
++#define LCDC_HCRCFG9_GA_OFFSET 16
++#define LCDC_HCRCFG9_GA_Msk (0xff << LCDC_HCRCFG9_GA_OFFSET)
++
++#define ATMEL_LCDC_BASECLUT 0x400
++#define LCDC_BASECLUT_BCLUT_OFFSET 0
++#define LCDC_BASECLUT_BCLUT (0xff << LCDC_BASECLUT_BCLUT_OFFSET)
++#define LCDC_BASECLUT_GCLUT_OFFSET 8
++#define LCDC_BASECLUT_GCLUT (0xff << LCDC_BASECLUT_GCLUT_OFFSET)
++#define LCDC_BASECLUT_RCLUT_OFFSET 16
++#define LCDC_BASECLUT_RCLUT (0xff << LCDC_BASECLUT_RCLUT_OFFSET)
++
++#define ATMEL_LCDC_OVR1CLUT 0x800
++#define LCDC_OVR1CLUT_BCLUT_OFFSET 0
++#define LCDC_OVR1CLUT_BCLUT (0xff << LCDC_OVR1CLUT_BCLUT_OFFSET)
++#define LCDC_OVR1CLUT_GCLUT_OFFSET 8
++#define LCDC_OVR1CLUT_GCLUT (0xff << LCDC_OVR1CLUT_GCLUT_OFFSET)
++#define LCDC_OVR1CLUT_RCLUT_OFFSET 16
++#define LCDC_OVR1CLUT_RCLUT (0xff << LCDC_OVR1CLUT_RCLUT_OFFSET)
++#define LCDC_OVR1CLUT_ACLUT_OFFSET 24
++#define LCDC_OVR1CLUT_ACLUT (0xff << LCDC_OVR1CLUT_ACLUT_OFFSET)
++
++#define ATMEL_LCDC_HEOCLUT 0x1000
++#define LCDC_HEOCLUT_BCLUT_OFFSET 0
++#define LCDC_HEOCLUT_BCLUT (0xff << LCDC_HEOCLUT_BCLUT_OFFSET)
++#define LCDC_HEOCLUT_GCLUT_OFFSET 8
++#define LCDC_HEOCLUT_GCLUT (0xff << LCDC_HEOCLUT_GCLUT_OFFSET)
++#define LCDC_HEOCLUT_RCLUT_OFFSET 16
++#define LCDC_HEOCLUT_RCLUT (0xff << LCDC_HEOCLUT_RCLUT_OFFSET)
++#define LCDC_HEOCLUT_ACLUT_OFFSET 24
++#define LCDC_HEOCLUT_ACLUT (0xff << LCDC_HEOCLUT_ACLUT_OFFSET)
++
++#define ATMEL_LCDC_HCRCLUT 0x1400
++#define LCDC_HCRCLUT_BCLUT_OFFSET 0
++#define LCDC_HCRCLUT_BCLUT (0xff << LCDC_HCRCLUT_BCLUT_OFFSET)
++#define LCDC_HCRCLUT_GCLUT_OFFSET 8
++#define LCDC_HCRCLUT_GCLUT (0xff << LCDC_HCRCLUT_GCLUT_OFFSET)
++#define LCDC_HCRCLUT_RCLUT_OFFSET 16
++#define LCDC_HCRCLUT_RCLUT (0xff << LCDC_HCRCLUT_RCLUT_OFFSET)
++#define LCDC_HCRCLUT_ACLUT_OFFSET 24
++#define LCDC_HCRCLUT_ACLUT (0xff << LCDC_HCRCLUT_ACLUT_OFFSET)
++
++/* Base layer CLUT */
++#define ATMEL_HLCDC_LUT 0x0400
++
++
++#endif /* __MACH_ATMEL_HLCDC4_H__ */
+diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h b/arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h
+new file mode 100644
+index 0000000..4416403
+--- /dev/null
++++ b/arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h
+@@ -0,0 +1,156 @@
++#ifndef __MACH_ATMEL_HLCD_OVL_H__
++#define __MACH_ATMEL_HLCD_OVL_H__
++
++/*
++ * OVL has a seperate resource which already starts at offset 0x100.
++ * So, these defines start at 0x0. The manual will list them at 0x100.
++ */
++
++#define ATMEL_LCDC_OVRCHER1 0x0000
++#define LCDC_OVRCHER1_CHEN (0x1 << 0)
++#define LCDC_OVRCHER1_UPDATEEN (0x1 << 1)
++#define LCDC_OVRCHER1_A2QEN (0x1 << 2)
++
++#define ATMEL_LCDC_OVRCHDR1 0x0004
++#define LCDC_OVRCHDR1_CHDIS (0x1 << 0)
++#define LCDC_OVRCHDR1_CHRST (0x1 << 8)
++
++#define ATMEL_LCDC_OVRCHSR1 0x0008
++#define LCDC_OVRCHSR1_CHSR (0x1 << 0)
++#define LCDC_OVRCHSR1_UPDATESR (0x1 << 1)
++#define LCDC_OVRCHSR1_A2QSR (0x1 << 2)
++
++#define ATMEL_LCDC_OVRIER1 0x000C
++#define LCDC_OVRIER1_DMA (0x1 << 2)
++#define LCDC_OVRIER1_DSCR (0x1 << 3)
++#define LCDC_OVRIER1_ADD (0x1 << 4)
++#define LCDC_OVRIER1_DONE (0x1 << 5)
++#define LCDC_OVRIER1_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_OVRIDR1 0x0010
++#define LCDC_OVRIDR1_DMA (0x1 << 2)
++#define LCDC_OVRIDR1_DSCR (0x1 << 3)
++#define LCDC_OVRIDR1_ADD (0x1 << 4)
++#define LCDC_OVRIDR1_DONE (0x1 << 5)
++#define LCDC_OVRIDR1_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_OVRIMR1 0x0014
++#define LCDC_OVRIMR1_DMA (0x1 << 2)
++#define LCDC_OVRIMR1_DSCR (0x1 << 3)
++#define LCDC_OVRIMR1_ADD (0x1 << 4)
++#define LCDC_OVRIMR1_DONE (0x1 << 5)
++#define LCDC_OVRIMR1_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_OVRISR1 0x0018
++#define LCDC_OVRISR1_DMA (0x1 << 2)
++#define LCDC_OVRISR1_DSCR (0x1 << 3)
++#define LCDC_OVRISR1_ADD (0x1 << 4)
++#define LCDC_OVRISR1_DONE (0x1 << 5)
++#define LCDC_OVRISR1_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_OVRHEAD1 0x001C
++
++#define ATMEL_LCDC_OVRADDR1 0x0020
++
++#define ATMEL_LCDC_OVRCTRL1 0x0024
++#define LCDC_OVRCTRL1_DFETCH (0x1 << 0)
++#define LCDC_OVRCTRL1_LFETCH (0x1 << 1)
++#define LCDC_OVRCTRL1_DMAIEN (0x1 << 2)
++#define LCDC_OVRCTRL1_DSCRIEN (0x1 << 3)
++#define LCDC_OVRCTRL1_ADDIEN (0x1 << 4)
++#define LCDC_OVRCTRL1_DONEIEN (0x1 << 5)
++
++#define ATMEL_LCDC_OVRNEXT1 0x0028
++
++#define ATMEL_LCDC_OVR1CFG0 0x002C
++#define LCDC_OVR1CFG0_BLEN_OFFSET 4
++#define LCDC_OVR1CFG0_BLEN (0x3 << LCDC_OVR1CFG0_BLEN_OFFSET)
++#define LCDC_OVR1CFG0_BLEN_AHB_SINGLE (0x0 << 4)
++#define LCDC_OVR1CFG0_BLEN_AHB_INCR4 (0x1 << 4)
++#define LCDC_OVR1CFG0_BLEN_AHB_INCR8 (0x2 << 4)
++#define LCDC_OVR1CFG0_BLEN_AHB_INCR16 (0x3 << 4)
++#define LCDC_OVR1CFG0_DLBO (0x1 << 8)
++#define LCDC_OVR1CFG0_ROTDIS (0x1 << 12)
++#define LCDC_OVR1CFG0_LOCKDIS (0x1 << 13)
++
++#define ATMEL_LCDC_OVR1CFG1 0x0030
++#define LCDC_OVR1CFG1_CLUTEN (0x1 << 0)
++#define LCDC_OVR1CFG1_RGBMODE_OFFSET 4
++#define LCDC_OVR1CFG1_RGBMODE (0xf << LCDC_OVR1CFG1_RGBMODE_OFFSET)
++#define LCDC_OVR1CFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
++#define LCDC_OVR1CFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
++#define LCDC_OVR1CFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
++#define LCDC_OVR1CFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
++#define LCDC_OVR1CFG1_CLUTMODE_OFFSET 8
++#define LCDC_OVR1CFG1_CLUTMODE (0x3 << LCDC_OVR1CFG1_CLUTMODE_OFFSET)
++#define LCDC_OVR1CFG1_CLUTMODE_1BPP (0x0 << 8)
++#define LCDC_OVR1CFG1_CLUTMODE_2BPP (0x1 << 8)
++#define LCDC_OVR1CFG1_CLUTMODE_4BPP (0x2 << 8)
++#define LCDC_OVR1CFG1_CLUTMODE_8BPP (0x3 << 8)
++
++#define ATMEL_LCDC_OVR1CFG2 0x0034
++#define LCDC_OVR1CFG2_XOFFSET_OFFSET 0
++#define LCDC_OVR1CFG2_XOFFSET (0x7ff << LCDC_OVR1CFG2_XOFFSET_OFFSET)
++#define LCDC_OVR1CFG2_YOFFSET_OFFSET 16
++#define LCDC_OVR1CFG2_YOFFSET (0x7ff << LCDC_OVR1CFG2_YOFFSET_OFFSET)
++
++#define ATMEL_LCDC_OVR1CFG3 0x0038
++#define LCDC_OVR1CFG3_XSIZE_OFFSET 0
++#define LCDC_OVR1CFG3_XSIZE (0x7ff << LCDC_OVR1CFG3_XSIZE_OFFSET)
++#define LCDC_OVR1CFG3_YSIZE_OFFSET 16
++#define LCDC_OVR1CFG3_YSIZE (0x7ff << LCDC_OVR1CFG3_YSIZE_OFFSET)
++
++#define ATMEL_LCDC_OVR1CFG4 0x003C
++
++#define ATMEL_LCDC_OVR1CFG5 0x0040
++
++#define ATMEL_LCDC_OVR1CFG6 0x0044
++#define LCDC_OVR1CFG6_BDEF_OFFSET 0
++#define LCDC_OVR1CFG6_BDEF (0xff << LCDC_OVR1CFG6_BDEF_OFFSET)
++#define LCDC_OVR1CFG6_GDEF_OFFSET 8
++#define LCDC_OVR1CFG6_GDEF (0xff << LCDC_OVR1CFG6_GDEF_OFFSET)
++#define LCDC_OVR1CFG6_RDEF_OFFSET 16
++#define LCDC_OVR1CFG6_RDEF (0xff << LCDC_OVR1CFG6_RDEF_OFFSET)
++
++#define ATMEL_LCDC_OVR1CFG7 0x0048
++#define LCDC_OVR1CFG7_BKEY_OFFSET 0
++#define LCDC_OVR1CFG7_BKEY (0xff << LCDC_OVR1CFG7_BKEY_OFFSET)
++#define LCDC_OVR1CFG7_GKEY_OFFSET 8
++#define LCDC_OVR1CFG7_GKEY (0xff << LCDC_OVR1CFG7_GKEY_OFFST)
++#define LCDC_OVR1CFG7_RKEY_OFFSET 16
++#define LCDC_OVR1CFG7_RKEY (0xff << LCDC_OVR1CFG7_RKEY_OFFSET)
++
++#define ATMEL_LCDC_OVR1CFG8 0x004C
++#define LCDC_OVR1CFG8_BMASK_OFFSET 0
++#define LCDC_OVR1CFG8_BMASK (0xff << LCDC_OVR1CFG8_BMASK_OFFSET)
++#define LCDC_OVR1CFG8_GMASK_OFFSET 8
++#define LCDC_OVR1CFG8_GMASK (0xff << LCDC_OVR1CFG8_GMASK_OFFSET)
++#define LCDC_OVR1CFG8_RMASK_OFFSET 16
++#define LCDC_OVR1CFG8_RMASK (0xff << LCDC_OVR1CFG8_RMASK_OFFSET)
++
++#define ATMEL_LCDC_OVR1CFG9 0x0050
++#define LCDC_OVR1CFG9_CRKEY (0x1 << 0)
++#define LCDC_OVR1CFG9_INV (0x1 << 1)
++#define LCDC_OVR1CFG9_ITER2BL (0x1 << 2)
++#define LCDC_OVR1CFG9_ITER (0x1 << 3)
++#define LCDC_OVR1CFG9_REVALPHA (0x1 << 4)
++#define LCDC_OVR1CFG9_GAEN (0x1 << 5)
++#define LCDC_OVR1CFG9_LAEN (0x1 << 6)
++#define LCDC_OVR1CFG9_OVR (0x1 << 7)
++#define LCDC_OVR1CFG9_DMA (0x1 << 8)
++#define LCDC_OVR1CFG9_REP (0x1 << 9)
++#define LCDC_OVR1CFG9_DSTKEY (0x1 << 10)
++#define LCDC_OVR1CFG9_GA_OFFSET 16
++#define LCDC_OVR1CFG9_GA (0xff << LCDC_OVR1CFG9_GA_OFFSET)
++
++#endif /* __MACH_ATMEL_HLCD_OVL_H__ */
+diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h b/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h
+deleted file mode 100644
+index debb8ce..0000000
+--- a/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h
++++ /dev/null
+@@ -1,868 +0,0 @@
+-/*
+- * Header file for AT91 High end LCD Controller
+- *
+- * Data structure and register user interface
+- *
+- * Copyright (C) 2010 Atmel Corporation
+- *
+- * 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.
+- *
+- * 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 PUROFFSETE. 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 __ATMEL_HLCD_H__
+-#define __ATMEL_HLCD_H__
+-
+-/* Lcdc hardware registers */
+-#define ATMEL_LCDC_LCDCFG0 0x0000
+-#define LCDC_LCDCFG0_CLKPOL (0x1 << 0)
+-#define LCDC_LCDCFG0_CLKSEL (0x1 << 2)
+-#define LCDC_LCDCFG0_CLKPWMSEL (0x1 << 3)
+-#define LCDC_LCDCFG0_CGDISBASE (0x1 << 8)
+-#define LCDC_LCDCFG0_CGDISOVR1 (0x1 << 9)
+-/* XXX: maybe this is 1 << 10? At least the LCD Interrupt registers
+- * use 10 while the documentation specifies 11.
+- */
+-#define LCDC_LCDCFG0_CGDISHEO (0x1 << 11)
+-#define LCDC_LCDCFG0_CGDISHCR (0x1 << 12)
+-#define LCDC_LCDCFG0_CLKDIV_OFFSET 16
+-#define LCDC_LCDCFG0_CLKDIV (0xff << LCDC_LCDCFG0_CLKDIV_OFFSET)
+-
+-#define ATMEL_LCDC_LCDCFG1 0x0004
+-#define LCDC_LCDCFG1_HSPW_OFFSET 0
+-#define LCDC_LCDCFG1_HSPW (0x3f << LCDC_LCDCFG1_HSPW_OFFSET)
+-#define LCDC_LCDCFG1_VSPW_OFFSET 16
+-#define LCDC_LCDCFG1_VSPW (0x3f << LCDC_LCDCFG1_VSPW_OFFSET)
+-
+-#define ATMEL_LCDC_LCDCFG2 0x0008
+-#define LCDC_LCDCFG2_VFPW_OFFSET 0
+-#define LCDC_LCDCFG2_VFPW (0x3f << LCDC_LCDCFG2_VFPW_OFFSET)
+-#define LCDC_LCDCFG2_VBPW_OFFSET 16
+-#define LCDC_LCDCFG2_VBPW (0x3f << LCDC_LCDCFG2_VBPW_OFFSET)
+-
+-#define ATMEL_LCDC_LCDCFG3 0x000C
+-#define LCDC_LCDCFG3_HFPW_OFFSET 0
+-#define LCDC_LCDCFG3_HFPW (0xff << LCDC_LCDCFG3_HFPW_OFFSET)
+-#define LCDC_LCDCFG3_HBPW_OFFSET 16
+-#define LCDC_LCDCFG3_HBPW (0xff << LCDC_LCDCFG3_HBPW_OFFSET)
+-
+-#define ATMEL_LCDC_LCDCFG4 0x0010
+-#define LCDC_LCDCFG4_PPL_OFFSET 0
+-#define LCDC_LCDCFG4_PPL (0x7ff << LCDC_LCDCFG4_PPL_OFFSET)
+-#define LCDC_LCDCFG4_RPF_OFFSET 16
+-#define LCDC_LCDCFG4_RPF (0x7ff << LCDC_LCDCFG4_RPF_OFFSET)
+-
+-#define ATMEL_LCDC_LCDCFG5 0x0014
+-#define LCDC_LCDCFG5_HSPOL (0x1 << 0)
+-#define LCDC_LCDCFG5_VSPOL (0x1 << 1)
+-#define LCDC_LCDCFG5_VSPDLYS (0x1 << 2)
+-#define LCDC_LCDCFG5_VSPDLYE (0x1 << 3)
+-#define LCDC_LCDCFG5_DISPPOL (0x1 << 4)
+-#define LCDC_LCDCFG5_SERIAL (0x1 << 5)
+-#define LCDC_LCDCFG5_DITHER (0x1 << 6)
+-#define LCDC_LCDCFG5_DISPDLY (0x1 << 7)
+-#define LCDC_LCDCFG5_MODE_OFFSET 8
+-#define LCDC_LCDCFG5_MODE (0x3 << LCDC_LCDCFG5_MODE_OFFSET)
+-#define LCDC_LCDCFG5_MODE_OUTPUT_12BPP (0x0 << 8)
+-#define LCDC_LCDCFG5_MODE_OUTPUT_16BPP (0x1 << 8)
+-#define LCDC_LCDCFG5_MODE_OUTPUT_18BPP (0x2 << 8)
+-#define LCDC_LCDCFG5_MODE_OUTPUT_24BPP (0x3 << 8)
+-#define LCDC_LCDCFG5_VSPSU (0x1 << 12)
+-#define LCDC_LCDCFG5_VSPHO (0x1 << 13)
+-#define LCDC_LCDCFG5_GUARDTIME_OFFSET 16
+-#define LCDC_LCDCFG5_GUARDTIME (0x1f << LCDC_LCDCFG5_GUARDTIME_OFFSET)
+-
+-#define ATMEL_LCDC_LCDCFG6 0x0018
+-#define LCDC_LCDCFG6_PWMPS_OFFSET 0
+-#define LCDC_LCDCFG6_PWMPS (0x7 << LCDC_LCDCFG6_PWMPS_OFFSET)
+-#define LCDC_LCDCFG6_PWMPOL (0x1 << 4)
+-#define LCDC_LCDCFG6_PWMCVAL_OFFSET 8
+-#define LCDC_LCDCFG6_PWMCVAL (0xff << LCDC_LCDCFG6_PWMCVAL_OFFSET)
+-
+-#define ATMEL_LCDC_LCDEN 0x0020
+-#define LCDC_LCDEN_CLKEN (0x1 << 0)
+-#define LCDC_LCDEN_SYNCEN (0x1 << 1)
+-#define LCDC_LCDEN_DISPEN (0x1 << 2)
+-#define LCDC_LCDEN_PWMEN (0x1 << 3)
+-
+-#define ATMEL_LCDC_LCDDIS 0x0024
+-#define LCDC_LCDDIS_CLKDIS (0x1 << 0)
+-#define LCDC_LCDDIS_SYNCDIS (0x1 << 1)
+-#define LCDC_LCDDIS_DISPDIS (0x1 << 2)
+-#define LCDC_LCDDIS_PWMDIS (0x1 << 3)
+-#define LCDC_LCDDIS_CLKRST (0x1 << 8)
+-#define LCDC_LCDDIS_SYNCRST (0x1 << 9)
+-#define LCDC_LCDDIS_DISPRST (0x1 << 10)
+-#define LCDC_LCDDIS_PWMRST (0x1 << 11)
+-
+-#define ATMEL_LCDC_LCDSR 0x0028
+-#define LCDC_LCDSR_CLKSTS (0x1 << 0)
+-#define LCDC_LCDSR_LCDSTS (0x1 << 1)
+-#define LCDC_LCDSR_DISPSTS (0x1 << 2)
+-#define LCDC_LCDSR_PWMSTS (0x1 << 3)
+-#define LCDC_LCDSR_SIPSTS (0x1 << 4)
+-
+-#define ATMEL_LCDC_LCDIER 0x002C
+-#define LCDC_LCDIER_SOFIE (0x1 << 0)
+-#define LCDC_LCDIER_DISIE (0x1 << 1)
+-#define LCDC_LCDIER_DISPIE (0x1 << 2)
+-#define LCDC_LCDIER_FIFOERRIE (0x1 << 4)
+-#define LCDC_LCDIER_BASEIE (0x1 << 8)
+-#define LCDC_LCDIER_OVR1IE (0x1 << 9)
+-#define LCDC_LCDIER_HEOIE (0x1 << 10)
+-#define LCDC_LCDIER_HCRIE (0x1 << 12)
+-
+-#define ATMEL_LCDC_LCDIDR 0x0030
+-#define LCDC_LCDIDR_SOFID (0x1 << 0)
+-#define LCDC_LCDIDR_DISID (0x1 << 1)
+-#define LCDC_LCDIDR_DISPID (0x1 << 2)
+-#define LCDC_LCDIDR_FIFOERRID (0x1 << 4)
+-#define LCDC_LCDIDR_BASEID (0x1 << 8)
+-#define LCDC_LCDIDR_OVR1ID (0x1 << 9)
+-#define LCDC_LCDIDR_HEOID (0x1 << 10)
+-#define LCDC_LCDIDR_HCRID (0x1 << 12)
+-
+-#define ATMEL_LCDC_LCDIMR 0x0034
+-#define LCDC_LCDIMR_SOFIM (0x1 << 0)
+-#define LCDC_LCDIMR_DISIM (0x1 << 1)
+-#define LCDC_LCDIMR_DISPIM (0x1 << 2)
+-#define LCDC_LCDIMR_FIFOERRIM (0x1 << 4)
+-#define LCDC_LCDIMR_BASEIM (0x1 << 8)
+-#define LCDC_LCDIMR_OVR1IM (0x1 << 9)
+-#define LCDC_LCDIMR_HEOIM (0x1 << 10)
+-#define LCDC_LCDIMR_HCRIM (0x1 << 12)
+-
+-#define ATMEL_LCDC_LCDISR 0x0038
+-#define LCDC_LCDISR_SOF (0x1 << 0)
+-#define LCDC_LCDISR_DIS (0x1 << 1)
+-#define LCDC_LCDISR_DISP (0x1 << 2)
+-#define LCDC_LCDISR_FIFOERR (0x1 << 4)
+-#define LCDC_LCDISR_BASE (0x1 << 8)
+-#define LCDC_LCDISR_OVR1 (0x1 << 9)
+-#define LCDC_LCDISR_HEO (0x1 << 10)
+-#define LCDC_LCDISR_HCR (0x1 << 12)
+-
+-#define ATMEL_LCDC_BASECHER 0x0040
+-#define LCDC_BASECHER_CHEN (0x1 << 0)
+-#define LCDC_BASECHER_UPDATEEN (0x1 << 1)
+-#define LCDC_BASECHER_A2QEN (0x1 << 2)
+-
+-#define ATMEL_LCDC_BASECHDR 0x0044
+-#define LCDC_BASECHDR_CHDIS (0x1 << 0)
+-#define LCDC_BASECHDR_CHRST (0x1 << 8)
+-
+-#define ATMEL_LCDC_BASECHSR 0x0048
+-#define LCDC_BASECHSR_CHSR (0x1 << 0)
+-#define LCDC_BASECHSR_UPDATESR (0x1 << 1)
+-#define LCDC_BASECHSR_A2QSR (0x1 << 2)
+-
+-#define ATMEL_LCDC_BASEIER 0x004C
+-#define LCDC_BASEIER_DMA (0x1 << 2)
+-#define LCDC_BASEIER_DSCR (0x1 << 3)
+-#define LCDC_BASEIER_ADD (0x1 << 4)
+-#define LCDC_BASEIER_DONE (0x1 << 5)
+-#define LCDC_BASEIER_OVR (0x1 << 6)
+-
+-#define ATMEL_LCDC_BASEIDR 0x0050
+-#define LCDC_BASEIDR_DMA (0x1 << 2)
+-#define LCDC_BASEIDR_DSCR (0x1 << 3)
+-#define LCDC_BASEIDR_ADD (0x1 << 4)
+-#define LCDC_BASEIDR_DONE (0x1 << 5)
+-#define LCDC_BASEIDR_OVR (0x1 << 6)
+-
+-#define ATMEL_LCDC_BASEIMR 0x0054
+-#define LCDC_BASEIMR_DMA (0x1 << 2)
+-#define LCDC_BASEIMR_DSCR (0x1 << 3)
+-#define LCDC_BASEIMR_ADD (0x1 << 4)
+-#define LCDC_BASEIMR_DONE (0x1 << 5)
+-#define LCDC_BASEIMR_OVR (0x1 << 6)
+-
+-#define ATMEL_LCDC_BASEISR 0x0058
+-#define LCDC_BASEISR_DMA (0x1 << 2)
+-#define LCDC_BASEISR_DSCR (0x1 << 3)
+-#define LCDC_BASEISR_ADD (0x1 << 4)
+-#define LCDC_BASEISR_DONE (0x1 << 5)
+-#define LCDC_BASEISR_OVR (0x1 << 6)
+-
+-#define ATMEL_LCDC_BASEHEAD 0x005C
+-
+-#define ATMEL_LCDC_BASEADDR 0x0060
+-
+-#define ATMEL_LCDC_BASECTRL 0x0064
+-#define LCDC_BASECTRL_DFETCH (0x1 << 0)
+-#define LCDC_BASECTRL_LFETCH (0x1 << 1)
+-#define LCDC_BASECTRL_DMAIEN (0x1 << 2)
+-#define LCDC_BASECTRL_DSCRIEN (0x1 << 3)
+-#define LCDC_BASECTRL_ADDIEN (0x1 << 4)
+-#define LCDC_BASECTRL_DONEIEN (0x1 << 5)
+-
+-#define ATMEL_LCDC_BASENEXT 0x0068
+-
+-#define ATMEL_LCDC_BASECFG0 0x006C
+-#define LCDC_BASECFG0_BLEN_OFFSET 4
+-#define LCDC_BASECFG0_BLEN (0x3 << LCDC_BASECFG0_BLEN_OFFSET)
+-#define LCDC_BASECFG0_BLEN_AHB_SINGLE (0x0 << 4)
+-#define LCDC_BASECFG0_BLEN_AHB_INCR4 (0x1 << 4)
+-#define LCDC_BASECFG0_BLEN_AHB_INCR8 (0x2 << 4)
+-#define LCDC_BASECFG0_BLEN_AHB_INCR16 (0x3 << 4)
+-#define LCDC_BASECFG0_DLBO (0x1 << 8)
+-
+-#define ATMEL_LCDC_BASECFG1 0x0070
+-#define LCDC_BASECFG1_CLUTEN (0x1 << 0)
+-#define LCDC_BASECFG1_RGBMODE_OFFSET 4
+-#define LCDC_BASECFG1_RGBMODE (0xf << LCDC_BASECFG1_RGBMODE_OFFSET)
+-#define LCDC_BASECFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
+-#define LCDC_BASECFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
+-#define LCDC_BASECFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
+-#define LCDC_BASECFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
+-#define LCDC_BASECFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
+-#define LCDC_BASECFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
+-#define LCDC_BASECFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
+-#define LCDC_BASECFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
+-#define LCDC_BASECFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
+-#define LCDC_BASECFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
+-#define LCDC_BASECFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
+-#define LCDC_BASECFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
+-#define LCDC_BASECFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
+-#define LCDC_BASECFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
+-#define LCDC_BASECFG1_CLUTMODE_OFFSET 8
+-#define LCDC_BASECFG1_CLUTMODE (0x3 << LCDC_BASECFG1_CLUTMODE_OFFSET)
+-#define LCDC_BASECFG1_CLUTMODE_1BPP (0x0 << 8)
+-#define LCDC_BASECFG1_CLUTMODE_2BPP (0x1 << 8)
+-#define LCDC_BASECFG1_CLUTMODE_4BPP (0x2 << 8)
+-#define LCDC_BASECFG1_CLUTMODE_8BPP (0x3 << 8)
+-
+-#define ATMEL_LCDC_BASECFG2 0x0074
+-
+-#define ATMEL_LCDC_BASECFG3 0x0078
+-#define LCDC_BASECFG3_BDEF_OFFSET 0
+-#define LCDC_BASECFG3_BDEF (0xff << LCDC_BASECFG3_BDEF_OFFSET)
+-#define LCDC_BASECFG3_GDEF_OFFSET 8
+-#define LCDC_BASECFG3_GDEF (0xff << LCDC_BASECFG3_GDEF_OFFSET)
+-#define LCDC_BASECFG3_RDEF_OFFSET 16
+-#define LCDC_BASECFG3_RDEF (0xff << LCDC_BASECFG3_RDEF_OFFSET)
+-
+-#define ATMEL_LCDC_BASECFG4 0x007C
+-#define LCDC_BASECFG4_DMA (0x1 << 8)
+-#define LCDC_BASECFG4_REP (0x1 << 9)
+-
+-#define ATMEL_LCDC_OVRCHER1 0x0100
+-#define LCDC_OVRCHER1_CHEN (0x1 << 0)
+-#define LCDC_OVRCHER1_UPDATEEN (0x1 << 1)
+-#define LCDC_OVRCHER1_A2QEN (0x1 << 2)
+-
+-#define ATMEL_LCDC_OVRCHDR1 0x0104
+-#define LCDC_OVRCHDR1_CHDIS (0x1 << 0)
+-#define LCDC_OVRCHDR1_CHRST (0x1 << 8)
+-
+-#define ATMEL_LCDC_OVRCHSR1 0x0108
+-#define LCDC_OVRCHSR1_CHSR (0x1 << 0)
+-#define LCDC_OVRCHSR1_UPDATESR (0x1 << 1)
+-#define LCDC_OVRCHSR1_A2QSR (0x1 << 2)
+-
+-#define ATMEL_LCDC_OVRIER1 0x010C
+-#define LCDC_OVRIER1_DMA (0x1 << 2)
+-#define LCDC_OVRIER1_DSCR (0x1 << 3)
+-#define LCDC_OVRIER1_ADD (0x1 << 4)
+-#define LCDC_OVRIER1_DONE (0x1 << 5)
+-#define LCDC_OVRIER1_OVR (0x1 << 6)
+-
+-#define ATMEL_LCDC_OVRIDR1 0x0110
+-#define LCDC_OVRIDR1_DMA (0x1 << 2)
+-#define LCDC_OVRIDR1_DSCR (0x1 << 3)
+-#define LCDC_OVRIDR1_ADD (0x1 << 4)
+-#define LCDC_OVRIDR1_DONE (0x1 << 5)
+-#define LCDC_OVRIDR1_OVR (0x1 << 6)
+-
+-#define ATMEL_LCDC_OVRIMR1 0x0114
+-#define LCDC_OVRIMR1_DMA (0x1 << 2)
+-#define LCDC_OVRIMR1_DSCR (0x1 << 3)
+-#define LCDC_OVRIMR1_ADD (0x1 << 4)
+-#define LCDC_OVRIMR1_DONE (0x1 << 5)
+-#define LCDC_OVRIMR1_OVR (0x1 << 6)
+-
+-#define ATMEL_LCDC_OVRISR1 0x0118
+-#define LCDC_OVRISR1_DMA (0x1 << 2)
+-#define LCDC_OVRISR1_DSCR (0x1 << 3)
+-#define LCDC_OVRISR1_ADD (0x1 << 4)
+-#define LCDC_OVRISR1_DONE (0x1 << 5)
+-#define LCDC_OVRISR1_OVR (0x1 << 6)
+-
+-#define ATMEL_LCDC_OVRHEAD1 0x011C
+-
+-#define ATMEL_LCDC_OVRADDR1 0x0120
+-
+-#define ATMEL_LCDC_OVRCTRL1 0x0124
+-#define LCDC_OVRCTRL1_DFETCH (0x1 << 0)
+-#define LCDC_OVRCTRL1_LFETCH (0x1 << 1)
+-#define LCDC_OVRCTRL1_DMAIEN (0x1 << 2)
+-#define LCDC_OVRCTRL1_DSCRIEN (0x1 << 3)
+-#define LCDC_OVRCTRL1_ADDIEN (0x1 << 4)
+-#define LCDC_OVRCTRL1_DONEIEN (0x1 << 5)
+-
+-#define ATMEL_LCDC_OVRNEXT1 0x0128
+-
+-#define ATMEL_LCDC_OVR1CFG0 0x012C
+-#define LCDC_OVR1CFG0_BLEN_OFFSET 4
+-#define LCDC_OVR1CFG0_BLEN (0x3 << LCDC_OVR1CFG0_BLEN_OFFSET)
+-#define LCDC_OVR1CFG0_BLEN_AHB_SINGLE (0x0 << 4)
+-#define LCDC_OVR1CFG0_BLEN_AHB_INCR4 (0x1 << 4)
+-#define LCDC_OVR1CFG0_BLEN_AHB_INCR8 (0x2 << 4)
+-#define LCDC_OVR1CFG0_BLEN_AHB_INCR16 (0x3 << 4)
+-#define LCDC_OVR1CFG0_DLBO (0x1 << 8)
+-#define LCDC_OVR1CFG0_ROTDIS (0x1 << 12)
+-#define LCDC_OVR1CFG0_LOCKDIS (0x1 << 13)
+-
+-#define ATMEL_LCDC_OVR1CFG1 0x0130
+-#define LCDC_OVR1CFG1_CLUTEN (0x1 << 0)
+-#define LCDC_OVR1CFG1_RGBMODE_OFFSET 4
+-#define LCDC_OVR1CFG1_RGBMODE (0xf << LCDC_OVR1CFG1_RGBMODE_OFFSET)
+-#define LCDC_OVR1CFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
+-#define LCDC_OVR1CFG1_CLUTMODE_OFFSET 8
+-#define LCDC_OVR1CFG1_CLUTMODE (0x3 << LCDC_OVR1CFG1_CLUTMODE_OFFSET)
+-#define LCDC_OVR1CFG1_CLUTMODE_1BPP (0x0 << 8)
+-#define LCDC_OVR1CFG1_CLUTMODE_2BPP (0x1 << 8)
+-#define LCDC_OVR1CFG1_CLUTMODE_4BPP (0x2 << 8)
+-#define LCDC_OVR1CFG1_CLUTMODE_8BPP (0x3 << 8)
+-
+-#define ATMEL_LCDC_OVR1CFG2 0x0134
+-#define LCDC_OVR1CFG2_XOFFSET_OFFSET 0
+-#define LCDC_OVR1CFG2_XOFFSET (0x7ff << LCDC_OVR1CFG2_XOFFSET_OFFSET)
+-#define LCDC_OVR1CFG2_YOFFSET_OFFSET 16
+-#define LCDC_OVR1CFG2_YOFFSET (0x7ff << LCDC_OVR1CFG2_YOFFSET_OFFSET)
+-
+-#define ATMEL_LCDC_OVR1CFG3 0x0138
+-#define LCDC_OVR1CFG3_XSIZE_OFFSET 0
+-#define LCDC_OVR1CFG3_XSIZE (0x7ff << LCDC_OVR1CFG3_XSIZE_OFFSET)
+-#define LCDC_OVR1CFG3_YSIZE_OFFSET 16
+-#define LCDC_OVR1CFG3_YSIZE (0x7ff << LCDC_OVR1CFG3_YSIZE_OFFSET)
+-
+-#define ATMEL_LCDC_OVR1CFG4 0x013C
+-
+-#define ATMEL_LCDC_OVR1CFG5 0x0140
+-
+-#define ATMEL_LCDC_OVR1CFG6 0x0144
+-#define LCDC_OVR1CFG6_BDEF_OFFSET 0
+-#define LCDC_OVR1CFG6_BDEF (0xff << LCDC_OVR1CFG6_BDEF_OFFSET)
+-#define LCDC_OVR1CFG6_GDEF_OFFSET 8
+-#define LCDC_OVR1CFG6_GDEF (0xff << LCDC_OVR1CFG6_GDEF_OFFSET)
+-#define LCDC_OVR1CFG6_RDEF_OFFSET 16
+-#define LCDC_OVR1CFG6_RDEF (0xff << LCDC_OVR1CFG6_RDEF_OFFSET)
+-
+-#define ATMEL_LCDC_OVR1CFG7 0x0148
+-#define LCDC_OVR1CFG7_BKEY_OFFSET 0
+-#define LCDC_OVR1CFG7_BKEY (0xff << LCDC_OVR1CFG7_BKEY_OFFSET)
+-#define LCDC_OVR1CFG7_GKEY_OFFSET 8
+-#define LCDC_OVR1CFG7_GKEY (0xff << LCDC_OVR1CFG7_GKEY_OFFST)
+-#define LCDC_OVR1CFG7_RKEY_OFFSET 16
+-#define LCDC_OVR1CFG7_RKEY (0xff << LCDC_OVR1CFG7_RKEY_OFFSET)
+-
+-#define ATMEL_LCDC_OVR1CFG8 0x014C
+-#define LCDC_OVR1CFG8_BMASK_OFFSET 0
+-#define LCDC_OVR1CFG8_BMASK (0xff << LCDC_OVR1CFG8_BMASK_OFFSET)
+-#define LCDC_OVR1CFG8_GMASK_OFFSET 8
+-#define LCDC_OVR1CFG8_GMASK (0xff << LCDC_OVR1CFG8_GMASK_OFFSET)
+-#define LCDC_OVR1CFG8_RMASK_OFFSET 16
+-#define LCDC_OVR1CFG8_RMASK (0xff << LCDC_OVR1CFG8_RMASK_OFFSET)
+-
+-#define ATMEL_LCDC_OVR1CFG9 0x0150
+-#define LCDC_OVR1CFG9_CRKEY (0x1 << 0)
+-#define LCDC_OVR1CFG9_INV (0x1 << 1)
+-#define LCDC_OVR1CFG9_ITER2BL (0x1 << 2)
+-#define LCDC_OVR1CFG9_ITER (0x1 << 3)
+-#define LCDC_OVR1CFG9_REVALPHA (0x1 << 4)
+-#define LCDC_OVR1CFG9_GAEN (0x1 << 5)
+-#define LCDC_OVR1CFG9_LAEN (0x1 << 6)
+-#define LCDC_OVR1CFG9_OVR (0x1 << 7)
+-#define LCDC_OVR1CFG9_DMA (0x1 << 8)
+-#define LCDC_OVR1CFG9_REP (0x1 << 9)
+-#define LCDC_OVR1CFG9_DSTKEY (0x1 << 10)
+-#define LCDC_OVR1CFG9_GA_OFFSET 16
+-#define LCDC_OVR1CFG9_GA (0xff << LCDC_OVR1CFG9_GA_OFFSET)
+-
+-#define ATMEL_LCDC_HEOCHER 0x0280
+-#define LCDC_HEOCHER_CHEN (0x1 << 0)
+-#define LCDC_HEOCHER_UPDATEEN (0x1 << 1)
+-#define LCDC_HEOCHER_A2QEN (0x1 << 2)
+-
+-#define ATMEL_LCDC_HEOCHDR 0x0284
+-#define LCDC_HEOCHDR_CHDIS (0x1 << 0)
+-#define LCDC_HEOCHDR_CHRST (0x1 << 8)
+-
+-#define ATMEL_LCDC_HEOCHSR 0x0288
+-#define LCDC_HEOCHSR_CHSR (0x1 << 0)
+-#define LCDC_HEOCHSR_UPDATESR (0x1 << 1)
+-#define LCDC_HEOCHSR_A2QSR (0x1 << 2)
+-
+-#define ATMEL_LCDC_HEOIER 0x028C
+-#define LCDC_HEOIER_DMA (0x1 << 2)
+-#define LCDC_HEOIER_DSCR (0x1 << 3)
+-#define LCDC_HEOIER_ADD (0x1 << 4)
+-#define LCDC_HEOIER_DONE (0x1 << 5)
+-#define LCDC_HEOIER_OVR (0x1 << 6)
+-#define LCDC_HEOIER_UDMA (0x1 << 10)
+-#define LCDC_HEOIER_UDSCR (0x1 << 11)
+-#define LCDC_HEOIER_UADD (0x1 << 12)
+-#define LCDC_HEOIER_UDONE (0x1 << 13)
+-#define LCDC_HEOIER_UOVR (0x1 << 14)
+-#define LCDC_HEOIER_VDMA (0x1 << 18)
+-#define LCDC_HEOIER_VDSCR (0x1 << 19)
+-#define LCDC_HEOIER_VADD (0x1 << 20)
+-#define LCDC_HEOIER_VDONE (0x1 << 21)
+-#define LCDC_HEOIER_VOVR (0x1 << 22)
+-
+-#define ATMEL_LCDC_HEOIDR 0x0290
+-#define LCDC_HEOIDR_DMA (0x1 << 2)
+-#define LCDC_HEOIDR_DSCR (0x1 << 3)
+-#define LCDC_HEOIDR_ADD (0x1 << 4)
+-#define LCDC_HEOIDR_DONE (0x1 << 5)
+-#define LCDC_HEOIDR_OVR (0x1 << 6)
+-#define LCDC_HEOIDR_UDMA (0x1 << 10)
+-#define LCDC_HEOIDR_UDSCR (0x1 << 11)
+-#define LCDC_HEOIDR_UADD (0x1 << 12)
+-#define LCDC_HEOIDR_UDONE (0x1 << 13)
+-#define LCDC_HEOIDR_UOVR (0x1 << 14)
+-#define LCDC_HEOIDR_VDMA (0x1 << 18)
+-#define LCDC_HEOIDR_VDSCR (0x1 << 19)
+-#define LCDC_HEOIDR_VADD (0x1 << 20)
+-#define LCDC_HEOIDR_VDONE (0x1 << 21)
+-#define LCDC_HEOIDR_VOVR (0x1 << 22)
+-
+-#define ATMEL_LCDC_HEOIMR 0x0294
+-#define LCDC_HEOIMR_DMA (0x1 << 2)
+-#define LCDC_HEOIMR_DSCR (0x1 << 3)
+-#define LCDC_HEOIMR_ADD (0x1 << 4)
+-#define LCDC_HEOIMR_DONE (0x1 << 5)
+-#define LCDC_HEOIMR_OVR (0x1 << 6)
+-#define LCDC_HEOIMR_UDMA (0x1 << 10)
+-#define LCDC_HEOIMR_UDSCR (0x1 << 11)
+-#define LCDC_HEOIMR_UADD (0x1 << 12)
+-#define LCDC_HEOIMR_UDONE (0x1 << 13)
+-#define LCDC_HEOIMR_UOVR (0x1 << 14)
+-#define LCDC_HEOIMR_VDMA (0x1 << 18)
+-#define LCDC_HEOIMR_VDSCR (0x1 << 19)
+-#define LCDC_HEOIMR_VADD (0x1 << 20)
+-#define LCDC_HEOIMR_VDONE (0x1 << 21)
+-#define LCDC_HEOIMR_VOVR (0x1 << 22)
+-
+-#define ATMEL_LCDC_HEOISR 0x0298
+-#define LCDC_HEOISR_DMA (0x1 << 2)
+-#define LCDC_HEOISR_DSCR (0x1 << 3)
+-#define LCDC_HEOISR_ADD (0x1 << 4)
+-#define LCDC_HEOISR_DONE (0x1 << 5)
+-#define LCDC_HEOISR_OVR (0x1 << 6)
+-#define LCDC_HEOISR_UDMA (0x1 << 10)
+-#define LCDC_HEOISR_UDSCR (0x1 << 11)
+-#define LCDC_HEOISR_UADD (0x1 << 12)
+-#define LCDC_HEOISR_UDONE (0x1 << 13)
+-#define LCDC_HEOISR_UOVR (0x1 << 14)
+-#define LCDC_HEOISR_VDMA (0x1 << 18)
+-#define LCDC_HEOISR_VDSCR (0x1 << 19)
+-#define LCDC_HEOISR_VADD (0x1 << 20)
+-#define LCDC_HEOISR_VDONE (0x1 << 21)
+-#define LCDC_HEOISR_VOVR (0x1 << 22)
+-
+-#define ATMEL_LCDC_HEOHEAD 0x029C
+-
+-#define ATMEL_LCDC_HEOADDR 0x02A0
+-
+-#define ATMEL_LCDC_HEOCTRL 0x02A4
+-#define LCDC_HEOCTRL_DFETCH (0x1 << 0)
+-#define LCDC_HEOCTRL_LFETCH (0x1 << 1)
+-#define LCDC_HEOCTRL_DMAIEN (0x1 << 2)
+-#define LCDC_HEOCTRL_DSCRIEN (0x1 << 3)
+-#define LCDC_HEOCTRL_ADDIEN (0x1 << 4)
+-#define LCDC_HEOCTRL_DONEIEN (0x1 << 5)
+-
+-#define ATMEL_LCDC_HEONEXT 0x02A8
+-
+-#define ATMEL_LCDC_HEOUHEAD 0x02AC
+-
+-#define ATMEL_LCDC_HEOUADDR 0x02B0
+-
+-#define ATMEL_LCDC_HEOUCTRL 0x02B4
+-#define LCDC_HEOUCTRL_UDFETCH (0x1 << 0)
+-#define LCDC_HEOUCTRL_UDMAIEN (0x1 << 2)
+-#define LCDC_HEOUCTRL_UDSCRIEN (0x1 << 3)
+-#define LCDC_HEOUCTRL_UADDIEN (0x1 << 4)
+-#define LCDC_HEOUCTRL_UDONEIEN (0x1 << 5)
+-
+-#define ATMEL_LCDC_HEOUNEXT 0x02B8
+-
+-#define ATMEL_LCDC_HEOVHEAD 0x02BC
+-
+-#define ATMEL_LCDC_HEOVADDR 0x02C0
+-
+-#define ATMEL_LCDC_HEOVCTRL 0x02C4
+-#define LCDC_HEOVCTRL_VDFETCH (0x1 << 0)
+-#define LCDC_HEOVCTRL_VDMAIEN (0x1 << 2)
+-#define LCDC_HEOVCTRL_VDSCRIEN (0x1 << 3)
+-#define LCDC_HEOVCTRL_VADDIEN (0x1 << 4)
+-#define LCDC_HEOVCTRL_VDONEIEN (0x1 << 5)
+-
+-#define ATMEL_LCDC_HEOVNEXT 0x02C8
+-
+-#define ATMEL_LCDC_HEOCFG0 0x02CC
+-#define LCDC_HEOCFG0_BLEN_OFFSET 4
+-#define LCDC_HEOCFG0_BLEN (0x3 << LCDC_HEOCFG0_BLEN_OFFSET)
+-#define LCDC_HEOCFG0_BLEN_AHB_SINGLE (0x0 << 4)
+-#define LCDC_HEOCFG0_BLEN_AHB_INCR4 (0x1 << 4)
+-#define LCDC_HEOCFG0_BLEN_AHB_INCR8 (0x2 << 4)
+-#define LCDC_HEOCFG0_BLEN_AHB_INCR16 (0x3 << 4)
+-#define LCDC_HEOCFG0_BLENUV_OFFSET 6
+-#define LCDC_HEOCFG0_BLENUV (0x3 << LCDC_HEOCFG0_BLENUV_OFFSET)
+-#define LCDC_HEOCFG0_BLENUV_AHB_SINGLE (0x0 << 6)
+-#define LCDC_HEOCFG0_BLENUV_AHB_INCR4 (0x1 << 6)
+-#define LCDC_HEOCFG0_BLENUV_AHB_INCR8 (0x2 << 6)
+-#define LCDC_HEOCFG0_BLENUV_AHB_INCR16 (0x3 << 6)
+-#define LCDC_HEOCFG0_DLBO (0x1 << 8)
+-#define LCDC_HEOCFG0_ROTDIS (0x1 << 12)
+-#define LCDC_HEOCFG0_LOCKDIS (0x1 << 13)
+-
+-#define ATMEL_LCDC_HEOCFG1 0x02D0
+-#define LCDC_HEOCFG1_CLUTEN (0x1 << 0)
+-#define LCDC_HEOCFG1_YUVEN (0x1 << 1)
+-#define LCDC_HEOCFG1_RGBMODE_OFFSET 4
+-#define LCDC_HEOCFG1_RGBMODE (0xf << LCDC_HEOCFG1_RGBMODE_OFFSET)
+-#define LCDC_HEOCFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
+-#define LCDC_HEOCFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
+-#define LCDC_HEOCFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
+-#define LCDC_HEOCFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
+-#define LCDC_HEOCFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
+-#define LCDC_HEOCFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
+-#define LCDC_HEOCFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
+-#define LCDC_HEOCFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
+-#define LCDC_HEOCFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
+-#define LCDC_HEOCFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
+-#define LCDC_HEOCFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
+-#define LCDC_HEOCFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
+-#define LCDC_HEOCFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
+-#define LCDC_HEOCFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
+-#define LCDC_HEOCFG1_CLUTMODE_OFFSET 8
+-#define LCDC_HEOCFG1_CLUTMODE (0x3 << LCDC_HEOCFG1_CLUTMODE_OFFSET)
+-#define LCDC_HEOCFG1_CLUTMODE_1BPP (0x0 << 8)
+-#define LCDC_HEOCFG1_CLUTMODE_2BPP (0x1 << 8)
+-#define LCDC_HEOCFG1_CLUTMODE_4BPP (0x2 << 8)
+-#define LCDC_HEOCFG1_CLUTMODE_8BPP (0x3 << 8)
+-#define LCDC_HEOCFG1_YUVMODE_OFFSET 12
+-#define LCDC_HEOCFG1_YUVMODE (0xf << LCDC_HEOCFG1_YUVMODE_OFFSET)
+-#define LCDC_HEOCFG1_YUVMODE_32BPP_AYCBCR (0x0 << 12)
+-#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE0 (0x1 << 12)
+-#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE1 (0x2 << 12)
+-#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE2 (0x3 << 12)
+-#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE3 (0x4 << 12)
+-#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_SEMIPLANAR (0x5 << 12)
+-#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_PLANAR (0x6 << 12)
+-#define LCDC_HEOCFG1_YUVMODE_12BPP_YCBCR_SEMIPLANAR (0x7 << 12)
+-#define LCDC_HEOCFG1_YUVMODE_12BPP_YCBCR_PLANAR (0x8 << 12)
+-#define LCDC_HEOCFG1_YUV422ROT (0x1 << 16)
+-#define LCDC_HEOCFG1_YUV422SWP (0x1 << 17)
+-
+-#define ATMEL_LCDC_HEOCFG2 0x02D4
+-#define LCDC_HEOCFG2_XOFFSET_OFFSET 0
+-#define LCDC_HEOCFG2_XOFFSET (0x7ff << LCDC_HEOCFG2_XOFFSET_OFFSET)
+-#define LCDC_HEOCFG2_YOFFSET_OFFSET 16
+-#define LCDC_HEOCFG2_YOFFSET (0x7ff << LCDC_HEOCFG2_YOFFSET_OFFSET)
+-
+-#define ATMEL_LCDC_HEOCFG3 0x02D8
+-#define LCDC_HEOCFG3_XSIZE_OFFSET 0
+-#define LCDC_HEOCFG3_XSIZE (0x7ff << LCDC_HEOCFG3_XSIZE_OFFSET)
+-#define LCDC_HEOCFG3_YSIZE_OFFSET 16
+-#define LCDC_HEOCFG3_YSIZE (0x7ff << LCDC_HEOCFG3_YSIZE_OFFSET)
+-
+-#define ATMEL_LCDC_HEOCFG4 0x02DC
+-#define LCDC_HEOCFG4_XMEM_SIZE_OFFSET 0
+-#define LCDC_HEOCFG4_XMEM_SIZE (0x7ff << LCDC_HEOCFG4_XMEM_SIZE_OFFSET)
+-#define LCDC_HEOCFG4_YMEM_SIZE_OFFSET 16
+-#define LCDC_HEOCFG4_YMEM_SIZE (0x7ff << LCDC_HEOCFG4_YMEM_SIZE_OFFSET)
+-
+-#define ATMEL_LCDC_HEOCFG5 0x02E0
+-
+-#define ATMEL_LCDC_HEOCFG6 0x02E4
+-
+-#define ATMEL_LCDC_HEOCFG7 0x02E8
+-
+-#define ATMEL_LCDC_HEOCFG8 0x02EC
+-
+-#define ATMEL_LCDC_HEOCFG9 0x02F0
+-#define LCDC_HEOCFG9_BDEF_OFFSET 0
+-#define LCDC_HEOCFG9_BDEF (0xff << LCDC_HEOCFG9_BDEF_OFFSET)
+-#define LCDC_HEOCFG9_GDEF_OFFSET 8
+-#define LCDC_HEOCFG9_GDEF (0xff << LCDC_HEOCFG9_GDEF_OFFSET)
+-#define LCDC_HEOCFG9_RDEF_OFFSET 16
+-#define LCDC_HEOCFG9_RDEF (0xff << LCDC_HEOCFG9_RDEF_OFFSET)
+-
+-#define ATMEL_LCDC_HEOCFG10 0x02F4
+-#define LCDC_HEOCFG10_BKEY_OFFSET 0
+-#define LCDC_HEOCFG10_BKEY (0xff << LCDC_HEOCFG10_BKEY_OFFSET)
+-#define LCDC_HEOCFG10_GKEY_OFFSET 8
+-#define LCDC_HEOCFG10_GKEY (0xff << LCDC_HEOCFG10_GKEY_OFFSET)
+-#define LCDC_HEOCFG10_RKEY_OFFSET 16
+-#define LCDC_HEOCFG10_RKEY (0xff << LCDC_HEOCFG10_RKEY_OFFSET)
+-
+-#define ATMEL_LCDC_HEOCFG11 0x02F8
+-#define LCDC_HEOCFG11_BMASK_OFFSET 0
+-#define LCDC_HEOCFG11_BMASK (0xff << LCDC_HEOCFG11_BMASK_OFFSET)
+-#define LCDC_HEOCFG11_GMASK_OFFSET 8
+-#define LCDC_HEOCFG11_GMASK (0xff << LCDC_HEOCFG11_GMASK_OFFSET)
+-#define LCDC_HEOCFG11_RMASK_OFFSET 16
+-#define LCDC_HEOCFG11_RMASK (0xff << LCDC_HEOCFG11_RMASK_OFFSET)
+-
+-#define ATMEL_LCDC_HEOCFG12 0x02FC
+-#define LCDC_HEOCFG12_CRKEY (0x1 << 0)
+-#define LCDC_HEOCFG12_INV (0x1 << 1)
+-#define LCDC_HEOCFG12_ITER2BL (0x1 << 2)
+-#define LCDC_HEOCFG12_ITER (0x1 << 3)
+-#define LCDC_HEOCFG12_REVALPHA (0x1 << 4)
+-#define LCDC_HEOCFG12_GAEN (0x1 << 5)
+-#define LCDC_HEOCFG12_LAEN (0x1 << 6)
+-#define LCDC_HEOCFG12_OVR (0x1 << 7)
+-#define LCDC_HEOCFG12_DMA (0x1 << 8)
+-#define LCDC_HEOCFG12_REP (0x1 << 9)
+-#define LCDC_HEOCFG12_DSTKEY (0x1 << 10)
+-#define LCDC_HEOCFG12_VIDPRI (0x1 << 12)
+-#define LCDC_HEOCFG12_GA_OFFSET 16
+-#define LCDC_HEOCFG12_GA (0xff << LCDC_HEOCFG12_GA_OFFSET)
+-
+-#define ATMEL_LCDC_HEOCFG13 0x0300
+-#define LCDC_HEOCFG13_XFACTOR_OFFSET 0
+-#define LCDC_HEOCFG13_XFACTOR (0x1fff << LCDC_HEOCFG13_XFACTOR_OFFSET)
+-#define LCDC_HEOCFG13_YFACTOR_OFFSET 16
+-#define LCDC_HEOCFG13_YFACTOR (0x1fff << LCDC_HEOCFG13_YFACTOR_OFFSET)
+-#define LCDC_HEOCFG13_SCALEN (0x1 << 31)
+-
+-#define ATMEL_LCDC_HEOCFG14 0x0304
+-#define LCDC_HEOCFG14_CSCRY_OFFSET 0
+-#define LCDC_HEOCFG14_CSCRY (0x3ff << LCDC_HEOCFG14_CSCRY_OFFSET)
+-#define LCDC_HEOCFG14_CSCRU_OFFSET 10
+-#define LCDC_HEOCFG14_CSCRU (0x3ff << LCDC_HEOCFG14_CSCRU_OFFSET)
+-#define LCDC_HEOCFG14_CSCRV_OFFSET 20
+-#define LCDC_HEOCFG14_CSCRV (0x3ff << LCDC_HEOCFG14_CSCRV_OFFSET)
+-#define LCDC_HEOCFG14_CSCYOFF (0x1 << 30)
+-
+-#define ATMEL_LCDC_HEOCFG15 0x0308
+-#define LCDC_HEOCFG15_CSCGY_OFFSET 0
+-#define LCDC_HEOCFG15_CSCGY (0x3ff << LCDC_HEOCFG15_CSCGY_OFFSET)
+-#define LCDC_HEOCFG15_CSCGU_OFFSET 10
+-#define LCDC_HEOCFG15_CSCGU (0x3ff << LCDC_HEOCFG15_CSCGU_OFFSET)
+-#define LCDC_HEOCFG15_CSCGV_OFFSET 20
+-#define LCDC_HEOCFG15_CSCGV (0x3ff << LCDC_HEOCFG15_CSCGV_OFFSET)
+-#define LCDC_HEOCFG15_CSCUOFF (0x1 << 30)
+-
+-#define ATMEL_LCDC_HEOCFG16 0x030C
+-#define LCDC_HEOCFG16_CSCBY_OFFSET 0
+-#define LCDC_HEOCFG16_CSCBY (0x3ff << LCDC_HEOCFG16_CSCBY_OFFSET)
+-#define LCDC_HEOCFG16_CSCBU_OFFSET 10
+-#define LCDC_HEOCFG16_CSCBU (0x3ff << LCDC_HEOCFG16_CSCBU_OFFSET)
+-#define LCDC_HEOCFG16_CSCBV_OFFSET 20
+-#define LCDC_HEOCFG16_CSCBV (0x3ff << LCDC_HEOCFG16_CSCBV_OFFSET)
+-#define LCDC_HEOCFG16_CSCVOFF (0x1 << 30)
+-
+-#define ATMEL_LCDC_HCRCHER 0x0340
+-#define LCDC_HCRCHER_CHEN (0x1 << 0)
+-#define LCDC_HCRCHER_UPDATEEN (0x1 << 1)
+-#define LCDC_HCRCHER_A2QEN (0x1 << 2)
+-
+-#define ATMEL_LCDC_HCRCHDR 0x0344
+-#define LCDC_HCRCHDR_CHDIS (0x1 << 0)
+-#define LCDC_HCRCHDR_CHRST (0x1 << 8)
+-
+-#define ATMEL_LCDC_HCRCHSR 0x0348
+-#define LCDC_HCRCHSR_CHSR (0x1 << 0)
+-#define LCDC_HCRCHSR_UPDATESR (0x1 << 1)
+-#define LCDC_HCRCHSR_A2QSR (0x1 << 2)
+-
+-#define ATMEL_LCDC_HCRIER 0x034C
+-#define LCDC_HCRIER_DMA (0x1 << 2)
+-#define LCDC_HCRIER_DSCR (0x1 << 3)
+-#define LCDC_HCRIER_ADD (0x1 << 4)
+-#define LCDC_HCRIER_DONE (0x1 << 5)
+-#define LCDC_HCRIER_OVR (0x1 << 6)
+-
+-#define ATMEL_LCDC_HCRIDR 0x0350
+-#define LCDC_HCRIDR_DMA (0x1 << 2)
+-#define LCDC_HCRIDR_DSCR (0x1 << 3)
+-#define LCDC_HCRIDR_ADD (0x1 << 4)
+-#define LCDC_HCRIDR_DONE (0x1 << 5)
+-#define LCDC_HCRIDR_OVR (0x1 << 6)
+-
+-#define ATMEL_LCDC_HCRIMR 0x0354
+-#define LCDC_HCRIMR_DMA (0x1 << 2)
+-#define LCDC_HCRIMR_DSCR (0x1 << 3)
+-#define LCDC_HCRIMR_ADD (0x1 << 4)
+-#define LCDC_HCRIMR_DONE (0x1 << 5)
+-#define LCDC_HCRIMR_OVR (0x1 << 6)
+-
+-#define ATMEL_LCDC_HCRISR 0x0358
+-#define LCDC_HCRISR_DMA (0x1 << 2)
+-#define LCDC_HCRISR_DSCR (0x1 << 3)
+-#define LCDC_HCRISR_ADD (0x1 << 4)
+-#define LCDC_HCRISR_DONE (0x1 << 5)
+-#define LCDC_HCRISR_OVR (0x1 << 6)
+-
+-#define ATMEL_LCDC_HCRHEAD 0x035C
+-
+-#define ATMEL_LCDC_HCRADDR 0x0360
+-
+-#define ATMEL_LCDC_HCRCTRL 0x0364
+-#define LCDC_HCRCTRL_DFETCH (0x1 << 0)
+-#define LCDC_HCRCTRL_LFETCH (0x1 << 1)
+-#define LCDC_HCRCTRL_DMAIEN (0x1 << 2)
+-#define LCDC_HCRCTRL_DSCRIEN (0x1 << 3)
+-#define LCDC_HCRCTRL_ADDIEN (0x1 << 4)
+-#define LCDC_HCRCTRL_DONEIEN (0x1 << 5)
+-
+-#define ATMEL_LCDC_HCRNEXT 0x0368
+-
+-#define ATMEL_LCDC_HCRCFG0 0x036C
+-#define LCDC_HCRCFG0_BLEN_OFFSET 4
+-#define LCDC_HCRCFG0_BLEN (0x3 << LCDC_HCRCFG0_BLEN_OFFSET)
+-#define LCDC_HCRCFG0_BLEN_AHB_SINGLE (0x0 << 4)
+-#define LCDC_HCRCFG0_BLEN_AHB_INCR4 (0x1 << 4)
+-#define LCDC_HCRCFG0_BLEN_AHB_INCR8 (0x2 << 4)
+-#define LCDC_HCRCFG0_BLEN_AHB_INCR16 (0x3 << 4)
+-#define LCDC_HCRCFG0_DLBO (0x1 << 8)
+-
+-#define ATMEL_LCDC_HCRCFG1 0x0370
+-#define LCDC_HCRCFG1_CLUTEN (0x1 << 0)
+-#define LCDC_HCRCFG1_RGBMODE_OFFSET 4
+-#define LCDC_HCRCFG1_RGBMODE (0xf << LCDC_HCRCFG1_RGBMODE_OFFSET)
+-#define LCDC_HCRCFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
+-#define LCDC_HCRCFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
+-#define LCDC_HCRCFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
+-#define LCDC_HCRCFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
+-#define LCDC_HCRCFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
+-#define LCDC_HCRCFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
+-#define LCDC_HCRCFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
+-#define LCDC_HCRCFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
+-#define LCDC_HCRCFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
+-#define LCDC_HCRCFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
+-#define LCDC_HCRCFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
+-#define LCDC_HCRCFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
+-#define LCDC_HCRCFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
+-#define LCDC_HCRCFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
+-#define LCDC_HCRCFG1_CLUTMODE_OFFSET 8
+-#define LCDC_HCRCFG1_CLUTMODE (0x3 << LCDC_HCRCFG1_CLUTMODE_OFFSET)
+-#define LCDC_HCRCFG1_CLUTMODE_1BPP (0x0 << 8)
+-#define LCDC_HCRCFG1_CLUTMODE_2BPP (0x1 << 8)
+-#define LCDC_HCRCFG1_CLUTMODE_4BPP (0x2 << 8)
+-#define LCDC_HCRCFG1_CLUTMODE_8BPP (0x3 << 8)
+-
+-#define ATMEL_LCDC_HCRCFG2 0x0374
+-#define LCDC_HCRCFG2_XOFFSET_OFFSET 0
+-#define LCDC_HCRCFG2_XOFFSET (0x7ff << LCDC_HCRCFG2_XOFFSET_OFFSET)
+-#define LCDC_HCRCFG2_YOFFSET_OFFSET 16
+-#define LCDC_HCRCFG2_YOFFSET (0x7ff << LCDC_HCRCFG2_YOFFSET_OFFSET)
+-
+-#define ATMEL_LCDC_HCRCFG3 0x0378
+-#define LCDC_HCRCFG3_XSIZE_OFFSET 0
+-#define LCDC_HCRCFG3_XSIZE (0x7f << LCDC_HCRCFG3_XSIZE_OFFSET)
+-#define LCDC_HCRCFG3_YSIZE_OFFSET 16
+-#define LCDC_HCRCFG3_YSIZE (0x7f << LCDC_HCRCFG3_YSIZE_OFFSET)
+-
+-#define ATMEL_LCDC_HCRCFG4 0x037C
+-
+-#define ATMEL_LCDC_HCRCFG6 0x0384
+-#define LCDC_HCRCFG6_BDEF_OFFSET 0
+-#define LCDC_HCRCFG6_BDEF (0xff << LCDC_HCRCFG6_BDEF_OFFSET)
+-#define LCDC_HCRCFG6_GDEF_OFFSET 8
+-#define LCDC_HCRCFG6_GDEF (0xff << LCDC_HCRCFG6_GDEF_OFFSET)
+-#define LCDC_HCRCFG6_RDEF_OFFSET 16
+-#define LCDC_HCRCFG6_RDEF (0xff << LCDC_HCRCFG6_RDEF_OFFSET)
+-
+-#define ATMEL_LCDC_HCRCFG7 0x0388
+-#define LCDC_HCRCFG7_BKEY_OFFSET 0
+-#define LCDC_HCRCFG7_BKEY (0xff << LCDC_HCRCFG7_BKEY_OFFSET)
+-#define LCDC_HCRCFG7_GKEY_OFFSET 8
+-#define LCDC_HCRCFG7_GKEY (0xff << LCDC_HCRCFG7_GKEY_OFFSET)
+-#define LCDC_HCRCFG7_RKEY_OFFSET 16
+-#define LCDC_HCRCFG7_RKEY (0xff << LCDC_HCRCFG7_RKEY_OFFSET)
+-
+-#define ATMEL_LCDC_HCRCFG8 0x038C
+-#define LCDC_HCRCFG8_BMASK_OFFSET 0
+-#define LCDC_HCRCFG8_BMASK (0xff << LCDC_HCRCFG8_BMASK_OFFSET)
+-#define LCDC_HCRCFG8_GMASK_OFFSET 8
+-#define LCDC_HCRCFG8_GMASK (0xff << LCDC_HCRCFG8_GMASK_OFFSET)
+-#define LCDC_HCRCFG8_RMASK_OFFSET 16
+-#define LCDC_HCRCFG8_RMASK (0xff << LCDC_HCRCFG8_RMASK_OFFSET)
+-
+-#define ATMEL_LCDC_HCRCFG9 0x0390
+-#define LCDC_HCRCFG9_CRKEY (0x1 << 0)
+-#define LCDC_HCRCFG9_INV (0x1 << 1)
+-#define LCDC_HCRCFG9_ITER2BL (0x1 << 2)
+-#define LCDC_HCRCFG9_ITER (0x1 << 3)
+-#define LCDC_HCRCFG9_REVALPHA (0x1 << 4)
+-#define LCDC_HCRCFG9_GAEN (0x1 << 5)
+-#define LCDC_HCRCFG9_LAEN (0x1 << 6)
+-#define LCDC_HCRCFG9_OVR (0x1 << 7)
+-#define LCDC_HCRCFG9_DMA (0x1 << 8)
+-#define LCDC_HCRCFG9_REP (0x1 << 9)
+-#define LCDC_HCRCFG9_DSTKEY (0x1 << 10)
+-#define LCDC_HCRCFG9_GA_OFFSET 16
+-#define LCDC_HCRCFG9_GA_Msk (0xff << LCDC_HCRCFG9_GA_OFFSET)
+-
+-#define ATMEL_LCDC_BASECLUT 0x400
+-#define LCDC_BASECLUT_BCLUT_OFFSET 0
+-#define LCDC_BASECLUT_BCLUT (0xff << LCDC_BASECLUT_BCLUT_OFFSET)
+-#define LCDC_BASECLUT_GCLUT_OFFSET 8
+-#define LCDC_BASECLUT_GCLUT (0xff << LCDC_BASECLUT_GCLUT_OFFSET)
+-#define LCDC_BASECLUT_RCLUT_OFFSET 16
+-#define LCDC_BASECLUT_RCLUT (0xff << LCDC_BASECLUT_RCLUT_OFFSET)
+-
+-#define ATMEL_LCDC_OVR1CLUT 0x800
+-#define LCDC_OVR1CLUT_BCLUT_OFFSET 0
+-#define LCDC_OVR1CLUT_BCLUT (0xff << LCDC_OVR1CLUT_BCLUT_OFFSET)
+-#define LCDC_OVR1CLUT_GCLUT_OFFSET 8
+-#define LCDC_OVR1CLUT_GCLUT (0xff << LCDC_OVR1CLUT_GCLUT_OFFSET)
+-#define LCDC_OVR1CLUT_RCLUT_OFFSET 16
+-#define LCDC_OVR1CLUT_RCLUT (0xff << LCDC_OVR1CLUT_RCLUT_OFFSET)
+-#define LCDC_OVR1CLUT_ACLUT_OFFSET 24
+-#define LCDC_OVR1CLUT_ACLUT (0xff << LCDC_OVR1CLUT_ACLUT_OFFSET)
+-
+-#define ATMEL_LCDC_HEOCLUT 0x1000
+-#define LCDC_HEOCLUT_BCLUT_OFFSET 0
+-#define LCDC_HEOCLUT_BCLUT (0xff << LCDC_HEOCLUT_BCLUT_OFFSET)
+-#define LCDC_HEOCLUT_GCLUT_OFFSET 8
+-#define LCDC_HEOCLUT_GCLUT (0xff << LCDC_HEOCLUT_GCLUT_OFFSET)
+-#define LCDC_HEOCLUT_RCLUT_OFFSET 16
+-#define LCDC_HEOCLUT_RCLUT (0xff << LCDC_HEOCLUT_RCLUT_OFFSET)
+-#define LCDC_HEOCLUT_ACLUT_OFFSET 24
+-#define LCDC_HEOCLUT_ACLUT (0xff << LCDC_HEOCLUT_ACLUT_OFFSET)
+-
+-#define ATMEL_LCDC_HCRCLUT 0x1400
+-#define LCDC_HCRCLUT_BCLUT_OFFSET 0
+-#define LCDC_HCRCLUT_BCLUT (0xff << LCDC_HCRCLUT_BCLUT_OFFSET)
+-#define LCDC_HCRCLUT_GCLUT_OFFSET 8
+-#define LCDC_HCRCLUT_GCLUT (0xff << LCDC_HCRCLUT_GCLUT_OFFSET)
+-#define LCDC_HCRCLUT_RCLUT_OFFSET 16
+-#define LCDC_HCRCLUT_RCLUT (0xff << LCDC_HCRCLUT_RCLUT_OFFSET)
+-#define LCDC_HCRCLUT_ACLUT_OFFSET 24
+-#define LCDC_HCRCLUT_ACLUT (0xff << LCDC_HCRCLUT_ACLUT_OFFSET)
+-
+-/* Base layer CLUT */
+-#define ATMEL_LCDC_LUT(n) (0x0400 + ((n)*4))
+-
+-
+-#endif /* __ATMEL_HLCDC4_H__ */
+diff --git a/arch/arm/mach-at91/include/mach/atmel_lcdc.h b/arch/arm/mach-at91/include/mach/atmel_lcdc.h
+new file mode 100644
+index 0000000..248fed3
+--- /dev/null
++++ b/arch/arm/mach-at91/include/mach/atmel_lcdc.h
+@@ -0,0 +1,177 @@
++/*
++ * Header file for AT91/AT32 LCD Controller
++ *
++ * Data structure and register user interface
++ *
++ * Copyright (C) 2007 Atmel Corporation
++ *
++ * 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.
++ *
++ * 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 __MACH_ATMEL_LCDC_H__
++#define __MACH_ATMEL_LCDC_H__
++
++#define ATMEL_LCDC_DMABADDR1 0x00
++#define ATMEL_LCDC_DMABADDR2 0x04
++#define ATMEL_LCDC_DMAFRMPT1 0x08
++#define ATMEL_LCDC_DMAFRMPT2 0x0c
++#define ATMEL_LCDC_DMAFRMADD1 0x10
++#define ATMEL_LCDC_DMAFRMADD2 0x14
++
++#define ATMEL_LCDC_DMAFRMCFG 0x18
++#define ATMEL_LCDC_FRSIZE (0x7fffff << 0)
++#define ATMEL_LCDC_BLENGTH_OFFSET 24
++#define ATMEL_LCDC_BLENGTH (0x7f << ATMEL_LCDC_BLENGTH_OFFSET)
++
++#define ATMEL_LCDC_DMACON 0x1c
++#define ATMEL_LCDC_DMAEN (0x1 << 0)
++#define ATMEL_LCDC_DMARST (0x1 << 1)
++#define ATMEL_LCDC_DMABUSY (0x1 << 2)
++#define ATMEL_LCDC_DMAUPDT (0x1 << 3)
++#define ATMEL_LCDC_DMA2DEN (0x1 << 4)
++
++#define ATMEL_LCDC_DMA2DCFG 0x20
++#define ATMEL_LCDC_ADDRINC_OFFSET 0
++#define ATMEL_LCDC_ADDRINC (0xffff)
++#define ATMEL_LCDC_PIXELOFF_OFFSET 24
++#define ATMEL_LCDC_PIXELOFF (0x1f << 24)
++
++#define ATMEL_LCDC_LCDCON1 0x0800
++#define ATMEL_LCDC_BYPASS (1 << 0)
++#define ATMEL_LCDC_CLKVAL_OFFSET 12
++#define ATMEL_LCDC_CLKVAL (0x1ff << ATMEL_LCDC_CLKVAL_OFFSET)
++#define ATMEL_LCDC_LINCNT (0x7ff << 21)
++
++#define ATMEL_LCDC_LCDCON2 0x0804
++#define ATMEL_LCDC_DISTYPE (3 << 0)
++#define ATMEL_LCDC_DISTYPE_STNMONO (0 << 0)
++#define ATMEL_LCDC_DISTYPE_STNCOLOR (1 << 0)
++#define ATMEL_LCDC_DISTYPE_TFT (2 << 0)
++#define ATMEL_LCDC_SCANMOD (1 << 2)
++#define ATMEL_LCDC_SCANMOD_SINGLE (0 << 2)
++#define ATMEL_LCDC_SCANMOD_DUAL (1 << 2)
++#define ATMEL_LCDC_IFWIDTH (3 << 3)
++#define ATMEL_LCDC_IFWIDTH_4 (0 << 3)
++#define ATMEL_LCDC_IFWIDTH_8 (1 << 3)
++#define ATMEL_LCDC_IFWIDTH_16 (2 << 3)
++#define ATMEL_LCDC_PIXELSIZE (7 << 5)
++#define ATMEL_LCDC_PIXELSIZE_1 (0 << 5)
++#define ATMEL_LCDC_PIXELSIZE_2 (1 << 5)
++#define ATMEL_LCDC_PIXELSIZE_4 (2 << 5)
++#define ATMEL_LCDC_PIXELSIZE_8 (3 << 5)
++#define ATMEL_LCDC_PIXELSIZE_16 (4 << 5)
++#define ATMEL_LCDC_PIXELSIZE_24 (5 << 5)
++#define ATMEL_LCDC_PIXELSIZE_32 (6 << 5)
++#define ATMEL_LCDC_INVVD (1 << 8)
++#define ATMEL_LCDC_INVVD_NORMAL (0 << 8)
++#define ATMEL_LCDC_INVVD_INVERTED (1 << 8)
++#define ATMEL_LCDC_INVFRAME (1 << 9 )
++#define ATMEL_LCDC_INVFRAME_NORMAL (0 << 9)
++#define ATMEL_LCDC_INVFRAME_INVERTED (1 << 9)
++#define ATMEL_LCDC_INVLINE (1 << 10)
++#define ATMEL_LCDC_INVLINE_NORMAL (0 << 10)
++#define ATMEL_LCDC_INVLINE_INVERTED (1 << 10)
++#define ATMEL_LCDC_INVCLK (1 << 11)
++#define ATMEL_LCDC_INVCLK_NORMAL (0 << 11)
++#define ATMEL_LCDC_INVCLK_INVERTED (1 << 11)
++#define ATMEL_LCDC_INVDVAL (1 << 12)
++#define ATMEL_LCDC_INVDVAL_NORMAL (0 << 12)
++#define ATMEL_LCDC_INVDVAL_INVERTED (1 << 12)
++#define ATMEL_LCDC_CLKMOD (1 << 15)
++#define ATMEL_LCDC_CLKMOD_ACTIVEDISPLAY (0 << 15)
++#define ATMEL_LCDC_CLKMOD_ALWAYSACTIVE (1 << 15)
++#define ATMEL_LCDC_MEMOR (1 << 31)
++#define ATMEL_LCDC_MEMOR_BIG (0 << 31)
++#define ATMEL_LCDC_MEMOR_LITTLE (1 << 31)
++
++#define ATMEL_LCDC_TIM1 0x0808
++#define ATMEL_LCDC_VFP (0xffU << 0)
++#define ATMEL_LCDC_VBP_OFFSET 8
++#define ATMEL_LCDC_VBP (0xffU << ATMEL_LCDC_VBP_OFFSET)
++#define ATMEL_LCDC_VPW_OFFSET 16
++#define ATMEL_LCDC_VPW (0x3fU << ATMEL_LCDC_VPW_OFFSET)
++#define ATMEL_LCDC_VHDLY_OFFSET 24
++#define ATMEL_LCDC_VHDLY (0xfU << ATMEL_LCDC_VHDLY_OFFSET)
++
++#define ATMEL_LCDC_TIM2 0x080c
++#define ATMEL_LCDC_HBP (0xffU << 0)
++#define ATMEL_LCDC_HPW_OFFSET 8
++#define ATMEL_LCDC_HPW (0x3fU << ATMEL_LCDC_HPW_OFFSET)
++#define ATMEL_LCDC_HFP_OFFSET 21
++#define ATMEL_LCDC_HFP (0x7ffU << ATMEL_LCDC_HFP_OFFSET)
++
++#define ATMEL_LCDC_LCDFRMCFG 0x0810
++#define ATMEL_LCDC_LINEVAL (0x7ff << 0)
++#define ATMEL_LCDC_HOZVAL_OFFSET 21
++#define ATMEL_LCDC_HOZVAL (0x7ff << ATMEL_LCDC_HOZVAL_OFFSET)
++
++#define ATMEL_LCDC_FIFO 0x0814
++#define ATMEL_LCDC_FIFOTH (0xffff)
++
++#define ATMEL_LCDC_MVAL 0x0818
++
++#define ATMEL_LCDC_DP1_2 0x081c
++#define ATMEL_LCDC_DP4_7 0x0820
++#define ATMEL_LCDC_DP3_5 0x0824
++#define ATMEL_LCDC_DP2_3 0x0828
++#define ATMEL_LCDC_DP5_7 0x082c
++#define ATMEL_LCDC_DP3_4 0x0830
++#define ATMEL_LCDC_DP4_5 0x0834
++#define ATMEL_LCDC_DP6_7 0x0838
++#define ATMEL_LCDC_DP1_2_VAL (0xff)
++#define ATMEL_LCDC_DP4_7_VAL (0xfffffff)
++#define ATMEL_LCDC_DP3_5_VAL (0xfffff)
++#define ATMEL_LCDC_DP2_3_VAL (0xfff)
++#define ATMEL_LCDC_DP5_7_VAL (0xfffffff)
++#define ATMEL_LCDC_DP3_4_VAL (0xffff)
++#define ATMEL_LCDC_DP4_5_VAL (0xfffff)
++#define ATMEL_LCDC_DP6_7_VAL (0xfffffff)
++
++#define ATMEL_LCDC_PWRCON 0x083c
++#define ATMEL_LCDC_PWR (1 << 0)
++#define ATMEL_LCDC_GUARDT_OFFSET 1
++#define ATMEL_LCDC_GUARDT (0x7f << ATMEL_LCDC_GUARDT_OFFSET)
++#define ATMEL_LCDC_BUSY (1 << 31)
++
++#define ATMEL_LCDC_CONTRAST_CTR 0x0840
++#define ATMEL_LCDC_PS (3 << 0)
++#define ATMEL_LCDC_PS_DIV1 (0 << 0)
++#define ATMEL_LCDC_PS_DIV2 (1 << 0)
++#define ATMEL_LCDC_PS_DIV4 (2 << 0)
++#define ATMEL_LCDC_PS_DIV8 (3 << 0)
++#define ATMEL_LCDC_POL (1 << 2)
++#define ATMEL_LCDC_POL_NEGATIVE (0 << 2)
++#define ATMEL_LCDC_POL_POSITIVE (1 << 2)
++#define ATMEL_LCDC_ENA (1 << 3)
++#define ATMEL_LCDC_ENA_PWMDISABLE (0 << 3)
++#define ATMEL_LCDC_ENA_PWMENABLE (1 << 3)
++
++#define ATMEL_LCDC_CONTRAST_VAL 0x0844
++#define ATMEL_LCDC_CVAL (0xff)
++
++#define ATMEL_LCDC_IER 0x0848
++#define ATMEL_LCDC_IDR 0x084c
++#define ATMEL_LCDC_IMR 0x0850
++#define ATMEL_LCDC_ISR 0x0854
++#define ATMEL_LCDC_ICR 0x0858
++#define ATMEL_LCDC_LNI (1 << 0)
++#define ATMEL_LCDC_LSTLNI (1 << 1)
++#define ATMEL_LCDC_EOFI (1 << 2)
++#define ATMEL_LCDC_UFLWI (1 << 4)
++#define ATMEL_LCDC_OWRI (1 << 5)
++#define ATMEL_LCDC_MERI (1 << 6)
++
++#define ATMEL_LCDC_LUT 0x0c00
++
++#endif /* __MACH_ATMEL_LCDC_H__ */
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 7a48e9c..8d7992c 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -19,8 +19,9 @@
+
+ #include <mach/board.h>
+ #include <mach/cpu.h>
++#include <mach/atmel_lcdc.h>
+
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ /* configurable parameters */
+ #define ATMEL_LCDC_CVAL_DEFAULT 0xc8
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index 20a4e4f..060d41f 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -22,7 +22,7 @@
+ #include <mach/cpu.h>
+ #include <mach/gpio.h>
+
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ /* configurable parameters */
+ #define ATMEL_LCDC_CVAL_DEFAULT 0xc8
+diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
+deleted file mode 100644
+index 6031b5a..0000000
+--- a/include/video/atmel_lcdc.h
++++ /dev/null
+@@ -1,248 +0,0 @@
+-/*
+- * Header file for AT91/AT32 LCD Controller
+- *
+- * Data structure and register user interface
+- *
+- * Copyright (C) 2007 Atmel Corporation
+- *
+- * 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.
+- *
+- * 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 __ATMEL_LCDC_H__
+-#define __ATMEL_LCDC_H__
+-
+-#include <linux/workqueue.h>
+-#include <linux/interrupt.h>
+-#include <linux/backlight.h>
+-
+-/* Way LCD wires are connected to the chip:
+- * Some Atmel chips use BGR color mode (instead of standard RGB)
+- * A swapped wiring onboard can bring to RGB mode.
+- */
+-#define ATMEL_LCDC_WIRING_BGR 0
+-#define ATMEL_LCDC_WIRING_RGB 1
+-#define ATMEL_LCDC_WIRING_RGB555 2
+-
+-#define ATMEL_LCDC_STOP_NOWAIT (1 << 0)
+-
+-extern void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo);
+-extern void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo);
+-extern int __atmel_lcdfb_probe(struct platform_device *pdev,
+- struct atmel_lcdfb_devdata *devdata);
+-extern int __atmel_lcdfb_remove(struct platform_device *pdev);
+-
+-struct atmel_lcdfb_info;
+-
+-struct atmel_lcdfb_devdata {
+- int (*setup_core)(struct fb_info *info);
+- void (*start)(struct atmel_lcdfb_info *sinfo);
+- void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags);
+- irqreturn_t (*isr)(int irq, void *dev_id);
+- void (*update_dma)(struct fb_info *info, struct fb_var_screeninfo *var);
+- void (*init_contrast)(struct atmel_lcdfb_info *sinfo);
+- void (*limit_screeninfo)(struct fb_var_screeninfo *var);
+- const struct backlight_ops *bl_ops;
+- int fbinfo_flags;
+- u32 lut_base;
+-};
+-
+- /* LCD Controller info data structure, stored in device platform_data */
+-struct atmel_lcdfb_info {
+- spinlock_t lock;
+- struct fb_info *info;
+- void __iomem *mmio;
+- int irq_base;
+- struct atmel_lcdfb_devdata *dev_data;
+- struct work_struct task;
+-
+- unsigned int guard_time;
+- unsigned int smem_len;
+- struct platform_device *pdev;
+- struct clk *bus_clk;
+- struct clk *lcdc_clk;
+-
+-#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+- struct backlight_device *backlight;
+- u8 bl_power;
+-#endif
+- bool lcdcon_is_backlight;
+- bool lcdcon_pol_negative;
+- bool alpha_enabled;
+- u8 saved_lcdcon;
+-
+- u8 default_bpp;
+- u8 lcd_wiring_mode;
+- unsigned int default_lcdcon2;
+- unsigned int default_dmacon;
+- void (*atmel_lcdfb_power_control)(int on);
+- struct fb_monspecs *default_monspecs;
+- u32 pseudo_palette[16];
+-};
+-
+-#define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg))
+-#define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg))
+-
+-#define ATMEL_LCDC_DMABADDR1 0x00
+-#define ATMEL_LCDC_DMABADDR2 0x04
+-#define ATMEL_LCDC_DMAFRMPT1 0x08
+-#define ATMEL_LCDC_DMAFRMPT2 0x0c
+-#define ATMEL_LCDC_DMAFRMADD1 0x10
+-#define ATMEL_LCDC_DMAFRMADD2 0x14
+-
+-#define ATMEL_LCDC_DMAFRMCFG 0x18
+-#define ATMEL_LCDC_FRSIZE (0x7fffff << 0)
+-#define ATMEL_LCDC_BLENGTH_OFFSET 24
+-#define ATMEL_LCDC_BLENGTH (0x7f << ATMEL_LCDC_BLENGTH_OFFSET)
+-
+-#define ATMEL_LCDC_DMACON 0x1c
+-#define ATMEL_LCDC_DMAEN (0x1 << 0)
+-#define ATMEL_LCDC_DMARST (0x1 << 1)
+-#define ATMEL_LCDC_DMABUSY (0x1 << 2)
+-#define ATMEL_LCDC_DMAUPDT (0x1 << 3)
+-#define ATMEL_LCDC_DMA2DEN (0x1 << 4)
+-
+-#define ATMEL_LCDC_DMA2DCFG 0x20
+-#define ATMEL_LCDC_ADDRINC_OFFSET 0
+-#define ATMEL_LCDC_ADDRINC (0xffff)
+-#define ATMEL_LCDC_PIXELOFF_OFFSET 24
+-#define ATMEL_LCDC_PIXELOFF (0x1f << 24)
+-
+-#define ATMEL_LCDC_LCDCON1 0x0800
+-#define ATMEL_LCDC_BYPASS (1 << 0)
+-#define ATMEL_LCDC_CLKVAL_OFFSET 12
+-#define ATMEL_LCDC_CLKVAL (0x1ff << ATMEL_LCDC_CLKVAL_OFFSET)
+-#define ATMEL_LCDC_LINCNT (0x7ff << 21)
+-
+-#define ATMEL_LCDC_LCDCON2 0x0804
+-#define ATMEL_LCDC_DISTYPE (3 << 0)
+-#define ATMEL_LCDC_DISTYPE_STNMONO (0 << 0)
+-#define ATMEL_LCDC_DISTYPE_STNCOLOR (1 << 0)
+-#define ATMEL_LCDC_DISTYPE_TFT (2 << 0)
+-#define ATMEL_LCDC_SCANMOD (1 << 2)
+-#define ATMEL_LCDC_SCANMOD_SINGLE (0 << 2)
+-#define ATMEL_LCDC_SCANMOD_DUAL (1 << 2)
+-#define ATMEL_LCDC_IFWIDTH (3 << 3)
+-#define ATMEL_LCDC_IFWIDTH_4 (0 << 3)
+-#define ATMEL_LCDC_IFWIDTH_8 (1 << 3)
+-#define ATMEL_LCDC_IFWIDTH_16 (2 << 3)
+-#define ATMEL_LCDC_PIXELSIZE (7 << 5)
+-#define ATMEL_LCDC_PIXELSIZE_1 (0 << 5)
+-#define ATMEL_LCDC_PIXELSIZE_2 (1 << 5)
+-#define ATMEL_LCDC_PIXELSIZE_4 (2 << 5)
+-#define ATMEL_LCDC_PIXELSIZE_8 (3 << 5)
+-#define ATMEL_LCDC_PIXELSIZE_16 (4 << 5)
+-#define ATMEL_LCDC_PIXELSIZE_24 (5 << 5)
+-#define ATMEL_LCDC_PIXELSIZE_32 (6 << 5)
+-#define ATMEL_LCDC_INVVD (1 << 8)
+-#define ATMEL_LCDC_INVVD_NORMAL (0 << 8)
+-#define ATMEL_LCDC_INVVD_INVERTED (1 << 8)
+-#define ATMEL_LCDC_INVFRAME (1 << 9 )
+-#define ATMEL_LCDC_INVFRAME_NORMAL (0 << 9)
+-#define ATMEL_LCDC_INVFRAME_INVERTED (1 << 9)
+-#define ATMEL_LCDC_INVLINE (1 << 10)
+-#define ATMEL_LCDC_INVLINE_NORMAL (0 << 10)
+-#define ATMEL_LCDC_INVLINE_INVERTED (1 << 10)
+-#define ATMEL_LCDC_INVCLK (1 << 11)
+-#define ATMEL_LCDC_INVCLK_NORMAL (0 << 11)
+-#define ATMEL_LCDC_INVCLK_INVERTED (1 << 11)
+-#define ATMEL_LCDC_INVDVAL (1 << 12)
+-#define ATMEL_LCDC_INVDVAL_NORMAL (0 << 12)
+-#define ATMEL_LCDC_INVDVAL_INVERTED (1 << 12)
+-#define ATMEL_LCDC_CLKMOD (1 << 15)
+-#define ATMEL_LCDC_CLKMOD_ACTIVEDISPLAY (0 << 15)
+-#define ATMEL_LCDC_CLKMOD_ALWAYSACTIVE (1 << 15)
+-#define ATMEL_LCDC_MEMOR (1 << 31)
+-#define ATMEL_LCDC_MEMOR_BIG (0 << 31)
+-#define ATMEL_LCDC_MEMOR_LITTLE (1 << 31)
+-
+-#define ATMEL_LCDC_TIM1 0x0808
+-#define ATMEL_LCDC_VFP (0xffU << 0)
+-#define ATMEL_LCDC_VBP_OFFSET 8
+-#define ATMEL_LCDC_VBP (0xffU << ATMEL_LCDC_VBP_OFFSET)
+-#define ATMEL_LCDC_VPW_OFFSET 16
+-#define ATMEL_LCDC_VPW (0x3fU << ATMEL_LCDC_VPW_OFFSET)
+-#define ATMEL_LCDC_VHDLY_OFFSET 24
+-#define ATMEL_LCDC_VHDLY (0xfU << ATMEL_LCDC_VHDLY_OFFSET)
+-
+-#define ATMEL_LCDC_TIM2 0x080c
+-#define ATMEL_LCDC_HBP (0xffU << 0)
+-#define ATMEL_LCDC_HPW_OFFSET 8
+-#define ATMEL_LCDC_HPW (0x3fU << ATMEL_LCDC_HPW_OFFSET)
+-#define ATMEL_LCDC_HFP_OFFSET 21
+-#define ATMEL_LCDC_HFP (0x7ffU << ATMEL_LCDC_HFP_OFFSET)
+-
+-#define ATMEL_LCDC_LCDFRMCFG 0x0810
+-#define ATMEL_LCDC_LINEVAL (0x7ff << 0)
+-#define ATMEL_LCDC_HOZVAL_OFFSET 21
+-#define ATMEL_LCDC_HOZVAL (0x7ff << ATMEL_LCDC_HOZVAL_OFFSET)
+-
+-#define ATMEL_LCDC_FIFO 0x0814
+-#define ATMEL_LCDC_FIFOTH (0xffff)
+-
+-#define ATMEL_LCDC_MVAL 0x0818
+-
+-#define ATMEL_LCDC_DP1_2 0x081c
+-#define ATMEL_LCDC_DP4_7 0x0820
+-#define ATMEL_LCDC_DP3_5 0x0824
+-#define ATMEL_LCDC_DP2_3 0x0828
+-#define ATMEL_LCDC_DP5_7 0x082c
+-#define ATMEL_LCDC_DP3_4 0x0830
+-#define ATMEL_LCDC_DP4_5 0x0834
+-#define ATMEL_LCDC_DP6_7 0x0838
+-#define ATMEL_LCDC_DP1_2_VAL (0xff)
+-#define ATMEL_LCDC_DP4_7_VAL (0xfffffff)
+-#define ATMEL_LCDC_DP3_5_VAL (0xfffff)
+-#define ATMEL_LCDC_DP2_3_VAL (0xfff)
+-#define ATMEL_LCDC_DP5_7_VAL (0xfffffff)
+-#define ATMEL_LCDC_DP3_4_VAL (0xffff)
+-#define ATMEL_LCDC_DP4_5_VAL (0xfffff)
+-#define ATMEL_LCDC_DP6_7_VAL (0xfffffff)
+-
+-#define ATMEL_LCDC_PWRCON 0x083c
+-#define ATMEL_LCDC_PWR (1 << 0)
+-#define ATMEL_LCDC_GUARDT_OFFSET 1
+-#define ATMEL_LCDC_GUARDT (0x7f << ATMEL_LCDC_GUARDT_OFFSET)
+-#define ATMEL_LCDC_BUSY (1 << 31)
+-
+-#define ATMEL_LCDC_CONTRAST_CTR 0x0840
+-#define ATMEL_LCDC_PS (3 << 0)
+-#define ATMEL_LCDC_PS_DIV1 (0 << 0)
+-#define ATMEL_LCDC_PS_DIV2 (1 << 0)
+-#define ATMEL_LCDC_PS_DIV4 (2 << 0)
+-#define ATMEL_LCDC_PS_DIV8 (3 << 0)
+-#define ATMEL_LCDC_POL (1 << 2)
+-#define ATMEL_LCDC_POL_NEGATIVE (0 << 2)
+-#define ATMEL_LCDC_POL_POSITIVE (1 << 2)
+-#define ATMEL_LCDC_ENA (1 << 3)
+-#define ATMEL_LCDC_ENA_PWMDISABLE (0 << 3)
+-#define ATMEL_LCDC_ENA_PWMENABLE (1 << 3)
+-
+-#define ATMEL_LCDC_CONTRAST_VAL 0x0844
+-#define ATMEL_LCDC_CVAL (0xff)
+-
+-#define ATMEL_LCDC_IER 0x0848
+-#define ATMEL_LCDC_IDR 0x084c
+-#define ATMEL_LCDC_IMR 0x0850
+-#define ATMEL_LCDC_ISR 0x0854
+-#define ATMEL_LCDC_ICR 0x0858
+-#define ATMEL_LCDC_LNI (1 << 0)
+-#define ATMEL_LCDC_LSTLNI (1 << 1)
+-#define ATMEL_LCDC_EOFI (1 << 2)
+-#define ATMEL_LCDC_UFLWI (1 << 4)
+-#define ATMEL_LCDC_OWRI (1 << 5)
+-#define ATMEL_LCDC_MERI (1 << 6)
+-
+-#define ATMEL_LCDC_LUT 0x0c00
+-
+-#endif /* __ATMEL_LCDC_H__ */
+diff --git a/include/video/atmel_lcdfb.h b/include/video/atmel_lcdfb.h
+new file mode 100644
+index 0000000..3a0dfc7
+--- /dev/null
++++ b/include/video/atmel_lcdfb.h
+@@ -0,0 +1,100 @@
++/*
++ * Header file for AT91/AT32 LCD Controller
++ *
++ * Data structure and register user interface
++ *
++ * Copyright (C) 2007 Atmel Corporation
++ *
++ * 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.
++ *
++ * 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 __ATMEL_LCDC_H__
++#define __ATMEL_LCDC_H__
++
++#include <linux/workqueue.h>
++#include <linux/interrupt.h>
++#include <linux/backlight.h>
++
++/* Way LCD wires are connected to the chip:
++ * Some Atmel chips use BGR color mode (instead of standard RGB)
++ * A swapped wiring onboard can bring to RGB mode.
++ */
++#define ATMEL_LCDC_WIRING_BGR 0
++#define ATMEL_LCDC_WIRING_RGB 1
++#define ATMEL_LCDC_WIRING_RGB555 2
++
++#define ATMEL_LCDC_STOP_NOWAIT (1 << 0)
++
++struct atmel_lcdfb_info;
++
++struct atmel_lcdfb_devdata {
++ int (*setup_core)(struct fb_info *info);
++ void (*start)(struct atmel_lcdfb_info *sinfo);
++ void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags);
++ irqreturn_t (*isr)(int irq, void *dev_id);
++ void (*update_dma)(struct fb_info *info, struct fb_var_screeninfo *var);
++ void (*init_contrast)(struct atmel_lcdfb_info *sinfo);
++ void (*limit_screeninfo)(struct fb_var_screeninfo *var);
++ const struct backlight_ops *bl_ops;
++ int fbinfo_flags;
++ u32 lut_base;
++ int dma_desc_size;
++};
++
++extern void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo);
++extern void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo);
++extern int __atmel_lcdfb_probe(struct platform_device *pdev,
++ struct atmel_lcdfb_devdata *devdata);
++extern int __atmel_lcdfb_remove(struct platform_device *pdev);
++
++ /* LCD Controller info data structure, stored in device platform_data */
++struct atmel_lcdfb_info {
++ spinlock_t lock;
++ struct fb_info *info;
++ void __iomem *mmio;
++ int irq_base;
++ struct atmel_lcdfb_devdata *dev_data;
++ struct work_struct task;
++
++ void *dma_desc;
++ dma_addr_t dma_desc_phys;
++
++ unsigned int guard_time;
++ unsigned int smem_len;
++ struct platform_device *pdev;
++ struct clk *bus_clk;
++ struct clk *lcdc_clk;
++
++#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
++ struct backlight_device *backlight;
++ u8 bl_power;
++#endif
++ bool lcdcon_is_backlight;
++ bool lcdcon_pol_negative;
++ bool alpha_enabled;
++ u8 saved_lcdcon;
++
++ u8 default_bpp;
++ u8 lcd_wiring_mode;
++ unsigned int default_lcdcon2;
++ unsigned int default_dmacon;
++ void (*atmel_lcdfb_power_control)(int on);
++ struct fb_monspecs *default_monspecs;
++ u32 pseudo_palette[16];
++};
++
++#define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg))
++#define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg))
++
++#endif /* __ATMEL_LCDC_H__ */
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0082-video-atmel_hlcdfb-add-new-driver.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0082-video-atmel_hlcdfb-add-new-driver.patch
new file mode 100644
index 0000000..73f8a47
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0082-video-atmel_hlcdfb-add-new-driver.patch
@@ -0,0 +1,606 @@
+From 27ccf3bffa571397ccd64704334c60a0687bfdef Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Mon, 23 May 2011 15:36:52 +0200
+Subject: [PATCH 082/107] video: atmel_hlcdfb: add new driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/Kconfig | 9 +
+ drivers/video/Makefile | 1 +
+ drivers/video/atmel_hlcdfb.c | 514 ++++++++++++++++++++++++++++++++++++++
+ drivers/video/atmel_lcdfb_core.c | 15 ++
+ 4 files changed, 539 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/video/atmel_hlcdfb.c
+
+diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
+index e6a8d8c..8b25a8e 100644
+--- a/drivers/video/Kconfig
++++ b/drivers/video/Kconfig
+@@ -1022,6 +1022,15 @@ config FB_ATMEL_STN
+
+ If unsure, say N.
+
++config FB_ATMEL_HLCD
++ tristate "AT91 HLCD Controller support"
++ depends on FB && HAVE_FB_ATMEL
++ select FB_CFB_FILLRECT
++ select FB_CFB_COPYAREA
++ select FB_CFB_IMAGEBLIT
++ help
++ This enables support for the AT91 HLCD Controller.
++
+ config FB_NVIDIA
+ tristate "nVidia Framebuffer Support"
+ depends on FB && PCI
+diff --git a/drivers/video/Makefile b/drivers/video/Makefile
+index e963559..2597768 100644
+--- a/drivers/video/Makefile
++++ b/drivers/video/Makefile
+@@ -92,6 +92,7 @@ obj-$(CONFIG_FB_SA1100) += sa1100fb.o
+ obj-$(CONFIG_FB_HIT) += hitfb.o
+ obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o
+ obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o atmel_lcdfb_core.o
++obj-$(CONFIG_FB_ATMEL_HLCD) += atmel_hlcdfb.o atmel_lcdfb_core.o
+ obj-$(CONFIG_FB_PVR2) += pvr2fb.o
+ obj-$(CONFIG_FB_VOODOO1) += sstfb.o
+ obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o
+diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c
+new file mode 100644
+index 0000000..b772841
+--- /dev/null
++++ b/drivers/video/atmel_hlcdfb.c
+@@ -0,0 +1,514 @@
++/*
++ * Driver for AT91/AT32 LCD Controller
++ *
++ * Copyright (C) 2007 Atmel Corporation
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive for
++ * more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <linux/interrupt.h>
++#include <linux/backlight.h>
++#include <linux/fb.h>
++#include <linux/clk.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++
++#include <mach/board.h>
++#include <mach/cpu.h>
++#include <mach/atmel_hlcdc.h>
++#include <mach/atmel_hlcdc_ovl.h>
++
++#include <video/atmel_lcdfb.h>
++
++#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
++ | FBINFO_PARTIAL_PAN_OK \
++ | FBINFO_HWACCEL_YPAN)
++
++#define ATMEL_LCDC_CVAL_DEFAULT 0xc8
++
++struct atmel_hlcd_dma_desc {
++ u32 address;
++ u32 control;
++ u32 next;
++};
++
++static void atmel_hlcdfb_update_dma_base(struct fb_info *info,
++
++ struct fb_var_screeninfo *var)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ struct fb_fix_screeninfo *fix = &info->fix;
++ unsigned long dma_addr;
++ struct atmel_hlcd_dma_desc *desc;
++
++ dma_addr = (fix->smem_start + var->yoffset * fix->line_length
++ + var->xoffset * var->bits_per_pixel / 8);
++
++ dma_addr &= ~3UL;
++
++ /* Setup the DMA descriptor, this descriptor will loop to itself */
++ desc = sinfo->dma_desc;
++
++ desc->address = dma_addr;
++ /* Disable DMA transfer interrupt & descriptor loaded interrupt. */
++ desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN
++ | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH;
++ desc->next = sinfo->dma_desc_phys;
++
++ lcdc_writel(sinfo, ATMEL_LCDC_BASEADDR, dma_addr);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECTRL, desc->control);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASENEXT, sinfo->dma_desc_phys);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECHER, LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN);
++}
++
++static void atmel_hlcdfb_update_dma_ovl(struct fb_info *info,
++ struct fb_var_screeninfo *var)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ struct fb_fix_screeninfo *fix = &info->fix;
++ unsigned long dma_addr;
++ struct atmel_hlcd_dma_desc *desc;
++
++ dma_addr = (fix->smem_start + var->yoffset * fix->line_length
++ + var->xoffset * var->bits_per_pixel / 8);
++
++ dma_addr &= ~3UL;
++
++ /* Setup the DMA descriptor, this descriptor will loop to itself */
++ desc = sinfo->dma_desc;
++
++ desc->address = dma_addr;
++ /* Disable DMA transfer interrupt & descriptor loaded interrupt. */
++ desc->control = LCDC_OVRCTRL1_ADDIEN | LCDC_OVRCTRL1_DSCRIEN
++ | LCDC_OVRCTRL1_DMAIEN | LCDC_OVRCTRL1_DFETCH;
++ desc->next = sinfo->dma_desc_phys;
++
++ lcdc_writel(sinfo, ATMEL_LCDC_OVRADDR1, dma_addr);
++ lcdc_writel(sinfo, ATMEL_LCDC_OVRCTRL1, desc->control);
++ lcdc_writel(sinfo, ATMEL_LCDC_OVRNEXT1, sinfo->dma_desc_phys);
++ lcdc_writel(sinfo, ATMEL_LCDC_OVRCHER1, LCDC_OVRCHER1_CHEN | LCDC_OVRCHER1_UPDATEEN);
++}
++
++/* some bl->props field just changed */
++static int atmel_bl_update_status(struct backlight_device *bl)
++{
++ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
++ int power = sinfo->bl_power;
++ int brightness = bl->props.brightness;
++ u32 reg;
++
++ /* REVISIT there may be a meaningful difference between
++ * fb_blank and power ... there seem to be some cases
++ * this doesn't handle correctly.
++ */
++ if (bl->props.fb_blank != sinfo->bl_power)
++ power = bl->props.fb_blank;
++ else if (bl->props.power != sinfo->bl_power)
++ power = bl->props.power;
++
++ if (brightness < 0 && power == FB_BLANK_UNBLANK)
++ brightness = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6)
++ >> LCDC_LCDCFG6_PWMCVAL_OFFSET;
++ else if (power != FB_BLANK_UNBLANK)
++ brightness = 0;
++
++ reg = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) & ~LCDC_LCDCFG6_PWMCVAL;
++ reg |= brightness << LCDC_LCDCFG6_PWMCVAL_OFFSET;
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, reg);
++
++ bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
++
++ return 0;
++}
++
++static int atmel_bl_get_brightness(struct backlight_device *bl)
++{
++ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
++
++ return lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) >> LCDC_LCDCFG6_PWMCVAL_OFFSET;
++}
++
++static const struct backlight_ops atmel_hlcdc_bl_ops = {
++ .update_status = atmel_bl_update_status,
++ .get_brightness = atmel_bl_get_brightness,
++};
++
++static void atmel_hlcdfb_init_contrast(struct atmel_lcdfb_info *sinfo)
++{
++ /* have some default contrast/backlight settings */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, LCDC_LCDCFG6_PWMPOL |
++ (ATMEL_LCDC_CVAL_DEFAULT << LCDC_LCDCFG6_PWMCVAL_OFFSET));
++}
++
++void atmel_hlcdfb_start(struct atmel_lcdfb_info *sinfo)
++{
++ u32 value;
++
++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_CLKEN);
++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS))
++ msleep(1);
++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_SYNCEN);
++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS))
++ msleep(1);
++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_DISPEN);
++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS))
++ msleep(1);
++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_PWMEN);
++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS))
++ msleep(1);
++}
++
++static void atmel_hlcdfb_stop(struct atmel_lcdfb_info *sinfo, u32 flags)
++{
++ /* Disable DISP signal */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_DISPDIS);
++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS))
++ msleep(1);
++ /* Disable synchronization */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_SYNCDIS);
++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS))
++ msleep(1);
++ /* Disable pixel clock */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_CLKDIS);
++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS))
++ msleep(1);
++ /* Disable PWM */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_PWMDIS);
++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS))
++ msleep(1);
++
++ if (!(flags & ATMEL_LCDC_STOP_NOWAIT))
++ /* Wait for the end of DMA transfer */
++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_BASEISR) & LCDC_BASEISR_DMA))
++ msleep(10);
++ //FIXME: OVL DMA?
++}
++
++static u32 atmel_hlcdfb_get_rgbmode(struct fb_info *info)
++{
++ u32 value = 0;
++
++ switch (info->var.bits_per_pixel) {
++ case 1:
++ value = LCDC_BASECFG1_CLUTMODE_1BPP | LCDC_BASECFG1_CLUTEN;
++ break;
++ case 2:
++ value = LCDC_BASECFG1_CLUTMODE_2BPP | LCDC_BASECFG1_CLUTEN;
++ break;
++ case 4:
++ value = LCDC_BASECFG1_CLUTMODE_4BPP | LCDC_BASECFG1_CLUTEN;
++ break;
++ case 8:
++ value = LCDC_BASECFG1_CLUTMODE_8BPP | LCDC_BASECFG1_CLUTEN;
++ break;
++ case 12:
++ value = LCDC_BASECFG1_RGBMODE_12BPP_RGB_444;
++ break;
++ case 16:
++ if (info->var.transp.offset)
++ value = LCDC_BASECFG1_RGBMODE_16BPP_ARGB_4444;
++ else
++ value = LCDC_BASECFG1_RGBMODE_16BPP_RGB_565;
++ break;
++ case 18:
++ value = LCDC_BASECFG1_RGBMODE_18BPP_RGB_666_PACKED;
++ break;
++ case 24:
++ value = LCDC_BASECFG1_RGBMODE_24BPP_RGB_888_PACKED;
++ break;
++ case 32:
++ value = LCDC_BASECFG1_RGBMODE_32BPP_ARGB_8888;
++ break;
++ default:
++ dev_err(info->device, "Cannot set video mode for %dbpp\n",
++ info->var.bits_per_pixel);
++ break;
++ }
++
++ return value;
++}
++
++static int atmel_hlcdfb_setup_core_base(struct fb_info *info)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ unsigned long value;
++ unsigned long clk_value_khz;
++
++ dev_dbg(info->device, "%s:\n", __func__);
++ /* Set pixel clock */
++ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
++
++ value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
++
++ if (value < 1) {
++ dev_notice(info->device, "using system clock as pixel clock\n");
++ value = LCDC_LCDCFG0_CLKPOL | LCDC_LCDCFG0_CLKPWMSEL | LCDC_LCDCFG0_CGDISBASE;
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value);
++ } else {
++ info->var.pixclock = KHZ2PICOS(clk_value_khz / value);
++ dev_dbg(info->device, " updated pixclk: %lu KHz\n",
++ PICOS2KHZ(info->var.pixclock));
++ value = value - 2;
++ dev_dbg(info->device, " * programming CLKDIV = 0x%08lx\n",
++ value);
++ value = (value << LCDC_LCDCFG0_CLKDIV_OFFSET)
++ | LCDC_LCDCFG0_CLKPOL
++ | LCDC_LCDCFG0_CGDISBASE;
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value);
++ }
++
++ /* Initialize control register 5 */
++ /* In 9x5, the default_lcdcon2 will use for LCDCFG5 */
++ value = sinfo->default_lcdcon2;
++ value |= (sinfo->guard_time << LCDC_LCDCFG5_GUARDTIME_OFFSET)
++ | LCDC_LCDCFG5_DISPDLY
++ | LCDC_LCDCFG5_VSPDLYS;
++
++ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
++ value |= LCDC_LCDCFG5_HSPOL;
++ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
++ value |= LCDC_LCDCFG5_VSPOL;
++
++ dev_dbg(info->device, " * LCDC_LCDCFG5 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG5, value);
++
++ /* Vertical & Horizontal Timing */
++ value = (info->var.vsync_len - 1) << LCDC_LCDCFG1_VSPW_OFFSET;
++ value |= (info->var.hsync_len - 1) << LCDC_LCDCFG1_HSPW_OFFSET;
++ dev_dbg(info->device, " * LCDC_LCDCFG1 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG1, value);
++
++ value = (info->var.lower_margin) << LCDC_LCDCFG2_VBPW_OFFSET;
++ value |= (info->var.upper_margin - 1) << LCDC_LCDCFG2_VFPW_OFFSET;
++ dev_dbg(info->device, " * LCDC_LCDCFG2 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG2, value);
++
++ value = (info->var.right_margin - 1) << LCDC_LCDCFG3_HBPW_OFFSET;
++ value |= (info->var.left_margin - 1) << LCDC_LCDCFG3_HFPW_OFFSET;
++ dev_dbg(info->device, " * LCDC_LCDCFG3 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG3, value);
++
++ /* Display size */
++ value = (info->var.yres - 1) << LCDC_LCDCFG4_RPF_OFFSET;
++ value |= (info->var.xres - 1) << LCDC_LCDCFG4_PPL_OFFSET;
++ dev_dbg(info->device, " * LCDC_LCDCFG4 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG4, value);
++
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG0, LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG1, atmel_hlcdfb_get_rgbmode(info));
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG2, 0);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG3, 0); /* Default color */
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG4, LCDC_BASECFG4_DMA);
++
++ /* Disable all interrupts */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL);
++ /* Enable BASE LAYER overflow interrupts, if want to enable DMA interrupt, also need set it at LCDC_BASECTRL reg */
++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR);
++ //FIXME: Let video-driver register a callback
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE |
++ LCDC_LCDIER_BASEIE | LCDC_LCDIER_HEOIE);
++
++ return 0;
++}
++
++static int atmel_hlcdfb_setup_core_ovl(struct fb_info *info)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ u32 xpos, ypos, xres, yres, cfg9;
++
++ if (info->var.nonstd >> 31) {
++ xpos = (info->var.nonstd >> 10) & 0x3ff;
++ ypos = info->var.nonstd & 0x3ff;
++ xres = info->var.xres ? info->var.xres - 1 : 0;
++ yres = info->var.yres ? info->var.yres - 1 : 0;
++ cfg9 = LCDC_OVR1CFG9_DMA | LCDC_OVR1CFG9_OVR |
++ LCDC_OVR1CFG9_ITER | LCDC_OVR1CFG9_ITER2BL |
++ LCDC_OVR1CFG9_REP;
++ if (info->var.transp.offset)
++ cfg9 |= LCDC_OVR1CFG9_LAEN;
++ else
++ cfg9 |= LCDC_OVR1CFG9_GAEN | LCDC_OVR1CFG9_GA;
++ } else {
++ xpos = ypos = yres = xres = cfg9 = 0;
++ }
++
++ lcdc_writel(sinfo, ATMEL_LCDC_OVR1CFG0,
++ LCDC_OVR1CFG0_BLEN_AHB_INCR4 | LCDC_OVR1CFG0_DLBO);
++ lcdc_writel(sinfo, ATMEL_LCDC_OVR1CFG1,
++ atmel_hlcdfb_get_rgbmode(info));
++ lcdc_writel(sinfo, ATMEL_LCDC_OVR1CFG2, xpos |
++ (ypos << LCDC_OVR1CFG2_YOFFSET_OFFSET));
++ lcdc_writel(sinfo, ATMEL_LCDC_OVR1CFG3, xres |
++ (yres << LCDC_OVR1CFG3_YSIZE_OFFSET));
++ lcdc_writel(sinfo, ATMEL_LCDC_OVR1CFG9, cfg9);
++
++ return 0;
++}
++static void atmelfb_limit_screeninfo(struct fb_var_screeninfo *var)
++{
++ /* Saturate vertical and horizontal timings at maximum values */
++ var->vsync_len = min_t(u32, var->vsync_len,
++ (LCDC_LCDCFG1_VSPW >> LCDC_LCDCFG1_VSPW_OFFSET) + 1);
++ var->upper_margin = min_t(u32, var->upper_margin,
++ (LCDC_LCDCFG2_VFPW >> LCDC_LCDCFG2_VFPW_OFFSET) + 1);
++ var->lower_margin = min_t(u32, var->lower_margin,
++ LCDC_LCDCFG2_VBPW >> LCDC_LCDCFG2_VBPW_OFFSET);
++ var->right_margin = min_t(u32, var->right_margin,
++ (LCDC_LCDCFG3_HBPW >> LCDC_LCDCFG3_HBPW_OFFSET) + 1);
++ var->hsync_len = min_t(u32, var->hsync_len,
++ (LCDC_LCDCFG1_HSPW >> LCDC_LCDCFG1_HSPW_OFFSET) + 1);
++ var->left_margin = min_t(u32, var->left_margin,
++ (LCDC_LCDCFG3_HFPW >> LCDC_LCDCFG3_HFPW_OFFSET) + 1);
++
++}
++
++static irqreturn_t atmel_hlcdfb_interrupt(int irq, void *dev_id)
++{
++ struct fb_info *info = dev_id;
++ struct atmel_lcdfb_info *sinfo = info->par;
++ u32 status, baselayer_status;
++
++ /* Check for error status via interrupt.*/
++ status = lcdc_readl(sinfo, ATMEL_LCDC_LCDISR);
++ if (status & LCDC_LCDISR_HEO)
++ return IRQ_NONE;
++
++ if (status & LCDC_LCDISR_FIFOERR)
++ dev_warn(info->device, "FIFO underflow %#x\n", status);
++
++ if (status & LCDC_LCDISR_BASE) {
++ /* Check base layer's overflow error. */
++ baselayer_status = lcdc_readl(sinfo, ATMEL_LCDC_BASEISR);
++
++ if (baselayer_status & LCDC_BASEISR_OVR)
++ dev_warn(info->device, "base layer overflow %#x\n",
++ baselayer_status);
++ }
++
++ return IRQ_HANDLED;
++}
++
++
++#ifdef CONFIG_PM
++
++static int atmel_hlcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
++{
++ struct fb_info *info = platform_get_drvdata(pdev);
++ struct atmel_lcdfb_info *sinfo = info->par;
++
++ /*
++ * We don't want to handle interrupts while the clock is
++ * stopped. It may take forever.
++ */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL);
++
++ if (sinfo->atmel_lcdfb_power_control)
++ sinfo->atmel_lcdfb_power_control(0);
++
++ atmel_hlcdfb_stop(sinfo, 0);
++ atmel_lcdfb_stop_clock(sinfo);
++
++ return 0;
++}
++
++static int atmel_hlcdfb_resume(struct platform_device *pdev)
++{
++ struct fb_info *info = platform_get_drvdata(pdev);
++ struct atmel_lcdfb_info *sinfo = info->par;
++
++ atmel_lcdfb_start_clock(sinfo);
++ atmel_hlcdfb_start(sinfo);
++ if (sinfo->atmel_lcdfb_power_control)
++ sinfo->atmel_lcdfb_power_control(1);
++
++ /* Enable fifo error & BASE LAYER overflow interrupts */
++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE |
++ LCDC_LCDIER_BASEIE | LCDC_LCDIER_HEOIE);
++
++ return 0;
++}
++
++#else
++#define atmel_hlcdfb_suspend NULL
++#define atmel_hlcdfb_resume NULL
++#endif
++
++static struct atmel_lcdfb_devdata dev_data_base = {
++ .setup_core = atmel_hlcdfb_setup_core_base,
++ .start = atmel_hlcdfb_start,
++ .stop = atmel_hlcdfb_stop,
++ .isr = atmel_hlcdfb_interrupt,
++ .update_dma = atmel_hlcdfb_update_dma_base,
++ .bl_ops = &atmel_hlcdc_bl_ops,
++ .init_contrast = atmel_hlcdfb_init_contrast,
++ .limit_screeninfo = atmelfb_limit_screeninfo,
++ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
++ .lut_base = ATMEL_HLCDC_LUT,
++ .dma_desc_size = sizeof(struct atmel_hlcd_dma_desc),
++};
++
++static struct atmel_lcdfb_devdata dev_data_ovl = {
++ .setup_core = atmel_hlcdfb_setup_core_ovl,
++ .update_dma = atmel_hlcdfb_update_dma_ovl,
++ .limit_screeninfo = atmelfb_limit_screeninfo,
++ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
++ .lut_base = 0x800, //FIXME: add define
++ .dma_desc_size = sizeof(struct atmel_hlcd_dma_desc),
++};
++
++static const struct platform_device_id atmelfb_dev_table[] = {
++ { "atmel_hlcdfb_base", (kernel_ulong_t)&dev_data_base },
++ { "atmel_hlcdfb_ovl", (kernel_ulong_t)&dev_data_ovl },
++}
++MODULE_DEVICE_TABLE(platform, atmelfb_dev_table);
++
++static int __init atmel_hlcdfb_probe(struct platform_device *pdev)
++{
++ const struct platform_device_id *id = platform_get_device_id(pdev);
++
++ return __atmel_lcdfb_probe(pdev, (struct atmel_lcdfb_devdata *)id->driver_data);
++}
++static int __exit atmel_hlcdfb_remove(struct platform_device *pdev)
++{
++ return __atmel_lcdfb_remove(pdev);
++}
++
++static struct platform_driver atmel_hlcdfb_driver = {
++ .remove = __exit_p(atmel_hlcdfb_remove),
++ .suspend = atmel_hlcdfb_suspend,
++ .resume = atmel_hlcdfb_resume,
++
++ .driver = {
++ .name = "atmel_hlcdfb",
++ .owner = THIS_MODULE,
++ },
++ .id_table = atmelfb_dev_table,
++};
++
++static int __init atmel_hlcdfb_init(void)
++{
++ return platform_driver_probe(&atmel_hlcdfb_driver, atmel_hlcdfb_probe);
++}
++module_init(atmel_hlcdfb_init);
++
++static void __exit atmel_hlcdfb_exit(void)
++{
++ platform_driver_unregister(&atmel_hlcdfb_driver);
++}
++module_exit(atmel_hlcdfb_exit);
++
++MODULE_DESCRIPTION("AT91 HLCD Controller framebuffer driver");
++MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com> "
++ "and Wolfram Sang <w.sang@pengutronix.de");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index 060d41f..cd57361 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -90,6 +90,10 @@ static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
+
+ dma_free_writecombine(info->device, info->fix.smem_len,
+ info->screen_base, info->fix.smem_start);
++
++ if (sinfo->dev_data->dma_desc_size && sinfo->dma_desc)
++ dma_free_writecombine(info->device, sinfo->dev_data->dma_desc_size,
++ sinfo->dma_desc, sinfo->dma_desc_phys);
+ }
+
+ /**
+@@ -118,6 +122,17 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
+
+ memset(info->screen_base, 0, info->fix.smem_len);
+
++ if (sinfo->dev_data->dma_desc_size) {
++ sinfo->dma_desc = dma_alloc_writecombine(info->device,
++ sinfo->dev_data->dma_desc_size,
++ &(sinfo->dma_desc_phys), GFP_KERNEL);
++
++ if (!sinfo->dma_desc) {
++ dma_free_writecombine(info->device, info->fix.smem_len,
++ info->screen_base, info->fix.smem_start);
++ return -ENOMEM;
++ }
++ }
+ return 0;
+ }
+
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0083-arm-at91-sam9x5-use-new-hlcdc-driver.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0083-arm-at91-sam9x5-use-new-hlcdc-driver.patch
new file mode 100644
index 0000000..1327181
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0083-arm-at91-sam9x5-use-new-hlcdc-driver.patch
@@ -0,0 +1,30 @@
+From 094052d49cb1fedf9eabd0aa628f4bb52ad9e945 Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Mon, 6 Jun 2011 22:04:17 +0200
+Subject: [PATCH 083/107] arm: at91: sam9x5: use new hlcdc-driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ arch/arm/mach-at91/at91sam9x5_devices.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9x5_devices.c b/arch/arm/mach-at91/at91sam9x5_devices.c
+index 36a192a..ee4278d 100644
+--- a/arch/arm/mach-at91/at91sam9x5_devices.c
++++ b/arch/arm/mach-at91/at91sam9x5_devices.c
+@@ -1024,7 +1024,7 @@ static struct resource lcdc_resources[] = {
+ };
+
+ static struct platform_device at91_lcdc_device = {
+- .name = "atmel_lcdfb",
++ .name = "atmel_hlcdfb",
+ .id = 0,
+ .dev = {
+ .dma_mask = &lcdc_dmamask,
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0084-arm-at91-sam9x5ek-use-16bpp-as-default-for-fb.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0084-arm-at91-sam9x5ek-use-16bpp-as-default-for-fb.patch
new file mode 100644
index 0000000..4f2acfc
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0084-arm-at91-sam9x5ek-use-16bpp-as-default-for-fb.patch
@@ -0,0 +1,34 @@
+From 279b0e3f969ace5f1cee3eca57610f300de47ec7 Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Mon, 6 Jun 2011 22:06:03 +0200
+Subject: [PATCH 084/107] arm: at91: sam9x5ek: use 16bpp as default for fb
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Also reserve enough memory for 32bpp.
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ arch/arm/mach-at91/board-sam9x5ek.c | 4 +++-
+ 1 files changed, 3 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/mach-at91/board-sam9x5ek.c b/arch/arm/mach-at91/board-sam9x5ek.c
+index a005b69..54fd7cc 100644
+--- a/arch/arm/mach-at91/board-sam9x5ek.c
++++ b/arch/arm/mach-at91/board-sam9x5ek.c
+@@ -150,7 +150,9 @@ static struct fb_monspecs at91fb_default_monspecs = {
+ static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+ .lcdcon_is_backlight = true,
+ .alpha_enabled = false,
+- .default_bpp = 24,
++ .default_bpp = 16,
++ /* Reserve enough memory for 32bpp */
++ .smem_len = 800 * 480 * 4,
+ /* In 9x5 default_lcdcon2 is used for LCDCFG5 */
+ .default_lcdcon2 = AT91SAM9X5_DEFAULT_LCDCFG5,
+ .default_monspecs = &at91fb_default_monspecs,
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0085-create-platform-device-for-ovl1.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0085-create-platform-device-for-ovl1.patch
new file mode 100644
index 0000000..88fecd7
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0085-create-platform-device-for-ovl1.patch
@@ -0,0 +1,97 @@
+From 4d60230588345e54789b9d4b7e12bf7ba1a7fc9e Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Mon, 30 May 2011 15:02:53 +0200
+Subject: [PATCH 085/107] create platform device for ovl1
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+not-really-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ arch/arm/mach-at91/at91sam9x5_devices.c | 45 ++++++++++++++++++++++++++-----
+ 1 files changed, 38 insertions(+), 7 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9x5_devices.c b/arch/arm/mach-at91/at91sam9x5_devices.c
+index ee4278d..cd642e2 100644
+--- a/arch/arm/mach-at91/at91sam9x5_devices.c
++++ b/arch/arm/mach-at91/at91sam9x5_devices.c
+@@ -1010,29 +1010,59 @@ void __init at91_add_device_can(int id, struct at91_can_data *data) {}
+ static u64 lcdc_dmamask = DMA_BIT_MASK(32);
+ static struct atmel_lcdfb_info lcdc_data;
+
+-static struct resource lcdc_resources[] = {
++static struct resource lcdc_base_resources[] = {
+ [0] = {
+ .start = AT91SAM9X5_BASE_LCDC,
+- .end = AT91SAM9X5_BASE_LCDC + SZ_16K - 1,
++ .end = AT91SAM9X5_BASE_LCDC + 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
++ .start = AT91SAM9X5_BASE_LCDC + ATMEL_LCDC_BASECLUT,
++ .end = AT91SAM9X5_BASE_LCDC + ATMEL_LCDC_BASECLUT + SZ_1K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [2] = {
+ .start = AT91SAM9X5_ID_LCDC,
+ .end = AT91SAM9X5_ID_LCDC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+
+-static struct platform_device at91_lcdc_device = {
+- .name = "atmel_hlcdfb",
++static struct platform_device at91_lcdc_base_device = {
++ .name = "atmel_hlcdfb_base",
++ .id = 0,
++ .dev = {
++ .dma_mask = &lcdc_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &lcdc_data,
++ },
++ .resource = lcdc_base_resources,
++ .num_resources = ARRAY_SIZE(lcdc_base_resources),
++};
++
++static struct resource lcdc_ovl1_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_BASE_LCDC + 0x100,
++ .end = AT91SAM9X5_BASE_LCDC + 0x27f,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_BASE_LCDC + ATMEL_LCDC_OVR1CLUT,
++ .end = AT91SAM9X5_BASE_LCDC + ATMEL_LCDC_OVR1CLUT + SZ_1K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++};
++
++static struct platform_device at91_lcdc_ovl_device = {
++ .name = "atmel_hlcdfb_ovl",
+ .id = 0,
+ .dev = {
+ .dma_mask = &lcdc_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &lcdc_data,
+ },
+- .resource = lcdc_resources,
+- .num_resources = ARRAY_SIZE(lcdc_resources),
++ .resource = lcdc_ovl1_resources,
++ .num_resources = ARRAY_SIZE(lcdc_ovl1_resources),
+ };
+
+ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
+@@ -1075,7 +1105,8 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
+ at91_set_A_periph(AT91_PIN_PC23, 0); /* LCDD23 */
+
+ lcdc_data = *data;
+- platform_device_register(&at91_lcdc_device);
++ platform_device_register(&at91_lcdc_base_device);
++ platform_device_register(&at91_lcdc_ovl_device);
+ }
+ #else
+ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0086-WIP-add-clut-resource.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0086-WIP-add-clut-resource.patch
new file mode 100644
index 0000000..de27e9d
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0086-WIP-add-clut-resource.patch
@@ -0,0 +1,167 @@
+From 6ee30e0b97801fb4a8dac9e9c4a1888e6f00514b Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Mon, 30 May 2011 17:04:35 +0200
+Subject: [PATCH 086/107] WIP: add clut resource
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Warning: will currently break old AT91-boards!
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/atmel_hlcdfb.c | 2 --
+ drivers/video/atmel_lcdfb.c | 1 -
+ drivers/video/atmel_lcdfb_core.c | 35 ++++++++++++++++++++++++++---------
+ include/video/atmel_lcdfb.h | 2 +-
+ 4 files changed, 27 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c
+index b772841..346bb80 100644
+--- a/drivers/video/atmel_hlcdfb.c
++++ b/drivers/video/atmel_hlcdfb.c
+@@ -454,7 +454,6 @@ static struct atmel_lcdfb_devdata dev_data_base = {
+ .init_contrast = atmel_hlcdfb_init_contrast,
+ .limit_screeninfo = atmelfb_limit_screeninfo,
+ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
+- .lut_base = ATMEL_HLCDC_LUT,
+ .dma_desc_size = sizeof(struct atmel_hlcd_dma_desc),
+ };
+
+@@ -463,7 +462,6 @@ static struct atmel_lcdfb_devdata dev_data_ovl = {
+ .update_dma = atmel_hlcdfb_update_dma_ovl,
+ .limit_screeninfo = atmelfb_limit_screeninfo,
+ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
+- .lut_base = 0x800, //FIXME: add define
+ .dma_desc_size = sizeof(struct atmel_hlcd_dma_desc),
+ };
+
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 8d7992c..402cb24 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -399,7 +399,6 @@ static struct atmel_lcdfb_devdata dev_data = {
+ .init_contrast = atmel_lcdfb_init_contrast,
+ .limit_screeninfo = atmelfb_limit_screeninfo,
+ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
+- .lut_base = ATMEL_LCDC_LUT,
+ };
+
+ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index cd57361..89d974a 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -426,9 +426,7 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
+ * TODO: intensity bit. Maybe something like
+ * ~(red[10] ^ green[10] ^ blue[10]) & 1
+ */
+-
+- lcdc_writel(sinfo, sinfo->dev_data->lut_base + regno * 4,
+- val);
++ writel(val, sinfo->clut + regno * 4);
+ ret = 0;
+ }
+ break;
+@@ -436,8 +434,7 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
+ case FB_VISUAL_MONO01:
+ if (regno < 2) {
+ val = (regno == 0) ? 0x00 : 0x1F;
+- lcdc_writel(sinfo, sinfo->dev_data->lut_base + regno * 4,
+- val);
++ writel(val, sinfo->clut + regno * 4);
+ ret = 0;
+ }
+ break;
+@@ -553,7 +550,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ struct atmel_lcdfb_info *sinfo;
+ struct atmel_lcdfb_info *pdata_sinfo;
+ struct fb_videomode fbmode;
+- struct resource *regs = NULL;
++ struct resource *regs = NULL, *clut = NULL;
+ struct resource *map = NULL;
+ int ret;
+
+@@ -628,11 +625,19 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ goto stop_clk;
+ }
+
++ clut = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ if (!clut) {
++ dev_err(dev, "clut resources unusable\n");
++ ret = -ENXIO;
++ goto stop_clk;
++ }
++
+ /* No error checking, some devices can do without IRQ */
+ sinfo->irq_base = platform_get_irq(pdev, 0);
+
+ /* Initialize video memory */
+- map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ //FIXME: Fix LUTs for old platforms
++ map = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ if (map) {
+ /* use a pre-allocated memory buffer */
+ info->fix.smem_start = map->start;
+@@ -676,6 +681,17 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ goto release_mem;
+ }
+
++ //FIXME: proper request_region and cleanup
++ if (!request_mem_region(clut->start, resource_size(clut), pdev->name)) {
++ ret = -EBUSY;
++ goto unmap_mmio;
++ }
++ sinfo->clut = ioremap(clut->start, resource_size(clut));
++ if (!sinfo->clut) {
++ dev_err(dev, "cannot map CLUT\n");
++ goto unmap_mmio;
++ }
++
+ /* Initialize PWM for contrast or backlight ("off") */
+ if (sinfo->dev_data->init_contrast)
+ sinfo->dev_data->init_contrast(sinfo);
+@@ -688,7 +704,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ IRQF_SHARED, pdev->name, info);
+ if (ret) {
+ dev_err(dev, "request_irq failed: %d\n", ret);
+- goto unmap_mmio;
++ goto clear_backlight;
+ }
+ }
+
+@@ -746,8 +762,9 @@ unregister_irqs:
+ cancel_work_sync(&sinfo->task);
+ if (sinfo->irq_base >= 0)
+ free_irq(sinfo->irq_base, info);
+-unmap_mmio:
++clear_backlight:
+ exit_backlight(sinfo);
++unmap_mmio:
+ iounmap(sinfo->mmio);
+ release_mem:
+ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+diff --git a/include/video/atmel_lcdfb.h b/include/video/atmel_lcdfb.h
+index 3a0dfc7..a9563b8 100644
+--- a/include/video/atmel_lcdfb.h
++++ b/include/video/atmel_lcdfb.h
+@@ -48,7 +48,6 @@ struct atmel_lcdfb_devdata {
+ void (*limit_screeninfo)(struct fb_var_screeninfo *var);
+ const struct backlight_ops *bl_ops;
+ int fbinfo_flags;
+- u32 lut_base;
+ int dma_desc_size;
+ };
+
+@@ -63,6 +62,7 @@ struct atmel_lcdfb_info {
+ spinlock_t lock;
+ struct fb_info *info;
+ void __iomem *mmio;
++ void __iomem *clut;
+ int irq_base;
+ struct atmel_lcdfb_devdata *dev_data;
+ struct work_struct task;
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0087-video-atmel_lcdfb-add-error-msg-when-out-of-memory.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0087-video-atmel_lcdfb-add-error-msg-when-out-of-memory.patch
new file mode 100644
index 0000000..776b581
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0087-video-atmel_lcdfb-add-error-msg-when-out-of-memory.patch
@@ -0,0 +1,33 @@
+From 6d6df1c6bd82a56ad081ec305742c83f420db4bb Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Tue, 7 Jun 2011 12:58:36 +0200
+Subject: [PATCH 087/107] video: atmel_lcdfb: add error-msg when out of memory
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/atmel_lcdfb_core.c | 4 +++-
+ 1 files changed, 3 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index 89d974a..ff84234 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -221,8 +221,10 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
+ if (info->fix.smem_len) {
+ unsigned int smem_len = (var->xres_virtual * var->yres_virtual
+ * ((var->bits_per_pixel + 7) / 8));
+- if (smem_len > info->fix.smem_len)
++ if (smem_len > info->fix.smem_len) {
++ dev_err(dev, "not enough memory for this mode\n");
+ return -EINVAL;
++ }
+ }
+
+ /* Saturate vertical and horizontal timings at maximum values */
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0088-Don-t-shortcut-vb2_reqbufs-in-case-the-format-change.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0088-Don-t-shortcut-vb2_reqbufs-in-case-the-format-change.patch
new file mode 100644
index 0000000..2136509
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0088-Don-t-shortcut-vb2_reqbufs-in-case-the-format-change.patch
@@ -0,0 +1,42 @@
+From e62cc3751425d342f13497be5877a380f4e8a5c9 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
+Date: Wed, 8 Jun 2011 11:17:02 +0200
+Subject: [PATCH 088/107] Don't shortcut vb2_reqbufs in case the format
+ changed
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Just checking for number of buffers and memory access method isn't
+enough because the format might have changed since the buffers were
+allocated and the new format might need bigger ones.
+
+This reverts commit 31901a078af29c33c736dcbf815656920e904632.
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Forwarded: http://mid.gmane.org/1307525477-18491-1-git-send-email-u.kleine-koenig@pengutronix.de
+---
+ drivers/media/video/videobuf2-core.c | 7 -------
+ 1 files changed, 0 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c
+index 6ba1461..6489aa2 100644
+--- a/drivers/media/video/videobuf2-core.c
++++ b/drivers/media/video/videobuf2-core.c
+@@ -492,13 +492,6 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
+ return -EINVAL;
+ }
+
+- /*
+- * If the same number of buffers and memory access method is requested
+- * then return immediately.
+- */
+- if (q->memory == req->memory && req->count == q->num_buffers)
+- return 0;
+-
+ if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) {
+ /*
+ * We already have buffers allocated, so first check if they
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0089-at91-video-change-atmel-lcdfb-driver-selection-mode.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0089-at91-video-change-atmel-lcdfb-driver-selection-mode.patch
new file mode 100644
index 0000000..d02a1f7
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0089-at91-video-change-atmel-lcdfb-driver-selection-mode.patch
@@ -0,0 +1,95 @@
+From 904d3f56a0667c0ea225ddc751bf4e5f19ec7ac1 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 9 Jun 2011 17:37:07 +0200
+Subject: [PATCH 089/107] at91: video: change atmel lcdfb driver selection
+ mode
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+LCD driver for AT91 chips is selected by a single entry in Kconfig.
+The new hlcdfb is only selected on supported platforms.
+
+Backlight is selected if needed.
+
+XXX/nfe: improve commit log, move backlight to a separate patch
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/Kconfig | 13 ++++---------
+ drivers/video/Makefile | 5 ++++-
+ drivers/video/backlight/Kconfig | 2 +-
+ 3 files changed, 9 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
+index 8b25a8e..aa423d2 100644
+--- a/drivers/video/Kconfig
++++ b/drivers/video/Kconfig
+@@ -8,6 +8,9 @@ menu "Graphics support"
+ config HAVE_FB_ATMEL
+ bool
+
++config FB_ATMEL_HLCD
++ bool
++
+ config HAVE_FB_IMX
+ bool
+
+@@ -1002,6 +1005,7 @@ config FB_ATMEL
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
++ select FB_ATMEL_HLCD if ARCH_AT91SAM9X5
+ help
+ This enables support for the AT91/AT32 LCD Controller.
+
+@@ -1022,15 +1026,6 @@ config FB_ATMEL_STN
+
+ If unsure, say N.
+
+-config FB_ATMEL_HLCD
+- tristate "AT91 HLCD Controller support"
+- depends on FB && HAVE_FB_ATMEL
+- select FB_CFB_FILLRECT
+- select FB_CFB_COPYAREA
+- select FB_CFB_IMAGEBLIT
+- help
+- This enables support for the AT91 HLCD Controller.
+-
+ config FB_NVIDIA
+ tristate "nVidia Framebuffer Support"
+ depends on FB && PCI
+diff --git a/drivers/video/Makefile b/drivers/video/Makefile
+index 2597768..ea6c5a3 100644
+--- a/drivers/video/Makefile
++++ b/drivers/video/Makefile
+@@ -91,8 +91,11 @@ obj-$(CONFIG_FB_EP93XX) += ep93xx-fb.o
+ obj-$(CONFIG_FB_SA1100) += sa1100fb.o
+ obj-$(CONFIG_FB_HIT) += hitfb.o
+ obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o
++ifdef CONFIG_FB_ATMEL_HLCD
++obj-y += atmel_hlcdfb.o atmel_lcdfb_core.o
++else
+ obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o atmel_lcdfb_core.o
+-obj-$(CONFIG_FB_ATMEL_HLCD) += atmel_hlcdfb.o atmel_lcdfb_core.o
++endif
+ obj-$(CONFIG_FB_PVR2) += pvr2fb.o
+ obj-$(CONFIG_FB_VOODOO1) += sstfb.o
+ obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o
+diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
+index 0c9373b..ffd9fef 100644
+--- a/drivers/video/backlight/Kconfig
++++ b/drivers/video/backlight/Kconfig
+@@ -137,7 +137,7 @@ if BACKLIGHT_CLASS_DEVICE
+ config BACKLIGHT_ATMEL_LCDC
+ bool "Atmel LCDC Contrast-as-Backlight control"
+ depends on FB_ATMEL
+- default y if MACH_SAM9261EK || MACH_SAM9G10EK || MACH_SAM9263EK
++ default y if MACH_SAM9261EK || MACH_SAM9G10EK || MACH_SAM9263EK || MACH_AT91SAM9X5EK
+ help
+ This provides a backlight control internal to the Atmel LCDC
+ driver. If the LCD "contrast control" on your board is wired
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0090-sound-atmel_ssc_dai-add-a-missing-space-to-an-error-.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0090-sound-atmel_ssc_dai-add-a-missing-space-to-an-error-.patch
new file mode 100644
index 0000000..48e5d4f
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0090-sound-atmel_ssc_dai-add-a-missing-space-to-an-error-.patch
@@ -0,0 +1,35 @@
+From 238c10baa2393d20f2f1b905a08ddd15f0fb3c25 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
+Date: Fri, 10 Jun 2011 00:37:28 +0200
+Subject: [PATCH 090/107] sound/atmel_ssc_dai: add a missing space to an error
+ message
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Liam Girdwood <lrg@ti.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Applied-Upstream: v3.1, commit:2f2b3cf1dddf9
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ sound/soc/atmel/atmel_ssc_dai.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
+index 43cce80..8c89514 100644
+--- a/sound/soc/atmel/atmel_ssc_dai.c
++++ b/sound/soc/atmel/atmel_ssc_dai.c
+@@ -405,7 +405,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
+ if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S
+ && bits > 16) {
+ printk(KERN_WARNING
+- "atmel_ssc_dai: sample size %d"
++ "atmel_ssc_dai: sample size %d "
+ "is too large for I2S\n", bits);
+ return -EINVAL;
+ }
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0091-at91-add-Atmel-Image-Sensor-Interface-ISI-support.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0091-at91-add-Atmel-Image-Sensor-Interface-ISI-support.patch
new file mode 100644
index 0000000..a7221fb
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0091-at91-add-Atmel-Image-Sensor-Interface-ISI-support.patch
@@ -0,0 +1,1233 @@
+From 3cc75ebabf66c90f0a7f99600c4d30d6069103d6 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Wed, 8 Jun 2011 14:53:52 +0800
+Subject: [PATCH 091/107] at91: add Atmel Image Sensor Interface (ISI) support
+
+This patch is to enable Atmel Image Sensor Interface (ISI) driver support.
+- Using soc-camera framework with videobuf2 dma-contig allocator
+- Supporting video streaming of YUV packed format
+- Tested on AT91SAM9M10G45-EK with OV2640
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ drivers/media/video/Kconfig | 8 +
+ drivers/media/video/Makefile | 1 +
+ drivers/media/video/atmel-isi.c | 1048 +++++++++++++++++++++++++++++++++++++++
+ include/media/atmel-isi.h | 119 +++++
+ 4 files changed, 1176 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/media/video/atmel-isi.c
+ create mode 100644 include/media/atmel-isi.h
+
+diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
+index c937e4d..a301a69 100644
+--- a/drivers/media/video/Kconfig
++++ b/drivers/media/video/Kconfig
+@@ -888,6 +888,14 @@ config VIDEO_MX3
+ ---help---
+ This is a v4l2 driver for the i.MX3x Camera Sensor Interface
+
++config VIDEO_ATMEL_ISI
++ tristate "ATMEL Image Sensor Interface (ISI) support"
++ depends on VIDEO_DEV && SOC_CAMERA && ARCH_AT91
++ select VIDEOBUF2_DMA_CONTIG
++ ---help---
++ This module makes the ATMEL Image Sensor Interface available
++ as a v4l2 device.
++
+ config VIDEO_PXA27x
+ tristate "PXA27x Quick Capture Interface driver"
+ depends on VIDEO_DEV && PXA27x && SOC_CAMERA
+diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
+index 5a7620d..f9f8f12 100644
+--- a/drivers/media/video/Makefile
++++ b/drivers/media/video/Makefile
+@@ -166,6 +166,7 @@ obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o
+ obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
+ obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o
+ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/
++obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o
+
+ obj-$(CONFIG_ARCH_DAVINCI) += davinci/
+
+diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c
+new file mode 100644
+index 0000000..4742c28
+--- /dev/null
++++ b/drivers/media/video/atmel-isi.c
+@@ -0,0 +1,1048 @@
++/*
++ * Copyright (c) 2011 Atmel Corporation
++ * Josh Wu, <josh.wu@atmel.com>
++ *
++ * Based on previous work by Lars Haring, <lars.haring@atmel.com>
++ * and Sedji Gaouaou
++ * Based on the bttv driver for Bt848 with respective copyright holders
++ *
++ * 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/clk.h>
++#include <linux/completion.h>
++#include <linux/delay.h>
++#include <linux/fs.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#include <media/atmel-isi.h>
++#include <media/soc_camera.h>
++#include <media/soc_mediabus.h>
++#include <media/videobuf2-dma-contig.h>
++
++#define MAX_BUFFER_NUM 32
++#define MAX_SUPPORT_WIDTH 2048
++#define MAX_SUPPORT_HEIGHT 2048
++#define VID_LIMIT_BYTES (16 * 1024 * 1024)
++#define MIN_FRAME_RATE 15
++#define FRAME_INTERVAL_MILLI_SEC (1000 / MIN_FRAME_RATE)
++
++/* ISI states */
++enum {
++ ISI_STATE_IDLE = 0,
++ ISI_STATE_READY,
++ ISI_STATE_WAIT_SOF,
++};
++
++/* Frame buffer descriptor */
++struct fbd {
++ /* Physical address of the frame buffer */
++ u32 fb_address;
++ /* DMA Control Register(only in HISI2) */
++ u32 dma_ctrl;
++ /* Physical address of the next fbd */
++ u32 next_fbd_address;
++};
++
++static void set_dma_ctrl(struct fbd *fb_desc, u32 ctrl)
++{
++ fb_desc->dma_ctrl = ctrl;
++}
++
++struct isi_dma_desc {
++ struct list_head list;
++ struct fbd *p_fbd;
++ u32 fbd_phys;
++};
++
++/* Frame buffer data */
++struct frame_buffer {
++ struct vb2_buffer vb;
++ struct isi_dma_desc *p_dma_desc;
++ struct list_head list;
++};
++
++struct atmel_isi {
++ /* Protects the access of variables shared with the ISR */
++ spinlock_t lock;
++ void __iomem *regs;
++
++ int sequence;
++ /* State of the ISI module in capturing mode */
++ int state;
++
++ /* Wait queue for waiting for SOF */
++ wait_queue_head_t vsync_wq;
++
++ struct vb2_alloc_ctx *alloc_ctx;
++
++ /* Allocate descriptors for dma buffer use */
++ struct fbd *p_fb_descriptors;
++ u32 fb_descriptors_phys;
++ struct list_head dma_desc_head;
++ struct isi_dma_desc dma_desc[MAX_BUFFER_NUM];
++
++ struct completion complete;
++ struct clk *pclk;
++ unsigned int irq;
++
++ struct isi_platform_data *pdata;
++
++ struct list_head video_buffer_list;
++ struct frame_buffer *active;
++
++ struct soc_camera_device *icd;
++ struct soc_camera_host soc_host;
++};
++
++static void isi_writel(struct atmel_isi *isi, u32 reg, u32 val)
++{
++ writel(val, isi->regs + reg);
++}
++static u32 isi_readl(struct atmel_isi *isi, u32 reg)
++{
++ return readl(isi->regs + reg);
++}
++
++static int configure_geometry(struct atmel_isi *isi, u32 width,
++ u32 height, enum v4l2_mbus_pixelcode code)
++{
++ u32 cfg2, cr;
++
++ switch (code) {
++ /* YUV, including grey */
++ case V4L2_MBUS_FMT_Y8_1X8:
++ cr = ISI_CFG2_GRAYSCALE;
++ break;
++ case V4L2_MBUS_FMT_UYVY8_2X8:
++ cr = ISI_CFG2_YCC_SWAP_MODE_3;
++ break;
++ case V4L2_MBUS_FMT_VYUY8_2X8:
++ cr = ISI_CFG2_YCC_SWAP_MODE_2;
++ break;
++ case V4L2_MBUS_FMT_YUYV8_2X8:
++ cr = ISI_CFG2_YCC_SWAP_MODE_1;
++ break;
++ case V4L2_MBUS_FMT_YVYU8_2X8:
++ cr = ISI_CFG2_YCC_SWAP_DEFAULT;
++ break;
++ /* RGB, TODO */
++ default:
++ return -EINVAL;
++ }
++
++ isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
++
++ cfg2 = isi_readl(isi, ISI_CFG2);
++ cfg2 |= cr;
++ /* Set width */
++ cfg2 &= ~(ISI_CFG2_IM_HSIZE_MASK);
++ cfg2 |= ((width - 1) << ISI_CFG2_IM_HSIZE_OFFSET) &
++ ISI_CFG2_IM_HSIZE_MASK;
++ /* Set height */
++ cfg2 &= ~(ISI_CFG2_IM_VSIZE_MASK);
++ cfg2 |= ((height - 1) << ISI_CFG2_IM_VSIZE_OFFSET)
++ & ISI_CFG2_IM_VSIZE_MASK;
++ isi_writel(isi, ISI_CFG2, cfg2);
++
++ return 0;
++}
++
++static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi)
++{
++ if (isi->active) {
++ struct vb2_buffer *vb = &isi->active->vb;
++ struct frame_buffer *buf = isi->active;
++
++ list_del_init(&buf->list);
++ do_gettimeofday(&vb->v4l2_buf.timestamp);
++ vb->v4l2_buf.sequence = isi->sequence++;
++ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
++ }
++
++ if (list_empty(&isi->video_buffer_list)) {
++ isi->active = NULL;
++ } else {
++ /* start next dma frame. */
++ isi->active = list_entry(isi->video_buffer_list.next,
++ struct frame_buffer, list);
++ isi_writel(isi, ISI_DMA_C_DSCR,
++ isi->active->p_dma_desc->fbd_phys);
++ isi_writel(isi, ISI_DMA_C_CTRL,
++ ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
++ isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
++ }
++ return IRQ_HANDLED;
++}
++
++/* ISI interrupt service routine */
++static irqreturn_t isi_interrupt(int irq, void *dev_id)
++{
++ struct atmel_isi *isi = dev_id;
++ u32 status, mask, pending;
++ irqreturn_t ret = IRQ_NONE;
++
++ spin_lock(&isi->lock);
++
++ status = isi_readl(isi, ISI_STATUS);
++ mask = isi_readl(isi, ISI_INTMASK);
++ pending = status & mask;
++
++ if (pending & ISI_CTRL_SRST) {
++ complete(&isi->complete);
++ isi_writel(isi, ISI_INTDIS, ISI_CTRL_SRST);
++ ret = IRQ_HANDLED;
++ } else if (pending & ISI_CTRL_DIS) {
++ complete(&isi->complete);
++ isi_writel(isi, ISI_INTDIS, ISI_CTRL_DIS);
++ ret = IRQ_HANDLED;
++ } else {
++ if ((pending & ISI_SR_VSYNC) &&
++ (isi->state == ISI_STATE_IDLE)) {
++ isi->state = ISI_STATE_READY;
++ wake_up_interruptible(&isi->vsync_wq);
++ ret = IRQ_HANDLED;
++ }
++ if (likely(pending & ISI_SR_CXFR_DONE))
++ ret = atmel_isi_handle_streaming(isi);
++ }
++
++ spin_unlock(&isi->lock);
++ return ret;
++}
++
++#define WAIT_ISI_RESET 1
++#define WAIT_ISI_DISABLE 0
++static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset)
++{
++ unsigned long timeout;
++ /*
++ * The reset or disable will only succeed if we have a
++ * pixel clock from the camera.
++ */
++ init_completion(&isi->complete);
++
++ if (wait_reset) {
++ isi_writel(isi, ISI_INTEN, ISI_CTRL_SRST);
++ isi_writel(isi, ISI_CTRL, ISI_CTRL_SRST);
++ } else {
++ isi_writel(isi, ISI_INTEN, ISI_CTRL_DIS);
++ isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
++ }
++
++ timeout = wait_for_completion_timeout(&isi->complete,
++ msecs_to_jiffies(100));
++ if (timeout == 0)
++ return -ETIMEDOUT;
++
++ return 0;
++}
++
++/* ------------------------------------------------------------------
++ Videobuf operations
++ ------------------------------------------------------------------*/
++static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
++ unsigned int *nplanes, unsigned long sizes[],
++ void *alloc_ctxs[])
++{
++ struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct atmel_isi *isi = ici->priv;
++ unsigned long size;
++ int ret, bytes_per_line;
++
++ /* Reset ISI */
++ ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET);
++ if (ret < 0) {
++ dev_err(icd->dev.parent, "Reset ISI timed out\n");
++ return ret;
++ }
++ /* Disable all interrupts */
++ isi_writel(isi, ISI_INTDIS, ~0UL);
++
++ bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
++ icd->current_fmt->host_fmt);
++
++ if (bytes_per_line < 0)
++ return bytes_per_line;
++
++ size = bytes_per_line * icd->user_height;
++
++ if (!*nbuffers || *nbuffers > MAX_BUFFER_NUM)
++ *nbuffers = MAX_BUFFER_NUM;
++
++ if (size * *nbuffers > VID_LIMIT_BYTES)
++ *nbuffers = VID_LIMIT_BYTES / size;
++
++ *nplanes = 1;
++ sizes[0] = size;
++ alloc_ctxs[0] = isi->alloc_ctx;
++
++ isi->sequence = 0;
++ isi->active = NULL;
++
++ dev_dbg(icd->dev.parent, "%s, count=%d, size=%ld\n", __func__,
++ *nbuffers, size);
++
++ return 0;
++}
++
++static int buffer_init(struct vb2_buffer *vb)
++{
++ struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb);
++
++ buf->p_dma_desc = NULL;
++ INIT_LIST_HEAD(&buf->list);
++
++ return 0;
++}
++
++static int buffer_prepare(struct vb2_buffer *vb)
++{
++ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
++ struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb);
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct atmel_isi *isi = ici->priv;
++ unsigned long size;
++ struct isi_dma_desc *desc;
++ int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
++ icd->current_fmt->host_fmt);
++
++ if (bytes_per_line < 0)
++ return bytes_per_line;
++
++ size = bytes_per_line * icd->user_height;
++
++ if (vb2_plane_size(vb, 0) < size) {
++ dev_err(icd->dev.parent, "%s data will not fit into plane (%lu < %lu)\n",
++ __func__, vb2_plane_size(vb, 0), size);
++ return -EINVAL;
++ }
++
++ vb2_set_plane_payload(&buf->vb, 0, size);
++
++ if (!buf->p_dma_desc) {
++ if (list_empty(&isi->dma_desc_head)) {
++ dev_err(icd->dev.parent, "Not enough dma descriptors.\n");
++ return -EINVAL;
++ } else {
++ /* Get an available descriptor */
++ desc = list_entry(isi->dma_desc_head.next,
++ struct isi_dma_desc, list);
++ /* Delete the descriptor since now it is used */
++ list_del_init(&desc->list);
++
++ /* Initialize the dma descriptor */
++ desc->p_fbd->fb_address =
++ vb2_dma_contig_plane_paddr(vb, 0);
++ desc->p_fbd->next_fbd_address = 0;
++ set_dma_ctrl(desc->p_fbd, ISI_DMA_CTRL_WB);
++
++ buf->p_dma_desc = desc;
++ }
++ }
++ return 0;
++}
++
++static void buffer_cleanup(struct vb2_buffer *vb)
++{
++ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct atmel_isi *isi = ici->priv;
++ struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb);
++
++ /* This descriptor is available now and we add to head list */
++ if (buf->p_dma_desc)
++ list_add(&buf->p_dma_desc->list, &isi->dma_desc_head);
++}
++
++static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer)
++{
++ u32 ctrl, cfg1;
++
++ cfg1 = isi_readl(isi, ISI_CFG1);
++ /* Enable irq: cxfr for the codec path, pxfr for the preview path */
++ isi_writel(isi, ISI_INTEN,
++ ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE);
++
++ /* Check if already in a frame */
++ if (isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) {
++ dev_err(isi->icd->dev.parent, "Already in frame handling.\n");
++ return;
++ }
++
++ isi_writel(isi, ISI_DMA_C_DSCR, buffer->p_dma_desc->fbd_phys);
++ isi_writel(isi, ISI_DMA_C_CTRL, ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
++ isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
++
++ /* Enable linked list */
++ cfg1 |= isi->pdata->frate | ISI_CFG1_DISCR;
++
++ /* Enable codec path and ISI */
++ ctrl = ISI_CTRL_CDC | ISI_CTRL_EN;
++ isi_writel(isi, ISI_CTRL, ctrl);
++ isi_writel(isi, ISI_CFG1, cfg1);
++}
++
++static void buffer_queue(struct vb2_buffer *vb)
++{
++ struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct atmel_isi *isi = ici->priv;
++ struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb);
++ unsigned long flags = 0;
++
++ spin_lock_irqsave(&isi->lock, flags);
++ list_add_tail(&buf->list, &isi->video_buffer_list);
++
++ if (isi->active == NULL) {
++ isi->active = buf;
++ start_dma(isi, buf);
++ }
++ spin_unlock_irqrestore(&isi->lock, flags);
++}
++
++static int start_streaming(struct vb2_queue *vq)
++{
++ struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct atmel_isi *isi = ici->priv;
++
++ u32 sr = 0;
++ int ret;
++
++ spin_lock_irq(&isi->lock);
++ isi->state = ISI_STATE_IDLE;
++ /* Clear any pending SOF interrupt */
++ sr = isi_readl(isi, ISI_STATUS);
++ /* Enable VSYNC interrupt for SOF */
++ isi_writel(isi, ISI_INTEN, ISI_SR_VSYNC);
++ isi_writel(isi, ISI_CTRL, ISI_CTRL_EN);
++ spin_unlock_irq(&isi->lock);
++
++ dev_dbg(icd->dev.parent, "Waiting for SOF\n");
++ ret = wait_event_interruptible(isi->vsync_wq,
++ isi->state != ISI_STATE_IDLE);
++ if (ret)
++ return ret;
++
++ if (isi->state != ISI_STATE_READY)
++ return -EIO;
++
++ spin_lock_irq(&isi->lock);
++ isi->state = ISI_STATE_WAIT_SOF;
++ isi_writel(isi, ISI_INTDIS, ISI_SR_VSYNC);
++ spin_unlock_irq(&isi->lock);
++
++ return 0;
++}
++
++/* abort streaming and wait for last buffer */
++static int stop_streaming(struct vb2_queue *vq)
++{
++ struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct atmel_isi *isi = ici->priv;
++ struct frame_buffer *buf, *node;
++ int ret = 0;
++ unsigned long timeout;
++
++ spin_lock_irq(&isi->lock);
++ isi->active = NULL;
++ /* Release all active buffers */
++ list_for_each_entry_safe(buf, node, &isi->video_buffer_list, list) {
++ list_del_init(&buf->list);
++ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
++ }
++ spin_unlock_irq(&isi->lock);
++
++ timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ;
++ /* Wait until the end of the current frame. */
++ while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) &&
++ time_before(jiffies, timeout))
++ msleep(1);
++
++ if (time_after(jiffies, timeout)) {
++ dev_err(icd->dev.parent,
++ "Timeout waiting for finishing codec request\n");
++ return -ETIMEDOUT;
++ }
++
++ /* Disable interrupts */
++ isi_writel(isi, ISI_INTDIS,
++ ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE);
++
++ /* Disable ISI and wait for it is done */
++ ret = atmel_isi_wait_status(isi, WAIT_ISI_DISABLE);
++ if (ret < 0)
++ dev_err(icd->dev.parent, "Disable ISI timed out\n");
++
++ return ret;
++}
++
++static struct vb2_ops isi_video_qops = {
++ .queue_setup = queue_setup,
++ .buf_init = buffer_init,
++ .buf_prepare = buffer_prepare,
++ .buf_cleanup = buffer_cleanup,
++ .buf_queue = buffer_queue,
++ .start_streaming = start_streaming,
++ .stop_streaming = stop_streaming,
++ .wait_prepare = soc_camera_unlock,
++ .wait_finish = soc_camera_lock,
++};
++
++/* ------------------------------------------------------------------
++ SOC camera operations for the device
++ ------------------------------------------------------------------*/
++static int isi_camera_init_videobuf(struct vb2_queue *q,
++ struct soc_camera_device *icd)
++{
++ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ q->io_modes = VB2_MMAP;
++ q->drv_priv = icd;
++ q->buf_struct_size = sizeof(struct frame_buffer);
++ q->ops = &isi_video_qops;
++ q->mem_ops = &vb2_dma_contig_memops;
++
++ return vb2_queue_init(q);
++}
++
++static int isi_camera_set_fmt(struct soc_camera_device *icd,
++ struct v4l2_format *f)
++{
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct atmel_isi *isi = ici->priv;
++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
++ const struct soc_camera_format_xlate *xlate;
++ struct v4l2_pix_format *pix = &f->fmt.pix;
++ struct v4l2_mbus_framefmt mf;
++ int ret;
++
++ xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
++ if (!xlate) {
++ dev_warn(icd->dev.parent, "Format %x not found\n",
++ pix->pixelformat);
++ return -EINVAL;
++ }
++
++ dev_dbg(icd->dev.parent, "Plan to set format %dx%d\n",
++ pix->width, pix->height);
++
++ mf.width = pix->width;
++ mf.height = pix->height;
++ mf.field = pix->field;
++ mf.colorspace = pix->colorspace;
++ mf.code = xlate->code;
++
++ ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
++ if (ret < 0)
++ return ret;
++
++ if (mf.code != xlate->code)
++ return -EINVAL;
++
++ ret = configure_geometry(isi, pix->width, pix->height, xlate->code);
++ if (ret < 0)
++ return ret;
++
++ pix->width = mf.width;
++ pix->height = mf.height;
++ pix->field = mf.field;
++ pix->colorspace = mf.colorspace;
++ icd->current_fmt = xlate;
++
++ dev_dbg(icd->dev.parent, "Finally set format %dx%d\n",
++ pix->width, pix->height);
++
++ return ret;
++}
++
++static int isi_camera_try_fmt(struct soc_camera_device *icd,
++ struct v4l2_format *f)
++{
++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
++ const struct soc_camera_format_xlate *xlate;
++ struct v4l2_pix_format *pix = &f->fmt.pix;
++ struct v4l2_mbus_framefmt mf;
++ u32 pixfmt = pix->pixelformat;
++ int ret;
++
++ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
++ if (pixfmt && !xlate) {
++ dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt);
++ return -EINVAL;
++ }
++
++ /* limit to Atmel ISI hardware capabilities */
++ if (pix->height > MAX_SUPPORT_HEIGHT)
++ pix->height = MAX_SUPPORT_HEIGHT;
++ if (pix->width > MAX_SUPPORT_WIDTH)
++ pix->width = MAX_SUPPORT_WIDTH;
++
++ /* limit to sensor capabilities */
++ mf.width = pix->width;
++ mf.height = pix->height;
++ mf.field = pix->field;
++ mf.colorspace = pix->colorspace;
++ mf.code = xlate->code;
++
++ ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
++ if (ret < 0)
++ return ret;
++
++ pix->width = mf.width;
++ pix->height = mf.height;
++ pix->colorspace = mf.colorspace;
++
++ switch (mf.field) {
++ case V4L2_FIELD_ANY:
++ pix->field = V4L2_FIELD_NONE;
++ break;
++ case V4L2_FIELD_NONE:
++ break;
++ default:
++ dev_err(icd->dev.parent, "Field type %d unsupported.\n",
++ mf.field);
++ ret = -EINVAL;
++ }
++
++ return ret;
++}
++
++static const struct soc_mbus_pixelfmt isi_camera_formats[] = {
++ {
++ .fourcc = V4L2_PIX_FMT_YUYV,
++ .name = "Packed YUV422 16 bit",
++ .bits_per_sample = 8,
++ .packing = SOC_MBUS_PACKING_2X8_PADHI,
++ .order = SOC_MBUS_ORDER_LE,
++ },
++};
++
++/* This will be corrected as we get more formats */
++static bool isi_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt)
++{
++ return fmt->packing == SOC_MBUS_PACKING_NONE ||
++ (fmt->bits_per_sample == 8 &&
++ fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) ||
++ (fmt->bits_per_sample > 8 &&
++ fmt->packing == SOC_MBUS_PACKING_EXTEND16);
++}
++
++static unsigned long make_bus_param(struct atmel_isi *isi)
++{
++ unsigned long flags;
++ /*
++ * Platform specified synchronization and pixel clock polarities are
++ * only a recommendation and are only used during probing. Atmel ISI
++ * camera interface only works in master mode, i.e., uses HSYNC and
++ * VSYNC signals from the sensor
++ */
++ flags = SOCAM_MASTER |
++ SOCAM_HSYNC_ACTIVE_HIGH |
++ SOCAM_HSYNC_ACTIVE_LOW |
++ SOCAM_VSYNC_ACTIVE_HIGH |
++ SOCAM_VSYNC_ACTIVE_LOW |
++ SOCAM_PCLK_SAMPLE_RISING |
++ SOCAM_PCLK_SAMPLE_FALLING |
++ SOCAM_DATA_ACTIVE_HIGH;
++
++ if (isi->pdata->data_width_flags & ISI_DATAWIDTH_10)
++ flags |= SOCAM_DATAWIDTH_10;
++
++ if (isi->pdata->data_width_flags & ISI_DATAWIDTH_8)
++ flags |= SOCAM_DATAWIDTH_8;
++
++ if (flags & SOCAM_DATAWIDTH_MASK)
++ return flags;
++
++ return 0;
++}
++
++static int isi_camera_try_bus_param(struct soc_camera_device *icd,
++ unsigned char buswidth)
++{
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct atmel_isi *isi = ici->priv;
++ unsigned long camera_flags;
++ int ret;
++
++ camera_flags = icd->ops->query_bus_param(icd);
++ ret = soc_camera_bus_param_compatible(camera_flags,
++ make_bus_param(isi));
++ if (!ret)
++ return -EINVAL;
++ return 0;
++}
++
++
++static int isi_camera_get_formats(struct soc_camera_device *icd,
++ unsigned int idx,
++ struct soc_camera_format_xlate *xlate)
++{
++ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
++ int formats = 0, ret;
++ /* sensor format */
++ enum v4l2_mbus_pixelcode code;
++ /* soc camera host format */
++ const struct soc_mbus_pixelfmt *fmt;
++
++ ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
++ if (ret < 0)
++ /* No more formats */
++ return 0;
++
++ fmt = soc_mbus_get_fmtdesc(code);
++ if (!fmt) {
++ dev_err(icd->dev.parent,
++ "Invalid format code #%u: %d\n", idx, code);
++ return 0;
++ }
++
++ /* This also checks support for the requested bits-per-sample */
++ ret = isi_camera_try_bus_param(icd, fmt->bits_per_sample);
++ if (ret < 0) {
++ dev_err(icd->dev.parent,
++ "Fail to try the bus parameters.\n");
++ return 0;
++ }
++
++ switch (code) {
++ case V4L2_MBUS_FMT_UYVY8_2X8:
++ case V4L2_MBUS_FMT_VYUY8_2X8:
++ case V4L2_MBUS_FMT_YUYV8_2X8:
++ case V4L2_MBUS_FMT_YVYU8_2X8:
++ formats++;
++ if (xlate) {
++ xlate->host_fmt = &isi_camera_formats[0];
++ xlate->code = code;
++ xlate++;
++ dev_dbg(icd->dev.parent, "Providing format %s using code %d\n",
++ isi_camera_formats[0].name, code);
++ }
++ break;
++ default:
++ if (!isi_camera_packing_supported(fmt))
++ return 0;
++ if (xlate)
++ dev_dbg(icd->dev.parent,
++ "Providing format %s in pass-through mode\n",
++ fmt->name);
++ }
++
++ /* Generic pass-through */
++ formats++;
++ if (xlate) {
++ xlate->host_fmt = fmt;
++ xlate->code = code;
++ xlate++;
++ }
++
++ return formats;
++}
++
++/* Called with .video_lock held */
++static int isi_camera_add_device(struct soc_camera_device *icd)
++{
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct atmel_isi *isi = ici->priv;
++ int ret;
++
++ if (isi->icd)
++ return -EBUSY;
++
++ ret = clk_enable(isi->pclk);
++ if (ret)
++ return ret;
++
++ isi->icd = icd;
++ dev_dbg(icd->dev.parent, "Atmel ISI Camera driver attached to camera %d\n",
++ icd->devnum);
++ return 0;
++}
++/* Called with .video_lock held */
++static void isi_camera_remove_device(struct soc_camera_device *icd)
++{
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct atmel_isi *isi = ici->priv;
++
++ BUG_ON(icd != isi->icd);
++
++ clk_disable(isi->pclk);
++ isi->icd = NULL;
++
++ dev_dbg(icd->dev.parent, "Atmel ISI Camera driver detached from camera %d\n",
++ icd->devnum);
++}
++
++static unsigned int isi_camera_poll(struct file *file, poll_table *pt)
++{
++ struct soc_camera_device *icd = file->private_data;
++
++ return vb2_poll(&icd->vb2_vidq, file, pt);
++}
++
++static int isi_camera_querycap(struct soc_camera_host *ici,
++ struct v4l2_capability *cap)
++{
++ strcpy(cap->driver, "atmel-isi");
++ strcpy(cap->card, "Atmel Image Sensor Interface");
++ cap->capabilities = (V4L2_CAP_VIDEO_CAPTURE |
++ V4L2_CAP_STREAMING);
++ return 0;
++}
++
++static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt)
++{
++ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++ struct atmel_isi *isi = ici->priv;
++ unsigned long bus_flags, camera_flags, common_flags;
++ int ret;
++ u32 cfg1 = 0;
++
++ camera_flags = icd->ops->query_bus_param(icd);
++
++ bus_flags = make_bus_param(isi);
++ common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
++ dev_dbg(icd->dev.parent, "Flags cam: 0x%lx host: 0x%lx common: 0x%lx\n",
++ camera_flags, bus_flags, common_flags);
++ if (!common_flags)
++ return -EINVAL;
++
++ /* Make choises, based on platform preferences */
++ if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
++ (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
++ if (isi->pdata->hsync_act_low)
++ common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
++ else
++ common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
++ }
++
++ if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) &&
++ (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) {
++ if (isi->pdata->vsync_act_low)
++ common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH;
++ else
++ common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW;
++ }
++
++ if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
++ (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
++ if (isi->pdata->pclk_act_falling)
++ common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
++ else
++ common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
++ }
++
++ ret = icd->ops->set_bus_param(icd, common_flags);
++ if (ret < 0) {
++ dev_dbg(icd->dev.parent, "Camera set_bus_param(%lx) returned %d\n",
++ common_flags, ret);
++ return ret;
++ }
++
++ /* set bus param for ISI */
++ if (common_flags & SOCAM_HSYNC_ACTIVE_LOW)
++ cfg1 |= ISI_CFG1_HSYNC_POL_ACTIVE_LOW;
++ if (common_flags & SOCAM_VSYNC_ACTIVE_LOW)
++ cfg1 |= ISI_CFG1_VSYNC_POL_ACTIVE_LOW;
++ if (common_flags & SOCAM_PCLK_SAMPLE_FALLING)
++ cfg1 |= ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING;
++
++ if (isi->pdata->has_emb_sync)
++ cfg1 |= ISI_CFG1_EMB_SYNC;
++ if (isi->pdata->isi_full_mode)
++ cfg1 |= ISI_CFG1_FULL_MODE;
++
++ isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
++ isi_writel(isi, ISI_CFG1, cfg1);
++
++ return 0;
++}
++
++static struct soc_camera_host_ops isi_soc_camera_host_ops = {
++ .owner = THIS_MODULE,
++ .add = isi_camera_add_device,
++ .remove = isi_camera_remove_device,
++ .set_fmt = isi_camera_set_fmt,
++ .try_fmt = isi_camera_try_fmt,
++ .get_formats = isi_camera_get_formats,
++ .init_videobuf2 = isi_camera_init_videobuf,
++ .poll = isi_camera_poll,
++ .querycap = isi_camera_querycap,
++ .set_bus_param = isi_camera_set_bus_param,
++};
++
++/* -----------------------------------------------------------------------*/
++static int __devexit atmel_isi_remove(struct platform_device *pdev)
++{
++ struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
++ struct atmel_isi *isi = container_of(soc_host,
++ struct atmel_isi, soc_host);
++
++ free_irq(isi->irq, isi);
++ soc_camera_host_unregister(soc_host);
++ vb2_dma_contig_cleanup_ctx(isi->alloc_ctx);
++ dma_free_coherent(&pdev->dev,
++ sizeof(struct fbd) * MAX_BUFFER_NUM,
++ isi->p_fb_descriptors,
++ isi->fb_descriptors_phys);
++
++ iounmap(isi->regs);
++ clk_put(isi->pclk);
++ kfree(isi);
++
++ return 0;
++}
++
++static int __devinit atmel_isi_probe(struct platform_device *pdev)
++{
++ unsigned int irq;
++ struct atmel_isi *isi;
++ struct clk *pclk;
++ struct resource *regs;
++ int ret, i;
++ struct device *dev = &pdev->dev;
++ struct soc_camera_host *soc_host;
++ struct isi_platform_data *pdata;
++
++ pdata = dev->platform_data;
++ if (!pdata || !pdata->data_width_flags) {
++ dev_err(&pdev->dev,
++ "No config available for Atmel ISI\n");
++ return -EINVAL;
++ }
++
++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!regs)
++ return -ENXIO;
++
++ pclk = clk_get(&pdev->dev, "isi_clk");
++ if (IS_ERR(pclk))
++ return PTR_ERR(pclk);
++
++ isi = kzalloc(sizeof(struct atmel_isi), GFP_KERNEL);
++ if (!isi) {
++ ret = -ENOMEM;
++ dev_err(&pdev->dev, "Can't allocate interface!\n");
++ goto err_alloc_isi;
++ }
++
++ isi->pclk = pclk;
++ isi->pdata = pdata;
++ isi->active = NULL;
++ spin_lock_init(&isi->lock);
++ init_waitqueue_head(&isi->vsync_wq);
++ INIT_LIST_HEAD(&isi->video_buffer_list);
++ INIT_LIST_HEAD(&isi->dma_desc_head);
++
++ isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev,
++ sizeof(struct fbd) * MAX_BUFFER_NUM,
++ &isi->fb_descriptors_phys,
++ GFP_KERNEL);
++ if (!isi->p_fb_descriptors) {
++ ret = -ENOMEM;
++ dev_err(&pdev->dev, "Can't allocate descriptors!\n");
++ goto err_alloc_descriptors;
++ }
++
++ for (i = 0; i < MAX_BUFFER_NUM; i++) {
++ isi->dma_desc[i].p_fbd = isi->p_fb_descriptors + i;
++ isi->dma_desc[i].fbd_phys = isi->fb_descriptors_phys +
++ i * sizeof(struct fbd);
++ list_add(&isi->dma_desc[i].list, &isi->dma_desc_head);
++ }
++
++ isi->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
++ if (IS_ERR(isi->alloc_ctx)) {
++ ret = PTR_ERR(isi->alloc_ctx);
++ goto err_alloc_ctx;
++ }
++
++ isi->regs = ioremap(regs->start, resource_size(regs));
++ if (!isi->regs) {
++ ret = -ENOMEM;
++ goto err_ioremap;
++ }
++
++ isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
++
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0) {
++ ret = irq;
++ goto err_req_irq;
++ }
++
++ ret = request_irq(irq, isi_interrupt, 0, "isi", isi);
++ if (ret) {
++ dev_err(&pdev->dev, "Unable to request irq %d\n", irq);
++ goto err_req_irq;
++ }
++ isi->irq = irq;
++
++ soc_host = &isi->soc_host;
++ soc_host->drv_name = "isi-camera";
++ soc_host->ops = &isi_soc_camera_host_ops;
++ soc_host->priv = isi;
++ soc_host->v4l2_dev.dev = &pdev->dev;
++ soc_host->nr = pdev->id;
++
++ ret = soc_camera_host_register(soc_host);
++ if (ret) {
++ dev_err(&pdev->dev, "Unable to register soc camera host\n");
++ goto err_register_soc_camera_host;
++ }
++ return 0;
++
++err_register_soc_camera_host:
++ free_irq(isi->irq, isi);
++err_req_irq:
++ iounmap(isi->regs);
++err_ioremap:
++ vb2_dma_contig_cleanup_ctx(isi->alloc_ctx);
++err_alloc_ctx:
++ dma_free_coherent(&pdev->dev,
++ sizeof(struct fbd) * MAX_BUFFER_NUM,
++ isi->p_fb_descriptors,
++ isi->fb_descriptors_phys);
++err_alloc_descriptors:
++ kfree(isi);
++err_alloc_isi:
++ clk_put(isi->pclk);
++
++ return ret;
++}
++
++static struct platform_driver atmel_isi_driver = {
++ .probe = atmel_isi_probe,
++ .remove = __devexit_p(atmel_isi_remove),
++ .driver = {
++ .name = "atmel_isi",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init atmel_isi_init_module(void)
++{
++ return platform_driver_probe(&atmel_isi_driver, &atmel_isi_probe);
++}
++
++static void __exit atmel_isi_exit(void)
++{
++ platform_driver_unregister(&atmel_isi_driver);
++}
++module_init(atmel_isi_init_module);
++module_exit(atmel_isi_exit);
++
++MODULE_AUTHOR("Josh Wu <josh.wu@atmel.com>");
++MODULE_DESCRIPTION("The V4L2 driver for Atmel Linux");
++MODULE_LICENSE("GPL");
++MODULE_SUPPORTED_DEVICE("video");
+diff --git a/include/media/atmel-isi.h b/include/media/atmel-isi.h
+new file mode 100644
+index 0000000..26cece5
+--- /dev/null
++++ b/include/media/atmel-isi.h
+@@ -0,0 +1,119 @@
++/*
++ * Register definitions for the Atmel Image Sensor Interface.
++ *
++ * Copyright (C) 2011 Atmel Corporation
++ * Josh Wu, <josh.wu@atmel.com>
++ *
++ * Based on previous work by Lars Haring, <lars.haring@atmel.com>
++ * and Sedji Gaouaou
++ *
++ * 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 __ATMEL_ISI_H__
++#define __ATMEL_ISI_H__
++
++#include <linux/types.h>
++
++/* ISI_V2 register offsets */
++#define ISI_CFG1 0x0000
++#define ISI_CFG2 0x0004
++#define ISI_PSIZE 0x0008
++#define ISI_PDECF 0x000c
++#define ISI_Y2R_SET0 0x0010
++#define ISI_Y2R_SET1 0x0014
++#define ISI_R2Y_SET0 0x0018
++#define ISI_R2Y_SET1 0x001C
++#define ISI_R2Y_SET2 0x0020
++#define ISI_CTRL 0x0024
++#define ISI_STATUS 0x0028
++#define ISI_INTEN 0x002C
++#define ISI_INTDIS 0x0030
++#define ISI_INTMASK 0x0034
++#define ISI_DMA_CHER 0x0038
++#define ISI_DMA_CHDR 0x003C
++#define ISI_DMA_CHSR 0x0040
++#define ISI_DMA_P_ADDR 0x0044
++#define ISI_DMA_P_CTRL 0x0048
++#define ISI_DMA_P_DSCR 0x004C
++#define ISI_DMA_C_ADDR 0x0050
++#define ISI_DMA_C_CTRL 0x0054
++#define ISI_DMA_C_DSCR 0x0058
++
++/* Bitfields in CFG1 */
++#define ISI_CFG1_HSYNC_POL_ACTIVE_LOW (1 << 2)
++#define ISI_CFG1_VSYNC_POL_ACTIVE_LOW (1 << 3)
++#define ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING (1 << 4)
++#define ISI_CFG1_EMB_SYNC (1 << 6)
++#define ISI_CFG1_CRC_SYNC (1 << 7)
++/* Constants for FRATE(ISI_V2) */
++#define ISI_CFG1_FRATE_CAPTURE_ALL (0 << 8)
++#define ISI_CFG1_FRATE_DIV_2 (1 << 8)
++#define ISI_CFG1_FRATE_DIV_3 (2 << 8)
++#define ISI_CFG1_FRATE_DIV_4 (3 << 8)
++#define ISI_CFG1_FRATE_DIV_5 (4 << 8)
++#define ISI_CFG1_FRATE_DIV_6 (5 << 8)
++#define ISI_CFG1_FRATE_DIV_7 (6 << 8)
++#define ISI_CFG1_FRATE_DIV_8 (7 << 8)
++#define ISI_CFG1_DISCR (1 << 11)
++#define ISI_CFG1_FULL_MODE (1 << 12)
++
++/* Bitfields in CFG2 */
++#define ISI_CFG2_GRAYSCALE (1 << 13)
++/* Constants for YCC_SWAP(ISI_V2) */
++#define ISI_CFG2_YCC_SWAP_DEFAULT (0 << 28)
++#define ISI_CFG2_YCC_SWAP_MODE_1 (1 << 28)
++#define ISI_CFG2_YCC_SWAP_MODE_2 (2 << 28)
++#define ISI_CFG2_YCC_SWAP_MODE_3 (3 << 28)
++#define ISI_CFG2_IM_VSIZE_OFFSET 0
++#define ISI_CFG2_IM_HSIZE_OFFSET 16
++#define ISI_CFG2_IM_VSIZE_MASK (0x7FF << ISI_CFG2_IM_VSIZE_OFFSET)
++#define ISI_CFG2_IM_HSIZE_MASK (0x7FF << ISI_CFG2_IM_HSIZE_OFFSET)
++
++/* Bitfields in CTRL */
++/* Also using in SR(ISI_V2) */
++#define ISI_CTRL_EN (1 << 0)
++#define ISI_CTRL_CDC (1 << 8)
++/* Also using in SR/IER/IDR/IMR(ISI_V2) */
++#define ISI_CTRL_DIS (1 << 1)
++#define ISI_CTRL_SRST (1 << 2)
++
++/* Bitfields in SR */
++#define ISI_SR_SIP (1 << 19)
++/* Also using in SR/IER/IDR/IMR */
++#define ISI_SR_VSYNC (1 << 10)
++#define ISI_SR_PXFR_DONE (1 << 16)
++#define ISI_SR_CXFR_DONE (1 << 17)
++#define ISI_SR_P_OVR (1 << 24)
++#define ISI_SR_C_OVR (1 << 25)
++#define ISI_SR_CRC_ERR (1 << 26)
++#define ISI_SR_FR_OVR (1 << 27)
++
++/* Bitfields in DMA_C_CTRL & in DMA_P_CTRL */
++#define ISI_DMA_CTRL_FETCH (1 << 0)
++#define ISI_DMA_CTRL_WB (1 << 1)
++#define ISI_DMA_CTRL_IEN (1 << 2)
++#define ISI_DMA_CTRL_DONE (1 << 3)
++
++/* Bitfields in DMA_CHSR/CHER/CHDR */
++#define ISI_DMA_CHSR_P_CH (1 << 0)
++#define ISI_DMA_CHSR_C_CH (1 << 1)
++
++/* Definition for isi_platform_data */
++#define ISI_DATAWIDTH_8 0x01
++#define ISI_DATAWIDTH_10 0x02
++
++struct isi_platform_data {
++ u8 has_emb_sync;
++ u8 emb_crc_sync;
++ u8 hsync_act_low;
++ u8 vsync_act_low;
++ u8 pclk_act_falling;
++ u8 isi_full_mode;
++ u32 data_width_flags;
++ /* Using for ISI_CFG1 */
++ u32 frate;
++};
++
++#endif /* __ATMEL_ISI_H__ */
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0092-add-isi-support-in-board-files.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0092-add-isi-support-in-board-files.patch
new file mode 100644
index 0000000..a1b4d02
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0092-add-isi-support-in-board-files.patch
@@ -0,0 +1,238 @@
+From d904f14ba47c08d0b73de77b5066ecad7bec8953 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Fri, 27 May 2011 18:26:15 +0800
+Subject: [PATCH 092/107] add isi support in board files.
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ arch/arm/mach-at91/at91sam9g45_devices.c | 66 ++++++++++++++++++++
+ arch/arm/mach-at91/board-sam9m10g45ek.c | 97 ++++++++++++++++++++++++++++++
+ arch/arm/mach-at91/include/mach/board.h | 3 +-
+ 3 files changed, 165 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
+index f40b254..c9a61ff 100644
+--- a/arch/arm/mach-at91/at91sam9g45_devices.c
++++ b/arch/arm/mach-at91/at91sam9g45_devices.c
+@@ -29,6 +29,8 @@
+ #include <mach/at_hdmac.h>
+ #include <mach/atmel-mci.h>
+
++#include <media/atmel-isi.h>
++
+ #include "generic.h"
+
+
+@@ -873,6 +875,70 @@ void __init at91_add_device_ac97(struct ac97c_platform_data *data)
+ void __init at91_add_device_ac97(struct ac97c_platform_data *data) {}
+ #endif
+
++/* --------------------------------------------------------------------
++ * Image Sensor Interface
++ * -------------------------------------------------------------------- */
++#if defined(CONFIG_VIDEO_ATMEL_ISI) || defined(CONFIG_VIDEO_ATMEL_ISI_MODULE)
++static u64 isi_dmamask = DMA_BIT_MASK(32);
++static struct isi_platform_data isi_data;
++
++struct resource isi_resources[] = {
++ [0] = {
++ .start = AT91SAM9G45_BASE_ISI,
++ .end = AT91SAM9G45_BASE_ISI + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9G45_ID_ISI,
++ .end = AT91SAM9G45_ID_ISI,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91sam9g45_isi_device = {
++ .name = "atmel_isi",
++ .id = 0,
++ .dev = {
++ .dma_mask = &isi_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &isi_data,
++ },
++ .resource = isi_resources,
++ .num_resources = ARRAY_SIZE(isi_resources),
++};
++
++void __init at91_add_device_isi(struct isi_platform_data * data)
++{
++ struct platform_device *pdev;
++
++ if (!data)
++ return;
++ isi_data = *data;
++
++ at91_set_A_periph(AT91_PIN_PB20, 0); /* ISI_D0 */
++ at91_set_A_periph(AT91_PIN_PB21, 0); /* ISI_D1 */
++ at91_set_A_periph(AT91_PIN_PB22, 0); /* ISI_D2 */
++ at91_set_A_periph(AT91_PIN_PB23, 0); /* ISI_D3 */
++ at91_set_A_periph(AT91_PIN_PB24, 0); /* ISI_D4 */
++ at91_set_A_periph(AT91_PIN_PB25, 0); /* ISI_D5 */
++ at91_set_A_periph(AT91_PIN_PB26, 0); /* ISI_D6 */
++ at91_set_A_periph(AT91_PIN_PB27, 0); /* ISI_D7 */
++ at91_set_A_periph(AT91_PIN_PB28, 0); /* ISI_PCK */
++ at91_set_A_periph(AT91_PIN_PB30, 0); /* ISI_HSYNC */
++ at91_set_A_periph(AT91_PIN_PB29, 0); /* ISI_VSYNC */
++ at91_set_B_periph(AT91_PIN_PB31, 0); /* ISI_MCK (PCK1) */
++ at91_set_B_periph(AT91_PIN_PB8, 0); /* ISI_PD8 */
++ at91_set_B_periph(AT91_PIN_PB9, 0); /* ISI_PD9 */
++ at91_set_B_periph(AT91_PIN_PB10, 0); /* ISI_PD10 */
++ at91_set_B_periph(AT91_PIN_PB11, 0); /* ISI_PD11 */
++
++ pdev = &at91sam9g45_isi_device;
++ platform_device_register(pdev);
++}
++#else
++void __init at91_add_device_isi(struct isi_platform_data * data) { }
++#endif
++
+
+ /* --------------------------------------------------------------------
+ * LCD Controller
+diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
+index b2b1a8b..6fb7ce9 100644
+--- a/arch/arm/mach-at91/board-sam9m10g45ek.c
++++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
+@@ -25,9 +25,12 @@
+ #include <linux/leds.h>
+ #include <linux/clk.h>
+ #include <linux/atmel-mci.h>
++#include <linux/delay.h>
+
+ #include <mach/hardware.h>
+ #include <video/atmel_lcdfb.h>
++#include <media/soc_camera.h>
++#include <media/atmel-isi.h>
+
+ #include <asm/setup.h>
+ #include <asm/mach-types.h>
+@@ -195,6 +198,95 @@ static void __init ek_add_device_nand(void)
+ at91_add_device_nand(&ek_nand_data);
+ }
+
++/*
++ * ISI
++ */
++#if defined(CONFIG_VIDEO_ATMEL_ISI) || defined(CONFIG_VIDEO_ATMEL_ISI_MODULE)
++static struct isi_platform_data __initdata isi_data = {
++ .frate = ISI_CFG1_FRATE_CAPTURE_ALL,
++ .has_emb_sync = 0,
++ .emb_crc_sync = 0,
++ .hsync_act_low = 0,
++ .vsync_act_low = 0,
++ .pclk_act_falling = 0,
++ /* to use codec and preview path simultaneously */
++ .isi_full_mode = 1,
++ .data_width_flags = ISI_DATAWIDTH_8 | ISI_DATAWIDTH_10,
++};
++
++static void __init isi_set_clk(void)
++{
++ struct clk *pck1;
++ struct clk *plla;
++
++ pck1 = clk_get(NULL, "pck1");
++ plla = clk_get(NULL, "plla");
++
++ clk_set_parent(pck1, plla);
++ clk_set_rate(pck1, 25000000);
++ clk_enable(pck1);
++}
++#else
++static void __init isi_set_clk(void) {}
++
++static struct isi_platform_data __initdata isi_data;
++#endif
++
++/*
++ * soc-camera OV2640
++ */
++#if defined(CONFIG_SOC_CAMERA_OV2640)
++static unsigned long isi_camera_query_bus_param(struct soc_camera_link *link)
++{
++ /* ISI board for ek using default 8-bits connection */
++ return SOCAM_DATAWIDTH_8;
++}
++
++static int i2c_camera_power(struct device *dev, int on)
++{
++ /* enable or disable the camera */
++ pr_debug("%s: %s the camera\n", __func__, on ? "ENABLE" : "DISABLE");
++ at91_set_gpio_output(AT91_PIN_PD13, on ? 0 : 1);
++
++ if (!on)
++ goto out;
++
++ /* If enabled, give a reset impulse */
++ at91_set_gpio_output(AT91_PIN_PD12, 0);
++ msleep(20);
++ at91_set_gpio_output(AT91_PIN_PD12, 1);
++ msleep(100);
++
++out:
++ return 0;
++}
++
++static struct i2c_board_info i2c_camera = {
++ I2C_BOARD_INFO("ov2640", 0x30),
++};
++
++static struct soc_camera_link iclink_ov2640 = {
++ .bus_id = 0,
++ .board_info = &i2c_camera,
++ .i2c_adapter_id = 0,
++ .power = i2c_camera_power,
++ .query_bus_param = isi_camera_query_bus_param,
++};
++
++static struct platform_device isi_ov2640 = {
++ .name = "soc-camera-pdrv",
++ .id = 0,
++ .dev = {
++ .platform_data = &iclink_ov2640,
++ },
++};
++
++static struct platform_device *devices[] __initdata = {
++ &isi_ov2640,
++};
++#else
++static struct platform_device *devices[] __initdata = {};
++#endif
+
+ /*
+ * LCD Controller
+@@ -410,6 +502,11 @@ static void __init ek_board_init(void)
+ ek_add_device_nand();
+ /* I2C */
+ at91_add_device_i2c(0, NULL, 0);
++ /* ISI */
++ platform_add_devices(devices, ARRAY_SIZE(devices));
++ isi_set_clk();
++ at91_add_device_isi(&isi_data);
++
+ /* LCD Controller */
+ at91_add_device_lcdc(&ek_lcdc_data);
+ /* Touch Screen */
+diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
+index 42412d5..cf8d780 100644
+--- a/arch/arm/mach-at91/include/mach/board.h
++++ b/arch/arm/mach-at91/include/mach/board.h
+@@ -188,7 +188,8 @@ extern void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data);
+ extern void __init at91_add_device_ac97(struct ac97c_platform_data *data);
+
+ /* ISI */
+-extern void __init at91_add_device_isi(void);
++struct isi_platform_data;
++extern void __init at91_add_device_isi(struct isi_platform_data *data);
+
+ /* Touchscreen Controller */
+ struct at91_tsadcc_data {
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0093-media-at91-add-dumb-set_parm.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0093-media-at91-add-dumb-set_parm.patch
new file mode 100644
index 0000000..1f0b313
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0093-media-at91-add-dumb-set_parm.patch
@@ -0,0 +1,40 @@
+From 81827465ea87d7ad20dcb9f8abb7393af6333a5d Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Fri, 10 Jun 2011 17:21:28 +0200
+Subject: [PATCH 093/107] [media] at91: add dumb set_parm()
+
+Add dumb set_parm() function to struct soc_camera_host_ops.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/media/video/atmel-isi.c | 7 +++++++
+ 1 files changed, 7 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c
+index 4742c28..b7a0a20 100644
+--- a/drivers/media/video/atmel-isi.c
++++ b/drivers/media/video/atmel-isi.c
+@@ -868,6 +868,12 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt)
+ return 0;
+ }
+
++
++static int isi_camera_set_parm(struct soc_camera_device *icd, struct v4l2_streamparm *parm)
++{
++ return 0;
++}
++
+ static struct soc_camera_host_ops isi_soc_camera_host_ops = {
+ .owner = THIS_MODULE,
+ .add = isi_camera_add_device,
+@@ -879,6 +885,7 @@ static struct soc_camera_host_ops isi_soc_camera_host_ops = {
+ .poll = isi_camera_poll,
+ .querycap = isi_camera_querycap,
+ .set_bus_param = isi_camera_set_bus_param,
++ .set_parm = isi_camera_set_parm,
+ };
+
+ /* -----------------------------------------------------------------------*/
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0094-AT91-5series-add-ISI-device-and-board-support.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0094-AT91-5series-add-ISI-device-and-board-support.patch
new file mode 100644
index 0000000..1118a09
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0094-AT91-5series-add-ISI-device-and-board-support.patch
@@ -0,0 +1,232 @@
+From 07827ad93d921e852712a2f7f6b1d480c04c133c Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Fri, 10 Jun 2011 17:23:45 +0200
+Subject: [PATCH 094/107] AT91: 5series: add ISI device and board support
+
+New ISI / media SoC camera interface with ov2640 image sensor support.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/at91sam9x5_devices.c | 67 ++++++++++++++++++++
+ arch/arm/mach-at91/board-sam9x5ek.c | 103 ++++++++++++++++++++++++++++++-
+ 2 files changed, 169 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9x5_devices.c b/arch/arm/mach-at91/at91sam9x5_devices.c
+index cd642e2..4cafa1c 100644
+--- a/arch/arm/mach-at91/at91sam9x5_devices.c
++++ b/arch/arm/mach-at91/at91sam9x5_devices.c
+@@ -30,6 +30,8 @@
+ #include <mach/at_hdmac.h>
+ #include <mach/atmel-mci.h>
+
++#include <media/atmel-isi.h>
++
+ #include "generic.h"
+
+ /* --------------------------------------------------------------------
+@@ -931,6 +933,71 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
+ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {}
+ #endif
+
++/* --------------------------------------------------------------------
++ * Image Sensor Interface
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_VIDEO_ATMEL_ISI) || defined(CONFIG_VIDEO_ATMEL_ISI_MODULE)
++static u64 isi_dmamask = DMA_BIT_MASK(32);
++static struct isi_platform_data isi_data;
++
++struct resource isi_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_BASE_ISI,
++ .end = AT91SAM9X5_BASE_ISI + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_ISI,
++ .end = AT91SAM9X5_ID_ISI,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91sam9x5_isi_device = {
++ .name = "atmel_isi",
++ .id = 0,
++ .dev = {
++ .dma_mask = &isi_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &isi_data,
++ },
++ .resource = isi_resources,
++ .num_resources = ARRAY_SIZE(isi_resources),
++};
++
++void __init at91_add_device_isi(struct isi_platform_data *data)
++{
++ struct platform_device *pdev;
++
++ if (!data)
++ return;
++
++ at91_set_B_periph(AT91_PIN_PC0, 0); /* ISI_D0 */
++ at91_set_B_periph(AT91_PIN_PC1, 0); /* ISI_D1 */
++ at91_set_B_periph(AT91_PIN_PC2, 0); /* ISI_D2 */
++ at91_set_B_periph(AT91_PIN_PC3, 0); /* ISI_D3 */
++ at91_set_B_periph(AT91_PIN_PC4, 0); /* ISI_D4 */
++ at91_set_B_periph(AT91_PIN_PC5, 0); /* ISI_D5 */
++ at91_set_B_periph(AT91_PIN_PC6, 0); /* ISI_D6 */
++ at91_set_B_periph(AT91_PIN_PC7, 0); /* ISI_D7 */
++ at91_set_B_periph(AT91_PIN_PC12, 0); /* ISI_PCK */
++ at91_set_B_periph(AT91_PIN_PC14, 0); /* ISI_HSYNC */
++ at91_set_B_periph(AT91_PIN_PC13, 0); /* ISI_VSYNC */
++ at91_set_C_periph(AT91_PIN_PC15, 0); /* ISI_MCK (using PCK0 as clock) */
++ at91_set_B_periph(AT91_PIN_PC8, 0); /* ISI_PD8 */
++ at91_set_B_periph(AT91_PIN_PC9, 0); /* ISI_PD9 */
++ at91_set_B_periph(AT91_PIN_PC10, 0); /* ISI_PD10 */
++ at91_set_B_periph(AT91_PIN_PC11, 0); /* ISI_PD11 */
++
++ pdev = &at91sam9x5_isi_device;
++
++ isi_data = *data;
++ platform_device_register(pdev);
++}
++#else
++void __init at91_add_device_isi(struct isi_platform_data *data) {}
++#endif
+
+ /* --------------------------------------------------------------------
+ * CAN Controllers
+diff --git a/arch/arm/mach-at91/board-sam9x5ek.c b/arch/arm/mach-at91/board-sam9x5ek.c
+index 54fd7cc..826bb6e 100644
+--- a/arch/arm/mach-at91/board-sam9x5ek.c
++++ b/arch/arm/mach-at91/board-sam9x5ek.c
+@@ -22,9 +22,12 @@
+ #include <linux/input.h>
+ #include <linux/leds.h>
+ #include <linux/clk.h>
++#include <linux/delay.h>
+ #include <mach/cpu.h>
+
+ #include <video/atmel_lcdfb.h>
++#include <media/soc_camera.h>
++#include <media/atmel-isi.h>
+
+ #include <asm/setup.h>
+ #include <asm/mach-types.h>
+@@ -110,6 +113,95 @@ static struct mci_platform_data __initdata mci1_data = {
+ },
+ };
+
++/*
++ * ISI
++ */
++#if defined(CONFIG_VIDEO_ATMEL_ISI) || defined(CONFIG_VIDEO_ATMEL_ISI_MODULE)
++static struct isi_platform_data __initdata isi_data = {
++ .frate = ISI_CFG1_FRATE_CAPTURE_ALL,
++ .has_emb_sync = 0,
++ .emb_crc_sync = 0,
++ .hsync_act_low = 0,
++ .vsync_act_low = 0,
++ .pclk_act_falling = 0,
++ /* to use codec and preview path simultaneously */
++ .isi_full_mode = 1,
++ .data_width_flags = ISI_DATAWIDTH_8 | ISI_DATAWIDTH_10,
++};
++
++static void __init isi_set_clk(void)
++{
++ struct clk *pck0;
++ struct clk *plla;
++
++ pck0 = clk_get(NULL, "pck0");
++ plla = clk_get(NULL, "plla");
++
++ clk_set_parent(pck0, plla);
++ /* for the sensor ov9655: 10< Fclk < 48, Fclk typ = 24MHz */
++ clk_set_rate(pck0, 25000000);
++ clk_enable(pck0);
++}
++#else
++static void __init isi_set_clk(void) {}
++static struct isi_platform_data __initdata isi_data;
++#endif
++
++/*
++ * soc-camera OV2640
++ */
++#if defined(CONFIG_SOC_CAMERA_OV2640)
++static unsigned long isi_camera_query_bus_param(struct soc_camera_link *link)
++{
++ /* ISI board for ek using default 8-bits connection */
++ return SOCAM_DATAWIDTH_8;
++}
++
++static int i2c_camera_power(struct device *dev, int on)
++{
++ /* enable or disable the camera */
++ pr_debug("%s: %s the camera\n", __func__, on ? "ENABLE" : "DISABLE");
++ at91_set_gpio_output(AT91_PIN_PA13, on ? 0 : 1);
++
++ if (!on)
++ goto out;
++
++ /* If enabled, give a reset impulse */
++ at91_set_gpio_output(AT91_PIN_PA7, 0);
++ msleep(20);
++ at91_set_gpio_output(AT91_PIN_PA7, 1);
++ msleep(100);
++
++out:
++ return 0;
++}
++
++static struct i2c_board_info i2c_camera = {
++ I2C_BOARD_INFO("ov2640", 0x30),
++};
++
++static struct soc_camera_link iclink_ov2640 = {
++ .bus_id = 0,
++ .board_info = &i2c_camera,
++ .i2c_adapter_id = 0,
++ .power = i2c_camera_power,
++ .query_bus_param = isi_camera_query_bus_param,
++};
++
++static struct platform_device isi_ov2640 = {
++ .name = "soc-camera-pdrv",
++ .id = 0,
++ .dev = {
++ .platform_data = &iclink_ov2640,
++ },
++};
++
++static struct platform_device *soc_camera_devices[] __initdata = {
++ &isi_ov2640,
++};
++#else
++static struct platform_device *soc_camera_devices[] __initdata = {};
++#endif
+
+ /*
+ * LCD Controller
+@@ -314,7 +406,16 @@ static void __init ek_board_init(void)
+ at91_add_device_i2c(0,
+ ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
+
+- if (!cpu_is_at91sam9g25() && !cpu_is_at91sam9x25()) {
++ if (cpu_is_at91sam9g25()) {
++ /* ISI */
++ /* NOTE: PCK0 provides ISI_MCK to the ISI module.
++ ISI's PWD pin conflict with MCI1_CK due the hardware design.
++ */
++ platform_add_devices(soc_camera_devices,
++ ARRAY_SIZE(soc_camera_devices));
++ isi_set_clk();
++ at91_add_device_isi(&isi_data);
++ } else if (!cpu_is_at91sam9x25()) {
+ /* LCD Controller */
+ at91_add_device_lcdc(&ek_lcdc_data);
+ /* Touch Screen */
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0095-AT91-board-remove-not-needed-comments.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0095-AT91-board-remove-not-needed-comments.patch
new file mode 100644
index 0000000..1b3c43c
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0095-AT91-board-remove-not-needed-comments.patch
@@ -0,0 +1,47 @@
+From b2267ebc8cb722d8bb403da097cf2649616f8f62 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Fri, 10 Jun 2011 18:01:57 +0200
+Subject: [PATCH 095/107] AT91: board: remove not needed comments
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/board-sam9x5cm.c | 1 -
+ arch/arm/mach-at91/board-sam9x5ek.c | 3 +--
+ 2 files changed, 1 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/mach-at91/board-sam9x5cm.c b/arch/arm/mach-at91/board-sam9x5cm.c
+index 53d8046..a5f8f3d 100644
+--- a/arch/arm/mach-at91/board-sam9x5cm.c
++++ b/arch/arm/mach-at91/board-sam9x5cm.c
+@@ -228,7 +228,6 @@ void __init cm_board_init(u32 *cm_config)
+ /* LEDs */
+ at91_gpio_leds(cm_leds, ARRAY_SIZE(cm_leds));
+
+- /* TODO Remove: only for debugging */
+ if (cm_is_revA())
+ printk(KERN_CRIT "AT91: CM rev A\n");
+ else
+diff --git a/arch/arm/mach-at91/board-sam9x5ek.c b/arch/arm/mach-at91/board-sam9x5ek.c
+index 826bb6e..4f64903 100644
+--- a/arch/arm/mach-at91/board-sam9x5ek.c
++++ b/arch/arm/mach-at91/board-sam9x5ek.c
+@@ -433,7 +433,7 @@ static void __init ek_board_init(void)
+ #endif
+
+ if (cpu_is_at91sam9x25() || cpu_is_at91sam9x35())
+- /* XXX: this conflicts with usart.1 */
++ /* this conflicts with usart.1 */
+ at91_add_device_can(1, NULL);
+
+ /* Push Buttons */
+@@ -443,7 +443,6 @@ static void __init ek_board_init(void)
+ /* SSC (for WM8731) */
+ at91_add_device_ssc(AT91SAM9X5_ID_SSC, ATMEL_SSC_TX | ATMEL_SSC_RX);
+
+- /* TODO Remove: only for debugging */
+ if (ek_is_revA())
+ printk(KERN_CRIT "AT91: EK rev A\n");
+ else
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0096-AT91-5series-update-defconfig.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0096-AT91-5series-update-defconfig.patch
new file mode 100644
index 0000000..81d4fc7
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0096-AT91-5series-update-defconfig.patch
@@ -0,0 +1,266 @@
+From 63d2c71154c342c3a2e20828fc21e6d424e8fc67 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Fri, 10 Jun 2011 18:06:12 +0200
+Subject: [PATCH 096/107] AT91: 5series: update defconfig
+
+- ISI and V4L2 media/video
+- UBI / UBIFS
+- update driver support (sd/mmc, sound)
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/configs/at91sam9x5ek_defconfig | 130 +++++++++++++++++++++----------
+ 1 files changed, 89 insertions(+), 41 deletions(-)
+
+diff --git a/arch/arm/configs/at91sam9x5ek_defconfig b/arch/arm/configs/at91sam9x5ek_defconfig
+index 1b455fc..48af066 100644
+--- a/arch/arm/configs/at91sam9x5ek_defconfig
++++ b/arch/arm/configs/at91sam9x5ek_defconfig
+@@ -1,14 +1,14 @@
+ CONFIG_EXPERIMENTAL=y
++# CONFIG_LOCALVERSION_AUTO is not set
+ # CONFIG_SWAP is not set
+ CONFIG_SYSVIPC=y
+ CONFIG_POSIX_MQUEUE=y
+ CONFIG_LOG_BUF_SHIFT=14
+-# CONFIG_UTS_NS is not set
+-# CONFIG_IPC_NS is not set
+-# CONFIG_USER_NS is not set
+-# CONFIG_PID_NS is not set
+-# CONFIG_NET_NS is not set
+ CONFIG_BLK_DEV_INITRD=y
++CONFIG_RD_BZIP2=y
++CONFIG_RD_LZMA=y
++CONFIG_RD_LZO=y
++CONFIG_EMBEDDED=y
+ CONFIG_SLAB=y
+ CONFIG_MODULES=y
+ CONFIG_MODULE_UNLOAD=y
+@@ -28,7 +28,8 @@ CONFIG_LEDS_CPU=y
+ CONFIG_UACCESS_WITH_MEMCPY=y
+ CONFIG_ZBOOT_ROM_TEXT=0x0
+ CONFIG_ZBOOT_ROM_BSS=0x0
+-CONFIG_CMDLINE="mem=128M console=ttyS0,115200 initrd=0x21100000,8000000 root=/dev/ram0 rw mtdparts=atmel_nand:4M(bootstrap/uboot/kernel)ro,60M(rootfs),-(data)"
++CONFIG_CMDLINE="console=ttyS0,115200 mtdparts=atmel_nand:8M(bootstrap/uboot/kernel)ro,-(rootfs) root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:at91sam9x5ek-rootfs"
++CONFIG_AUTO_ZRELADDR=y
+ CONFIG_FPE_NWFPE=y
+ # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+ CONFIG_NET=y
+@@ -37,33 +38,20 @@ CONFIG_UNIX=y
+ CONFIG_INET=y
+ CONFIG_IP_MULTICAST=y
+ CONFIG_IP_ADVANCED_ROUTER=y
+-CONFIG_IP_PNP=y
+-CONFIG_IP_PNP_DHCP=y
+ # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+ # CONFIG_INET_XFRM_MODE_TUNNEL is not set
+ # CONFIG_INET_XFRM_MODE_BEET is not set
+ # CONFIG_INET_LRO is not set
+ # CONFIG_IPV6 is not set
+ CONFIG_NETFILTER=y
+-CONFIG_NETFILTER_NETLINK_QUEUE=m
+-CONFIG_NETFILTER_NETLINK_LOG=m
++# CONFIG_NETFILTER_ADVANCED is not set
+ CONFIG_NF_CONNTRACK=y
+-CONFIG_NF_CONNTRACK_MARK=y
+-CONFIG_NF_CONNTRACK_FTP=m
+-CONFIG_NF_CT_NETLINK=m
+ CONFIG_NF_CONNTRACK_IPV4=y
+ CONFIG_IP_NF_IPTABLES=y
+ CONFIG_IP_NF_FILTER=y
+-CONFIG_IP_NF_TARGET_REJECT=m
+-CONFIG_IP_NF_TARGET_LOG=m
+-CONFIG_IP_NF_TARGET_ULOG=m
+ CONFIG_NF_NAT=y
+ CONFIG_IP_NF_TARGET_MASQUERADE=y
+-CONFIG_IP_NF_TARGET_NETMAP=y
+-CONFIG_IP_NF_TARGET_REDIRECT=y
+-CONFIG_IP_NF_RAW=m
+-CONFIG_IP_NF_ARPTABLES=m
+-CONFIG_BRIDGE=y
++CONFIG_BRIDGE=m
+ CONFIG_VLAN_8021Q=m
+ CONFIG_NET_SCHED=y
+ CONFIG_NET_SCH_CBQ=m
+@@ -76,7 +64,9 @@ CONFIG_CAN_RAW=y
+ CONFIG_CAN_DEV=y
+ CONFIG_CAN_CALC_BITTIMING=y
+ CONFIG_CAN_AT91=y
+-# CONFIG_WIRELESS is not set
++CONFIG_CFG80211=y
++CONFIG_LIB80211=y
++CONFIG_MAC80211=y
+ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+ # CONFIG_STANDALONE is not set
+ # CONFIG_PREVENT_FIRMWARE_BUILD is not set
+@@ -87,15 +77,16 @@ CONFIG_MTD_PARTITIONS=y
+ CONFIG_MTD_CMDLINE_PARTS=y
+ CONFIG_MTD_CHAR=y
+ CONFIG_MTD_BLOCK=y
+-CONFIG_MTD_M25P80=y
+ CONFIG_MTD_NAND=y
+ CONFIG_MTD_NAND_ATMEL=y
++CONFIG_MTD_UBI=y
+ CONFIG_BLK_DEV_LOOP=y
+ CONFIG_BLK_DEV_RAM=y
+ CONFIG_BLK_DEV_RAM_COUNT=4
+ CONFIG_BLK_DEV_RAM_SIZE=8192
+ CONFIG_MISC_DEVICES=y
+ CONFIG_ATMEL_TCLIB=y
++CONFIG_ATMEL_SSC=y
+ CONFIG_SCSI=y
+ CONFIG_BLK_DEV_SD=y
+ CONFIG_SCSI_MULTI_LUN=y
+@@ -107,32 +98,89 @@ CONFIG_NET_ETHERNET=y
+ CONFIG_MACB=y
+ # CONFIG_NETDEV_1000 is not set
+ # CONFIG_NETDEV_10000 is not set
+-# CONFIG_WLAN is not set
+-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+-CONFIG_INPUT_MOUSEDEV_SCREEN_X=800
+-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480
++CONFIG_LIBERTAS_THINFIRM=m
++CONFIG_LIBERTAS_THINFIRM_USB=m
++CONFIG_AT76C50X_USB=m
++CONFIG_USB_ZD1201=m
++CONFIG_RTL8187=m
++CONFIG_ATH_COMMON=m
++CONFIG_ATH9K_HTC=m
++CONFIG_AR9170_USB=m
++CONFIG_CARL9170=m
++CONFIG_B43=m
++CONFIG_B43_SDIO=y
++CONFIG_B43_PHY_N=y
++CONFIG_LIBERTAS=m
++CONFIG_LIBERTAS_USB=m
++CONFIG_LIBERTAS_SDIO=m
++CONFIG_LIBERTAS_SPI=m
++CONFIG_RT2X00=m
++CONFIG_RT2500USB=m
++CONFIG_RT73USB=m
++CONFIG_RT2800USB=m
++CONFIG_RT2800USB_RT33XX=y
++CONFIG_RT2800USB_RT35XX=y
++CONFIG_RT2800USB_UNKNOWN=y
++CONFIG_RTL8192CU=m
++CONFIG_WL1251=m
++CONFIG_WL1251_SDIO=m
++CONFIG_WL12XX_MENU=m
++CONFIG_WL12XX=m
++CONFIG_WL12XX_SDIO=m
++CONFIG_ZD1211RW=m
++# CONFIG_INPUT_MOUSEDEV is not set
+ CONFIG_INPUT_EVDEV=y
+ # CONFIG_KEYBOARD_ATKBD is not set
++CONFIG_KEYBOARD_QT1070=y
+ CONFIG_KEYBOARD_GPIO=y
+ # CONFIG_INPUT_MOUSE is not set
+ CONFIG_INPUT_TOUCHSCREEN=y
++CONFIG_TOUCHSCREEN_ATMEL_MXT=m
+ CONFIG_TOUCHSCREEN_ATMEL_TSADCC=y
+ CONFIG_LEGACY_PTY_COUNT=8
+ CONFIG_SERIAL_ATMEL=y
+ CONFIG_SERIAL_ATMEL_CONSOLE=y
+ CONFIG_HW_RANDOM=y
++CONFIG_I2C=y
++# CONFIG_I2C_COMPAT is not set
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_GPIO=y
+ CONFIG_SPI=y
+ CONFIG_SPI_ATMEL=y
+ CONFIG_GPIO_SYSFS=y
+ # CONFIG_HWMON is not set
+ # CONFIG_MFD_SUPPORT is not set
++CONFIG_MEDIA_SUPPORT=y
++CONFIG_MEDIA_CONTROLLER=y
++CONFIG_VIDEO_DEV=y
++CONFIG_VIDEO_V4L2_SUBDEV_API=y
++CONFIG_VIDEO_AT91SAM9X5=y
++CONFIG_VIDEO_FIXED_MINOR_RANGES=y
++CONFIG_SOC_CAMERA=y
++CONFIG_SOC_CAMERA_OV2640=y
++CONFIG_VIDEO_ATMEL_ISI=y
++# CONFIG_V4L_USB_DRIVERS is not set
++CONFIG_VIDEO_AT91SAM9X5=y
++# CONFIG_RADIO_ADAPTERS is not set
+ CONFIG_FB=y
+ CONFIG_FB_ATMEL=y
+ CONFIG_BACKLIGHT_LCD_SUPPORT=y
+ # CONFIG_LCD_CLASS_DEVICE is not set
+ CONFIG_BACKLIGHT_CLASS_DEVICE=y
+ CONFIG_BACKLIGHT_ATMEL_LCDC=y
+-# CONFIG_BACKLIGHT_GENERIC is not set
++CONFIG_SOUND=y
++CONFIG_SND=y
++CONFIG_SND_SEQUENCER=y
++CONFIG_SND_MIXER_OSS=y
++CONFIG_SND_PCM_OSS=y
++# CONFIG_SND_SUPPORT_OLD_API is not set
++# CONFIG_SND_DRIVERS is not set
++# CONFIG_SND_ARM is not set
++# CONFIG_SND_SPI is not set
++CONFIG_SND_USB_AUDIO=m
++CONFIG_SND_SOC=y
++CONFIG_SND_ATMEL_SOC=y
++CONFIG_SND_AT91_SOC_SAM9X5_WM8731=y
+ CONFIG_USB=y
+ # CONFIG_USB_DEVICE_CLASS is not set
+ CONFIG_USB_EHCI_HCD=y
+@@ -148,6 +196,10 @@ CONFIG_USB_G_SERIAL=m
+ CONFIG_USB_CDC_COMPOSITE=m
+ CONFIG_USB_G_MULTI=m
+ CONFIG_USB_G_MULTI_CDC=y
++CONFIG_MMC=y
++# CONFIG_MMC_BLOCK_BOUNCE is not set
++CONFIG_MMC_ATMELMCI=y
++CONFIG_MMC_ATMELMCI_DMA=y
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_CLASS=y
+ CONFIG_LEDS_GPIO=y
+@@ -162,34 +214,30 @@ CONFIG_AT_HDMAC=y
+ CONFIG_DMATEST=m
+ CONFIG_UIO=y
+ CONFIG_UIO_PDRV=m
+-CONFIG_UIO_PDRV_GENIRQ=y
++CONFIG_UIO_PDRV_GENIRQ=m
+ CONFIG_EXT2_FS=y
++CONFIG_FANOTIFY=y
+ CONFIG_MSDOS_FS=y
+ CONFIG_VFAT_FS=y
+ CONFIG_TMPFS=y
+ CONFIG_JFFS2_FS=y
+ CONFIG_JFFS2_SUMMARY=y
+-CONFIG_LOGFS=m
+-CONFIG_CRAMFS=y
++CONFIG_UBIFS_FS=y
++CONFIG_UBIFS_FS_XATTR=y
++CONFIG_UBIFS_FS_ADVANCED_COMPR=y
++CONFIG_CRAMFS=m
+ CONFIG_SQUASHFS=m
+ CONFIG_NFS_FS=y
+ CONFIG_NFS_V3=y
+ CONFIG_NFS_V4=y
+-CONFIG_ROOT_NFS=y
+ CONFIG_NLS_CODEPAGE_437=y
+ CONFIG_NLS_CODEPAGE_850=y
+ CONFIG_NLS_ISO8859_1=y
+ CONFIG_NLS_ISO8859_15=y
+ CONFIG_NLS_UTF8=y
+-# CONFIG_ENABLE_WARN_DEPRECATED is not set
+ CONFIG_DEBUG_FS=y
+-CONFIG_DEBUG_KERNEL=y
+-CONFIG_LOCKUP_DETECTOR=y
+-CONFIG_DETECT_HUNG_TASK=y
+-CONFIG_PROVE_LOCKING=y
+-CONFIG_DEBUG_SPINLOCK_SLEEP=y
+-CONFIG_DEBUG_INFO=y
+-# CONFIG_FTRACE is not set
+-# CONFIG_ARM_UNWIND is not set
+ CONFIG_DEBUG_USER=y
++CONFIG_CRYPTO_CBC=y
++CONFIG_CRYPTO_MD5=y
++CONFIG_CRYPTO_DES=y
+ # CONFIG_CRYPTO_HW is not set
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0097-AT91-input-atmel_tsadcc-rework-irq-infrastructure-an.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0097-AT91-input-atmel_tsadcc-rework-irq-infrastructure-an.patch
new file mode 100644
index 0000000..dc1df4f
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0097-AT91-input-atmel_tsadcc-rework-irq-infrastructure-an.patch
@@ -0,0 +1,191 @@
+From 562108acaa9c456611ec27d708c33d0d3e6a299e Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 16 Jun 2011 19:24:04 +0200
+Subject: [PATCH 097/107] AT91/input: atmel_tsadcc: rework irq infrastructure
+ and parameters
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/board-sam9x5ek.c | 10 +---
+ drivers/input/touchscreen/atmel_tsadcc.c | 70 +++++++++++++++++-------------
+ 2 files changed, 43 insertions(+), 37 deletions(-)
+
+diff --git a/arch/arm/mach-at91/board-sam9x5ek.c b/arch/arm/mach-at91/board-sam9x5ek.c
+index 4f64903..4626a42 100644
+--- a/arch/arm/mach-at91/board-sam9x5ek.c
++++ b/arch/arm/mach-at91/board-sam9x5ek.c
+@@ -261,13 +261,9 @@ static struct atmel_lcdfb_info __initdata ek_lcdc_data;
+ */
+ static struct at91_tsadcc_data ek_tsadcc_data = {
+ .adc_clock = 300000,
+- /*
+- * XXX: ukl: disable averaging for now at it's broken without a hardware
+- * change
+- */
+- .filtering_average = 0x00, /* averages 2^filtering_average ADC conversions */
+- .pendet_debounce = 0x0d,
+- .pendet_sensitivity = 0x03,
++ .filtering_average = 0x03, /* averages 2^filtering_average ADC conversions */
++ .pendet_debounce = 0x08,
++ .pendet_sensitivity = 0x02, /* 2 = set to default */
+ .ts_sample_hold_time = 0x0a,
+ };
+
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
+index 9c3b330..5209df0 100644
+--- a/drivers/input/touchscreen/atmel_tsadcc.c
++++ b/drivers/input/touchscreen/atmel_tsadcc.c
+@@ -30,6 +30,7 @@
+ #define cpu_has_9x5_adc() (cpu_is_at91sam9x5())
+
+ #define ADC_DEFAULT_CLOCK 100000
++#define ZTHRESHOLD 3200
+
+ struct atmel_tsadcc {
+ struct input_dev *input;
+@@ -39,7 +40,6 @@ struct atmel_tsadcc {
+ unsigned int prev_absx;
+ unsigned int prev_absy;
+ unsigned int prev_absz;
+- unsigned char bufferedmeasure;
+ };
+
+ static void __iomem *tsc_base;
+@@ -62,6 +62,7 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ {
+ struct atmel_tsadcc *ts_dev = (struct atmel_tsadcc *)dev;
+ struct input_dev *input_dev = ts_dev->input;
++ struct at91_tsadcc_data *pdata = input_dev->dev.parent->platform_data;
+
+ unsigned int status;
+ unsigned int reg;
+@@ -76,7 +77,7 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ /* Contact lost */
+ if (cpu_has_9x5_adc()) {
+ /* 9X5 using TSMR to set PENDBC time */
+- reg = atmel_tsadcc_read(ATMEL_TSADCC_TSMR) | ATMEL_TSADCC_PENDBC;
++ reg = atmel_tsadcc_read(ATMEL_TSADCC_TSMR) | ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC);
+ atmel_tsadcc_write(ATMEL_TSADCC_TSMR, reg);
+ } else {
+ reg = atmel_tsadcc_read(ATMEL_TSADCC_MR) | ATMEL_TSADCC_PENDBC;
+@@ -88,7 +89,6 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
+
+ input_report_key(input_dev, BTN_TOUCH, 0);
+- ts_dev->bufferedmeasure = 0;
+ input_sync(input_dev);
+
+ } else if (status & ATMEL_TSADCC_PENCNT) {
+@@ -118,27 +118,20 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ } else if ((status & ATMEL_TSADCC_CONVERSION_END) == ATMEL_TSADCC_CONVERSION_END) {
+ /* Conversion finished */
+
+- if (ts_dev->bufferedmeasure) {
+- /* Last measurement is always discarded, since it can
+- * be erroneous.
+- * Always report previous measurement */
+- dev_dbg(&input_dev->dev,
+- "x = %d, y = %d, pressure = %d\n",
+- ts_dev->prev_absx, ts_dev->prev_absy,
+- ts_dev->prev_absz);
+- input_report_abs(input_dev, ABS_X, ts_dev->prev_absx);
+- input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy);
+- input_report_key(input_dev, BTN_TOUCH, 1);
+- if (cpu_has_9x5_adc())
+- input_report_abs(input_dev, ABS_PRESSURE, ts_dev->prev_absz);
+- input_sync(input_dev);
+- } else
+- ts_dev->bufferedmeasure = 1;
+-
+- /* Now make new measurement */
++ /* make new measurement */
+ if (cpu_has_9x5_adc()) {
+- ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_XPOSR) & 0xffff;
+- ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_YPOSR) & 0xffff;
++ unsigned int xscale, yscale;
++
++ /* calculate position */
++ reg = atmel_tsadcc_read(ATMEL_TSADCC_XPOSR);
++ ts_dev->prev_absx = (reg & ATMEL_TSADCC_XPOS) << 10;
++ xscale = (reg & ATMEL_TSADCC_XSCALE) >> 16;
++ ts_dev->prev_absx /= xscale ? xscale: 1;
++
++ reg = atmel_tsadcc_read(ATMEL_TSADCC_YPOSR);
++ ts_dev->prev_absy = (reg & ATMEL_TSADCC_YPOS) << 10;
++ yscale = (reg & ATMEL_TSADCC_YSCALE) >> 16;
++ ts_dev->prev_absy /= yscale ? yscale: 1 << 10;
+
+ /* calculate the pressure */
+ reg = atmel_tsadcc_read(ATMEL_TSADCC_PRESSR);
+@@ -157,6 +150,23 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10;
+ ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0);
+ }
++
++ /* report measurement to input layer */
++ if (ts_dev->prev_absz < ZTHRESHOLD) {
++ dev_dbg(&input_dev->dev,
++ "x = %d, y = %d, pressure = %d\n",
++ ts_dev->prev_absx, ts_dev->prev_absy,
++ ts_dev->prev_absz);
++ input_report_abs(input_dev, ABS_X, ts_dev->prev_absx);
++ input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy);
++ if (cpu_has_9x5_adc())
++ input_report_abs(input_dev, ABS_PRESSURE, ts_dev->prev_absz);
++ input_report_key(input_dev, BTN_TOUCH, 1);
++ input_sync(input_dev);
++ } else {
++ dev_dbg(&input_dev->dev,
++ "pressure too low: not reporting\n");
++ }
+ }
+
+ return IRQ_HANDLED;
+@@ -233,7 +243,6 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+ }
+
+ ts_dev->input = input_dev;
+- ts_dev->bufferedmeasure = 0;
+
+ snprintf(ts_dev->phys, sizeof(ts_dev->phys),
+ "%s/input0", dev_name(&pdev->dev));
+@@ -275,10 +284,10 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+ dev_info(&pdev->dev, "Prescaler is set at: %d\n", prsc);
+
+ if (cpu_has_9x5_adc()) {
+- reg = ((0x01 << 5) & ATMEL_TSADCC_SLEEP) | /* Sleep Mode */
+- ((0x01 << 6) & ATMEL_TSADCC_FWUP) | /* Fast Wake Up */
++ reg = ((0x00 << 5) & ATMEL_TSADCC_SLEEP) | /* no Sleep Mode */
++ ((0x00 << 6) & ATMEL_TSADCC_FWUP) | /* no Fast Wake Up needed */
+ (prsc << 8) |
+- ((0x8 << 16) & ATMEL_TSADCC_STARTUP) |
++ ((0x4 << 16) & ATMEL_TSADCC_STARTUP) |
+ ((pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TRACKTIM);
+ } else {
+ reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE |
+@@ -296,10 +305,10 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+ if (cpu_has_9x5_adc()) {
+ atmel_tsadcc_write(ATMEL_TSADCC_TSMR,
+ ATMEL_TSADCC_TSMODE_4WIRE_PRESS |
+- (pdata->filtering_average << 4) | /* Touchscreen average */
++ ((pdata->filtering_average << 4) & ATMEL_TSADCC_TSAV) | /* Touchscreen average */
+ ATMEL_TSADCC_NOTSDMA |
+ ATMEL_TSADCC_PENDET_ENA |
+- (pdata->pendet_debounce << 28) |
++ ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC) |
+ (0x3 << 8)); /* Touchscreen freq */
+ } else {
+ atmel_tsadcc_write(ATMEL_TSADCC_TSR,
+@@ -312,7 +321,8 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+ * option only available on ES2 and higher
+ */
+ if (cpu_has_9x5_adc()) {
+- atmel_tsadcc_write(ATMEL_TSADCC_ACR, pdata->pendet_sensitivity);
++ if (pdata->pendet_sensitivity <= ATMEL_TSADCC_PENDET_SENSITIVITY)
++ atmel_tsadcc_write(ATMEL_TSADCC_ACR, pdata->pendet_sensitivity);
+ }
+
+ atmel_tsadcc_read(ATMEL_TSADCC_SR);
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0098-5series-Update-LCD-timings-to-avoid-flickering.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0098-5series-Update-LCD-timings-to-avoid-flickering.patch
new file mode 100644
index 0000000..6abef90
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0098-5series-Update-LCD-timings-to-avoid-flickering.patch
@@ -0,0 +1,33 @@
+From 4d939804a14dc62b4096486c8e3ab20c14976f15 Mon Sep 17 00:00:00 2001
+From: Patrice Vilchez <patrice.vilchez@atmel.com>
+Date: Mon, 20 Jun 2011 13:39:37 +0200
+Subject: [PATCH 098/107] 5series: Update LCD timings to avoid flickering
+
+Timings changed according to FoxLink LCD datasheet.
+
+Signed-off-by: Patrice Vilchez <patrice.vilchez@atmel.com>
+---
+ arch/arm/mach-at91/board-sam9x5ek.c | 6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/mach-at91/board-sam9x5ek.c b/arch/arm/mach-at91/board-sam9x5ek.c
+index 4626a42..ce801ee 100644
+--- a/arch/arm/mach-at91/board-sam9x5ek.c
++++ b/arch/arm/mach-at91/board-sam9x5ek.c
+@@ -212,10 +212,10 @@ static struct fb_videomode at91_tft_vga_modes[] = {
+ .name = "LG",
+ .refresh = 60,
+ .xres = 800, .yres = 480,
+- .pixclock = KHZ2PICOS(22223),
++ .pixclock = KHZ2PICOS(33260),
+
+- .left_margin = 64, .right_margin = 64,
+- .upper_margin = 22, .lower_margin = 21,
++ .left_margin = 88, .right_margin = 168,
++ .upper_margin = 8, .lower_margin = 37,
+ .hsync_len = 128, .vsync_len = 2,
+
+ .sync = 0,
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0099-atmel_lcdfb-change-pixel-clock-ratio-calculation.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0099-atmel_lcdfb-change-pixel-clock-ratio-calculation.patch
new file mode 100644
index 0000000..0950f88
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0099-atmel_lcdfb-change-pixel-clock-ratio-calculation.patch
@@ -0,0 +1,31 @@
+From 335ac3c48f86475d261504d9fed3dd3cb728a804 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Fri, 24 Jun 2011 13:03:29 +0200
+Subject: [PATCH 099/107] atmel_lcdfb: change pixel clock ratio calculation
+
+DIV_ROUND_UP() was used to calculate the pixel clock divider
+in atmel_hlcdfb_setup_core_base().
+But this rounding was producing a bigger divider each time it was called.
+We replace by DIV_ROUND_CLOSEST() to calculate it.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/video/atmel_hlcdfb.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c
+index 346bb80..fde9009 100644
+--- a/drivers/video/atmel_hlcdfb.c
++++ b/drivers/video/atmel_hlcdfb.c
+@@ -246,7 +246,7 @@ static int atmel_hlcdfb_setup_core_base(struct fb_info *info)
+ /* Set pixel clock */
+ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+
+- value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
++ value = DIV_ROUND_CLOSEST(clk_value_khz, PICOS2KHZ(info->var.pixclock));
+
+ if (value < 1) {
+ dev_notice(info->device, "using system clock as pixel clock\n");
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0100-MTD-atmel_nand_pmecc-fix-warning-about-uninitialized.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0100-MTD-atmel_nand_pmecc-fix-warning-about-uninitialized.patch
new file mode 100644
index 0000000..f220350
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0100-MTD-atmel_nand_pmecc-fix-warning-about-uninitialized.patch
@@ -0,0 +1,27 @@
+From 06cfbe5a6d459d57415606e3034749d41b133e47 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 28 Jun 2011 15:37:21 +0200
+Subject: [PATCH 100/107] MTD: atmel_nand_pmecc: fix warning about
+ uninitialized variable
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/mtd/nand/atmel_nand_pmecc.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand_pmecc.c b/drivers/mtd/nand/atmel_nand_pmecc.c
+index 3230666..289e4a5 100644
+--- a/drivers/mtd/nand/atmel_nand_pmecc.c
++++ b/drivers/mtd/nand/atmel_nand_pmecc.c
+@@ -494,7 +494,7 @@ static void atmel_nand_pmecc_write_page(struct mtd_info *mtd,
+
+ static void atmel_init_pmecc(struct mtd_info *mtd)
+ {
+- uint32_t val;
++ uint32_t val = 0;
+ struct nand_chip *nand_chip = mtd->priv;
+ struct atmel_nand_host *host = nand_chip->priv;
+ struct nand_ecclayout *ecc_layout;
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0101-MTD-atmel_nand-fix-wrong-use-of-0-as-NULL.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0101-MTD-atmel_nand-fix-wrong-use-of-0-as-NULL.patch
new file mode 100644
index 0000000..a131811
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0101-MTD-atmel_nand-fix-wrong-use-of-0-as-NULL.patch
@@ -0,0 +1,29 @@
+From bbb862609be395eed477794daf28cec8ec9c1b73 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 28 Jun 2011 16:03:24 +0200
+Subject: [PATCH 101/107] MTD: atmel_nand: fix wrong use of 0 as NULL
+
+Fixing this error:
+atmel_nand.c:718:20: warning: Using plain integer as NULL pointer
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/mtd/nand/atmel_nand.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index c4e07be..9f990b9 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -715,7 +715,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_MEMCPY, mask);
+- host->dma_chan = dma_request_channel(mask, 0, NULL);
++ host->dma_chan = dma_request_channel(mask, NULL, NULL);
+ if (!host->dma_chan) {
+ dev_err(host->dev, "Failed to request DMA channel\n");
+ use_dma = 0;
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0102-ASoC-wm8731-active-bit-and-OSC-management.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0102-ASoC-wm8731-active-bit-and-OSC-management.patch
new file mode 100644
index 0000000..d40140c
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0102-ASoC-wm8731-active-bit-and-OSC-management.patch
@@ -0,0 +1,98 @@
+From e53520aa1f4e3c6d59e224b57d2b80326c6e30b6 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 5 Jul 2011 11:08:43 +0200
+Subject: [PATCH 102/107] ASoC: wm8731: active bit and OSC management
+
+Is a merge of several updates from ASoC:
+- remove the OSC special management: now OSC deal with it in 2.6.39
+- adding "Manage WM8731 ACTIVE bit as a supply widget" patch from Mark Brown
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ sound/soc/codecs/wm8731.c | 34 ++++------------------------------
+ 1 files changed, 4 insertions(+), 30 deletions(-)
+
+diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
+index ec176b6..1af0548 100644
+--- a/sound/soc/codecs/wm8731.c
++++ b/sound/soc/codecs/wm8731.c
+@@ -175,6 +175,7 @@ static const struct snd_kcontrol_new wm8731_input_mux_controls =
+ SOC_DAPM_ENUM("Input Select", wm8731_insel_enum);
+
+ static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
++SND_SOC_DAPM_SUPPLY("ACTIVE",WM8731_ACTIVE, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("OSC", WM8731_PWR, 5, 1, NULL, 0),
+ SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1,
+ &wm8731_output_mixer_controls[0],
+@@ -204,6 +205,8 @@ static int wm8731_check_osc(struct snd_soc_dapm_widget *source,
+ static const struct snd_soc_dapm_route intercon[] = {
+ {"DAC", NULL, "OSC", wm8731_check_osc},
+ {"ADC", NULL, "OSC", wm8731_check_osc},
++ {"DAC", NULL, "ACTIVE"},
++ {"ADC", NULL, "ACTIVE"},
+
+ /* output mixer */
+ {"Output Mixer", "Line Bypass Switch", "Line Input"},
+@@ -326,29 +329,6 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
+ return 0;
+ }
+
+-static int wm8731_pcm_prepare(struct snd_pcm_substream *substream,
+- struct snd_soc_dai *dai)
+-{
+- struct snd_soc_codec *codec = dai->codec;
+-
+- /* set active */
+- snd_soc_write(codec, WM8731_ACTIVE, 0x0001);
+-
+- return 0;
+-}
+-
+-static void wm8731_shutdown(struct snd_pcm_substream *substream,
+- struct snd_soc_dai *dai)
+-{
+- struct snd_soc_codec *codec = dai->codec;
+-
+- /* deactivate */
+- if (!codec->active) {
+- udelay(50);
+- snd_soc_write(codec, WM8731_ACTIVE, 0x0);
+- }
+-}
+-
+ static int wm8731_mute(struct snd_soc_dai *dai, int mute)
+ {
+ struct snd_soc_codec *codec = dai->codec;
+@@ -491,9 +471,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
+ snd_soc_write(codec, WM8731_PWR, reg | 0x0040);
+ break;
+ case SND_SOC_BIAS_OFF:
+- snd_soc_write(codec, WM8731_ACTIVE, 0x0);
+- /* standby: keep crystal oscillator enabled */
+- snd_soc_write(codec, WM8731_PWR, 0x00df);
++ snd_soc_write(codec, WM8731_PWR, 0xffff);
+ regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies),
+ wm8731->supplies);
+ break;
+@@ -508,9 +486,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+ static struct snd_soc_dai_ops wm8731_dai_ops = {
+- .prepare = wm8731_pcm_prepare,
+ .hw_params = wm8731_hw_params,
+- .shutdown = wm8731_shutdown,
+ .digital_mute = wm8731_mute,
+ .set_sysclk = wm8731_set_dai_sysclk,
+ .set_fmt = wm8731_set_dai_fmt,
+@@ -545,8 +521,6 @@ static int wm8731_suspend(struct snd_soc_codec *codec, pm_message_t state)
+ static int wm8731_resume(struct snd_soc_codec *codec)
+ {
+ wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+- if (codec->active)
+- snd_soc_write(codec, WM8731_ACTIVE, 0x0001);
+
+ return 0;
+ }
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0103-AT91-at91sam9x5-add-can-clocks-to-9x25-chip.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0103-AT91-at91sam9x5-add-can-clocks-to-9x25-chip.patch
new file mode 100644
index 0000000..78d638b
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0103-AT91-at91sam9x5-add-can-clocks-to-9x25-chip.patch
@@ -0,0 +1,27 @@
+From 27e57621faa944f78e07acd48b9ec4b6fc0611eb Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 5 Jul 2011 17:21:11 +0200
+Subject: [PATCH 103/107] AT91: at91sam9x5: add can clocks to 9x25 chip
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/at91sam9x5.c | 3 ++-
+ 1 files changed, 2 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
+index de456e6..c1b071b 100644
+--- a/arch/arm/mach-at91/at91sam9x5.c
++++ b/arch/arm/mach-at91/at91sam9x5.c
+@@ -294,7 +294,8 @@ static void __init at91sam9x5_register_clocks(void)
+ if (cpu_is_at91sam9x25())
+ clk_register(&macb1_clk);
+
+- if (cpu_is_at91sam9x35()) {
++ if (cpu_is_at91sam9x25()
++ || cpu_is_at91sam9x35()) {
+ clk_register(&can0_clk);
+ clk_register(&can1_clk);
+ }
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0104-AT91-LCD-include-remove-not-needed-comment.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0104-AT91-LCD-include-remove-not-needed-comment.patch
new file mode 100644
index 0000000..1ce9695
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0104-AT91-LCD-include-remove-not-needed-comment.patch
@@ -0,0 +1,27 @@
+From 73a398fad996d19d50cf61dfdaf9b96c3f62634f Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 6 Jul 2011 15:29:39 +0200
+Subject: [PATCH 104/107] AT91: LCD include: remove not needed comment
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/include/mach/atmel_hlcdc.h | 3 ---
+ 1 files changed, 0 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdc.h b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
+index 0b26f27..24b38d1 100644
+--- a/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
++++ b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
+@@ -29,9 +29,6 @@
+ #define LCDC_LCDCFG0_CLKPWMSEL (0x1 << 3)
+ #define LCDC_LCDCFG0_CGDISBASE (0x1 << 8)
+ #define LCDC_LCDCFG0_CGDISOVR1 (0x1 << 9)
+-/* XXX: maybe this is 1 << 10? At least the LCD Interrupt registers
+- * use 10 while the documentation specifies 11.
+- */
+ #define LCDC_LCDCFG0_CGDISHEO (0x1 << 11)
+ #define LCDC_LCDCFG0_CGDISHCR (0x1 << 12)
+ #define LCDC_LCDCFG0_CLKDIV_OFFSET 16
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0105-AT91-5series-fix-SPI0-MCI1-ISI-pins-conflicts-in-boa.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0105-AT91-5series-fix-SPI0-MCI1-ISI-pins-conflicts-in-boa.patch
new file mode 100644
index 0000000..a5b6866
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0105-AT91-5series-fix-SPI0-MCI1-ISI-pins-conflicts-in-boa.patch
@@ -0,0 +1,102 @@
+From 518000b8060b353c9b303e20d43efc3cdac1bc59 Mon Sep 17 00:00:00 2001
+From: Elen Song <elen.song@atmel.com>
+Date: Thu, 18 Aug 2011 09:34:51 +0800
+Subject: [PATCH 105/107] AT91: 5series: fix SPI0/MCI1/ISI pins conflicts in
+ board file
+
+ISI's PWD pin confilct with MCI1_CK and SPI0_CK due to hardware design.
+This cause spi flash can not work while ISI is enable. Do not add ISI device
+while SPI0 is enable, and do not add MCI1 while SPI0 or ISI is enable.
+Add print conflict information.
+
+Signed-off-by: Elen Song <elen.song@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/board-sam9x5ek.c | 40 ++++++++++++++++++++++++++++-------
+ 1 files changed, 32 insertions(+), 8 deletions(-)
+
+diff --git a/arch/arm/mach-at91/board-sam9x5ek.c b/arch/arm/mach-at91/board-sam9x5ek.c
+index ce801ee..ea49a23 100644
+--- a/arch/arm/mach-at91/board-sam9x5ek.c
++++ b/arch/arm/mach-at91/board-sam9x5ek.c
+@@ -376,6 +376,8 @@ static void __init ek_board_configure_pins(void)
+ static void __init ek_board_init(void)
+ {
+ u32 cm_config;
++ int i;
++ bool config_isi_enabled = false;
+
+ cm_board_init(&cm_config);
+ ek_board_configure_pins();
+@@ -389,11 +391,8 @@ static void __init ek_board_init(void)
+ /* Ethernet */
+ at91_add_device_eth(0, &ek_macb0_data);
+ at91_add_device_eth(1, &ek_macb1_data);
+- /* MMC */
++ /* MMC0 */
+ at91_add_device_mci(0, &mci0_data);
+- /* Conflict between SPI0 and MCI1 pins */
+- if (!(cm_config & CM_CONFIG_SPI0_ENABLE))
+- at91_add_device_mci(1, &mci1_data);
+ /* I2C */
+ if (cm_config & CM_CONFIG_I2C0_ENABLE)
+ i2c_register_board_info(0,
+@@ -405,12 +404,22 @@ static void __init ek_board_init(void)
+ if (cpu_is_at91sam9g25()) {
+ /* ISI */
+ /* NOTE: PCK0 provides ISI_MCK to the ISI module.
+- ISI's PWD pin conflict with MCI1_CK due the hardware design.
++ * ISI's PWD pin (PA13) conflicts with MCI1_CK, and SPI0_SPCK
++ * due to hardware design.
++ * Do not add ISI device if SPI0 is enabled.
+ */
+- platform_add_devices(soc_camera_devices,
++ if (!(cm_config & CM_CONFIG_SPI0_ENABLE)) {
++ platform_add_devices(soc_camera_devices,
+ ARRAY_SIZE(soc_camera_devices));
+- isi_set_clk();
+- at91_add_device_isi(&isi_data);
++ isi_set_clk();
++ at91_add_device_isi(&isi_data);
++ for (i = 0; i < ARRAY_SIZE(soc_camera_devices); i++) {
++ if (soc_camera_devices[i]->name != NULL) {
++ config_isi_enabled = true;
++ break;
++ }
++ }
++ }
+ } else if (!cpu_is_at91sam9x25()) {
+ /* LCD Controller */
+ at91_add_device_lcdc(&ek_lcdc_data);
+@@ -418,6 +427,13 @@ static void __init ek_board_init(void)
+ at91_add_device_tsadcc(&ek_tsadcc_data);
+ }
+
++ /* MMC1 */
++ /* Conflict between SPI0, MCI1 and ISI pins.
++ * add MCI1 only if SPI0 and ISI are both disabled.
++ */
++ if (!(cm_config & CM_CONFIG_SPI0_ENABLE) && !config_isi_enabled)
++ at91_add_device_mci(1, &mci1_data);
++
+ #if 0
+ if (cpu_is_at91sam9x25() || cpu_is_at91sam9x35())
+ /*
+@@ -443,6 +459,14 @@ static void __init ek_board_init(void)
+ printk(KERN_CRIT "AT91: EK rev A\n");
+ else
+ printk(KERN_CRIT "AT91: EK rev B and higher\n");
++
++ /* print conflict information */
++ if (cm_config & CM_CONFIG_SPI0_ENABLE)
++ printk(KERN_CRIT
++ "AT91: SPI0 conflicts with MCI1 and ISI, disable MCI1 and ISI\n");
++ else if (config_isi_enabled)
++ printk(KERN_CRIT
++ "AT91: ISI conficts with MCI1, disable MCI1\n");
+ }
+
+ MACHINE_START(AT91SAM9X5EK, "Atmel AT91SAM9X5-EK")
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0106-PMECC-Fix-bug-incorrect-register-address-for-remaind.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0106-PMECC-Fix-bug-incorrect-register-address-for-remaind.patch
new file mode 100644
index 0000000..187ba53
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0106-PMECC-Fix-bug-incorrect-register-address-for-remaind.patch
@@ -0,0 +1,27 @@
+From f689b25f100349903741cfd59cb17ca828a46eef Mon Sep 17 00:00:00 2001
+From: Hong Xu <hong.xu@atmel.com>
+Date: Thu, 3 Nov 2011 14:17:38 +0800
+Subject: [PATCH 106/107] PMECC: Fix bug: incorrect register address for
+ remainder register
+
+Signed-off-by: Hong Xu <hong.xu@atmel.com>
+---
+ drivers/mtd/nand/atmel_nand.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index 9f990b9..60dc6c9 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -77,7 +77,7 @@ module_param(on_flash_bbt, int, 0);
+ __raw_readb((addr) + ATMEL_PMECC_ECCx + ((sector) * 0x40) + (n))
+
+ #define pmecc_readl_rem(addr, sector, n) \
+- __raw_readl((addr) + ATMEL_PMECC_REMx + ((sector) * 0x40) + (n))
++ __raw_readl((addr) + ATMEL_PMECC_REMx + ((sector) * 0x40) + ((n) * 4))
+
+ #define pmerrloc_readl(addr, reg) \
+ __raw_readl((addr) + ATMEL_PMERRLOC_##reg)
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0107-ARM-at91-add-smd-device-definition.patch b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0107-ARM-at91-add-smd-device-definition.patch
new file mode 100644
index 0000000..537a5d9
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/2.6.39-at91-exp.2/2.6.39-at91-exp.2-0107-ARM-at91-add-smd-device-definition.patch
@@ -0,0 +1,112 @@
+From 7a4491817bc1a0b816722e937cdba81f41980a01 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 8 Nov 2011 17:27:20 +0100
+Subject: [PATCH 107/107] ARM: at91: add smd device definition
+
+This patch adds SMD definition and DMA interface in device file.
+The EK board contains a SmartDAA so we register the SMD interface
+from that board file.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/at91sam9x5_devices.c | 54 +++++++++++++++++++++++++++++++
+ arch/arm/mach-at91/board-sam9x5ek.c | 3 ++
+ arch/arm/mach-at91/include/mach/board.h | 3 ++
+ 3 files changed, 60 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9x5_devices.c b/arch/arm/mach-at91/at91sam9x5_devices.c
+index 4cafa1c..cee42dc 100644
+--- a/arch/arm/mach-at91/at91sam9x5_devices.c
++++ b/arch/arm/mach-at91/at91sam9x5_devices.c
+@@ -1469,6 +1469,60 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins)
+ void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
+ #endif
+
++/* --------------------------------------------------------------------
++ * SMD
++ * -------------------------------------------------------------------- */
++
++static u64 smd_dmamask = DMA_BIT_MASK(32);
++static struct at_dma_slave smd_dmadata;
++
++static struct resource smd_resources[] = {
++ [0] = {
++ .start = AT91SAM9X5_SMD_BASE,
++ .end = AT91SAM9X5_SMD_BASE + SZ_512 - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = AT91SAM9X5_ID_SMD,
++ .end = AT91SAM9X5_ID_SMD,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91sam9x5_smd_device = {
++ .name = "atmel_smd",
++ .id = -1,
++ .dev = {
++ .dma_mask = &smd_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &smd_dmadata,
++ },
++ .resource = smd_resources,
++ .num_resources = ARRAY_SIZE(smd_resources),
++};
++
++void __init at91_add_device_smd(void)
++{
++#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE)
++ struct at_dma_slave *atslave;
++
++ atslave = kzalloc(sizeof(struct at_dma_slave), GFP_KERNEL);
++
++ /* DMA slave channel configuration */
++ atslave->reg_width = AT_DMA_SLAVE_WIDTH_32BIT;
++ atslave->cfg = ATC_FIFOCFG_HALFFIFO
++ | ATC_SRC_H2SEL_HW
++ | ATC_DST_H2SEL_HW;
++ atslave->ctrla = ATC_SCSIZE_4 | ATC_DCSIZE_4;
++ atslave->cfg |= ATC_SRC_PER(AT_DMA_ID_SMD_RX)
++ | ATC_DST_PER(AT_DMA_ID_SMD_TX);
++ atslave->dma_dev = &at_hdmac1_device.dev;
++
++ smd_dmadata = *atslave;
++#endif
++
++ platform_device_register(&at91sam9x5_smd_device);
++}
+
+ /* --------------------------------------------------------------------
+ * UART
+diff --git a/arch/arm/mach-at91/board-sam9x5ek.c b/arch/arm/mach-at91/board-sam9x5ek.c
+index ea49a23..8c06040 100644
+--- a/arch/arm/mach-at91/board-sam9x5ek.c
++++ b/arch/arm/mach-at91/board-sam9x5ek.c
+@@ -455,6 +455,9 @@ static void __init ek_board_init(void)
+ /* SSC (for WM8731) */
+ at91_add_device_ssc(AT91SAM9X5_ID_SSC, ATMEL_SSC_TX | ATMEL_SSC_RX);
+
++ /* SMD */
++ at91_add_device_smd();
++
+ if (ek_is_revA())
+ printk(KERN_CRIT "AT91: EK rev A\n");
+ else
+diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
+index cf8d780..04dcec1 100644
+--- a/arch/arm/mach-at91/include/mach/board.h
++++ b/arch/arm/mach-at91/include/mach/board.h
+@@ -211,6 +211,9 @@ extern void __init at91_add_device_can(int id, struct at91_can_data *data);
+ extern void __init at91_add_device_can(struct at91_can_data *data);
+ #endif
+
++ /* SMD */
++extern void __init at91_add_device_smd(void);
++
+ /* LEDs */
+ extern void __init at91_init_leds(u8 cpu_led, u8 timer_led);
+ extern void __init at91_gpio_leds(struct gpio_led *leds, int nr);
+--
+1.7.5.4
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0001-Revert-MTD-atmel_nand-Add-PMECC-controller-support.patch b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0001-Revert-MTD-atmel_nand-Add-PMECC-controller-support.patch
new file mode 100644
index 0000000..e83822b
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0001-Revert-MTD-atmel_nand-Add-PMECC-controller-support.patch
@@ -0,0 +1,1177 @@
+From 0bc01b4e2b487f7ca9d15e3e05c9da68ed7d62b4 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Wed, 26 Dec 2012 11:46:00 +0800
+Subject: [PATCH 1/9] Revert "MTD: atmel_nand: Add PMECC controller support"
+
+This reverts commit f3b6daeff4340b90ce98966871fbbdd3e1249578.
+
+prepare to use mainline PMECC patch.
+
+Conflicts:
+
+ drivers/mtd/nand/atmel_nand_pmecc.c
+
+Conflicts:
+
+ drivers/mtd/nand/atmel_nand.c
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ drivers/mtd/nand/Kconfig | 17 -
+ drivers/mtd/nand/atmel_nand.c | 236 ++++--------
+ drivers/mtd/nand/atmel_nand_ecc.h | 84 -----
+ drivers/mtd/nand/atmel_nand_pmecc.c | 674 -----------------------------------
+ 4 files changed, 64 insertions(+), 947 deletions(-)
+ delete mode 100644 drivers/mtd/nand/atmel_nand_pmecc.c
+
+diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
+index b7b870c..edec457 100644
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -371,23 +371,6 @@ config MTD_NAND_ATMEL_ECC_HW
+
+ If unsure, say Y
+
+-config MTD_NAND_ATMEL_PMECC_HW
+- bool "Programmable Hardware ECC (BCH code)"
+- depends on ARCH_AT91SAM9X5
+- help
+- Use Programmable Hardware ECC controller.
+-
+- The PMECC Controller is a programmable binary BCH (Bose, Chaudhuri
+- and Hocquenghem) encoder/decoder. This controller can be used to
+- generate redundancy information for both SLC and MLC NAND Flash
+- devices.
+-
+- NB : hardware and software ECC schemes are incompatible.
+- If you switch from one to another, you'll have to erase your
+- mtd partition.
+-
+- If unsure, say Y
+-
+ config MTD_NAND_ATMEL_ECC_SOFT
+ bool "Software ECC"
+ help
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index 60dc6c9..12de424 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -15,8 +15,6 @@
+ * (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
+ * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
+ *
+- * Add PMECC support for AT91SAM9X5 Series
+- * (C) Copyright 2011 ATMEL, Hong Xu
+ *
+ * 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
+@@ -38,9 +36,7 @@
+ #include <mach/board.h>
+ #include <mach/cpu.h>
+
+-#if defined(CONFIG_MTD_NAND_ATMEL_ECC_HW)
+-#define hard_ecc 1
+-#elif defined(CONFIG_MTD_NAND_ATMEL_PMECC_HW)
++#ifdef CONFIG_MTD_NAND_ATMEL_ECC_HW
+ #define hard_ecc 1
+ #else
+ #define hard_ecc 0
+@@ -55,8 +51,6 @@
+ static int use_dma = 1;
+ module_param(use_dma, int, 0);
+
+-#define NB_ERROR_MAX 25
+-
+ static int on_flash_bbt = 0;
+ module_param(on_flash_bbt, int, 0);
+
+@@ -66,38 +60,8 @@ module_param(on_flash_bbt, int, 0);
+ #define ecc_writel(add, reg, value) \
+ __raw_writel((value), add + ATMEL_ECC_##reg)
+
+-/* Register access macros for PMECC */
+-#define pmecc_readl(addr, reg) \
+- __raw_readl((addr) + ATMEL_PMECC_##reg)
+-
+-#define pmecc_writel(addr, reg, value) \
+- __raw_writel((value), (addr) + ATMEL_PMECC_##reg)
+-
+-#define pmecc_readb_ecc(addr, sector, n) \
+- __raw_readb((addr) + ATMEL_PMECC_ECCx + ((sector) * 0x40) + (n))
+-
+-#define pmecc_readl_rem(addr, sector, n) \
+- __raw_readl((addr) + ATMEL_PMECC_REMx + ((sector) * 0x40) + ((n) * 4))
+-
+-#define pmerrloc_readl(addr, reg) \
+- __raw_readl((addr) + ATMEL_PMERRLOC_##reg)
+-
+-#define pmerrloc_writel(addr, reg, value) \
+- __raw_writel((value), (addr) + ATMEL_PMERRLOC_##reg)
+-
+-#define pmerrloc_writel_sigma(addr, n, value) \
+- __raw_writel((value), (addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
+-
+-#define pmerrloc_readl_sigma(addr, n) \
+- __raw_readl((addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
+-
+-#define pmerrloc_readl_el(addr, n) \
+- __raw_readl((addr) + ATMEL_PMERRLOC_ELx + ((n) * 4))
++#include "atmel_nand_ecc.h" /* Hardware ECC registers */
+
+-/* Include Hardware ECC registers */
+-#include "atmel_nand_ecc.h"
+-
+-#if defined(CONFIG_MTD_NAND_ATMEL_ECC_HW)
+ /* oob layout for large page size
+ * bad block info is on bytes 0 and 1
+ * the bytes have to be consecutives to avoid
+@@ -123,7 +87,6 @@ static struct nand_ecclayout atmel_oobinfo_small = {
+ {6, 10}
+ },
+ };
+-#endif
+
+ struct atmel_nand_host {
+ struct nand_chip nand_chip;
+@@ -136,45 +99,11 @@ struct atmel_nand_host {
+
+ struct completion comp;
+ struct dma_chan *dma_chan;
+-
+-#if defined(CONFIG_MTD_NAND_ATMEL_PMECC_HW)
+- void __iomem *pmerrloc_base;
+- void __iomem *rom_base;
+- /* defines the error correcting capability */
+- int tt;
+- /* The number of ecc bytes for one sector */
+- int ecc_bytes_per_sector;
+- /* degree of the remainders, GF(2**mm) */
+- int mm;
+- /* length of codeword, nn=2**mm -1 */
+- int nn;
+- /* sector number per page */
+- int sector_number;
+- /* sector size in bytes */
+- int sector_size;
+-
+- /* PMECC lookup table for alpha_to and index_of */
+- int16_t *alpha_to;
+- int16_t *index_of;
+-
+- int16_t partial_syn[100];
+- int16_t si[100];
+- /* Sigma table */
+- int16_t smu[NB_ERROR_MAX + 2][2 * NB_ERROR_MAX + 1];
+- /** polynomal order */
+- int16_t lmu[NB_ERROR_MAX + 1];
+- uint8_t ecc_table[42 * 8];
+-#endif
+ };
+
+-#if defined(CONFIG_MTD_NAND_ATMEL_PMECC_HW)
+-#include "atmel_nand_pmecc.c"
+-#endif
+-
+ static int cpu_has_dma(void)
+ {
+- return cpu_is_at91sam9rl() || cpu_is_at91sam9g45()
+- || cpu_is_at91sam9x5();
++ return cpu_is_at91sam9rl() || cpu_is_at91sam9g45();
+ }
+
+ /*
+@@ -355,7 +284,6 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+ memcpy(chip->IO_ADDR_W, (void *)pbuf, len);
+ }
+
+-#if defined(CONFIG_MTD_NAND_ATMEL_ECC_HW)
+ /*
+ * Calculate HW ECC
+ *
+@@ -542,84 +470,6 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
+ }
+ }
+
+-static int __init atmel_nand_init_params(struct platform_device *pdev,
+- struct atmel_nand_host *host)
+-{
+- struct resource *regs;
+- struct nand_chip *nand_chip;
+- struct mtd_info *mtd;
+-
+- nand_chip = &host->nand_chip;
+- mtd = &host->mtd;
+-
+- regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+- if (!regs && hard_ecc) {
+- dev_err(host->dev, "atmel_nand: can't get I/O resource "
+- "regs\nFalling back on software ECC\n");
+- }
+-
+- nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */
+- if (no_ecc)
+- nand_chip->ecc.mode = NAND_ECC_NONE;
+- if (hard_ecc && regs) {
+- host->ecc = ioremap(regs->start, regs->end - regs->start + 1);
+- if (host->ecc == NULL) {
+- printk(KERN_ERR "atmel_nand: ioremap failed\n");
+- goto err_ecc_ioremap;
+- }
+-
+- nand_chip->ecc.mode = NAND_ECC_HW;
+- nand_chip->ecc.calculate = atmel_nand_calculate;
+- nand_chip->ecc.correct = atmel_nand_correct;
+- nand_chip->ecc.hwctl = atmel_nand_hwctl;
+- nand_chip->ecc.read_page = atmel_nand_read_page;
+- nand_chip->ecc.bytes = 4;
+- }
+-
+- if (nand_chip->ecc.mode == NAND_ECC_HW) {
+- /* ECC is calculated for the whole page (1 step) */
+- nand_chip->ecc.size = mtd->writesize;
+-
+- /* set ECC page size and oob layout */
+- switch (mtd->writesize) {
+- case 512:
+- nand_chip->ecc.layout = &atmel_oobinfo_small;
+- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528);
+- break;
+- case 1024:
+- nand_chip->ecc.layout = &atmel_oobinfo_large;
+- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056);
+- break;
+- case 2048:
+- nand_chip->ecc.layout = &atmel_oobinfo_large;
+- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112);
+- break;
+- case 4096:
+- nand_chip->ecc.layout = &atmel_oobinfo_large;
+- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224);
+- break;
+- default:
+- /* page size not handled by HW ECC */
+- /* switching back to soft ECC */
+- nand_chip->ecc.mode = NAND_ECC_SOFT;
+- nand_chip->ecc.calculate = NULL;
+- nand_chip->ecc.correct = NULL;
+- nand_chip->ecc.hwctl = NULL;
+- nand_chip->ecc.read_page = NULL;
+- nand_chip->ecc.postpad = 0;
+- nand_chip->ecc.prepad = 0;
+- nand_chip->ecc.bytes = 0;
+- break;
+- }
+- }
+-
+- return 0;
+-
+-err_ecc_ioremap:
+- return -EIO;
+-}
+-#endif
+-
+ #ifdef CONFIG_MTD_CMDLINE_PARTS
+ static const char *part_probes[] = { "cmdlinepart", NULL };
+ #endif
+@@ -632,8 +482,9 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ struct atmel_nand_host *host;
+ struct mtd_info *mtd;
+ struct nand_chip *nand_chip;
++ struct resource *regs;
+ struct resource *mem;
+- int res = 0;
++ int res;
+
+ #ifdef CONFIG_MTD_PARTITIONS
+ struct mtd_partition *partitions = NULL;
+@@ -679,9 +530,29 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ if (host->board->rdy_pin)
+ nand_chip->dev_ready = atmel_nand_device_ready;
+
++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ if (!regs && hard_ecc) {
++ printk(KERN_ERR "atmel_nand: can't get I/O resource "
++ "regs\nFalling back on software ECC\n");
++ }
++
+ nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */
+ if (no_ecc)
+ nand_chip->ecc.mode = NAND_ECC_NONE;
++ if (hard_ecc && regs) {
++ host->ecc = ioremap(regs->start, regs->end - regs->start + 1);
++ if (host->ecc == NULL) {
++ printk(KERN_ERR "atmel_nand: ioremap failed\n");
++ res = -EIO;
++ goto err_ecc_ioremap;
++ }
++ nand_chip->ecc.mode = NAND_ECC_HW;
++ nand_chip->ecc.calculate = atmel_nand_calculate;
++ nand_chip->ecc.correct = atmel_nand_correct;
++ nand_chip->ecc.hwctl = atmel_nand_hwctl;
++ nand_chip->ecc.read_page = atmel_nand_read_page;
++ nand_chip->ecc.bytes = 4;
++ }
+
+ nand_chip->chip_delay = 20; /* 20us command delay time */
+
+@@ -733,13 +604,42 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ goto err_scan_ident;
+ }
+
+-#if defined(CONFIG_MTD_NAND_ATMEL_ECC_HW)
+- res = atmel_nand_init_params(pdev, host);
+-#elif defined(CONFIG_MTD_NAND_ATMEL_PMECC_HW)
+- res = atmel_pmecc_init_params(pdev, host);
+-#endif
+- if (res != 0)
+- goto err;
++ if (nand_chip->ecc.mode == NAND_ECC_HW) {
++ /* ECC is calculated for the whole page (1 step) */
++ nand_chip->ecc.size = mtd->writesize;
++
++ /* set ECC page size and oob layout */
++ switch (mtd->writesize) {
++ case 512:
++ nand_chip->ecc.layout = &atmel_oobinfo_small;
++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528);
++ break;
++ case 1024:
++ nand_chip->ecc.layout = &atmel_oobinfo_large;
++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056);
++ break;
++ case 2048:
++ nand_chip->ecc.layout = &atmel_oobinfo_large;
++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112);
++ break;
++ case 4096:
++ nand_chip->ecc.layout = &atmel_oobinfo_large;
++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224);
++ break;
++ default:
++ /* page size not handled by HW ECC */
++ /* switching back to soft ECC */
++ nand_chip->ecc.mode = NAND_ECC_SOFT;
++ nand_chip->ecc.calculate = NULL;
++ nand_chip->ecc.correct = NULL;
++ nand_chip->ecc.hwctl = NULL;
++ nand_chip->ecc.read_page = NULL;
++ nand_chip->ecc.postpad = 0;
++ nand_chip->ecc.prepad = 0;
++ nand_chip->ecc.bytes = 0;
++ break;
++ }
++ }
+
+ /* second phase scan */
+ if (nand_scan_tail(mtd)) {
+@@ -771,7 +671,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ if (!res)
+ return res;
+
+-err:
+ #ifdef CONFIG_MTD_PARTITIONS
+ err_no_partitions:
+ #endif
+@@ -783,6 +682,9 @@ err_no_card:
+ platform_set_drvdata(pdev, NULL);
+ if (host->dma_chan)
+ dma_release_channel(host->dma_chan);
++ if (host->ecc)
++ iounmap(host->ecc);
++err_ecc_ioremap:
+ iounmap(host->io_base);
+ err_nand_ioremap:
+ kfree(host);
+@@ -801,16 +703,6 @@ static int __exit atmel_nand_remove(struct platform_device *pdev)
+
+ atmel_nand_disable(host);
+
+-#if defined(CONFIG_MTD_NAND_ATMEL_PMECC_HW)
+- if (cpu_has_pmecc())
+- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
+- if (host->pmerrloc_base) {
+- pmerrloc_writel(host->pmerrloc_base, ELDIS, 0xffffffff);
+- iounmap(host->pmerrloc_base);
+- }
+- if (host->rom_base)
+- iounmap(host->rom_base);
+-#endif
+ if (host->ecc)
+ iounmap(host->ecc);
+
+diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h
+index 6e0e2f3..578c776 100644
+--- a/drivers/mtd/nand/atmel_nand_ecc.h
++++ b/drivers/mtd/nand/atmel_nand_ecc.h
+@@ -36,88 +36,4 @@
+ #define ATMEL_ECC_NPR 0x10 /* NParity register */
+ #define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */
+
+-/* PMECC Register Definitions */
+-#define ATMEL_PMECC_CFG 0x000 /* Configuration Register */
+-#define PMECC_CFG_BCH_ERR2 (0 << 0)
+-#define PMECC_CFG_BCH_ERR4 (1 << 0)
+-#define PMECC_CFG_BCH_ERR8 (2 << 0)
+-#define PMECC_CFG_BCH_ERR12 (3 << 0)
+-#define PMECC_CFG_BCH_ERR24 (4 << 0)
+-
+-#define PMECC_CFG_SECTOR512 (0 << 4)
+-#define PMECC_CFG_SECTOR1024 (1 << 4)
+-
+-#define PMECC_CFG_PAGE_1SECTOR (0 << 8)
+-#define PMECC_CFG_PAGE_2SECTORS (1 << 8)
+-#define PMECC_CFG_PAGE_4SECTORS (2 << 8)
+-#define PMECC_CFG_PAGE_8SECTORS (3 << 8)
+-
+-#define PMECC_CFG_READ_OP (0 << 12)
+-#define PMECC_CFG_WRITE_OP (1 << 12)
+-
+-#define PMECC_CFG_SPARE_ENABLE (1 << 16)
+-#define PMECC_CFG_SPARE_DISABLE (0 << 16)
+-
+-#define PMECC_CFG_AUTO_ENABLE (1 << 20)
+-#define PMECC_CFG_AUTO_DISABLE (0 << 20)
+-
+-#define ATMEL_PMECC_SAREA 0x004 /* Spare area size */
+-#define ATMEL_PMECC_SADDR 0x008 /* PMECC starting address */
+-#define ATMEL_PMECC_EADDR 0x00c /* PMECC ending address */
+-#define ATMEL_PMECC_CLK 0x010 /* PMECC clock control */
+-#define PMECC_CLK_133MHZ (2 << 0)
+-
+-#define ATMEL_PMECC_CTRL 0x014 /* PMECC control register */
+-#define PMECC_CTRL_RST (1 << 0)
+-#define PMECC_CTRL_DATA (1 << 1)
+-#define PMECC_CTRL_USER (1 << 2)
+-#define PMECC_CTRL_ENABLE (1 << 4)
+-#define PMECC_CTRL_DISABLE (1 << 5)
+-
+-#define ATMEL_PMECC_SR 0x018 /* PMECC status register */
+-#define PMECC_SR_BUSY (1 << 0)
+-#define PMECC_SR_ENABLE (1 << 4)
+-
+-#define ATMEL_PMECC_IER 0x01c /* PMECC interrupt enable */
+-#define PMECC_IER_ENABLE (1 << 0)
+-#define ATMEL_PMECC_IDR 0x020 /* PMECC interrupt disable */
+-#define PMECC_IER_DISABLE (1 << 0)
+-#define ATMEL_PMECC_IMR 0x024 /* PMECC interrupt mask */
+-#define PMECC_IER_MASK (1 << 0)
+-#define ATMEL_PMECC_ISR 0x028 /* PMECC interrupt status */
+-#define ATMEL_PMECC_ECCx 0x040 /* PMECC ECC x */
+-#define ATMEL_PMECC_REMx 0x240 /* PMECC REM x */
+-
+-/* PMERRLOC Register Definitions */
+-#define ATMEL_PMERRLOC_ELCFG 0x000 /* Error location config */
+-#define PMERRLOC_ELCFG_SECTOR_512 (0 << 0)
+-#define PMERRLOC_ELCFG_SECTOR_1024 (1 << 0)
+-#define PMERRLOC_ELCFG_NUM_ERRORS(n) ((n) << 16)
+-
+-#define ATMEL_PMERRLOC_ELPRIM 0x004 /* Error location primitive */
+-#define ATMEL_PMERRLOC_ELEN 0x008 /* Error location enable */
+-#define ATMEL_PMERRLOC_ELDIS 0x00c /* Error location disable */
+-#define PMERRLOC_DISABLE (1 << 0)
+-
+-#define ATMEL_PMERRLOC_ELSR 0x010 /* Error location status */
+-#define PMERRLOC_ELSR_BUSY (1 << 0)
+-#define ATMEL_PMERRLOC_ELIER 0x014 /* Error location int enable */
+-#define ATMEL_PMERRLOC_ELIDR 0x018 /* Error location int disable */
+-#define ATMEL_PMERRLOC_ELIMR 0x01c /* Error location int mask */
+-#define ATMEL_PMERRLOC_ELISR 0x020 /* Error location int status */
+-#define PMERRLOC_ERR_NUM_MASK (0x1f << 8)
+-#define PMERRLOC_CALC_DONE (1 << 0)
+-#define ATMEL_PMERRLOC_SIGMAx 0x028 /* Error location SIGMA x */
+-#define ATMEL_PMERRLOC_ELx 0x08c /* Error location x */
+-
+-/* Galois field dimension */
+-#define GF_DIMENSION_13 13
+-#define GF_DIMENSION_14 14
+-
+-#define PMECC_LOOKUP_TABLE_SIZE_512 0x2000
+-#define PMECC_LOOKUP_TABLE_SIZE_1024 0x4000
+-
+-#define PMECC_LOOKUP_TABLE_OFFSET_512 0x8000
+-#define PMECC_LOOKUP_TABLE_OFFSET_1024 0x10000
+-
+ #endif
+diff --git a/drivers/mtd/nand/atmel_nand_pmecc.c b/drivers/mtd/nand/atmel_nand_pmecc.c
+deleted file mode 100644
+index 289e4a5..0000000
+--- a/drivers/mtd/nand/atmel_nand_pmecc.c
++++ /dev/null
+@@ -1,674 +0,0 @@
+-/*
+- * (C) Copyright 2011 ATMEL, Hong Xu
+- *
+- * PMECC related definitions and routines
+- *
+- * 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.
+- *
+- */
+-
+-static struct nand_ecclayout pmecc_oobinfo_2048 = {
+- .eccbytes = 16,
+- .eccpos = { 48, 49, 50, 51, 52, 53, 54, 55,
+- 56, 57, 58, 59, 60, 61, 62, 63
+- },
+- .oobfree = {
+- {2, 46},
+- },
+-};
+-
+-static int cpu_has_pmecc(void)
+-{
+- return cpu_is_at91sam9x5();
+-}
+-
+-static int16_t *pmecc_get_alpha_to(struct atmel_nand_host *host)
+-{
+- int16_t *p;
+-
+- if (cpu_is_at91sam9x5()) {
+- if (host->sector_size == 512) {
+- p = (int16_t *)((u32)host->rom_base +
+- PMECC_LOOKUP_TABLE_OFFSET_512);
+- return p + PMECC_LOOKUP_TABLE_SIZE_512;
+- } else {
+- p = (int16_t *)((u32)host->rom_base +
+- PMECC_LOOKUP_TABLE_OFFSET_1024);
+- return p + PMECC_LOOKUP_TABLE_SIZE_1024;
+- }
+- }
+-
+- return NULL;
+-}
+-
+-static int16_t *pmecc_get_index_of(struct atmel_nand_host *host)
+-{
+- int16_t *p = (int16_t *)host->rom_base;
+-
+- if (cpu_is_at91sam9x5()) {
+- if (host->sector_size == 512)
+- p = (int16_t *)((u32)host->rom_base +
+- PMECC_LOOKUP_TABLE_OFFSET_512);
+- else
+- p = (int16_t *)((u32)host->rom_base +
+- PMECC_LOOKUP_TABLE_OFFSET_1024);
+-
+- return p;
+- }
+-
+- return NULL;
+-}
+-
+-static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector)
+-{
+- int i;
+- uint32_t value;
+- struct nand_chip *nand_chip = mtd->priv;
+- struct atmel_nand_host *host = nand_chip->priv;
+-
+- /* Fill odd syndromes */
+- for (i = 0; i < host->tt; i++) {
+- value = pmecc_readl_rem(host->ecc, sector, i / 2);
+- if (i % 2 == 0)
+- host->partial_syn[(2 * i) + 1] = value & 0xffff;
+- else
+- host->partial_syn[(2 * i) + 1] = (value & 0xffff0000)
+- >> 16;
+- }
+-}
+-
+-static void pmecc_substitute(struct mtd_info *mtd)
+-{
+- int i, j;
+- struct nand_chip *nand_chip = mtd->priv;
+- struct atmel_nand_host *host = nand_chip->priv;
+- int16_t *si;
+- int16_t *partial_syn = host->partial_syn;
+- int16_t *alpha_to = host->alpha_to;
+- int16_t *index_of = host->index_of;
+-
+- /* si[] is a table that holds the current syndrome value,
+- * an element of that table belongs to the field
+- */
+- si = host->si;
+-
+- for (i = 1; i < 2 * NB_ERROR_MAX; i++)
+- si[i] = 0;
+-
+- /* Computation 2t syndromes based on S(x) */
+- /* Odd syndromes */
+- for (i = 1; i <= 2 * host->tt - 1; i = i + 2) {
+- si[i] = 0;
+- for (j = 0; j < host->mm; j++) {
+- if (partial_syn[i] & ((unsigned short)0x1 << j))
+- si[i] = alpha_to[(i * j)] ^ si[i];
+- }
+- }
+- /* Even syndrome = (Odd syndrome) ** 2 */
+- for (i = 2; i <= 2 * host->tt; i = i + 2) {
+- j = i / 2;
+- if (si[j] == 0)
+- si[i] = 0;
+- else
+- si[i] = alpha_to[(2 * index_of[si[j]]) % host->nn];
+- }
+-
+- return;
+-}
+-
+-static void pmecc_get_sigma(struct mtd_info *mtd)
+-{
+- int i, j, k;
+- struct nand_chip *nand_chip = mtd->priv;
+- struct atmel_nand_host *host = nand_chip->priv;
+- uint32_t dmu_0_count, tmp;
+- int16_t *lmu = host->lmu;
+- int16_t *si = host->si;
+- int16_t tt = host->tt;
+- int16_t *index_of = host->index_of;
+-
+- /* mu */
+- int mu[NB_ERROR_MAX + 1];
+-
+- /* discrepancy */
+- int dmu[NB_ERROR_MAX + 1];
+-
+- /* delta order */
+- int delta[NB_ERROR_MAX + 1];
+-
+- /* index of largest delta */
+- int ro;
+- int largest;
+- int diff;
+-
+- dmu_0_count = 0;
+-
+- /* First Row */
+-
+- /* Mu */
+- mu[0] = -1;
+-
+- /* Actually -1/2 */
+- /* Sigma(x) set to 1 */
+- for (i = 0; i < 2 * NB_ERROR_MAX + 1; i++)
+- host->smu[0][i] = 0;
+-
+- host->smu[0][0] = 1;
+-
+- /* discrepancy set to 1 */
+- dmu[0] = 1;
+- /* polynom order set to 0 */
+- lmu[0] = 0;
+- /* delta set to -1 */
+- delta[0] = (mu[0] * 2 - lmu[0]) >> 1;
+-
+- /* Second Row */
+-
+- /* Mu */
+- mu[1] = 0;
+- /* Sigma(x) set to 1 */
+- for (i = 0; i < (2 * NB_ERROR_MAX + 1); i++)
+- host->smu[1][i] = 0;
+-
+- host->smu[1][0] = 1;
+-
+- /* discrepancy set to S1 */
+- dmu[1] = si[1];
+-
+- /* polynom order set to 0 */
+- lmu[1] = 0;
+-
+- /* delta set to 0 */
+- delta[1] = (mu[1] * 2 - lmu[1]) >> 1;
+-
+- /* Init the Sigma(x) last row */
+- for (i = 0; i < (2 * NB_ERROR_MAX + 1); i++)
+- host->smu[tt + 1][i] = 0;
+-
+- for (i = 1; i <= tt; i++) {
+- mu[i+1] = i << 1;
+- /* Begin Computing Sigma (Mu+1) and L(mu) */
+- /* check if discrepancy is set to 0 */
+- if (dmu[i] == 0) {
+- dmu_0_count++;
+-
+- if ((tt - (lmu[i] >> 1) - 1) & 0x1)
+- tmp = ((tt - (lmu[i] >> 1) - 1) / 2) + 2;
+- else
+- tmp = ((tt - (lmu[i] >> 1) - 1) / 2) + 1;
+-
+- if (dmu_0_count == tmp) {
+- for (j = 0; j <= (lmu[i] >> 1) + 1; j++)
+- host->smu[tt + 1][j] = host->smu[i][j];
+-
+- lmu[tt + 1] = lmu[i];
+- return;
+- }
+-
+- /* copy polynom */
+- for (j = 0; j <= lmu[i] >> 1; j++)
+- host->smu[i + 1][j] = host->smu[i][j];
+-
+- /* copy previous polynom order to the next */
+- lmu[i + 1] = lmu[i];
+- } else {
+- ro = 0;
+- largest = -1;
+- /* find largest delta with dmu != 0 */
+- for (j = 0; j < i; j++) {
+- if ((dmu[j]) && (delta[j] > largest)) {
+- largest = delta[j];
+- ro = j;
+- }
+- }
+-
+- /* compute difference */
+- diff = (mu[i] - mu[ro]);
+-
+- /* Compute degree of the new smu polynomial */
+- if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff))
+- lmu[i + 1] = lmu[i];
+- else
+- lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2;
+-
+- /* Init smu[i+1] with 0 */
+- for (k = 0; k < (2 * NB_ERROR_MAX + 1); k++)
+- host->smu[i+1][k] = 0;
+-
+- /* Compute smu[i+1] */
+- for (k = 0; k <= lmu[ro] >> 1; k++) {
+- if (!(host->smu[ro][k] && dmu[i]))
+- continue;
+-
+- tmp = host->index_of[dmu[i]] + (host->nn -
+- host->index_of[dmu[ro]]) +
+- host->index_of[host->smu[ro][k]];
+- host->smu[i + 1][k + diff] =
+- host->alpha_to[tmp % host->nn];
+- }
+-
+- for (k = 0; k <= lmu[i] >> 1; k++)
+- host->smu[i + 1][k] ^= host->smu[i][k];
+- }
+-
+- /* End Computing Sigma (Mu+1) and L(mu) */
+- /* In either case compute delta */
+- delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1;
+-
+- /* Do not compute discrepancy for the last iteration */
+- if (i >= tt)
+- continue;
+-
+- for (k = 0 ; k <= (lmu[i + 1] >> 1); k++) {
+- tmp = 2 * (i - 1);
+- if (k == 0)
+- dmu[i + 1] = si[tmp + 3];
+- else if (host->smu[i+1][k] && si[tmp + 3 - k]) {
+- tmp = index_of[host->smu[i + 1][k]] +
+- index_of[si[2 * (i - 1) + 3 - k]];
+- tmp %= host->nn;
+- dmu[i + 1] = host->alpha_to[tmp] ^ dmu[i + 1];
+- }
+- }
+- }
+-
+- return;
+-}
+-
+-
+-static int pmecc_err_location(struct mtd_info *mtd)
+-{
+- int i;
+- /* number of error */
+- int err_nbr;
+- /* number of roots */
+- int roots_nbr;
+- int gf_dimension;
+- uint32_t val;
+- struct nand_chip *nand_chip = mtd->priv;
+- struct atmel_nand_host *host = nand_chip->priv;
+-
+- if (host->sector_size == 512)
+- gf_dimension = GF_DIMENSION_13;
+- else
+- gf_dimension = GF_DIMENSION_14;
+-
+- /* Disable PMECC Error Location IP */
+- pmerrloc_writel(host->pmerrloc_base, ELDIS, 0xffffffff);
+- err_nbr = 0;
+-
+- for (i = 0; i <= host->lmu[host->tt + 1] >> 1; i++) {
+- pmerrloc_writel_sigma(host->pmerrloc_base, i,
+- host->smu[host->tt + 1][i]);
+- err_nbr++;
+- }
+-
+- val = pmerrloc_readl(host->pmerrloc_base, ELCFG);
+- val |= ((err_nbr - 1) << 16);
+- pmerrloc_writel(host->pmerrloc_base, ELCFG, val);
+-
+- pmerrloc_writel(host->pmerrloc_base, ELEN,
+- host->sector_size * 8 + gf_dimension * host->tt);
+-
+- while (!(pmerrloc_readl(host->pmerrloc_base, ELISR)
+- & PMERRLOC_CALC_DONE))
+- cpu_relax();
+-
+- roots_nbr = (pmerrloc_readl(host->pmerrloc_base, ELISR)
+- & PMERRLOC_ERR_NUM_MASK) >> 8;
+-
+- /* Number of roots == degree of smu hence <= tt */
+- if (roots_nbr == host->lmu[host->tt + 1] >> 1)
+- return err_nbr - 1;
+-
+- /* Number of roots does not match the degree of smu
+- * unable to correct error */
+- return -1;
+-}
+-
+-static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf,
+- int extra_bytes, int err_nbr)
+-{
+- int i = 0;
+- int byte_pos, bit_pos;
+- int sector_size, ecc_size;
+- uint32_t tmp;
+- struct nand_chip *nand_chip = mtd->priv;
+- struct atmel_nand_host *host = nand_chip->priv;
+-
+- sector_size = host->sector_size;
+- /* Get number of ECC bytes */
+- ecc_size = nand_chip->ecc.bytes;
+-
+- while (err_nbr) {
+- byte_pos = (pmerrloc_readl_el(host->pmerrloc_base, i) - 1) / 8;
+- bit_pos = (pmerrloc_readl_el(host->pmerrloc_base, i) - 1) % 8;
+- dev_dbg(host->dev, "bad : %02x: byte_pos: %d, bit_pos: %d\n",
+- *(buf + byte_pos), byte_pos, bit_pos);
+-
+- if (byte_pos < (sector_size + extra_bytes)) {
+- tmp = sector_size + pmecc_readl(host->ecc, SADDR);
+- if (byte_pos < tmp) {
+- if (*(buf + byte_pos) & (1 << bit_pos))
+- *(buf + byte_pos) &=
+- (0xFF ^ (1 << bit_pos));
+- else
+- *(buf + byte_pos) |= (1 << bit_pos);
+- } else {
+- if (*(buf + byte_pos + ecc_size) &
+- (1 << bit_pos))
+- *(buf + byte_pos + ecc_size) &=
+- (0xFF ^ (1 << bit_pos));
+- else
+- *(buf + byte_pos + ecc_size) |=
+- (1 << bit_pos);
+- }
+- }
+- dev_dbg(host->dev, "corr: %02x\n", *(buf + byte_pos));
+- i++;
+- err_nbr--;
+- }
+-
+- return;
+-}
+-
+-static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
+- u8 *ecc)
+-{
+- int i, err_nbr;
+- uint8_t *buf_pos;
+- struct nand_chip *nand_chip = mtd->priv;
+- int eccbytes = nand_chip->ecc.bytes;
+- struct atmel_nand_host *host = nand_chip->priv;
+-
+- for (i = 0; i < eccbytes; i++)
+- if (ecc[i] != 0xff)
+- break;
+- /* Erased page, return OK */
+- if (i == eccbytes)
+- return 0;
+-
+- pmerrloc_writel(host->pmerrloc_base, ELCFG,
+- (host->sector_size == 512) ? 0 : 1);
+-
+- i = 0;
+- while (i < host->sector_number) {
+- err_nbr = 0;
+- if (pmecc_stat & 0x1) {
+- buf_pos = buf + i * host->sector_size;
+-
+- pmecc_gen_syndrome(mtd, i);
+- pmecc_substitute(mtd);
+- pmecc_get_sigma(mtd);
+-
+- err_nbr = pmecc_err_location(mtd);
+- if (err_nbr == -1) {
+- dev_err(host->dev, "Too many error.\n");
+- mtd->ecc_stats.failed++;
+- return -EFAULT;
+- } else {
+- dev_dbg(host->dev, "Correct bits...\n");
+- pmecc_correct_data(mtd, buf_pos, 0, err_nbr);
+- mtd->ecc_stats.corrected += err_nbr;
+- }
+- }
+- i++;
+- pmecc_stat >>= 1;
+- }
+-
+- return 0;
+-}
+-
+-static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
+- struct nand_chip *chip, uint8_t *buf, int32_t page)
+-{
+- struct atmel_nand_host *host = chip->priv;
+- int eccsize = chip->ecc.size;
+- uint32_t *eccpos = chip->ecc.layout->eccpos;
+- int err = 0, stat;
+- int timeout = 10;
+- uint8_t *oob = chip->oob_poi;
+-
+- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
+- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
+- pmecc_writel(host->ecc, CFG, (pmecc_readl(host->ecc, CFG)
+- & ~PMECC_CFG_WRITE_OP) | PMECC_CFG_AUTO_ENABLE);
+-
+- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
+-
+- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
+-
+- chip->read_buf(mtd, buf, eccsize);
+- chip->read_buf(mtd, oob, mtd->oobsize);
+-
+- while ((pmecc_readl(host->ecc, SR) & PMECC_SR_BUSY) && (timeout-- > 0))
+- cpu_relax();
+-
+- stat = pmecc_readl(host->ecc, ISR);
+-
+- if (stat != 0) {
+- if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]))
+- err = -1;
+- }
+-
+- return err;
+-}
+-
+-static void atmel_nand_pmecc_write_page(struct mtd_info *mtd,
+- struct nand_chip *chip, const uint8_t *buf)
+-{
+- int i, j;
+- int timeout = 10;
+- struct atmel_nand_host *host = chip->priv;
+- uint32_t *eccpos = chip->ecc.layout->eccpos;
+-
+- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
+- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
+-
+- pmecc_writel(host->ecc, CFG, (pmecc_readl(host->ecc, CFG) |
+- PMECC_CFG_WRITE_OP) & ~PMECC_CFG_AUTO_ENABLE);
+-
+- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
+- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
+-
+- chip->write_buf(mtd, (u8 *)buf, mtd->writesize);
+-
+- while ((pmecc_readl(host->ecc, SR) & PMECC_SR_BUSY) && (timeout-- > 0))
+- cpu_relax();
+-
+- for (i = 0; i < host->sector_number; i++) {
+- for (j = 0; j < host->ecc_bytes_per_sector; j++) {
+- int pos;
+-
+- pos = i * host->ecc_bytes_per_sector + j;
+- chip->oob_poi[eccpos[pos]] =
+- pmecc_readb_ecc(host->ecc, i, j);
+- }
+- }
+- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+-
+- return;
+-}
+-
+-static void atmel_init_pmecc(struct mtd_info *mtd)
+-{
+- uint32_t val = 0;
+- struct nand_chip *nand_chip = mtd->priv;
+- struct atmel_nand_host *host = nand_chip->priv;
+- struct nand_ecclayout *ecc_layout;
+-
+- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
+- pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
+-
+- switch (host->tt) {
+- case 2:
+- val = PMECC_CFG_BCH_ERR2;
+- break;
+- case 4:
+- val = PMECC_CFG_BCH_ERR4;
+- break;
+- case 8:
+- val = PMECC_CFG_BCH_ERR8;
+- break;
+- case 12:
+- val = PMECC_CFG_BCH_ERR12;
+- break;
+- case 24:
+- val = PMECC_CFG_BCH_ERR24;
+- break;
+- }
+-
+- if (host->sector_size == 512)
+- val |= PMECC_CFG_SECTOR512;
+- else if (host->sector_size == 1024)
+- val |= PMECC_CFG_SECTOR1024;
+-
+- switch (host->sector_number) {
+- case 1:
+- val |= PMECC_CFG_PAGE_1SECTOR;
+- break;
+- case 2:
+- val |= PMECC_CFG_PAGE_2SECTORS;
+- break;
+- case 4:
+- val |= PMECC_CFG_PAGE_4SECTORS;
+- break;
+- case 8:
+- val |= PMECC_CFG_PAGE_8SECTORS;
+- break;
+- }
+-
+- val |= PMECC_CFG_READ_OP | PMECC_CFG_SPARE_DISABLE
+- | PMECC_CFG_AUTO_DISABLE;
+- pmecc_writel(host->ecc, CFG, val);
+-
+- ecc_layout = nand_chip->ecc.layout;
+- pmecc_writel(host->ecc, SAREA, mtd->oobsize - 1);
+- pmecc_writel(host->ecc, SADDR, ecc_layout->eccpos[0]);
+- pmecc_writel(host->ecc, EADDR,
+- ecc_layout->eccpos[ecc_layout->eccbytes - 1]);
+- pmecc_writel(host->ecc, CLK, PMECC_CLK_133MHZ);
+- pmecc_writel(host->ecc, IDR, 0xff);
+-
+- val = pmecc_readl(host->ecc, CTRL);
+- val |= PMECC_CTRL_ENABLE;
+- pmecc_writel(host->ecc, CTRL, val);
+-}
+-
+-static int __init atmel_pmecc_init_params(struct platform_device *pdev,
+- struct atmel_nand_host *host)
+-{
+- struct resource *regs;
+- struct resource *regs_pmerr, *regs_rom;
+- struct nand_chip *nand_chip;
+- struct mtd_info *mtd;
+- int res;
+-
+- printk(KERN_ERR "atmel_pmecc_init_params\n");
+-
+- nand_chip = &host->nand_chip;
+- mtd = &host->mtd;
+-
+- regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+- if (!regs && hard_ecc) {
+- dev_warn(host->dev, "Can't get I/O resource regs\nFalling "
+- "back on software ECC\n");
+- }
+-
+- nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */
+- if (no_ecc)
+- nand_chip->ecc.mode = NAND_ECC_NONE;
+- if (hard_ecc && regs) {
+- host->ecc = ioremap(regs->start, regs->end - regs->start + 1);
+- if (host->ecc == NULL) {
+- printk(KERN_ERR "atmel_nand: ioremap failed\n");
+- res = -EIO;
+- goto err_pmecc_ioremap;
+- }
+-
+- regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM,
+- 2);
+- regs_rom = platform_get_resource(pdev, IORESOURCE_MEM,
+- 3);
+- if (regs_pmerr && regs_rom) {
+- host->pmerrloc_base = ioremap(regs_pmerr->start,
+- regs_pmerr->end - regs_pmerr->start + 1);
+- host->rom_base = ioremap(regs_rom->start,
+- regs_rom->end - regs_rom->start + 1);
+-
+- if (host->pmerrloc_base && host->rom_base) {
+- nand_chip->ecc.mode = NAND_ECC_HW;
+- nand_chip->ecc.read_page =
+- atmel_nand_pmecc_read_page;
+- nand_chip->ecc.write_page =
+- atmel_nand_pmecc_write_page;
+- } else {
+- dev_err(host->dev, "Can not get I/O resource"
+- " for HW PMECC controller!\n");
+- goto err_pmloc_remap;
+- }
+- }
+-
+- if (nand_chip->ecc.mode != NAND_ECC_HW)
+- printk(KERN_ERR "atmel_nand: Can not get I/O resource"
+- " for HW ECC Rolling back to software ECC\n");
+- }
+-
+- if (nand_chip->ecc.mode == NAND_ECC_HW) {
+- /* ECC is calculated for the whole page (1 step) */
+- nand_chip->ecc.size = mtd->writesize;
+-
+- /* set ECC page size and oob layout */
+- switch (mtd->writesize) {
+- case 2048:
+- nand_chip->ecc.bytes = 16;
+- nand_chip->ecc.steps = 1;
+- nand_chip->ecc.layout = &pmecc_oobinfo_2048;
+- host->mm = GF_DIMENSION_13;
+- host->nn = (1 << host->mm) - 1;
+- /* 2-bits correction */
+- host->tt = 2;
+- host->sector_size = 512;
+- host->sector_number = mtd->writesize /
+- host->sector_size;
+- host->ecc_bytes_per_sector = 4;
+- host->alpha_to = pmecc_get_alpha_to(host);
+- host->index_of = pmecc_get_index_of(host);
+- break;
+- case 512:
+- case 1024:
+- case 4096:
+- /* TODO */
+- dev_warn(host->dev, "Only 2048 page size is currently"
+- "supported, Rolling back to software ECC\n");
+- default:
+- /* page size not handled by HW ECC */
+- /* switching back to soft ECC */
+- nand_chip->ecc.mode = NAND_ECC_SOFT;
+- nand_chip->ecc.calculate = NULL;
+- nand_chip->ecc.correct = NULL;
+- nand_chip->ecc.hwctl = NULL;
+- nand_chip->ecc.read_page = NULL;
+- nand_chip->ecc.postpad = 0;
+- nand_chip->ecc.prepad = 0;
+- nand_chip->ecc.bytes = 0;
+- break;
+- }
+- }
+-
+- /* Initialize PMECC core if applicable */
+- if ((nand_chip->ecc.mode == NAND_ECC_HW) && cpu_has_pmecc())
+- atmel_init_pmecc(mtd);
+-
+- return 0;
+-err_pmloc_remap:
+- iounmap(host->ecc);
+- if (host->pmerrloc_base)
+- iounmap(host->pmerrloc_base);
+- if (host->rom_base)
+- iounmap(host->rom_base);
+-err_pmecc_ioremap:
+- return -EIO;
+-}
+--
+1.7.9.5
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0002-Revert-MTD-atmel_nand-optimize-read-write-buffer-fun.patch b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0002-Revert-MTD-atmel_nand-optimize-read-write-buffer-fun.patch
new file mode 100644
index 0000000..ab52355
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0002-Revert-MTD-atmel_nand-optimize-read-write-buffer-fun.patch
@@ -0,0 +1,126 @@
+From 1ac5f32e63677a56f72e353b8f53447f63763852 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Tue, 25 Dec 2012 16:06:15 +0800
+Subject: [PATCH 2/9] Revert "MTD: atmel_nand: optimize read/write buffer
+ functions"
+
+This reverts commit 6ddc4f41327a2782c63817dc8b94dd92edad8352.
+
+In mainline this commit is also reverted. see:
+
+500823195d0c9eec2a4637484f30cc93ec633d4a (Revert "mtd: atmel_nand: optimize read/write buffer functions")
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ drivers/mtd/nand/atmel_nand.c | 71 ++++++++++++++++++++++++-----------------
+ 1 file changed, 41 insertions(+), 30 deletions(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index 12de424..9657532 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -159,6 +159,37 @@ static int atmel_nand_device_ready(struct mtd_info *mtd)
+ !!host->board->rdy_pin_active_low;
+ }
+
++/*
++ * Minimal-overhead PIO for data access.
++ */
++static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len)
++{
++ struct nand_chip *nand_chip = mtd->priv;
++
++ __raw_readsb(nand_chip->IO_ADDR_R, buf, len);
++}
++
++static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len)
++{
++ struct nand_chip *nand_chip = mtd->priv;
++
++ __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2);
++}
++
++static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len)
++{
++ struct nand_chip *nand_chip = mtd->priv;
++
++ __raw_writesb(nand_chip->IO_ADDR_W, buf, len);
++}
++
++static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len)
++{
++ struct nand_chip *nand_chip = mtd->priv;
++
++ __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2);
++}
++
+ static void dma_complete_func(void *completion)
+ {
+ complete(completion);
+@@ -235,53 +266,33 @@ err_buf:
+ static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+ {
+ struct nand_chip *chip = mtd->priv;
+- u32 align;
+- u8 *pbuf;
++ struct atmel_nand_host *host = chip->priv;
+
+ if (use_dma && len > mtd->oobsize)
+ /* only use DMA for bigger than oob size: better performances */
+ if (atmel_nand_dma_op(mtd, buf, len, 1) == 0)
+ return;
+
+- /* if no DMA operation possible, use PIO */
+- pbuf = buf;
+- align = 0x03 & ((unsigned)pbuf);
+-
+- if (align) {
+- u32 align_len = 4 - align;
+-
+- /* non aligned buffer: re-align to next word boundary */
+- ioread8_rep(chip->IO_ADDR_R, pbuf, align_len);
+- pbuf += align_len;
+- len -= align_len;
+- }
+- memcpy((void *)pbuf, chip->IO_ADDR_R, len);
++ if (host->board->bus_width_16)
++ atmel_read_buf16(mtd, buf, len);
++ else
++ atmel_read_buf8(mtd, buf, len);
+ }
+
+ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+ {
+ struct nand_chip *chip = mtd->priv;
+- u32 align;
+- const u8 *pbuf;
++ struct atmel_nand_host *host = chip->priv;
+
+ if (use_dma && len > mtd->oobsize)
+ /* only use DMA for bigger than oob size: better performances */
+ if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) == 0)
+ return;
+
+- /* if no DMA operation possible, use PIO */
+- pbuf = buf;
+- align = 0x03 & ((unsigned)pbuf);
+-
+- if (align) {
+- u32 align_len = 4 - align;
+-
+- /* non aligned buffer: re-align to next word boundary */
+- iowrite8_rep(chip->IO_ADDR_W, pbuf, align_len);
+- pbuf += align_len;
+- len -= align_len;
+- }
+- memcpy(chip->IO_ADDR_W, (void *)pbuf, len);
++ if (host->board->bus_width_16)
++ atmel_write_buf16(mtd, buf, len);
++ else
++ atmel_write_buf8(mtd, buf, len);
+ }
+
+ /*
+--
+1.7.9.5
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0003-mtd-at91-extract-hw-ecc-initialization-to-one-functi.patch b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0003-mtd-at91-extract-hw-ecc-initialization-to-one-functi.patch
new file mode 100644
index 0000000..91fd6f9
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0003-mtd-at91-extract-hw-ecc-initialization-to-one-functi.patch
@@ -0,0 +1,229 @@
+From 029192ec7ea78adaee41f14dd86dab768d56b172 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Mon, 25 Jun 2012 18:07:43 +0800
+Subject: [PATCH 3/9] mtd: at91: extract hw ecc initialization to one function
+
+This patch moves hw ecc initialization code to one function.
+
+Signed-off-by: Hong Xu <hong.xu@atmel.com>
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+
+port to 2.6.39
+
+Conflicts:
+
+ drivers/mtd/nand/atmel_nand.c
+---
+ arch/arm/mach-at91/include/mach/board.h | 1 +
+ drivers/mtd/nand/atmel_nand.c | 140 +++++++++++++++----------------
+ 2 files changed, 67 insertions(+), 74 deletions(-)
+
+diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
+index 04dcec1..392a7b3 100644
+--- a/arch/arm/mach-at91/include/mach/board.h
++++ b/arch/arm/mach-at91/include/mach/board.h
+@@ -117,6 +117,7 @@ struct atmel_nand_data {
+ u8 cle; /* address line number connected to CLE */
+ u8 bus_width_16; /* buswidth is 16 bit */
+ u8 bus_on_d0; /* pins of data bus are connected to D0~D15 */
++ u8 ecc_mode; /* can be NAND_ECC_HW/SOFT/NONE */
+ struct mtd_partition* (*partition_info)(int, int*);
+ };
+ extern void __init at91_add_device_nand(struct atmel_nand_data *data);
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index 9657532..d34d7f9 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -36,18 +36,6 @@
+ #include <mach/board.h>
+ #include <mach/cpu.h>
+
+-#ifdef CONFIG_MTD_NAND_ATMEL_ECC_HW
+-#define hard_ecc 1
+-#else
+-#define hard_ecc 0
+-#endif
+-
+-#ifdef CONFIG_MTD_NAND_ATMEL_ECC_NONE
+-#define no_ecc 1
+-#else
+-#define no_ecc 0
+-#endif
+-
+ static int use_dma = 1;
+ module_param(use_dma, int, 0);
+
+@@ -485,6 +473,65 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
+ static const char *part_probes[] = { "cmdlinepart", NULL };
+ #endif
+
++static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
++ struct atmel_nand_host *host)
++{
++ struct mtd_info *mtd = &host->mtd;
++ struct nand_chip *nand_chip = &host->nand_chip;
++ struct resource *regs;
++
++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ if (!regs) {
++ dev_err(host->dev,
++ "Can't get I/O resource regs, use software ECC\n");
++ nand_chip->ecc.mode = NAND_ECC_SOFT;
++ return 0;
++ }
++
++ host->ecc = ioremap(regs->start, resource_size(regs));
++ if (host->ecc == NULL) {
++ dev_err(host->dev, "ioremap failed\n");
++ return -EIO;
++ }
++
++ /* ECC is calculated for the whole page (1 step) */
++ nand_chip->ecc.size = mtd->writesize;
++
++ /* set ECC page size and oob layout */
++ switch (mtd->writesize) {
++ case 512:
++ nand_chip->ecc.layout = &atmel_oobinfo_small;
++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528);
++ break;
++ case 1024:
++ nand_chip->ecc.layout = &atmel_oobinfo_large;
++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056);
++ break;
++ case 2048:
++ nand_chip->ecc.layout = &atmel_oobinfo_large;
++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112);
++ break;
++ case 4096:
++ nand_chip->ecc.layout = &atmel_oobinfo_large;
++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224);
++ break;
++ default:
++ /* page size not handled by HW ECC */
++ /* switching back to soft ECC */
++ nand_chip->ecc.mode = NAND_ECC_SOFT;
++ return 0;
++ }
++
++ /* set up for HW ECC */
++ nand_chip->ecc.calculate = atmel_nand_calculate;
++ nand_chip->ecc.correct = atmel_nand_correct;
++ nand_chip->ecc.hwctl = atmel_nand_hwctl;
++ nand_chip->ecc.read_page = atmel_nand_read_page;
++ nand_chip->ecc.bytes = 4;
++
++ return 0;
++}
++
+ /*
+ * Probe for the NAND device.
+ */
+@@ -493,7 +540,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ struct atmel_nand_host *host;
+ struct mtd_info *mtd;
+ struct nand_chip *nand_chip;
+- struct resource *regs;
+ struct resource *mem;
+ int res;
+
+@@ -541,30 +587,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ if (host->board->rdy_pin)
+ nand_chip->dev_ready = atmel_nand_device_ready;
+
+- regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+- if (!regs && hard_ecc) {
+- printk(KERN_ERR "atmel_nand: can't get I/O resource "
+- "regs\nFalling back on software ECC\n");
+- }
+-
+- nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */
+- if (no_ecc)
+- nand_chip->ecc.mode = NAND_ECC_NONE;
+- if (hard_ecc && regs) {
+- host->ecc = ioremap(regs->start, regs->end - regs->start + 1);
+- if (host->ecc == NULL) {
+- printk(KERN_ERR "atmel_nand: ioremap failed\n");
+- res = -EIO;
+- goto err_ecc_ioremap;
+- }
+- nand_chip->ecc.mode = NAND_ECC_HW;
+- nand_chip->ecc.calculate = atmel_nand_calculate;
+- nand_chip->ecc.correct = atmel_nand_correct;
+- nand_chip->ecc.hwctl = atmel_nand_hwctl;
+- nand_chip->ecc.read_page = atmel_nand_read_page;
+- nand_chip->ecc.bytes = 4;
+- }
+-
++ nand_chip->ecc.mode = host->board->ecc_mode;
+ nand_chip->chip_delay = 20; /* 20us command delay time */
+
+ if (host->board->bus_width_16) /* 16-bit bus width */
+@@ -616,40 +639,9 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ }
+
+ if (nand_chip->ecc.mode == NAND_ECC_HW) {
+- /* ECC is calculated for the whole page (1 step) */
+- nand_chip->ecc.size = mtd->writesize;
+-
+- /* set ECC page size and oob layout */
+- switch (mtd->writesize) {
+- case 512:
+- nand_chip->ecc.layout = &atmel_oobinfo_small;
+- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528);
+- break;
+- case 1024:
+- nand_chip->ecc.layout = &atmel_oobinfo_large;
+- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056);
+- break;
+- case 2048:
+- nand_chip->ecc.layout = &atmel_oobinfo_large;
+- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112);
+- break;
+- case 4096:
+- nand_chip->ecc.layout = &atmel_oobinfo_large;
+- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224);
+- break;
+- default:
+- /* page size not handled by HW ECC */
+- /* switching back to soft ECC */
+- nand_chip->ecc.mode = NAND_ECC_SOFT;
+- nand_chip->ecc.calculate = NULL;
+- nand_chip->ecc.correct = NULL;
+- nand_chip->ecc.hwctl = NULL;
+- nand_chip->ecc.read_page = NULL;
+- nand_chip->ecc.postpad = 0;
+- nand_chip->ecc.prepad = 0;
+- nand_chip->ecc.bytes = 0;
+- break;
+- }
++ res = atmel_hw_nand_init_params(pdev, host);
++ if (res != 0)
++ goto err_hw_ecc;
+ }
+
+ /* second phase scan */
+@@ -687,15 +679,15 @@ err_no_partitions:
+ #endif
+ nand_release(mtd);
+ err_scan_tail:
++ if (host->ecc)
++ iounmap(host->ecc);
++err_hw_ecc:
+ err_scan_ident:
+ err_no_card:
+ atmel_nand_disable(host);
+ platform_set_drvdata(pdev, NULL);
+ if (host->dma_chan)
+ dma_release_channel(host->dma_chan);
+- if (host->ecc)
+- iounmap(host->ecc);
+-err_ecc_ioremap:
+ iounmap(host->io_base);
+ err_nand_ioremap:
+ kfree(host);
+--
+1.7.9.5
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0004-atmel_nand-add-PMECC-parameters-in-nand-structure.patch b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0004-atmel_nand-add-PMECC-parameters-in-nand-structure.patch
new file mode 100644
index 0000000..03bd6e1
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0004-atmel_nand-add-PMECC-parameters-in-nand-structure.patch
@@ -0,0 +1,30 @@
+From 0a42dbd4e968606801aa1292cb43e6835382a19f Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Tue, 25 Dec 2012 17:32:58 +0800
+Subject: [PATCH 4/9] atmel_nand: add PMECC parameters in nand structure.
+
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ drivers/mtd/nand/atmel_nand.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index d34d7f9..fbe0b11 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -87,6 +87,11 @@ struct atmel_nand_host {
+
+ struct completion comp;
+ struct dma_chan *dma_chan;
++
++ bool has_pmecc;
++ u8 pmecc_corr_cap;
++ u16 pmecc_sector_size;
++ u32 pmecc_lookup_table_offset;
+ };
+
+ static int cpu_has_dma(void)
+--
+1.7.9.5
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0005-mtd-at91-atmel_nand-add-Programmable-Multibit-ECC-co.patch b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0005-mtd-at91-atmel_nand-add-Programmable-Multibit-ECC-co.patch
new file mode 100644
index 0000000..0ed9119
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0005-mtd-at91-atmel_nand-add-Programmable-Multibit-ECC-co.patch
@@ -0,0 +1,980 @@
+From 548e5f480ba7799d694cc450473405bca6c2814c Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Fri, 29 Jun 2012 17:47:55 +0800
+Subject: [PATCH 5/9] mtd: at91: atmel_nand: add Programmable Multibit ECC
+ controller support
+
+The Programmable Multibit ECC (PMECC) controller is a programmable binary
+BCH(Bose, Chaudhuri and Hocquenghem) encoder and decoder. This controller
+can be used to support both SLC and MLC NAND Flash devices. It supports to
+generate ECC to correct 2, 4, 8, 12 or 24 bits of error per sector of data.
+
+To use PMECC in this driver, the user needs to set the address and size of
+PMECC, PMECC error location controllers and ROM. And also needs to pass the
+correction capability, the sector size and ROM lookup table offsets via dt.
+
+This driver has been tested on AT91SAM9X5-EK and AT91SAM9N12-EK with JFFS2,
+YAFFS2, UBIFS and mtd-utils.
+
+Signed-off-by: Hong Xu <hong.xu@atmel.com>
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+Tested-by: Richard Genoud <richard.genoud@gmail.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
+---
+ drivers/mtd/nand/atmel_nand.c | 757 ++++++++++++++++++++++++++++++++++++-
+ drivers/mtd/nand/atmel_nand_ecc.h | 114 +++++-
+ 2 files changed, 864 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index fbe0b11..a6fa5c1 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -1,20 +1,22 @@
+ /*
+- * Copyright (C) 2003 Rick Bronson
++ * Copyright © 2003 Rick Bronson
+ *
+ * Derived from drivers/mtd/nand/autcpu12.c
+- * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
++ * Copyright © 2001 Thomas Gleixner (gleixner@autronix.de)
+ *
+ * Derived from drivers/mtd/spia.c
+- * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
++ * Copyright © 2000 Steven J. Hill (sjhill@cotw.com)
+ *
+ *
+ * Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
+- * Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright (C) 2007
++ * Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright © 2007
+ *
+ * Derived from Das U-Boot source code
+ * (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
+- * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
++ * © Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
+ *
++ * Add Programmable Multibit ECC support for various AT91 SoC
++ * © Copyright 2012 ATMEL, Hong Xu
+ *
+ * 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
+@@ -92,8 +94,31 @@ struct atmel_nand_host {
+ u8 pmecc_corr_cap;
+ u16 pmecc_sector_size;
+ u32 pmecc_lookup_table_offset;
++
++ int pmecc_bytes_per_sector;
++ int pmecc_sector_number;
++ int pmecc_degree; /* Degree of remainders */
++ int pmecc_cw_len; /* Length of codeword */
++
++ void __iomem *pmerrloc_base;
++ void __iomem *pmecc_rom_base;
++
++ /* lookup table for alpha_to and index_of */
++ void __iomem *pmecc_alpha_to;
++ void __iomem *pmecc_index_of;
++
++ /* data for pmecc computation */
++ int16_t *pmecc_partial_syn;
++ int16_t *pmecc_si;
++ int16_t *pmecc_smu; /* Sigma table */
++ int16_t *pmecc_lmu; /* polynomal order */
++ int *pmecc_mu;
++ int *pmecc_dmu;
++ int *pmecc_delta;
+ };
+
++static struct nand_ecclayout atmel_pmecc_oobinfo;
++
+ static int cpu_has_dma(void)
+ {
+ return cpu_is_at91sam9rl() || cpu_is_at91sam9g45();
+@@ -289,6 +314,703 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+ }
+
+ /*
++ * Return number of ecc bytes per sector according to sector size and
++ * correction capability
++ *
++ * Following table shows what at91 PMECC supported:
++ * Correction Capability Sector_512_bytes Sector_1024_bytes
++ * ===================== ================ =================
++ * 2-bits 4-bytes 4-bytes
++ * 4-bits 7-bytes 7-bytes
++ * 8-bits 13-bytes 14-bytes
++ * 12-bits 20-bytes 21-bytes
++ * 24-bits 39-bytes 42-bytes
++ */
++static int __devinit pmecc_get_ecc_bytes(int cap, int sector_size)
++{
++ int m = 12 + sector_size / 512;
++ return (m * cap + 7) / 8;
++}
++
++static void __devinit pmecc_config_ecc_layout(struct nand_ecclayout *layout,
++ int oobsize, int ecc_len)
++{
++ int i;
++
++ layout->eccbytes = ecc_len;
++
++ /* ECC will occupy the last ecc_len bytes continuously */
++ for (i = 0; i < ecc_len; i++)
++ layout->eccpos[i] = oobsize - ecc_len + i;
++
++ layout->oobfree[0].offset = 2;
++ layout->oobfree[0].length =
++ oobsize - ecc_len - layout->oobfree[0].offset;
++}
++
++static void __devinit __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host)
++{
++ int table_size;
++
++ table_size = host->pmecc_sector_size == 512 ?
++ PMECC_LOOKUP_TABLE_SIZE_512 : PMECC_LOOKUP_TABLE_SIZE_1024;
++
++ return host->pmecc_rom_base + host->pmecc_lookup_table_offset +
++ table_size * sizeof(int16_t);
++}
++
++static void pmecc_data_free(struct atmel_nand_host *host)
++{
++ kfree(host->pmecc_partial_syn);
++ kfree(host->pmecc_si);
++ kfree(host->pmecc_lmu);
++ kfree(host->pmecc_smu);
++ kfree(host->pmecc_mu);
++ kfree(host->pmecc_dmu);
++ kfree(host->pmecc_delta);
++}
++
++static int __devinit pmecc_data_alloc(struct atmel_nand_host *host)
++{
++ const int cap = host->pmecc_corr_cap;
++
++ host->pmecc_partial_syn = kzalloc((2 * cap + 1) * sizeof(int16_t),
++ GFP_KERNEL);
++ host->pmecc_si = kzalloc((2 * cap + 1) * sizeof(int16_t), GFP_KERNEL);
++ host->pmecc_lmu = kzalloc((cap + 1) * sizeof(int16_t), GFP_KERNEL);
++ host->pmecc_smu = kzalloc((cap + 2) * (2 * cap + 1) * sizeof(int16_t),
++ GFP_KERNEL);
++ host->pmecc_mu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
++ host->pmecc_dmu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
++ host->pmecc_delta = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
++
++ if (host->pmecc_partial_syn &&
++ host->pmecc_si &&
++ host->pmecc_lmu &&
++ host->pmecc_smu &&
++ host->pmecc_mu &&
++ host->pmecc_dmu &&
++ host->pmecc_delta)
++ return 0;
++
++ /* error happened */
++ pmecc_data_free(host);
++ return -ENOMEM;
++}
++
++static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector)
++{
++ struct nand_chip *nand_chip = mtd->priv;
++ struct atmel_nand_host *host = nand_chip->priv;
++ int i;
++ uint32_t value;
++
++ /* Fill odd syndromes */
++ for (i = 0; i < host->pmecc_corr_cap; i++) {
++ value = pmecc_readl_rem_relaxed(host->ecc, sector, i / 2);
++ if (i & 1)
++ value >>= 16;
++ value &= 0xffff;
++ host->pmecc_partial_syn[(2 * i) + 1] = (int16_t)value;
++ }
++}
++
++static void pmecc_substitute(struct mtd_info *mtd)
++{
++ struct nand_chip *nand_chip = mtd->priv;
++ struct atmel_nand_host *host = nand_chip->priv;
++ int16_t __iomem *alpha_to = host->pmecc_alpha_to;
++ int16_t __iomem *index_of = host->pmecc_index_of;
++ int16_t *partial_syn = host->pmecc_partial_syn;
++ const int cap = host->pmecc_corr_cap;
++ int16_t *si;
++ int i, j;
++
++ /* si[] is a table that holds the current syndrome value,
++ * an element of that table belongs to the field
++ */
++ si = host->pmecc_si;
++
++ memset(&si[1], 0, sizeof(int16_t) * (2 * cap - 1));
++
++ /* Computation 2t syndromes based on S(x) */
++ /* Odd syndromes */
++ for (i = 1; i < 2 * cap; i += 2) {
++ for (j = 0; j < host->pmecc_degree; j++) {
++ if (partial_syn[i] & ((unsigned short)0x1 << j))
++ si[i] = readw_relaxed(alpha_to + i * j) ^ si[i];
++ }
++ }
++ /* Even syndrome = (Odd syndrome) ** 2 */
++ for (i = 2, j = 1; j <= cap; i = ++j << 1) {
++ if (si[j] == 0) {
++ si[i] = 0;
++ } else {
++ int16_t tmp;
++
++ tmp = readw_relaxed(index_of + si[j]);
++ tmp = (tmp * 2) % host->pmecc_cw_len;
++ si[i] = readw_relaxed(alpha_to + tmp);
++ }
++ }
++
++ return;
++}
++
++static void pmecc_get_sigma(struct mtd_info *mtd)
++{
++ struct nand_chip *nand_chip = mtd->priv;
++ struct atmel_nand_host *host = nand_chip->priv;
++
++ int16_t *lmu = host->pmecc_lmu;
++ int16_t *si = host->pmecc_si;
++ int *mu = host->pmecc_mu;
++ int *dmu = host->pmecc_dmu; /* Discrepancy */
++ int *delta = host->pmecc_delta; /* Delta order */
++ int cw_len = host->pmecc_cw_len;
++ const int16_t cap = host->pmecc_corr_cap;
++ const int num = 2 * cap + 1;
++ int16_t __iomem *index_of = host->pmecc_index_of;
++ int16_t __iomem *alpha_to = host->pmecc_alpha_to;
++ int i, j, k;
++ uint32_t dmu_0_count, tmp;
++ int16_t *smu = host->pmecc_smu;
++
++ /* index of largest delta */
++ int ro;
++ int largest;
++ int diff;
++
++ dmu_0_count = 0;
++
++ /* First Row */
++
++ /* Mu */
++ mu[0] = -1;
++
++ memset(smu, 0, sizeof(int16_t) * num);
++ smu[0] = 1;
++
++ /* discrepancy set to 1 */
++ dmu[0] = 1;
++ /* polynom order set to 0 */
++ lmu[0] = 0;
++ delta[0] = (mu[0] * 2 - lmu[0]) >> 1;
++
++ /* Second Row */
++
++ /* Mu */
++ mu[1] = 0;
++ /* Sigma(x) set to 1 */
++ memset(&smu[num], 0, sizeof(int16_t) * num);
++ smu[num] = 1;
++
++ /* discrepancy set to S1 */
++ dmu[1] = si[1];
++
++ /* polynom order set to 0 */
++ lmu[1] = 0;
++
++ delta[1] = (mu[1] * 2 - lmu[1]) >> 1;
++
++ /* Init the Sigma(x) last row */
++ memset(&smu[(cap + 1) * num], 0, sizeof(int16_t) * num);
++
++ for (i = 1; i <= cap; i++) {
++ mu[i + 1] = i << 1;
++ /* Begin Computing Sigma (Mu+1) and L(mu) */
++ /* check if discrepancy is set to 0 */
++ if (dmu[i] == 0) {
++ dmu_0_count++;
++
++ tmp = ((cap - (lmu[i] >> 1) - 1) / 2);
++ if ((cap - (lmu[i] >> 1) - 1) & 0x1)
++ tmp += 2;
++ else
++ tmp += 1;
++
++ if (dmu_0_count == tmp) {
++ for (j = 0; j <= (lmu[i] >> 1) + 1; j++)
++ smu[(cap + 1) * num + j] =
++ smu[i * num + j];
++
++ lmu[cap + 1] = lmu[i];
++ return;
++ }
++
++ /* copy polynom */
++ for (j = 0; j <= lmu[i] >> 1; j++)
++ smu[(i + 1) * num + j] = smu[i * num + j];
++
++ /* copy previous polynom order to the next */
++ lmu[i + 1] = lmu[i];
++ } else {
++ ro = 0;
++ largest = -1;
++ /* find largest delta with dmu != 0 */
++ for (j = 0; j < i; j++) {
++ if ((dmu[j]) && (delta[j] > largest)) {
++ largest = delta[j];
++ ro = j;
++ }
++ }
++
++ /* compute difference */
++ diff = (mu[i] - mu[ro]);
++
++ /* Compute degree of the new smu polynomial */
++ if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff))
++ lmu[i + 1] = lmu[i];
++ else
++ lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2;
++
++ /* Init smu[i+1] with 0 */
++ for (k = 0; k < num; k++)
++ smu[(i + 1) * num + k] = 0;
++
++ /* Compute smu[i+1] */
++ for (k = 0; k <= lmu[ro] >> 1; k++) {
++ int16_t a, b, c;
++
++ if (!(smu[ro * num + k] && dmu[i]))
++ continue;
++ a = readw_relaxed(index_of + dmu[i]);
++ b = readw_relaxed(index_of + dmu[ro]);
++ c = readw_relaxed(index_of + smu[ro * num + k]);
++ tmp = a + (cw_len - b) + c;
++ a = readw_relaxed(alpha_to + tmp % cw_len);
++ smu[(i + 1) * num + (k + diff)] = a;
++ }
++
++ for (k = 0; k <= lmu[i] >> 1; k++)
++ smu[(i + 1) * num + k] ^= smu[i * num + k];
++ }
++
++ /* End Computing Sigma (Mu+1) and L(mu) */
++ /* In either case compute delta */
++ delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1;
++
++ /* Do not compute discrepancy for the last iteration */
++ if (i >= cap)
++ continue;
++
++ for (k = 0; k <= (lmu[i + 1] >> 1); k++) {
++ tmp = 2 * (i - 1);
++ if (k == 0) {
++ dmu[i + 1] = si[tmp + 3];
++ } else if (smu[(i + 1) * num + k] && si[tmp + 3 - k]) {
++ int16_t a, b, c;
++ a = readw_relaxed(index_of +
++ smu[(i + 1) * num + k]);
++ b = si[2 * (i - 1) + 3 - k];
++ c = readw_relaxed(index_of + b);
++ tmp = a + c;
++ tmp %= cw_len;
++ dmu[i + 1] = readw_relaxed(alpha_to + tmp) ^
++ dmu[i + 1];
++ }
++ }
++ }
++
++ return;
++}
++
++static int pmecc_err_location(struct mtd_info *mtd)
++{
++ struct nand_chip *nand_chip = mtd->priv;
++ struct atmel_nand_host *host = nand_chip->priv;
++ unsigned long end_time;
++ const int cap = host->pmecc_corr_cap;
++ const int num = 2 * cap + 1;
++ int sector_size = host->pmecc_sector_size;
++ int err_nbr = 0; /* number of error */
++ int roots_nbr; /* number of roots */
++ int i;
++ uint32_t val;
++ int16_t *smu = host->pmecc_smu;
++
++ pmerrloc_writel(host->pmerrloc_base, ELDIS, PMERRLOC_DISABLE);
++
++ for (i = 0; i <= host->pmecc_lmu[cap + 1] >> 1; i++) {
++ pmerrloc_writel_sigma_relaxed(host->pmerrloc_base, i,
++ smu[(cap + 1) * num + i]);
++ err_nbr++;
++ }
++
++ val = (err_nbr - 1) << 16;
++ if (sector_size == 1024)
++ val |= 1;
++
++ pmerrloc_writel(host->pmerrloc_base, ELCFG, val);
++ pmerrloc_writel(host->pmerrloc_base, ELEN,
++ sector_size * 8 + host->pmecc_degree * cap);
++
++ end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
++ while (!(pmerrloc_readl_relaxed(host->pmerrloc_base, ELISR)
++ & PMERRLOC_CALC_DONE)) {
++ if (unlikely(time_after(jiffies, end_time))) {
++ dev_err(host->dev, "PMECC: Timeout to calculate error location.\n");
++ return -1;
++ }
++ cpu_relax();
++ }
++
++ roots_nbr = (pmerrloc_readl_relaxed(host->pmerrloc_base, ELISR)
++ & PMERRLOC_ERR_NUM_MASK) >> 8;
++ /* Number of roots == degree of smu hence <= cap */
++ if (roots_nbr == host->pmecc_lmu[cap + 1] >> 1)
++ return err_nbr - 1;
++
++ /* Number of roots does not match the degree of smu
++ * unable to correct error */
++ return -1;
++}
++
++static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
++ int sector_num, int extra_bytes, int err_nbr)
++{
++ struct nand_chip *nand_chip = mtd->priv;
++ struct atmel_nand_host *host = nand_chip->priv;
++ int i = 0;
++ int byte_pos, bit_pos, sector_size, pos;
++ uint32_t tmp;
++ uint8_t err_byte;
++
++ sector_size = host->pmecc_sector_size;
++
++ while (err_nbr) {
++ tmp = pmerrloc_readl_el_relaxed(host->pmerrloc_base, i) - 1;
++ byte_pos = tmp / 8;
++ bit_pos = tmp % 8;
++
++ if (byte_pos >= (sector_size + extra_bytes))
++ BUG(); /* should never happen */
++
++ if (byte_pos < sector_size) {
++ err_byte = *(buf + byte_pos);
++ *(buf + byte_pos) ^= (1 << bit_pos);
++
++ pos = sector_num * host->pmecc_sector_size + byte_pos;
++ dev_info(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
++ pos, bit_pos, err_byte, *(buf + byte_pos));
++ } else {
++ /* Bit flip in OOB area */
++ tmp = sector_num * host->pmecc_bytes_per_sector
++ + (byte_pos - sector_size);
++ err_byte = ecc[tmp];
++ ecc[tmp] ^= (1 << bit_pos);
++
++ pos = tmp + nand_chip->ecc.layout->eccpos[0];
++ dev_info(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
++ pos, bit_pos, err_byte, ecc[tmp]);
++ }
++
++ i++;
++ err_nbr--;
++ }
++
++ return;
++}
++
++static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
++ u8 *ecc)
++{
++ struct nand_chip *nand_chip = mtd->priv;
++ struct atmel_nand_host *host = nand_chip->priv;
++ int i, err_nbr, eccbytes;
++ uint8_t *buf_pos;
++
++ eccbytes = nand_chip->ecc.bytes;
++ for (i = 0; i < eccbytes; i++)
++ if (ecc[i] != 0xff)
++ goto normal_check;
++ /* Erased page, return OK */
++ return 0;
++
++normal_check:
++ for (i = 0; i < host->pmecc_sector_number; i++) {
++ err_nbr = 0;
++ if (pmecc_stat & 0x1) {
++ buf_pos = buf + i * host->pmecc_sector_size;
++
++ pmecc_gen_syndrome(mtd, i);
++ pmecc_substitute(mtd);
++ pmecc_get_sigma(mtd);
++
++ err_nbr = pmecc_err_location(mtd);
++ if (err_nbr == -1) {
++ dev_err(host->dev, "PMECC: Too many errors\n");
++ mtd->ecc_stats.failed++;
++ return -EIO;
++ } else {
++ pmecc_correct_data(mtd, buf_pos, ecc, i,
++ host->pmecc_bytes_per_sector, err_nbr);
++ mtd->ecc_stats.corrected += err_nbr;
++ }
++ }
++ pmecc_stat >>= 1;
++ }
++
++ return 0;
++}
++
++static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
++ struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
++{
++ struct atmel_nand_host *host = chip->priv;
++ int eccsize = chip->ecc.size;
++ uint8_t *oob = chip->oob_poi;
++ uint32_t *eccpos = chip->ecc.layout->eccpos;
++ uint32_t stat;
++ unsigned long end_time;
++
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
++ pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG)
++ & ~PMECC_CFG_WRITE_OP) | PMECC_CFG_AUTO_ENABLE);
++
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
++
++ chip->read_buf(mtd, buf, eccsize);
++ chip->read_buf(mtd, oob, mtd->oobsize);
++
++ end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
++ while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) {
++ if (unlikely(time_after(jiffies, end_time))) {
++ dev_err(host->dev, "PMECC: Timeout to get error status.\n");
++ return -EIO;
++ }
++ cpu_relax();
++ }
++
++ stat = pmecc_readl_relaxed(host->ecc, ISR);
++ if (stat != 0)
++ if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0)
++ return -EIO;
++
++ return 0;
++}
++
++static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
++ struct nand_chip *chip, const uint8_t *buf, int oob_required)
++{
++ struct atmel_nand_host *host = chip->priv;
++ uint32_t *eccpos = chip->ecc.layout->eccpos;
++ int i, j;
++ unsigned long end_time;
++
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
++
++ pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG) |
++ PMECC_CFG_WRITE_OP) & ~PMECC_CFG_AUTO_ENABLE);
++
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
++
++ chip->write_buf(mtd, (u8 *)buf, mtd->writesize);
++
++ end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
++ while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) {
++ if (unlikely(time_after(jiffies, end_time))) {
++ dev_err(host->dev, "PMECC: Timeout to get ECC value.\n");
++ return -EIO;
++ }
++ cpu_relax();
++ }
++
++ for (i = 0; i < host->pmecc_sector_number; i++) {
++ for (j = 0; j < host->pmecc_bytes_per_sector; j++) {
++ int pos;
++
++ pos = i * host->pmecc_bytes_per_sector + j;
++ chip->oob_poi[eccpos[pos]] =
++ pmecc_readb_ecc_relaxed(host->ecc, i, j);
++ }
++ }
++ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++ return 0;
++}
++
++static void atmel_pmecc_core_init(struct mtd_info *mtd)
++{
++ struct nand_chip *nand_chip = mtd->priv;
++ struct atmel_nand_host *host = nand_chip->priv;
++ uint32_t val = 0;
++ struct nand_ecclayout *ecc_layout;
++
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
++
++ switch (host->pmecc_corr_cap) {
++ case 2:
++ val = PMECC_CFG_BCH_ERR2;
++ break;
++ case 4:
++ val = PMECC_CFG_BCH_ERR4;
++ break;
++ case 8:
++ val = PMECC_CFG_BCH_ERR8;
++ break;
++ case 12:
++ val = PMECC_CFG_BCH_ERR12;
++ break;
++ case 24:
++ val = PMECC_CFG_BCH_ERR24;
++ break;
++ }
++
++ if (host->pmecc_sector_size == 512)
++ val |= PMECC_CFG_SECTOR512;
++ else if (host->pmecc_sector_size == 1024)
++ val |= PMECC_CFG_SECTOR1024;
++
++ switch (host->pmecc_sector_number) {
++ case 1:
++ val |= PMECC_CFG_PAGE_1SECTOR;
++ break;
++ case 2:
++ val |= PMECC_CFG_PAGE_2SECTORS;
++ break;
++ case 4:
++ val |= PMECC_CFG_PAGE_4SECTORS;
++ break;
++ case 8:
++ val |= PMECC_CFG_PAGE_8SECTORS;
++ break;
++ }
++
++ val |= (PMECC_CFG_READ_OP | PMECC_CFG_SPARE_DISABLE
++ | PMECC_CFG_AUTO_DISABLE);
++ pmecc_writel(host->ecc, CFG, val);
++
++ ecc_layout = nand_chip->ecc.layout;
++ pmecc_writel(host->ecc, SAREA, mtd->oobsize - 1);
++ pmecc_writel(host->ecc, SADDR, ecc_layout->eccpos[0]);
++ pmecc_writel(host->ecc, EADDR,
++ ecc_layout->eccpos[ecc_layout->eccbytes - 1]);
++ /* See datasheet about PMECC Clock Control Register */
++ pmecc_writel(host->ecc, CLK, 2);
++ pmecc_writel(host->ecc, IDR, 0xff);
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
++}
++
++static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
++ struct atmel_nand_host *host)
++{
++ struct mtd_info *mtd = &host->mtd;
++ struct nand_chip *nand_chip = &host->nand_chip;
++ struct resource *regs, *regs_pmerr, *regs_rom;
++ int cap, sector_size, err_no;
++
++ cap = host->pmecc_corr_cap;
++ sector_size = host->pmecc_sector_size;
++ dev_info(host->dev, "Initialize PMECC params, cap: %d, sector: %d\n",
++ cap, sector_size);
++
++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ if (!regs) {
++ dev_warn(host->dev,
++ "Can't get I/O resource regs for PMECC controller, rolling back on software ECC\n");
++ nand_chip->ecc.mode = NAND_ECC_SOFT;
++ return 0;
++ }
++
++ host->ecc = ioremap(regs->start, resource_size(regs));
++ if (host->ecc == NULL) {
++ dev_err(host->dev, "ioremap failed\n");
++ err_no = -EIO;
++ goto err_pmecc_ioremap;
++ }
++
++ regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, 2);
++ regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
++ if (regs_pmerr && regs_rom) {
++ host->pmerrloc_base = ioremap(regs_pmerr->start,
++ resource_size(regs_pmerr));
++ host->pmecc_rom_base = ioremap(regs_rom->start,
++ resource_size(regs_rom));
++ }
++
++ if (!host->pmerrloc_base || !host->pmecc_rom_base) {
++ dev_err(host->dev,
++ "Can not get I/O resource for PMECC ERRLOC controller or ROM!\n");
++ err_no = -EIO;
++ goto err_pmloc_ioremap;
++ }
++
++ /* ECC is calculated for the whole page (1 step) */
++ nand_chip->ecc.size = mtd->writesize;
++
++ /* set ECC page size and oob layout */
++ switch (mtd->writesize) {
++ case 2048:
++ host->pmecc_degree = PMECC_GF_DIMENSION_13;
++ host->pmecc_cw_len = (1 << host->pmecc_degree) - 1;
++ host->pmecc_sector_number = mtd->writesize / sector_size;
++ host->pmecc_bytes_per_sector = pmecc_get_ecc_bytes(
++ cap, sector_size);
++ host->pmecc_alpha_to = pmecc_get_alpha_to(host);
++ host->pmecc_index_of = host->pmecc_rom_base +
++ host->pmecc_lookup_table_offset;
++
++ nand_chip->ecc.steps = 1;
++ nand_chip->ecc.strength = cap;
++ nand_chip->ecc.bytes = host->pmecc_bytes_per_sector *
++ host->pmecc_sector_number;
++ if (nand_chip->ecc.bytes > mtd->oobsize - 2) {
++ dev_err(host->dev, "No room for ECC bytes\n");
++ err_no = -EINVAL;
++ goto err_no_ecc_room;
++ }
++ pmecc_config_ecc_layout(&atmel_pmecc_oobinfo,
++ mtd->oobsize,
++ nand_chip->ecc.bytes);
++ nand_chip->ecc.layout = &atmel_pmecc_oobinfo;
++ break;
++ case 512:
++ case 1024:
++ case 4096:
++ /* TODO */
++ dev_warn(host->dev,
++ "Unsupported page size for PMECC, use Software ECC\n");
++ default:
++ /* page size not handled by HW ECC */
++ /* switching back to soft ECC */
++ nand_chip->ecc.mode = NAND_ECC_SOFT;
++ return 0;
++ }
++
++ /* Allocate data for PMECC computation */
++ err_no = pmecc_data_alloc(host);
++ if (err_no) {
++ dev_err(host->dev,
++ "Cannot allocate memory for PMECC computation!\n");
++ goto err_pmecc_data_alloc;
++ }
++
++ nand_chip->ecc.read_page = atmel_nand_pmecc_read_page;
++ nand_chip->ecc.write_page = atmel_nand_pmecc_write_page;
++
++ atmel_pmecc_core_init(mtd);
++
++ return 0;
++
++err_pmecc_data_alloc:
++err_no_ecc_room:
++err_pmloc_ioremap:
++ iounmap(host->ecc);
++ if (host->pmerrloc_base)
++ iounmap(host->pmerrloc_base);
++ if (host->pmecc_rom_base)
++ iounmap(host->pmecc_rom_base);
++err_pmecc_ioremap:
++ return err_no;
++}
++
++/*
+ * Calculate HW ECC
+ *
+ * function called after a write
+@@ -644,7 +1366,11 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ }
+
+ if (nand_chip->ecc.mode == NAND_ECC_HW) {
+- res = atmel_hw_nand_init_params(pdev, host);
++ if (host->has_pmecc)
++ res = atmel_pmecc_nand_init_params(pdev, host);
++ else
++ res = atmel_hw_nand_init_params(pdev, host);
++
+ if (res != 0)
+ goto err_hw_ecc;
+ }
+@@ -684,8 +1410,16 @@ err_no_partitions:
+ #endif
+ nand_release(mtd);
+ err_scan_tail:
++ if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW) {
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
++ pmecc_data_free(host);
++ }
+ if (host->ecc)
+ iounmap(host->ecc);
++ if (host->pmerrloc_base)
++ iounmap(host->pmerrloc_base);
++ if (host->pmecc_rom_base)
++ iounmap(host->pmecc_rom_base);
+ err_hw_ecc:
+ err_scan_ident:
+ err_no_card:
+@@ -711,8 +1445,19 @@ static int __exit atmel_nand_remove(struct platform_device *pdev)
+
+ atmel_nand_disable(host);
+
++ if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW) {
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
++ pmerrloc_writel(host->pmerrloc_base, ELDIS,
++ PMERRLOC_DISABLE);
++ pmecc_data_free(host);
++ }
++
+ if (host->ecc)
+ iounmap(host->ecc);
++ if (host->pmecc_rom_base)
++ iounmap(host->pmecc_rom_base);
++ if (host->pmerrloc_base)
++ iounmap(host->pmerrloc_base);
+
+ if (host->dma_chan)
+ dma_release_channel(host->dma_chan);
+diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h
+index 578c776..8a1e9a6 100644
+--- a/drivers/mtd/nand/atmel_nand_ecc.h
++++ b/drivers/mtd/nand/atmel_nand_ecc.h
+@@ -3,7 +3,7 @@
+ * Based on AT91SAM9260 datasheet revision B.
+ *
+ * Copyright (C) 2007 Andrew Victor
+- * Copyright (C) 2007 Atmel Corporation.
++ * Copyright (C) 2007 - 2012 Atmel Corporation.
+ *
+ * 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
+@@ -36,4 +36,116 @@
+ #define ATMEL_ECC_NPR 0x10 /* NParity register */
+ #define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */
+
++/* PMECC Register Definitions */
++#define ATMEL_PMECC_CFG 0x000 /* Configuration Register */
++#define PMECC_CFG_BCH_ERR2 (0 << 0)
++#define PMECC_CFG_BCH_ERR4 (1 << 0)
++#define PMECC_CFG_BCH_ERR8 (2 << 0)
++#define PMECC_CFG_BCH_ERR12 (3 << 0)
++#define PMECC_CFG_BCH_ERR24 (4 << 0)
++
++#define PMECC_CFG_SECTOR512 (0 << 4)
++#define PMECC_CFG_SECTOR1024 (1 << 4)
++
++#define PMECC_CFG_PAGE_1SECTOR (0 << 8)
++#define PMECC_CFG_PAGE_2SECTORS (1 << 8)
++#define PMECC_CFG_PAGE_4SECTORS (2 << 8)
++#define PMECC_CFG_PAGE_8SECTORS (3 << 8)
++
++#define PMECC_CFG_READ_OP (0 << 12)
++#define PMECC_CFG_WRITE_OP (1 << 12)
++
++#define PMECC_CFG_SPARE_ENABLE (1 << 16)
++#define PMECC_CFG_SPARE_DISABLE (0 << 16)
++
++#define PMECC_CFG_AUTO_ENABLE (1 << 20)
++#define PMECC_CFG_AUTO_DISABLE (0 << 20)
++
++#define ATMEL_PMECC_SAREA 0x004 /* Spare area size */
++#define ATMEL_PMECC_SADDR 0x008 /* PMECC starting address */
++#define ATMEL_PMECC_EADDR 0x00c /* PMECC ending address */
++#define ATMEL_PMECC_CLK 0x010 /* PMECC clock control */
++#define PMECC_CLK_133MHZ (2 << 0)
++
++#define ATMEL_PMECC_CTRL 0x014 /* PMECC control register */
++#define PMECC_CTRL_RST (1 << 0)
++#define PMECC_CTRL_DATA (1 << 1)
++#define PMECC_CTRL_USER (1 << 2)
++#define PMECC_CTRL_ENABLE (1 << 4)
++#define PMECC_CTRL_DISABLE (1 << 5)
++
++#define ATMEL_PMECC_SR 0x018 /* PMECC status register */
++#define PMECC_SR_BUSY (1 << 0)
++#define PMECC_SR_ENABLE (1 << 4)
++
++#define ATMEL_PMECC_IER 0x01c /* PMECC interrupt enable */
++#define PMECC_IER_ENABLE (1 << 0)
++#define ATMEL_PMECC_IDR 0x020 /* PMECC interrupt disable */
++#define PMECC_IER_DISABLE (1 << 0)
++#define ATMEL_PMECC_IMR 0x024 /* PMECC interrupt mask */
++#define PMECC_IER_MASK (1 << 0)
++#define ATMEL_PMECC_ISR 0x028 /* PMECC interrupt status */
++#define ATMEL_PMECC_ECCx 0x040 /* PMECC ECC x */
++#define ATMEL_PMECC_REMx 0x240 /* PMECC REM x */
++
++/* PMERRLOC Register Definitions */
++#define ATMEL_PMERRLOC_ELCFG 0x000 /* Error location config */
++#define PMERRLOC_ELCFG_SECTOR_512 (0 << 0)
++#define PMERRLOC_ELCFG_SECTOR_1024 (1 << 0)
++#define PMERRLOC_ELCFG_NUM_ERRORS(n) ((n) << 16)
++
++#define ATMEL_PMERRLOC_ELPRIM 0x004 /* Error location primitive */
++#define ATMEL_PMERRLOC_ELEN 0x008 /* Error location enable */
++#define ATMEL_PMERRLOC_ELDIS 0x00c /* Error location disable */
++#define PMERRLOC_DISABLE (1 << 0)
++
++#define ATMEL_PMERRLOC_ELSR 0x010 /* Error location status */
++#define PMERRLOC_ELSR_BUSY (1 << 0)
++#define ATMEL_PMERRLOC_ELIER 0x014 /* Error location int enable */
++#define ATMEL_PMERRLOC_ELIDR 0x018 /* Error location int disable */
++#define ATMEL_PMERRLOC_ELIMR 0x01c /* Error location int mask */
++#define ATMEL_PMERRLOC_ELISR 0x020 /* Error location int status */
++#define PMERRLOC_ERR_NUM_MASK (0x1f << 8)
++#define PMERRLOC_CALC_DONE (1 << 0)
++#define ATMEL_PMERRLOC_SIGMAx 0x028 /* Error location SIGMA x */
++#define ATMEL_PMERRLOC_ELx 0x08c /* Error location x */
++
++/* Register access macros for PMECC */
++#define pmecc_readl_relaxed(addr, reg) \
++ readl_relaxed((addr) + ATMEL_PMECC_##reg)
++
++#define pmecc_writel(addr, reg, value) \
++ writel((value), (addr) + ATMEL_PMECC_##reg)
++
++#define pmecc_readb_ecc_relaxed(addr, sector, n) \
++ readb_relaxed((addr) + ATMEL_PMECC_ECCx + ((sector) * 0x40) + (n))
++
++#define pmecc_readl_rem_relaxed(addr, sector, n) \
++ readl_relaxed((addr) + ATMEL_PMECC_REMx + ((sector) * 0x40) + ((n) * 4))
++
++#define pmerrloc_readl_relaxed(addr, reg) \
++ readl_relaxed((addr) + ATMEL_PMERRLOC_##reg)
++
++#define pmerrloc_writel(addr, reg, value) \
++ writel((value), (addr) + ATMEL_PMERRLOC_##reg)
++
++#define pmerrloc_writel_sigma_relaxed(addr, n, value) \
++ writel_relaxed((value), (addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
++
++#define pmerrloc_readl_sigma_relaxed(addr, n) \
++ readl_relaxed((addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
++
++#define pmerrloc_readl_el_relaxed(addr, n) \
++ readl_relaxed((addr) + ATMEL_PMERRLOC_ELx + ((n) * 4))
++
++/* Galois field dimension */
++#define PMECC_GF_DIMENSION_13 13
++#define PMECC_GF_DIMENSION_14 14
++
++#define PMECC_LOOKUP_TABLE_SIZE_512 0x2000
++#define PMECC_LOOKUP_TABLE_SIZE_1024 0x4000
++
++/* Time out value for reading PMECC status register */
++#define PMECC_MAX_TIMEOUT_MS 100
++
+ #endif
+--
+1.7.9.5
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0006-atmel_nand-port-to-2.6.39.-modify-function-definitio.patch b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0006-atmel_nand-port-to-2.6.39.-modify-function-definitio.patch
new file mode 100644
index 0000000..f2fa778
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0006-atmel_nand-port-to-2.6.39.-modify-function-definitio.patch
@@ -0,0 +1,65 @@
+From 1cf98919781b2ff8047a16b28778a59ef65570e6 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Fri, 21 Sep 2012 15:49:29 +0200
+Subject: [PATCH 6/9] atmel_nand: port to 2.6.39. modify function definition
+ of read_page()/write_page() and remove ecc.strength.
+
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ drivers/mtd/nand/atmel_nand.c | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index a6fa5c1..8483d29 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -755,7 +755,7 @@ normal_check:
+ }
+
+ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
+- struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
++ struct nand_chip *chip, uint8_t *buf, int page)
+ {
+ struct atmel_nand_host *host = chip->priv;
+ int eccsize = chip->ecc.size;
+@@ -792,8 +792,8 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
+ return 0;
+ }
+
+-static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
+- struct nand_chip *chip, const uint8_t *buf, int oob_required)
++static void atmel_nand_pmecc_write_page(struct mtd_info *mtd,
++ struct nand_chip *chip, const uint8_t *buf)
+ {
+ struct atmel_nand_host *host = chip->priv;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
+@@ -815,7 +815,7 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
+ while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) {
+ if (unlikely(time_after(jiffies, end_time))) {
+ dev_err(host->dev, "PMECC: Timeout to get ECC value.\n");
+- return -EIO;
++ return;
+ }
+ cpu_relax();
+ }
+@@ -831,7 +831,7 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
+ }
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+- return 0;
++ return;
+ }
+
+ static void atmel_pmecc_core_init(struct mtd_info *mtd)
+@@ -957,7 +957,6 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
+ host->pmecc_lookup_table_offset;
+
+ nand_chip->ecc.steps = 1;
+- nand_chip->ecc.strength = cap;
+ nand_chip->ecc.bytes = host->pmecc_bytes_per_sector *
+ host->pmecc_sector_number;
+ if (nand_chip->ecc.bytes > mtd->oobsize - 2) {
+--
+1.7.9.5
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0007-atmel_nand-pass-the-pmecc-parameter-from-board-file-.patch b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0007-atmel_nand-pass-the-pmecc-parameter-from-board-file-.patch
new file mode 100644
index 0000000..2d7536e
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0007-atmel_nand-pass-the-pmecc-parameter-from-board-file-.patch
@@ -0,0 +1,86 @@
+From e7e9c9948a0dfac51cb88426f73001763ea79322 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Wed, 26 Dec 2012 16:10:27 +0800
+Subject: [PATCH 7/9] atmel_nand: pass the pmecc parameter from board file to
+ driver.
+
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ arch/arm/mach-at91/include/mach/board.h | 4 ++++
+ drivers/mtd/nand/atmel_nand.c | 37 +++++++++++++++++++++++++++++++
+ 2 files changed, 41 insertions(+)
+
+diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
+index 392a7b3..8c25c35 100644
+--- a/arch/arm/mach-at91/include/mach/board.h
++++ b/arch/arm/mach-at91/include/mach/board.h
+@@ -118,6 +118,10 @@ struct atmel_nand_data {
+ u8 bus_width_16; /* buswidth is 16 bit */
+ u8 bus_on_d0; /* pins of data bus are connected to D0~D15 */
+ u8 ecc_mode; /* can be NAND_ECC_HW/SOFT/NONE */
++ bool has_pmecc; /* use pmecc or not */
++ u8 pmecc_corr_cap; /* pmecc ecc bits, can be 2, 4, 8, 12, 24 */
++ u16 pmecc_sector_size; /* can be 512 or 1024 */
++ u32 pmecc_lookup_table_offset; /* offset in ROM */
+ struct mtd_partition* (*partition_info)(int, int*);
+ };
+ extern void __init at91_add_device_nand(struct atmel_nand_data *data);
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index 8483d29..f381f03 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -1314,6 +1314,42 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ nand_chip->dev_ready = atmel_nand_device_ready;
+
+ nand_chip->ecc.mode = host->board->ecc_mode;
++
++ /* Initialize HW ECC parameters */
++ host->has_pmecc = host->board->has_pmecc;
++ host->pmecc_corr_cap = host->board->pmecc_corr_cap;
++ host->pmecc_sector_size = host->board->pmecc_sector_size;
++ host->pmecc_lookup_table_offset =
++ host->board->pmecc_lookup_table_offset;
++
++ /* sanity check for the pmecc parameters */
++ if (nand_chip->ecc.mode == NAND_ECC_HW && host->has_pmecc) {
++ res = 0;
++ if (host->pmecc_corr_cap != 2 && host->pmecc_corr_cap != 4 &&
++ host->pmecc_corr_cap != 8 &&
++ host->pmecc_corr_cap != 12 &&
++ host->pmecc_corr_cap != 24) {
++ dev_err(host->dev, "Invalid PMECC correction bits: %d! Only support 2, 4, 8, 12, 24.\n",
++ host->pmecc_corr_cap);
++ res = -EINVAL;
++ }
++
++ if (host->pmecc_sector_size != 512 &&
++ host->pmecc_sector_size != 1024) {
++ dev_err(host->dev, "Invalid PMECC sector size: %d! Only support 512 and 1024.\n",
++ host->pmecc_sector_size);
++ res = -EINVAL;
++ }
++
++ if (!host->pmecc_lookup_table_offset) {
++ dev_err(host->dev, "Invalid PMECC lookup table offset.\n");
++ res = -EINVAL;
++ }
++
++ if (res == -EINVAL)
++ goto err_bad_pmecc;
++ }
++
+ nand_chip->chip_delay = 20; /* 20us command delay time */
+
+ if (host->board->bus_width_16) /* 16-bit bus width */
+@@ -1426,6 +1462,7 @@ err_no_card:
+ platform_set_drvdata(pdev, NULL);
+ if (host->dma_chan)
+ dma_release_channel(host->dma_chan);
++err_bad_pmecc:
+ iounmap(host->io_base);
+ err_nand_ioremap:
+ kfree(host);
+--
+1.7.9.5
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0008-atmel_nand-9x5ek-enable-PMECC-in-9x5ek-board.patch b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0008-atmel_nand-9x5ek-enable-PMECC-in-9x5ek-board.patch
new file mode 100644
index 0000000..57627bd
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0008-atmel_nand-9x5ek-enable-PMECC-in-9x5ek-board.patch
@@ -0,0 +1,38 @@
+From a012c64fa08e8f334edb944b4810f58cef3382d6 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Mon, 25 Jun 2012 18:07:43 +0800
+Subject: [PATCH 8/9] atmel_nand: 9x5ek: enable PMECC in 9x5ek board.
+
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ arch/arm/mach-at91/board-sam9x5cm.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/arch/arm/mach-at91/board-sam9x5cm.c b/arch/arm/mach-at91/board-sam9x5cm.c
+index a5f8f3d..3a78876 100644
+--- a/arch/arm/mach-at91/board-sam9x5cm.c
++++ b/arch/arm/mach-at91/board-sam9x5cm.c
+@@ -14,6 +14,7 @@
+ #include <linux/init.h>
+ #include <linux/mm.h>
+ #include <linux/module.h>
++#include <linux/mtd/nand.h>
+ #include <linux/platform_device.h>
+ #include <linux/spi/flash.h>
+ #include <linux/spi/spi.h>
+@@ -132,6 +133,11 @@ static struct atmel_nand_data __initdata cm_nand_data = {
+ .ale = 21,
+ .cle = 22,
+ .enable_pin = AT91_PIN_PD4,
++ .ecc_mode = NAND_ECC_HW,
++ .has_pmecc = 1,
++ .pmecc_corr_cap = 2,
++ .pmecc_sector_size = 512,
++ .pmecc_lookup_table_offset = 0x8000,
+ .partition_info = nand_partitions,
+ #if defined(CONFIG_MTD_NAND_AT91_BUSWIDTH_16)
+ .bus_width_16 = 1,
+--
+1.7.9.5
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0009-atmel_nand-enable-dma-for-9x5ek.patch b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0009-atmel_nand-enable-dma-for-9x5ek.patch
new file mode 100644
index 0000000..29f0ae0
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/9x5_pmecc_2639/0009-atmel_nand-enable-dma-for-9x5ek.patch
@@ -0,0 +1,28 @@
+From cc9b17713c8ae2cd06fb7b371f688ae33506e4a0 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Wed, 26 Dec 2012 16:03:42 +0800
+Subject: [PATCH 9/9] atmel_nand: enable dma for 9x5ek.
+
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ drivers/mtd/nand/atmel_nand.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index f381f03..73d20f2 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -121,7 +121,8 @@ static struct nand_ecclayout atmel_pmecc_oobinfo;
+
+ static int cpu_has_dma(void)
+ {
+- return cpu_is_at91sam9rl() || cpu_is_at91sam9g45();
++ return cpu_is_at91sam9rl() || cpu_is_at91sam9g45()
++ || cpu_is_at91sam9x5();
+ }
+
+ /*
+--
+1.7.9.5
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/linux-2.6.39.4-atmel_serial_disable_hwhs.patch b/multitech/recipes/linux/linux-2.6.39.4/linux-2.6.39.4-atmel_serial_disable_hwhs.patch
new file mode 100644
index 0000000..88fd8d5
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/linux-2.6.39.4-atmel_serial_disable_hwhs.patch
@@ -0,0 +1,32 @@
+Revert commit 8e706c4d0dab214c625a2df84a0ca69a76bae65d in linux-2.6:
+ avr32: add hardware handshake support to atmel_serial
+
+Reverting commit since it breaks hardware flow control for at91sam9g20
+
+diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
+index 9d948bc..b659f2c 100644
+--- a/drivers/tty/serial/atmel_serial.c
++++ b/drivers/tty/serial/atmel_serial.c
+@@ -1020,8 +1020,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
+
+ /* Get current mode register */
+ mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL
+- | ATMEL_US_NBSTOP | ATMEL_US_PAR
+- | ATMEL_US_USMODE);
++ | ATMEL_US_NBSTOP | ATMEL_US_PAR);
+
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+ quot = uart_get_divisor(port, baud);
+@@ -1066,12 +1065,6 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
+ } else
+ mode |= ATMEL_US_PAR_NONE;
+
+- /* hardware handshake (RTS/CTS) */
+- if (termios->c_cflag & CRTSCTS)
+- mode |= ATMEL_US_USMODE_HWHS;
+- else
+- mode |= ATMEL_US_USMODE_NORMAL;
+-
+ spin_lock_irqsave(&port->lock, flags);
+
+ port->read_status_mask = ATMEL_US_OVRE;
diff --git a/multitech/recipes/linux/linux-2.6.39.4/linux-2.6.39.4-ledtrig-netdev.patch b/multitech/recipes/linux/linux-2.6.39.4/linux-2.6.39.4-ledtrig-netdev.patch
new file mode 100644
index 0000000..ab4c91b
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/linux-2.6.39.4-ledtrig-netdev.patch
@@ -0,0 +1,488 @@
+Index: linux-2.6.39.4/drivers/leds/Kconfig
+===================================================================
+--- linux-2.6.39.4.orig/drivers/leds/Kconfig 2011-08-03 14:43:28.000000000 -0500
++++ linux-2.6.39.4/drivers/leds/Kconfig 2012-12-18 13:27:23.579027264 -0600
+@@ -417,6 +417,13 @@
+ load average.
+ If unsure, say Y.
+
++config LEDS_TRIGGER_NETDEV
++ tristate "LED Network Device Trigger"
++ depends on LEDS_TRIGGERS
++ help
++ This allows LEDs to be controlled by Network Device activity.
++ If unsure, say Y.
++
+ config LEDS_TRIGGER_BACKLIGHT
+ tristate "LED backlight Trigger"
+ depends on LEDS_TRIGGERS
+Index: linux-2.6.39.4/drivers/leds/Makefile
+===================================================================
+--- linux-2.6.39.4.orig/drivers/leds/Makefile 2011-08-03 14:43:28.000000000 -0500
++++ linux-2.6.39.4/drivers/leds/Makefile 2012-12-18 13:27:23.579027264 -0600
+@@ -50,6 +50,7 @@
+ obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
+ obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o
+ obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
++obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o
+ obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o
+ obj-$(CONFIG_LEDS_TRIGGER_GPIO) += ledtrig-gpio.o
+ obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
+Index: linux-2.6.39.4/drivers/leds/ledtrig-netdev.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.39.4/drivers/leds/ledtrig-netdev.c 2012-12-18 14:40:30.078735442 -0600
+@@ -0,0 +1,453 @@
++/*
++ * LED Kernel Netdev Trigger
++ *
++ * Toggles the LED to reflect the link and traffic state of a named net device
++ *
++ * Copyright 2007 Oliver Jowett <oliver@opencloud.com>
++ *
++ * Derived from ledtrig-timer.c which is:
++ * Copyright 2005-2006 Openedhand Ltd.
++ * Author: Richard Purdie <rpurdie@openedhand.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/module.h>
++#include <linux/jiffies.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/spinlock.h>
++#include <linux/device.h>
++#include <linux/sysdev.h>
++#include <linux/netdevice.h>
++#include <linux/timer.h>
++#include <linux/ctype.h>
++#include <linux/leds.h>
++#include <linux/version.h>
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
++#include <net/net_namespace.h>
++#endif
++
++#include "leds.h"
++
++/*
++ * Configurable sysfs attributes:
++ *
++ * device_name - network device name to monitor
++ *
++ * interval - duration of LED blink, in milliseconds
++ *
++ * mode - either "none" (LED is off) or a space separated list of one or more of:
++ * link: LED's normal state reflects whether the link is up (has carrier) or not
++ * tx: LED blinks on transmitted data
++ * rx: LED blinks on receive data
++ *
++ * Some suggestions:
++ *
++ * Simple link status LED:
++ * $ echo netdev >someled/trigger
++ * $ echo eth0 >someled/device_name
++ * $ echo link >someled/mode
++ *
++ * Ethernet-style link/activity LED:
++ * $ echo netdev >someled/trigger
++ * $ echo eth0 >someled/device_name
++ * $ echo "link tx rx" >someled/mode
++ *
++ * Modem-style tx/rx LEDs:
++ * $ echo netdev >led1/trigger
++ * $ echo ppp0 >led1/device_name
++ * $ echo tx >led1/mode
++ * $ echo netdev >led2/trigger
++ * $ echo ppp0 >led2/device_name
++ * $ echo rx >led2/mode
++ *
++ */
++
++#define MODE_LINK 1
++#define MODE_TX 2
++#define MODE_RX 4
++
++struct led_netdev_data {
++ rwlock_t lock;
++
++ struct timer_list timer;
++ struct notifier_block notifier;
++
++ struct led_classdev *led_cdev;
++ struct net_device *net_dev;
++
++ char device_name[IFNAMSIZ];
++ unsigned interval;
++ unsigned mode;
++ unsigned link_up;
++ unsigned last_activity;
++};
++
++static void set_baseline_state(struct led_netdev_data *trigger_data)
++{
++ if ((trigger_data->mode & MODE_LINK) != 0 && trigger_data->link_up)
++ led_set_brightness(trigger_data->led_cdev, LED_FULL);
++ else
++ led_set_brightness(trigger_data->led_cdev, LED_OFF);
++
++ if ((trigger_data->mode & (MODE_TX | MODE_RX)) != 0 && trigger_data->link_up)
++ mod_timer(&trigger_data->timer, jiffies + trigger_data->interval);
++ else
++ del_timer(&trigger_data->timer);
++}
++
++static ssize_t led_device_name_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct led_classdev *led_cdev = dev_get_drvdata(dev);
++ struct led_netdev_data *trigger_data = led_cdev->trigger_data;
++
++ read_lock(&trigger_data->lock);
++ sprintf(buf, "%s\n", trigger_data->device_name);
++ read_unlock(&trigger_data->lock);
++
++ return strlen(buf) + 1;
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
++extern struct net init_net;
++#endif
++
++static ssize_t led_device_name_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ struct led_classdev *led_cdev = dev_get_drvdata(dev);
++ struct led_netdev_data *trigger_data = led_cdev->trigger_data;
++
++ if (size < 0 || size >= IFNAMSIZ)
++ return -EINVAL;
++
++ write_lock(&trigger_data->lock);
++
++ strcpy(trigger_data->device_name, buf);
++ if (size > 0 && trigger_data->device_name[size-1] == '\n')
++ trigger_data->device_name[size-1] = 0;
++
++ if (trigger_data->device_name[0] != 0) {
++ /* check for existing device to update from */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
++ trigger_data->net_dev = dev_get_by_name(&init_net, trigger_data->device_name);
++#else
++ trigger_data->net_dev = dev_get_by_name(trigger_data->device_name);
++#endif
++ if (trigger_data->net_dev != NULL)
++ trigger_data->link_up = (dev_get_flags(trigger_data->net_dev) & IFF_LOWER_UP) != 0;
++ set_baseline_state(trigger_data); /* updates LEDs, may start timers */
++ }
++
++ write_unlock(&trigger_data->lock);
++ return size;
++}
++
++static DEVICE_ATTR(device_name, 0644, led_device_name_show, led_device_name_store);
++
++static ssize_t led_mode_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct led_classdev *led_cdev = dev_get_drvdata(dev);
++ struct led_netdev_data *trigger_data = led_cdev->trigger_data;
++
++ read_lock(&trigger_data->lock);
++
++ if (trigger_data->mode == 0) {
++ strcpy(buf, "none\n");
++ } else {
++ if (trigger_data->mode & MODE_LINK)
++ strcat(buf, "link ");
++ if (trigger_data->mode & MODE_TX)
++ strcat(buf, "tx ");
++ if (trigger_data->mode & MODE_RX)
++ strcat(buf, "rx ");
++ strcat(buf, "\n");
++ }
++
++ read_unlock(&trigger_data->lock);
++
++ return strlen(buf)+1;
++}
++
++static ssize_t led_mode_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ struct led_classdev *led_cdev = dev_get_drvdata(dev);
++ struct led_netdev_data *trigger_data = led_cdev->trigger_data;
++ char copybuf[1024];
++ int new_mode = -1;
++ char *p, *token;
++
++ /* take a copy since we don't want to trash the inbound buffer when using strsep */
++ strncpy(copybuf, buf, sizeof(copybuf));
++ copybuf[1023] = 0;
++ p = copybuf;
++
++ while ((token = strsep(&p, " \t\n")) != NULL) {
++ if (!*token)
++ continue;
++
++ if (new_mode == -1)
++ new_mode = 0;
++
++ if (!strcmp(token, "none"))
++ new_mode = 0;
++ else if (!strcmp(token, "tx"))
++ new_mode |= MODE_TX;
++ else if (!strcmp(token, "rx"))
++ new_mode |= MODE_RX;
++ else if (!strcmp(token, "link"))
++ new_mode |= MODE_LINK;
++ else
++ return -EINVAL;
++ }
++
++ if (new_mode == -1)
++ return -EINVAL;
++
++ write_lock(&trigger_data->lock);
++ trigger_data->mode = new_mode;
++ set_baseline_state(trigger_data);
++ write_unlock(&trigger_data->lock);
++
++ return size;
++}
++
++static DEVICE_ATTR(mode, 0644, led_mode_show, led_mode_store);
++
++static ssize_t led_interval_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct led_classdev *led_cdev = dev_get_drvdata(dev);
++ struct led_netdev_data *trigger_data = led_cdev->trigger_data;
++
++ read_lock(&trigger_data->lock);
++ sprintf(buf, "%u\n", jiffies_to_msecs(trigger_data->interval));
++ read_unlock(&trigger_data->lock);
++
++ return strlen(buf) + 1;
++}
++
++static ssize_t led_interval_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ struct led_classdev *led_cdev = dev_get_drvdata(dev);
++ struct led_netdev_data *trigger_data = led_cdev->trigger_data;
++ int ret = -EINVAL;
++ char *after;
++ unsigned long value = simple_strtoul(buf, &after, 10);
++ size_t count = after - buf;
++
++ if (*after && isspace(*after))
++ count++;
++
++ /* impose some basic bounds on the timer interval */
++ if (count == size && value >= 5 && value <= 10000) {
++ write_lock(&trigger_data->lock);
++ trigger_data->interval = msecs_to_jiffies(value);
++ set_baseline_state(trigger_data); // resets timer
++ write_unlock(&trigger_data->lock);
++ ret = count;
++ }
++
++ return ret;
++}
++
++static DEVICE_ATTR(interval, 0644, led_interval_show, led_interval_store);
++
++static int netdev_trig_notify(struct notifier_block *nb,
++ unsigned long evt,
++ void *dv)
++{
++ struct net_device *dev = dv;
++ struct led_netdev_data *trigger_data = container_of(nb, struct led_netdev_data, notifier);
++
++ if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER)
++ return NOTIFY_DONE;
++
++ write_lock(&trigger_data->lock);
++
++ if (strcmp(dev->name, trigger_data->device_name))
++ goto done;
++
++ if (evt == NETDEV_REGISTER) {
++ if (trigger_data->net_dev != NULL)
++ dev_put(trigger_data->net_dev);
++ dev_hold(dev);
++ trigger_data->net_dev = dev;
++ trigger_data->link_up = 0;
++ goto done;
++ }
++
++ if (evt == NETDEV_UNREGISTER && trigger_data->net_dev != NULL) {
++ dev_put(trigger_data->net_dev);
++ trigger_data->net_dev = NULL;
++ goto done;
++ }
++
++ /* UP / DOWN / CHANGE */
++
++ trigger_data->link_up = (evt != NETDEV_DOWN && netif_carrier_ok(dev));
++ set_baseline_state(trigger_data);
++
++done:
++ write_unlock(&trigger_data->lock);
++ return NOTIFY_DONE;
++}
++
++/* here's the real work! */
++static void netdev_trig_timer(unsigned long arg)
++{
++ struct led_netdev_data *trigger_data = (struct led_netdev_data *)arg;
++ unsigned new_activity;
++
++ struct rtnl_link_stats64 *dev_stats;
++ struct rtnl_link_stats64 temp;
++
++ write_lock(&trigger_data->lock);
++
++ if (!trigger_data->link_up || !trigger_data->net_dev || (trigger_data->mode & (MODE_TX | MODE_RX)) == 0) {
++ /* we don't need to do timer work, just reflect link state. */
++ led_set_brightness(trigger_data->led_cdev, ((trigger_data->mode & MODE_LINK) != 0 && trigger_data->link_up) ? LED_FULL : LED_OFF);
++ goto no_restart;
++ }
++
++ dev_stats = dev_get_stats(trigger_data->net_dev, &temp);
++ new_activity =
++ ((trigger_data->mode & MODE_TX) ? dev_stats->tx_packets : 0) +
++ ((trigger_data->mode & MODE_RX) ? dev_stats->rx_packets : 0);
++
++ if (trigger_data->mode & MODE_LINK) {
++ /* base state is ON (link present) */
++ /* if there's no link, we don't get this far and the LED is off */
++
++ /* OFF -> ON always */
++ /* ON -> OFF on activity */
++ if (trigger_data->led_cdev->brightness == LED_OFF) {
++ led_set_brightness(trigger_data->led_cdev, LED_FULL);
++ } else if (trigger_data->last_activity != new_activity) {
++ led_set_brightness(trigger_data->led_cdev, LED_OFF);
++ }
++ } else {
++ /* base state is OFF */
++ /* ON -> OFF always */
++ /* OFF -> ON on activity */
++ if (trigger_data->led_cdev->brightness == LED_FULL) {
++ led_set_brightness(trigger_data->led_cdev, LED_OFF);
++ } else if (trigger_data->last_activity != new_activity) {
++ led_set_brightness(trigger_data->led_cdev, LED_FULL);
++ }
++ }
++
++ trigger_data->last_activity = new_activity;
++ mod_timer(&trigger_data->timer, jiffies + trigger_data->interval);
++
++no_restart:
++ write_unlock(&trigger_data->lock);
++}
++
++static void netdev_trig_activate(struct led_classdev *led_cdev)
++{
++ struct led_netdev_data *trigger_data;
++ int rc;
++
++ trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL);
++ if (!trigger_data)
++ return;
++
++ rwlock_init(&trigger_data->lock);
++
++ trigger_data->notifier.notifier_call = netdev_trig_notify;
++ trigger_data->notifier.priority = 10;
++
++ setup_timer(&trigger_data->timer, netdev_trig_timer, (unsigned long) trigger_data);
++
++ trigger_data->led_cdev = led_cdev;
++ trigger_data->net_dev = NULL;
++ trigger_data->device_name[0] = 0;
++
++ trigger_data->mode = 0;
++ trigger_data->interval = msecs_to_jiffies(50);
++ trigger_data->link_up = 0;
++ trigger_data->last_activity = 0;
++
++ led_cdev->trigger_data = trigger_data;
++
++ rc = device_create_file(led_cdev->dev, &dev_attr_device_name);
++ if (rc)
++ goto err_out;
++ rc = device_create_file(led_cdev->dev, &dev_attr_mode);
++ if (rc)
++ goto err_out_device_name;
++ rc = device_create_file(led_cdev->dev, &dev_attr_interval);
++ if (rc)
++ goto err_out_mode;
++
++ register_netdevice_notifier(&trigger_data->notifier);
++ return;
++
++err_out_mode:
++ device_remove_file(led_cdev->dev, &dev_attr_mode);
++err_out_device_name:
++ device_remove_file(led_cdev->dev, &dev_attr_device_name);
++err_out:
++ led_cdev->trigger_data = NULL;
++ kfree(trigger_data);
++}
++
++static void netdev_trig_deactivate(struct led_classdev *led_cdev)
++{
++ struct led_netdev_data *trigger_data = led_cdev->trigger_data;
++
++ if (trigger_data) {
++ unregister_netdevice_notifier(&trigger_data->notifier);
++
++ device_remove_file(led_cdev->dev, &dev_attr_device_name);
++ device_remove_file(led_cdev->dev, &dev_attr_mode);
++ device_remove_file(led_cdev->dev, &dev_attr_interval);
++
++ write_lock(&trigger_data->lock);
++
++ if (trigger_data->net_dev) {
++ dev_put(trigger_data->net_dev);
++ trigger_data->net_dev = NULL;
++ }
++
++ write_unlock(&trigger_data->lock);
++
++ del_timer_sync(&trigger_data->timer);
++
++ kfree(trigger_data);
++ }
++}
++
++static struct led_trigger netdev_led_trigger = {
++ .name = "netdev",
++ .activate = netdev_trig_activate,
++ .deactivate = netdev_trig_deactivate,
++};
++
++static int __init netdev_trig_init(void)
++{
++ return led_trigger_register(&netdev_led_trigger);
++}
++
++static void __exit netdev_trig_exit(void)
++{
++ led_trigger_unregister(&netdev_led_trigger);
++}
++
++module_init(netdev_trig_init);
++module_exit(netdev_trig_exit);
++
++MODULE_AUTHOR("Oliver Jowett <oliver@opencloud.com>");
++MODULE_DESCRIPTION("Netdev LED trigger");
++MODULE_LICENSE("GPL");
diff --git a/multitech/recipes/linux/linux-2.6.39.4/linux-2.6.39.4-option-telit.patch b/multitech/recipes/linux/linux-2.6.39.4/linux-2.6.39.4-option-telit.patch
new file mode 100644
index 0000000..0a4baa1
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/linux-2.6.39.4-option-telit.patch
@@ -0,0 +1,43 @@
+From 7204cf584836c24b4b06e4ad4a8e6bb8ea84908e Mon Sep 17 00:00:00 2001
+From: Daniele Palmas <dnlplm@gmail.com>
+Date: Wed, 29 Feb 2012 15:32:05 +0100
+Subject: [PATCH] USB: option driver: adding support for Telit CC864-SINGLE,
+ CC864-DUAL and DE910-DUAL modems
+
+Adding PID for Telit CC864-SINGLE, CC864-DUAL and DE910-DUAL
+modems
+
+Signed-off-by: Daniele Palmas <dnlplm@gmail.com>
+Cc: stable <stable@vger.kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/serial/option.c | 6 ++++++
+ 1 files changed, 6 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
+index 005511b..f9b11fb 100644
+--- a/drivers/usb/serial/option.c
++++ b/drivers/usb/serial/option.c
+@@ -307,6 +307,9 @@ static void option_instat_callback(struct urb *urb);
+ #define TELIT_VENDOR_ID 0x1bc7
+ #define TELIT_PRODUCT_UC864E 0x1003
+ #define TELIT_PRODUCT_UC864G 0x1004
++#define TELIT_PRODUCT_CC864_DUAL 0x1005
++#define TELIT_PRODUCT_CC864_SINGLE 0x1006
++#define TELIT_PRODUCT_DE910_DUAL 0x1010
+
+ /* ZTE PRODUCTS */
+ #define ZTE_VENDOR_ID 0x19d2
+@@ -771,6 +774,9 @@ static const struct usb_device_id option_ids[] = {
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6008) },
+ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) },
+ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864G) },
++ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_DUAL) },
++ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) },
++ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
+--
+1.7.7.6
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/defconfig b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/defconfig
new file mode 100644
index 0000000..0afdbee
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/defconfig
@@ -0,0 +1,2328 @@
+#
+# Automatically generated make config: don't edit
+# Linux/arm 2.6.39.4 Kernel Configuration
+# Tue Feb 12 17:21:58 2013
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_KTIME_SCALAR=y
+CONFIG_HAVE_PROC_CPU=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_CPU_IDLE_WAIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_VECTORS_BASE=0xffff0000
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+CONFIG_HAVE_IRQ_WORK=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=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 is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_FHANDLE is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_HAVE_SPARSE_IRQ=y
+CONFIG_GENERIC_IRQ_SHOW=y
+# CONFIG_SPARSE_IRQ is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TINY_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+# CONFIG_CGROUP_NS is not set
+# CONFIG_CGROUP_FREEZER is not set
+# CONFIG_CGROUP_DEVICE is not set
+# CONFIG_CPUSETS is not set
+# CONFIG_CGROUP_CPUACCT is not set
+# CONFIG_RESOURCE_COUNTERS is not set
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_BLK_CGROUP=y
+# CONFIG_DEBUG_BLK_CGROUP is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+# CONFIG_SCHED_AUTOGROUP is not set
+# 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=y
+CONFIG_RD_LZMA=y
+CONFIG_RD_XZ=y
+CONFIG_RD_LZO=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EXPERT=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+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_EMBEDDED=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+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_DMA_API_DEBUG=y
+
+#
+# GCOV-based kernel profiling
+#
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+CONFIG_BLK_DEV_BSG=y
+# CONFIG_BLK_DEV_INTEGRITY is not set
+# CONFIG_BLK_DEV_THROTTLING is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CFQ_GROUP_IOSCHED is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+# 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=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# 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=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# 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=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# 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_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=y
+# 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_MXS 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_EXYNOS4 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_TCC_926 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 is not set
+# CONFIG_PLAT_SPEAR is not set
+# CONFIG_ARCH_VT8500 is not set
+
+#
+# Atmel AT91 System-on-Chip
+#
+# CONFIG_ARCH_AT91RM9200 is not set
+# CONFIG_ARCH_AT91SAM9260 is not set
+# CONFIG_ARCH_AT91SAM9261 is not set
+# CONFIG_ARCH_AT91SAM9G10 is not set
+# CONFIG_ARCH_AT91SAM9263 is not set
+# CONFIG_ARCH_AT91SAM9RL is not set
+# CONFIG_ARCH_AT91SAM9G20 is not set
+# CONFIG_ARCH_AT91SAM9G45 is not set
+CONFIG_ARCH_AT91SAM9X5=y
+# CONFIG_ARCH_AT91CAP9 is not set
+# CONFIG_ARCH_AT572D940HF is not set
+# CONFIG_ARCH_AT91X40 is not set
+CONFIG_AT91_PMC_UNIT=y
+
+#
+# AT91SAM9x5 Series Board Type
+#
+CONFIG_MACH_AT91SAM9X5EK=y
+
+#
+# AT91 Board Options
+#
+
+#
+# AT91 Feature Selections
+#
+CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
+CONFIG_AT91_SLOW_CLOCK=y
+CONFIG_AT91_TIMER_HZ=100
+CONFIG_AT91_EARLY_DBGU=y
+# CONFIG_AT91_EARLY_USART0 is not set
+# CONFIG_AT91_EARLY_USART1 is not set
+# CONFIG_AT91_EARLY_USART2 is not set
+# CONFIG_GPIO_PCA953X is not set
+
+#
+# System MMU
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_LEGACY=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+CONFIG_CPU_USE_DOMAINS=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+CONFIG_ARM_L1_CACHE_SHIFT=5
+
+#
+# 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 is not set
+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=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+# 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=999999
+# CONFIG_COMPACTION is not set
+# 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_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
+CONFIG_UACCESS_WITH_MEMCPY=y
+# 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=" quiet "
+# CONFIG_CMDLINE_FORCE is not set
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+CONFIG_AUTO_ZRELADDR=y
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_PM_SLEEP=y
+# CONFIG_PM_RUNTIME is not set
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+# CONFIG_APM_EMULATION is not set
+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=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=y
+CONFIG_NET_IPGRE_DEMUX=y
+CONFIG_NET_IPGRE=y
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_XFRM_TUNNEL=y
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=y
+CONFIG_NETFILTER_NETLINK_QUEUE=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+# CONFIG_NF_CONNTRACK_TIMESTAMP is not set
+# CONFIG_NF_CT_PROTO_DCCP is not set
+CONFIG_NF_CT_PROTO_GRE=y
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CT_PROTO_UDPLITE is not set
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+# CONFIG_NF_CONNTRACK_IRC is not set
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_SNMP is not set
+CONFIG_NF_CONNTRACK_PPTP=y
+# CONFIG_NF_CONNTRACK_SANE is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+# CONFIG_NF_CONNTRACK_TFTP is not set
+# CONFIG_NF_CT_NETLINK is not set
+# CONFIG_NETFILTER_TPROXY is not set
+CONFIG_NETFILTER_XTABLES=y
+
+#
+# Xtables combined modules
+#
+CONFIG_NETFILTER_XT_MARK=y
+CONFIG_NETFILTER_XT_CONNMARK=y
+
+#
+# Xtables targets
+#
+# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+# CONFIG_NETFILTER_XT_TARGET_HL is not set
+# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set
+# CONFIG_NETFILTER_XT_TARGET_LED is not set
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+# CONFIG_NETFILTER_XT_TARGET_TEE is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
+
+#
+# Xtables matches
+#
+# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+# CONFIG_NETFILTER_XT_MATCH_CPU is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
+CONFIG_NETFILTER_XT_MATCH_HL=y
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+# CONFIG_NETFILTER_XT_MATCH_OSF is not set
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+CONFIG_NETFILTER_XT_MATCH_RECENT=y
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_IP_SET is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_AH is not set
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_LOG=y
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_NF_NAT=y
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_NF_NAT_PROTO_GRE=y
+CONFIG_NF_NAT_FTP=y
+# CONFIG_NF_NAT_IRC is not set
+# CONFIG_NF_NAT_TFTP is not set
+# CONFIG_NF_NAT_AMANDA is not set
+CONFIG_NF_NAT_PPTP=y
+CONFIG_NF_NAT_H323=y
+# CONFIG_NF_NAT_SIP is not set
+CONFIG_IP_NF_MANGLE=y
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_TTL is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+CONFIG_L2TP=y
+# CONFIG_L2TP_V3 is not set
+CONFIG_STP=m
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# 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 is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+# CONFIG_NET_SCH_CBQ is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_MULTIQ is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFB is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_SCH_DRR is not set
+# CONFIG_NET_SCH_MQPRIO is not set
+# CONFIG_NET_SCH_CHOKE is not set
+
+#
+# Classification
+#
+# CONFIG_NET_CLS_BASIC is not set
+# CONFIG_NET_CLS_TCINDEX is not set
+# CONFIG_NET_CLS_ROUTE4 is not set
+# CONFIG_NET_CLS_FW is not set
+# CONFIG_NET_CLS_U32 is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_CLS_FLOW is not set
+# CONFIG_NET_CLS_CGROUP is not set
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_DCB is not set
+CONFIG_DNS_RESOLVER=y
+# CONFIG_BATMAN_ADV is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+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 is not set
+CONFIG_BT_HCIUART=m
+# CONFIG_BT_HCIUART_H4 is not set
+# CONFIG_BT_HCIUART_BCSP is not set
+# CONFIG_BT_HCIUART_ATH3K is not set
+CONFIG_BT_HCIUART_LL=y
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_BT_MRVL is not set
+# CONFIG_BT_ATH3K is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_PRIV=y
+CONFIG_CFG80211=m
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+CONFIG_CFG80211_WEXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+CONFIG_LIB80211=m
+# CONFIG_LIB80211_DEBUG is not set
+CONFIG_MAC80211=m
+CONFIG_MAC80211_HAS_RC=y
+# CONFIG_MAC80211_RC_PID is not set
+CONFIG_MAC80211_RC_MINSTREL=y
+CONFIG_MAC80211_RC_MINSTREL_HT=y
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
+# CONFIG_MAC80211_MESH is not set
+CONFIG_MAC80211_LEDS=y
+# CONFIG_MAC80211_DEBUG_MENU is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB 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_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# 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 is not set
+# 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_NAND_ECC_BCH 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_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+CONFIG_MTD_NAND_ATMEL=y
+CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
+# CONFIG_MTD_NAND_ATMEL_ECC_NONE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# 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
+# 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 is not set
+
+#
+# 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=32768
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
+# CONFIG_BLK_DEV_RBD is not set
+# CONFIG_SENSORS_LIS3LV02D is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_AD525X_DPOT is not set
+CONFIG_ATMEL_TCLIB=y
+CONFIG_ATMEL_TCB_CLKSRC=y
+CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0
+CONFIG_ATMEL_TCB_CLKSRC_32BIT=y
+# CONFIG_ICS932S401 is not set
+CONFIG_ATMEL_SSC=y
+# 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 is not set
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_APDS990X is not set
+# CONFIG_HMC6352 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+# CONFIG_BMP085 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+CONFIG_EEPROM_AT24=y
+CONFIG_EEPROM_AT25=y
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+CONFIG_EEPROM_93CX6=m
+# CONFIG_IWMC3200TOP is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+# CONFIG_SENSORS_LIS3_SPI is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+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 is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+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 is not set
+# 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 is not set
+# CONFIG_ISCSI_BOOT_SYSFS is not set
+# 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 is not set
+# CONFIG_TARGET_CORE is not set
+CONFIG_HAVE_NET_MACB=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_VETH is not set
+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 is not set
+# 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 is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MACB=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMC911X is not set
+# CONFIG_SMSC911X 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_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_FTMAC100 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=m
+# CONFIG_ATH_DEBUG is not set
+CONFIG_ATH9K_HW=m
+CONFIG_ATH9K_COMMON=m
+CONFIG_ATH9K_HTC=m
+# CONFIG_AR9170_USB is not set
+CONFIG_CARL9170=m
+CONFIG_CARL9170_LEDS=y
+CONFIG_CARL9170_WPC=y
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_IWM is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_P54_COMMON is not set
+CONFIG_RT2X00=m
+CONFIG_RT2500USB=m
+CONFIG_RT73USB=m
+CONFIG_RT2800USB=m
+CONFIG_RT2800USB_RT33XX=y
+CONFIG_RT2800USB_RT35XX=y
+# CONFIG_RT2800USB_UNKNOWN is not set
+CONFIG_RT2800_LIB=m
+CONFIG_RT2X00_LIB_USB=m
+CONFIG_RT2X00_LIB=m
+CONFIG_RT2X00_LIB_HT=y
+CONFIG_RT2X00_LIB_FIRMWARE=y
+CONFIG_RT2X00_LIB_CRYPTO=y
+CONFIG_RT2X00_LIB_LEDS=y
+# CONFIG_RT2X00_DEBUG is not set
+CONFIG_RTL8192CU=m
+CONFIG_RTLWIFI=m
+CONFIG_RTL8192C_COMMON=m
+# CONFIG_WL1251 is not set
+CONFIG_WL12XX_MENU=m
+CONFIG_WL12XX=m
+# CONFIG_WL12XX_HT is not set
+# CONFIG_WL12XX_SPI is not set
+CONFIG_WL12XX_SDIO=m
+CONFIG_WL12XX_SDIO_TEST=m
+CONFIG_WL12XX_PLATFORM_DATA=y
+# CONFIG_ZD1211RW is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_CDCETHER=m
+CONFIG_USB_NET_CDC_EEM=m
+CONFIG_USB_NET_CDC_NCM=m
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_SMSC75XX=m
+CONFIG_USB_NET_SMSC95XX=m
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_NET1080=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_NET_RNDIS_HOST=m
+CONFIG_USB_NET_CDC_SUBSET=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_EPSON2888 is not set
+CONFIG_USB_KC2190=y
+CONFIG_USB_NET_ZAURUS=m
+CONFIG_USB_NET_CX82310_ETH=m
+CONFIG_USB_NET_INT51X1=m
+CONFIG_USB_IPHETH=m
+CONFIG_USB_SIERRA_NET=m
+CONFIG_USB_VL600=m
+# CONFIG_WAN is not set
+
+#
+# CAIF transport drivers
+#
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=y
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPTP is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=y
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=16
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+CONFIG_DEVKMEM=y
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+CONFIG_SERIAL_ATMEL_DMA=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
+# CONFIG_SERIAL_MAX3100 is not set
+# CONFIG_SERIAL_MAX3107 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_IFX6X60 is not set
+# CONFIG_TTY_PRINTK is not set
+# CONFIG_HVC_DCC is not set
+# 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 is not set
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOBIT=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+CONFIG_I2C_GPIO=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_PXA_PCI is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_DIOLAN_U2C is not set
+# 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_ALTERA is not set
+CONFIG_SPI_ATMEL=y
+CONFIG_SPI_ATMEL_DMA=y
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+# CONFIG_SPI_OC_TINY is not set
+# CONFIG_SPI_PXA2XX_PCI is not set
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_BASIC_MMIO is not set
+# CONFIG_GPIO_IT8761E is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_SX150X is not set
+# CONFIG_GPIO_ADP5588 is not set
+
+#
+# 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 is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_AT91SAM9X_WATCHDOG=y
+# CONFIG_MAX63XX_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_MFD_SUPPORT=y
+# CONFIG_MFD_CORE is not set
+# 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_TPS6105X is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC3589X 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_MAX8997 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 is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_REGULATOR is not set
+CONFIG_MEDIA_SUPPORT=m
+
+#
+# Multimedia core support
+#
+# CONFIG_MEDIA_CONTROLLER is not set
+CONFIG_VIDEO_DEV=m
+CONFIG_VIDEO_V4L2_COMMON=m
+# CONFIG_DVB_CORE is not set
+CONFIG_VIDEO_MEDIA=m
+
+#
+# Multimedia drivers
+#
+# CONFIG_RC_CORE is not set
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_MEDIA_TUNER=m
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+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_XC2028=m
+CONFIG_MEDIA_TUNER_XC5000=m
+CONFIG_MEDIA_TUNER_MC44S803=m
+CONFIG_VIDEO_V4L2=m
+CONFIG_VIDEOBUF_GEN=m
+CONFIG_VIDEOBUF_VMALLOC=m
+CONFIG_VIDEO_TVEEPROM=m
+CONFIG_VIDEO_TUNER=m
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_AT91SAM9X5 is not set
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+
+#
+# Audio decoders
+#
+CONFIG_VIDEO_MSP3400=m
+CONFIG_VIDEO_CS53L32A=m
+CONFIG_VIDEO_WM8775=m
+
+#
+# RDS decoders
+#
+
+#
+# Video decoders
+#
+CONFIG_VIDEO_SAA711X=m
+
+#
+# Video and audio decoders
+#
+CONFIG_VIDEO_CX25840=m
+
+#
+# MPEG video encoders
+#
+CONFIG_VIDEO_CX2341X=m
+
+#
+# Video encoders
+#
+
+#
+# Video improvement chips
+#
+# CONFIG_VIDEO_CPIA2 is not set
+# CONFIG_VIDEO_TIMBERDALE is not set
+# CONFIG_VIDEO_SR030PC30 is not set
+# CONFIG_VIDEO_NOON010PC30 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=m
+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=m
+# CONFIG_USB_GSPCA_KONICA is not set
+CONFIG_USB_GSPCA_MARS=m
+CONFIG_USB_GSPCA_MR97310A=m
+# CONFIG_USB_GSPCA_NW80X 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=m
+CONFIG_USB_GSPCA_PAC7311=m
+CONFIG_USB_GSPCA_SN9C2028=m
+CONFIG_USB_GSPCA_SN9C20X=m
+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 is not set
+CONFIG_USB_GSPCA_SQ905=m
+CONFIG_USB_GSPCA_SQ905C=m
+# CONFIG_USB_GSPCA_SQ930X is not set
+CONFIG_USB_GSPCA_STK014=m
+CONFIG_USB_GSPCA_STV0680=m
+CONFIG_USB_GSPCA_SUNPLUS=m
+CONFIG_USB_GSPCA_T613=m
+CONFIG_USB_GSPCA_TV8532=m
+CONFIG_USB_GSPCA_VC032X=m
+# CONFIG_USB_GSPCA_VICAM is not set
+# CONFIG_USB_GSPCA_XIRLINK_CIT is not set
+CONFIG_USB_GSPCA_ZC3XX=m
+CONFIG_VIDEO_PVRUSB2=m
+CONFIG_VIDEO_PVRUSB2_SYSFS=y
+# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set
+CONFIG_VIDEO_HDPVR=m
+CONFIG_VIDEO_USBVISION=m
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_USB_SN9C102 is not set
+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 is not set
+# CONFIG_RADIO_ADAPTERS is not set
+
+#
+# Graphics support
+#
+CONFIG_HAVE_FB_ATMEL=y
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+# CONFIG_HID_PID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_ELECOM is not set
+# CONFIG_HID_MAGICMOUSE is not set
+# CONFIG_HID_WACOM 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_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=y
+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=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# 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 is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_WDM=m
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_REALTEK 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_STORAGE_ENE_UB6250 is not set
+# CONFIG_USB_UAS is not set
+# 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=m
+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 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19QW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19QI is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49WLC is not set
+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=m
+CONFIG_USB_SERIAL_SPCP8X5=m
+CONFIG_USB_SERIAL_HP4X=m
+# CONFIG_USB_SERIAL_SAFE is not set
+CONFIG_USB_SERIAL_SAMBA=m
+CONFIG_USB_SERIAL_SIEMENS_MPI=m
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+CONFIG_USB_SERIAL_SYMBOL=m
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_WWAN=m
+CONFIG_USB_SERIAL_OPTION=m
+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 is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+CONFIG_USB_SEVSEG=m
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+CONFIG_USB_LCD=m
+CONFIG_USB_LED=m
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+CONFIG_USB_CYTHERM=m
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_YUREX is not set
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
+CONFIG_USB_GADGET_ATMEL_USBA=y
+CONFIG_USB_ATMEL_USBA=m
+# CONFIG_USB_GADGET_FUSB300 is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
+# CONFIG_USB_GADGET_PXA_U2O 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=m
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_ETH_EEM is not set
+# CONFIG_USB_G_NCM is not set
+CONFIG_USB_GADGETFS=m
+# CONFIG_USB_FUNCTIONFS is not set
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_G_SERIAL=m
+# 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 is not set
+# CONFIG_USB_G_DBGP is not set
+# CONFIG_USB_G_WEBCAM is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_USB_ULPI is not set
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+# CONFIG_MMC_CLKGATE is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_MINORS=8
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_AT91 is not set
+CONFIG_MMC_ATMELMCI=m
+# CONFIG_MMC_ATMELMCI_DMA is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_MMC_DW is not set
+# CONFIG_MMC_USHC is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_LM3530 is not set
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_LP5521 is not set
+# CONFIG_LEDS_LP5523 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_BD2802 is not set
+# CONFIG_LEDS_LT3593 is not set
+CONFIG_LEDS_TRIGGERS=y
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_NETDEV=y
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+# CONFIG_NFC_DEVICES is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# 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 is not set
+# 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 is not set
+# 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_RTC_DRV_AT91RM9200=y
+CONFIG_DMADEVICES=y
+# CONFIG_DMADEVICES_DEBUG is not set
+
+#
+# DMA Devices
+#
+# CONFIG_DW_DMAC is not set
+CONFIG_AT_HDMAC=y
+# CONFIG_TIMB_DMA is not set
+CONFIG_DMA_ENGINE=y
+
+#
+# DMA Clients
+#
+# CONFIG_NET_DMA is not set
+# CONFIG_ASYNC_TX_DMA is not set
+# CONFIG_DMATEST is not set
+# CONFIG_AUXDISPLAY is not set
+CONFIG_UIO=m
+CONFIG_UIO_PDRV=m
+CONFIG_UIO_PDRV_GENIRQ=m
+# CONFIG_STAGING 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=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY 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_JBD2=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+CONFIG_GENERIC_ACL=y
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# 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 is not set
+
+#
+# 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 is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ECRYPT_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_FS_WBUF_VERIFY=y
+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=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+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 is not set
+CONFIG_CRAMFS=y
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+CONFIG_ROMFS_FS=y
+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_PSTORE is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS 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 is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_CEPH_FS is not set
+CONFIG_CIFS=y
+# CONFIG_CIFS_STATS is not set
+# 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 is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_SECTION_MISMATCH 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 is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# 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=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# 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_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_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_DMA_API_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_STRICT_DEVMEM is not set
+CONFIG_ARM_UNWIND=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_EARLY_PRINTK is not set
+# CONFIG_DEBUG_ICEDCC 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_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=y
+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 is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=y
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+CONFIG_CRYPTO_SHA1=y
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ANUBIS=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_BLOWFISH=y
+# CONFIG_CRYPTO_CAMELLIA is not set
+CONFIG_CRYPTO_CAST5=y
+CONFIG_CRYPTO_CAST6=y
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_FCRYPT=y
+CONFIG_CRYPTO_KHAZAD=y
+CONFIG_CRYPTO_SALSA20=y
+CONFIG_CRYPTO_SEED=y
+CONFIG_CRYPTO_SERPENT=y
+CONFIG_CRYPTO_TEA=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_TWOFISH_COMMON=y
+
+#
+# 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_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+CONFIG_CRC7=m
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_XZ_DEC=y
+CONFIG_XZ_DEC_X86=y
+CONFIG_XZ_DEC_POWERPC=y
+CONFIG_XZ_DEC_IA64=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_ARMTHUMB=y
+CONFIG_XZ_DEC_SPARC=y
+CONFIG_XZ_DEC_BCJ=y
+# CONFIG_XZ_DEC_TEST is not set
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_DECOMPRESS_XZ=y
+CONFIG_DECOMPRESS_LZO=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
+CONFIG_AVERAGE=y
diff --git a/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-at91sam9_wdt-10second-timeout.patch b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-at91sam9_wdt-10second-timeout.patch
new file mode 100644
index 0000000..90c906c
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-at91sam9_wdt-10second-timeout.patch
@@ -0,0 +1,14 @@
+Index: linux-2.6.39.4/drivers/watchdog/at91sam9_wdt.c
+===================================================================
+--- linux-2.6.39.4.orig/drivers/watchdog/at91sam9_wdt.c 2013-01-16 14:33:37.565560189 -0600
++++ linux-2.6.39.4/drivers/watchdog/at91sam9_wdt.c 2013-01-16 14:34:26.531727425 -0600
+@@ -43,7 +43,8 @@
+ #define ticks_to_ms(t) (((t + 1) * 1000) >> 8)
+
+ /* Hardware timeout in seconds */
+-#define WDT_HW_TIMEOUT 2
++/* MTR: use longer timeout */
++#define WDT_HW_TIMEOUT 10
+
+ /* Timer heartbeat (500ms) */
+ #define WDT_TIMEOUT (HZ/2)
diff --git a/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-at91sam9x5-extreset.patch b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-at91sam9x5-extreset.patch
new file mode 100644
index 0000000..31b7441
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-at91sam9x5-extreset.patch
@@ -0,0 +1,16 @@
+Index: linux-2.6.39.4/arch/arm/mach-at91/at91sam9x5.c
+===================================================================
+--- linux-2.6.39.4.orig/arch/arm/mach-at91/at91sam9x5.c 2012-06-25 17:00:27.060489533 -0500
++++ linux-2.6.39.4/arch/arm/mach-at91/at91sam9x5.c 2012-06-25 17:00:33.051404086 -0500
+@@ -330,7 +330,10 @@
+
+ static void at91sam9x5_reset(void)
+ {
+- at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
++ // MTR: generate an external reset (assert the NRST pin) on soft reset
++ // set reset duration to 125 ms --> set ERSTL to 0xb (0xb = 11 = 2^12 slow clock cycles = 4096 clocks = 125 ms)
++ at91_sys_write(AT91_RSTC_MR, AT91_RSTC_KEY | (0xb << 8));
++ at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST | AT91_RSTC_EXTRST);
+ }
+
+ static void at91sam9x5_poweroff(void)
diff --git a/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-atmel-mci-force-detect.patch b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-atmel-mci-force-detect.patch
new file mode 100644
index 0000000..d59a7cc
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-atmel-mci-force-detect.patch
@@ -0,0 +1,30 @@
+Index: linux-2.6.39.4/drivers/mmc/host/atmel-mci.c
+===================================================================
+--- linux-2.6.39.4.orig/drivers/mmc/host/atmel-mci.c 2012-05-10 11:44:02.069173755 -0500
++++ linux-2.6.39.4/drivers/mmc/host/atmel-mci.c 2012-05-11 11:21:42.119198300 -0500
+@@ -1059,6 +1059,10 @@
+ dev_dbg(&mmc->class_dev, "card is %spresent\n",
+ present ? "" : "not ");
+ }
++ else {
++ // jjg - assume card is present if detect pin is unset
++ present = 1;
++ }
+
+ return present;
+ }
+@@ -1655,8 +1659,12 @@
+ }
+ }
+
+- if (!gpio_is_valid(slot->detect_pin))
+- mmc->caps |= MMC_CAP_NEEDS_POLL;
++ // jjg - if detect pin isn't set, don't poll -- just assume device
++ // is there and mark it non-removable
++ if (!gpio_is_valid(slot->detect_pin)) {
++ dev_info(&host->pdev->dev,"No detect pin, marking non-removable and assuming device is present\n");
++ mmc->caps |= MMC_CAP_NONREMOVABLE;
++ }
+
+ if (gpio_is_valid(slot->wp_pin)) {
+ if (gpio_request(slot->wp_pin, "mmc_wp")) {
diff --git a/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-macb-force-link.patch b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-macb-force-link.patch
new file mode 100644
index 0000000..196a549
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-macb-force-link.patch
@@ -0,0 +1,75 @@
+Index: linux-2.6.39.4/drivers/net/macb.c
+===================================================================
+--- linux-2.6.39.4.orig/drivers/net/macb.c 2011-08-03 14:43:28.000000000 -0500
++++ linux-2.6.39.4/drivers/net/macb.c 2012-06-01 11:15:43.029717836 -0500
+@@ -193,7 +193,9 @@
+ struct eth_platform_data *pdata;
+ int ret;
+
+- phydev = phy_find_first(bp->mii_bus);
++ // MTR2: use phy 5
++ //phydev = phy_find_first(bp->mii_bus);
++ phydev = bp->mii_bus->phy_map[5];
+ if (!phydev) {
+ printk (KERN_ERR "%s: no PHY found\n", dev->name);
+ return -1;
+@@ -203,14 +205,19 @@
+ /* TODO : add pin_irq */
+
+ /* attach the mac to the phy */
+- ret = phy_connect_direct(dev, phydev, &macb_handle_link_change, 0,
++ // MTR2: attach directly to phy and set link state ourselves
++ //ret = phy_connect_direct(dev, phydev, &macb_handle_link_change, 0,
++ phy_attach(dev, dev_name(&phydev->dev), 0,
+ pdata && pdata->is_rmii ?
+ PHY_INTERFACE_MODE_RMII :
+ PHY_INTERFACE_MODE_MII);
++
++ /*
+ if (ret) {
+ printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
+ return ret;
+ }
++ */
+
+ /* mask with MAC supported features */
+ phydev->supported &= PHY_BASIC_FEATURES;
+@@ -966,7 +973,15 @@
+ macb_init_hw(bp);
+
+ /* schedule a link state check */
+- phy_start(bp->phy_dev);
++ // MTR2: disable link updates
++ //phy_start(bp->phy_dev);
++
++ // MTR2: force link up, 100MB, full duplex
++ printk(KERN_INFO "macb: forcing link to 100, full\n");
++ bp->phy_dev->link = 1;
++ bp->phy_dev->speed = SPEED_100;
++ bp->phy_dev->duplex = 1;
++ macb_handle_link_change(bp->dev);
+
+ netif_start_queue(dev);
+
+@@ -981,8 +996,19 @@
+ netif_stop_queue(dev);
+ napi_disable(&bp->napi);
+
+- if (bp->phy_dev)
+- phy_stop(bp->phy_dev);
++ // MTR2: disabled since we didn't call phy_start
++ //if (bp->phy_dev)
++ // phy_stop(bp->phy_dev);
++
++ // MTR2: set link down manually
++ if (bp->phy_dev) {
++ printk(KERN_INFO "macb: forcing link down\n");
++ bp->phy_dev->link = 0;
++ bp->phy_dev->speed = 0;
++ bp->phy_dev->duplex = -1;
++ }
++
++ macb_handle_link_change(bp->dev);
+
+ spin_lock_irqsave(&bp->lock, flags);
+ macb_reset_hw(bp);
diff --git a/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-mach-at91-mtocgd3.patch b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-mach-at91-mtocgd3.patch
new file mode 100644
index 0000000..e8c5add
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-mach-at91-mtocgd3.patch
@@ -0,0 +1,403 @@
+Index: linux-2.6.39.4/arch/arm/mach-at91/board-sam9x5cm.c
+===================================================================
+--- linux-2.6.39.4.orig/arch/arm/mach-at91/board-sam9x5cm.c 2013-02-06 09:03:14.041869154 -0600
++++ linux-2.6.39.4/arch/arm/mach-at91/board-sam9x5cm.c 2013-02-06 09:19:50.359999320 -0600
+@@ -18,6 +18,9 @@
+ #include <linux/platform_device.h>
+ #include <linux/spi/flash.h>
+ #include <linux/spi/spi.h>
++#include <linux/spi/eeprom.h>
++#include <linux/i2c/at24.h>
++#include <linux/delay.h>
+ #include <linux/fb.h>
+ #include <linux/gpio_keys.h>
+ #include <linux/input.h>
+@@ -103,6 +106,11 @@
+ .irq = -1,
+ },
+ #endif
++ {
++ .modalias = "mts-io-board-temp",
++ .chip_select = 1,
++ .bus_num = 1,
++ },
+ #endif
+ };
+
+@@ -111,13 +119,48 @@
+ */
+ static struct mtd_partition __initdata cm_nand_partition[] = {
+ {
+- .name = "Partition 1",
++ .name = "NANDFlash",
++ .offset = 0,
++ .size = 256*1024*1024,
++ },
++ {
++ .name = "AT91Bootstrap",
+ .offset = 0,
+- .size = SZ_64M,
++ .size = 256*1024,
++ },
++ {
++ .name = "UBoot",
++ .offset = 256*1024,
++ .size = 512*1024,
++ },
++ {
++ .name = "UBoot Config",
++ .offset = 768*1024,
++ .size = 640*1024,
++ },
++ {
++ .name = "UBoot Redundant Config",
++ .offset = 1408*1024,
++ .size = 640*1024,
++ },
++ {
++ .name = "uImage",
++ .offset = 2*1024*1024,
++ .size = 6*1024*1024,
++ },
++ {
++ .name = "Config",
++ .offset = 8*1024*1024,
++ .size = 8*1024*1024,
++ },
++ {
++ .name = "Oem Config",
++ .offset = 16*1024*1024,
++ .size = 8*1024*1024,
+ },
+ {
+- .name = "Partition 2",
+- .offset = MTDPART_OFS_NXTBLK,
++ .name = "Rootfs",
++ .offset = 24*1024*1024,
+ .size = MTDPART_SIZ_FULL,
+ },
+ };
+@@ -135,7 +178,8 @@
+ .enable_pin = AT91_PIN_PD4,
+ .ecc_mode = NAND_ECC_HW,
+ .has_pmecc = 1,
+- .pmecc_corr_cap = 2,
++// MTOCGD3: 4-bit PMECC
++ .pmecc_corr_cap = 4,
+ .pmecc_sector_size = 512,
+ .pmecc_lookup_table_offset = 0x8000,
+ .partition_info = nand_partitions,
+@@ -170,7 +214,13 @@
+ else
+ cm_nand_smc_config.mode |= AT91_SMC_DBW_8;
+
++ // MTOCGD3 Rev A
++ cm_nand_data.bus_on_d0 = 1;
++ cm_nand_data.rdy_pin = AT91_PIN_PC31;
++
++ // MTOCGD3: disable
+ /* revision of board modify NAND wiring */
++ /*
+ if (cm_is_revA()) {
+ cm_nand_data.bus_on_d0 = 1;
+ cm_nand_data.rdy_pin = AT91_PIN_PD6;
+@@ -178,6 +228,7 @@
+ cm_nand_data.bus_on_d0 = 0;
+ cm_nand_data.rdy_pin = AT91_PIN_PD5;
+ }
++ */
+
+ /* configure chip-select 3 (NAND) */
+ sam9_smc_configure(3, &cm_nand_smc_config);
+@@ -189,9 +240,16 @@
+ * LEDs
+ */
+ static struct gpio_led cm_leds[] = {
++ { /* Network Interface LED */
++ .name = "network:green:activity",
++ .gpio = AT91_PIN_PA29,
++ .active_low = 1
++ },
++// MTOCGD3: disable kernel driven LEDs, driven by mts-io instead
++#if 0
+ { /* "left" led, blue, userled1 */
+- .name = "d1",
+- .gpio = AT91_PIN_PB18,
++ .name = "status",
++ .gpio = AT91_PIN_PA24,
+ .default_trigger = "heartbeat",
+ },
+ { /* "right" led, red, userled2 */
+@@ -200,6 +258,32 @@
+ .active_low = 1,
+ .default_trigger = "mmc0",
+ },
++#endif
++};
++
++
++uint8_t mts_id_eeprom[512];
++
++EXPORT_SYMBOL(mts_id_eeprom);
++
++static void mts_id_eeprom_load(struct memory_accessor *macc, void *context)
++{
++ int tmp;
++
++ memset(mts_id_eeprom, 0, sizeof(mts_id_eeprom));
++
++ tmp = macc->read(macc, mts_id_eeprom, 0, sizeof(mts_id_eeprom));
++ if (tmp != sizeof(mts_id_eeprom)) {
++ printk(KERN_ERR "sam9x5: id eeprom read failed: %d\n", tmp);
++ } else {
++ printk(KERN_INFO "sam9x5: read %d bytes from id eeprom\n", tmp);
++ }
++}
++
++static struct at24_platform_data at24c04_data = {
++ .byte_len = SZ_4K / 8,
++ .page_size = 16,
++ .setup = mts_id_eeprom_load,
+ };
+
+ /*
+@@ -207,7 +291,8 @@
+ */
+ static struct i2c_board_info __initdata cm_i2c_devices[] = {
+ {
+- I2C_BOARD_INFO("24c512", 0x50)
++ I2C_BOARD_INFO("24c04", 0x56),
++ .platform_data = &at24c04_data,
+ },
+ };
+
+@@ -234,8 +319,12 @@
+ /* LEDs */
+ at91_gpio_leds(cm_leds, ARRAY_SIZE(cm_leds));
+
++ printk(KERN_CRIT "AT91: MTOCGD3 board\n");
++
++ /* MTOCGD3: disable
+ if (cm_is_revA())
+ printk(KERN_CRIT "AT91: CM rev A\n");
+ else
+ printk(KERN_CRIT "AT91: CM rev B and higher\n");
++ */
+ }
+Index: linux-2.6.39.4/arch/arm/mach-at91/board-sam9x5ek.c
+===================================================================
+--- linux-2.6.39.4.orig/arch/arm/mach-at91/board-sam9x5ek.c 2013-02-06 09:03:12.541870178 -0600
++++ linux-2.6.39.4/arch/arm/mach-at91/board-sam9x5ek.c 2013-02-06 09:03:14.541952299 -0600
+@@ -23,6 +23,7 @@
+ #include <linux/leds.h>
+ #include <linux/clk.h>
+ #include <linux/delay.h>
++#include <linux/wl12xx.h>
+ #include <mach/cpu.h>
+
+ #include <video/atmel_lcdfb.h>
+@@ -53,12 +54,10 @@
+ /* Initialize processor and DBGU */
+ cm_map_io();
+
+- /* USART0 on ttyS1. (Rx, Tx) */
+- at91_register_uart(AT91SAM9X5_ID_USART0, 1, 0);
+- /* USART1 on ttyS2. (Rx, Tx) */
+- at91_register_uart(AT91SAM9X5_ID_USART1, 2, 0);
+- /* USART2 on ttyS3. (Rx, Tx) */
+- at91_register_uart(AT91SAM9X5_ID_USART2, 3, 0);
++ // MTOCGD3: GPS on UART0 as ttyS1 with Rx/Tx only
++ at91_register_uart(AT91SAM9X5_ID_UART0, 1, 0);
++ // MTOCGD3 Rev A: Daughter card serial on USART1 as ttyS2 with RTS/CTS
++ at91_register_uart(AT91SAM9X5_ID_USART1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
+ }
+
+ /*
+@@ -89,34 +88,65 @@
+ * MACB Ethernet devices
+ */
+ static struct at91_eth_data __initdata ek_macb0_data = {
+- .is_rmii = 1,
++ .is_rmii = 0,
++ .phy_irq_pin = 0,
+ };
+
++/* MTOCGD3: no macb1
+ static struct at91_eth_data __initdata ek_macb1_data = {
+ .phy_irq_pin = AT91_PIN_PC26,
+ .is_rmii = 1,
+ };
++*/
+
+
+ /*
+ * MCI (SD/MMC)
+ */
+-/* mci0 detect_pin is revision dependent */
++// MTOCGD3: MCI0 is BT/Wifi
+ static struct mci_platform_data __initdata mci0_data = {
+ .slot[0] = {
+ .bus_width = 4,
++ .detect_pin = -1,
+ .wp_pin = -1,
+ },
+ };
+
++// MTOCGD3: MCI1 is SD card slot
+ static struct mci_platform_data __initdata mci1_data = {
+ .slot[0] = {
+ .bus_width = 4,
+- .detect_pin = AT91_PIN_PD14,
+- .wp_pin = -1,
++ .detect_pin = AT91_PIN_PA1,
++ .wp_pin = AT91_PIN_PA0,
+ },
+ };
+
++// MTR: Wi-fi
++static void wl12xx_enable(int poweron)
++{
++ if (poweron) {
++ at91_set_gpio_output_with_pullup(AT91_PIN_PC1, 0, 0);
++ msleep(10);
++ at91_set_gpio_output_with_pullup(AT91_PIN_PC1, 1, 0);
++ msleep(100);
++ printk(KERN_INFO "sam9x5: WLAN Enabled\n");
++ }
++ else {
++ at91_set_gpio_output_with_pullup(AT91_PIN_PC1, 0, 0);
++ msleep(10);
++ printk(KERN_INFO "sam9x5: WLAN Disabled\n");
++ }
++};
++
++// MTR: Wi-fi
++struct wl12xx_platform_data mtr_wlan_data __initdata = {
++ .irq = AT91_PIN_PC2,
++ /* ref clock is 38.4 MHz */
++ .board_ref_clock = WL12XX_REFCLOCK_38,
++ /* toggles the WLAN_ENABLE pin */
++ .set_power = wl12xx_enable,
++};
++
+ /*
+ * ISI
+ */
+@@ -326,9 +356,11 @@
+ * I2C Devices
+ */
+ static struct i2c_board_info __initdata ek_i2c_devices[] = {
++#if 0
+ {
+ I2C_BOARD_INFO("wm8731", 0x1a)
+ },
++#endif
+ #if defined(CONFIG_KEYBOARD_QT1070)
+ {
+ I2C_BOARD_INFO("qt1070", 0x1b),
+@@ -384,18 +416,24 @@
+ bool config_isi_enabled = false;
+
+ cm_board_init(&cm_config);
+- ek_board_configure_pins();
++ // MTOCGD3: disable
++ //ek_board_configure_pins();
+ /* Serial */
+ at91_add_device_serial();
+ /* USB HS Host */
+ at91_add_device_usbh_ohci(&ek_usbh_fs_data);
+ at91_add_device_usbh_ehci(&ek_usbh_hs_data);
+ /* USB HS Device */
++ // MTOCGD3: set usb device vcc pin
++ ek_usba_udc_data.vbus_pin = AT91_PIN_PC7;
+ at91_add_device_usba(&ek_usba_udc_data);
+ /* Ethernet */
+ at91_add_device_eth(0, &ek_macb0_data);
++ /* MTOCGD3: no macb1
+ at91_add_device_eth(1, &ek_macb1_data);
++ */
+ /* MMC0 */
++ // MTOCGD3: MCI0 for BT/Wifi
+ at91_add_device_mci(0, &mci0_data);
+ /* I2C */
+ if (cm_config & CM_CONFIG_I2C0_ENABLE)
+@@ -405,6 +443,15 @@
+ at91_add_device_i2c(0,
+ ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
+
++ // MTOCGD3: Wi-fi
++ at91_set_gpio_input(mtr_wlan_data.irq, 0);
++ at91_set_deglitch(mtr_wlan_data.irq, 1);
++
++ if (wl12xx_set_platform_data(&mtr_wlan_data))
++ pr_err("error setting wl12xx data\n");
++
++/* MTOCGD3: no LCD */
++#if 0
+ if (cpu_is_at91sam9g25()) {
+ /* ISI */
+ /* NOTE: PCK0 provides ISI_MCK to the ISI module.
+@@ -430,13 +477,10 @@
+ /* Touch Screen */
+ at91_add_device_tsadcc(&ek_tsadcc_data);
+ }
++#endif
+
+- /* MMC1 */
+- /* Conflict between SPI0, MCI1 and ISI pins.
+- * add MCI1 only if SPI0 and ISI are both disabled.
+- */
+- if (!(cm_config & CM_CONFIG_SPI0_ENABLE) && !config_isi_enabled)
+- at91_add_device_mci(1, &mci1_data);
++ // MTOCGD3: MCI1 to SD Card
++ at91_add_device_mci(1, &mci1_data);
+
+ #if 0
+ if (cpu_is_at91sam9x25() || cpu_is_at91sam9x35())
+@@ -448,6 +492,8 @@
+ at91_add_device_can(0, NULL);
+ #endif
+
++/* MTOCGD3: disable things we don't have */
++#if 0
+ if (cpu_is_at91sam9x25() || cpu_is_at91sam9x35())
+ /* this conflicts with usart.1 */
+ at91_add_device_can(1, NULL);
+@@ -474,6 +520,9 @@
+ else if (config_isi_enabled)
+ printk(KERN_CRIT
+ "AT91: ISI conficts with MCI1, disable MCI1\n");
++#endif
++
++ printk(KERN_CRIT "AT91: MTOCGD3 board EK init\n");
+ }
+
+ MACHINE_START(AT91SAM9X5EK, "Atmel AT91SAM9X5-EK")
+Index: linux-2.6.39.4/arch/arm/mach-at91/at91sam9x5_devices.c
+===================================================================
+--- linux-2.6.39.4.orig/arch/arm/mach-at91/at91sam9x5_devices.c 2013-02-06 09:03:13.541883138 -0600
++++ linux-2.6.39.4/arch/arm/mach-at91/at91sam9x5_devices.c 2013-02-06 09:03:14.541952299 -0600
+@@ -543,11 +543,11 @@
+ #endif
+
+ /* input/irq */
+- if (data->slot[0].detect_pin) {
++ if (data->slot[0].detect_pin > 0) {
+ at91_set_gpio_input(data->slot[0].detect_pin, 1);
+ at91_set_deglitch(data->slot[0].detect_pin, 1);
+ }
+- if (data->slot[0].wp_pin)
++ if (data->slot[0].wp_pin > 0)
+ at91_set_gpio_input(data->slot[0].wp_pin, 1);
+
+ if (mmc_id == 0) { /* MCI0 */
+@@ -849,7 +849,8 @@
+ .num_resources = ARRAY_SIZE(spi1_resources),
+ };
+
+-static const unsigned spi1_standard_cs[4] = { AT91_PIN_PA8, AT91_PIN_PA0, AT91_PIN_PA31, AT91_PIN_PA30 };
++// MTOCGD3: SPI1 chip selects on pins SPI1_NCS1 to SPI1_NCS5
++static const unsigned spi1_standard_cs[5] = { AT91_PIN_PC15, AT91_PIN_PC16, AT91_PIN_PC17, AT91_PIN_PC18, AT91_PIN_PC19 };
+
+ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
+ {
diff --git a/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-wl12xx-sdio-irq.patch b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-wl12xx-sdio-irq.patch
new file mode 100644
index 0000000..6c1abcd
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/mtocgd3/linux-2.6.39.4-wl12xx-sdio-irq.patch
@@ -0,0 +1,15 @@
+Index: linux-2.6.39.4/drivers/net/wireless/wl12xx/sdio.c
+===================================================================
+--- linux-2.6.39.4.orig/drivers/net/wireless/wl12xx/sdio.c 2012-05-10 11:49:16.349486059 -0500
++++ linux-2.6.39.4/drivers/net/wireless/wl12xx/sdio.c 2012-05-10 16:36:15.009543390 -0500
+@@ -241,7 +242,9 @@
+ wl->ref_clock = wlan_data->board_ref_clock;
+
+ ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq,
+- IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
++// MTR: use rising edge interrupts, level doesn't work
++// IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
++ IRQF_TRIGGER_RISING,
+ DRIVER_NAME, wl);
+ if (ret < 0) {
+ wl1271_error("request_irq() failed: %d", ret);
diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0001-DMA-AT91-Get-residual-bytes-in-dma-buffer.patch b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0001-DMA-AT91-Get-residual-bytes-in-dma-buffer.patch
new file mode 100644
index 0000000..7843ccb
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0001-DMA-AT91-Get-residual-bytes-in-dma-buffer.patch
@@ -0,0 +1,327 @@
+From 4af81f1015ac481cb900a27867a83a93924f3599 Mon Sep 17 00:00:00 2001
+From: Elen Song <elen.song@atmel.com>
+Date: Tue, 11 Dec 2012 18:24:48 +0800
+Subject: [PATCH 01/10] DMA: AT91: Get residual bytes in dma buffer
+
+Add support for returning the residue for current transfer cookie by
+reading the transfered buffer size(BTSIZE) in CTRLA register.
+
+For a single buffer cookie, the descriptor length minus BTSIZE
+can get the residue.
+
+For a lli cookie, remain_desc will record remain descriptor length
+when last descriptor finish, the remain_desc minus BTSIZE can get the
+current residue.
+
+If the cookie has completed successfully, the residue will be zero.
+If the cookie is in progress or the channel is paused, it will be
+the number of bytes yet to be transferred.If get residue error,
+the cookie will be turn into error status.
+
+Signed-off-by: Elen Song <elen.song@atmel.com>
+---
+ drivers/dma/at_hdmac.c | 157 +++++++++++++++++++++++++++++++++++++------
+ drivers/dma/at_hdmac_regs.h | 5 ++
+ 2 files changed, 143 insertions(+), 19 deletions(-)
+
+diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
+index f793804..22739de 100644
+--- a/drivers/dma/at_hdmac.c
++++ b/drivers/dma/at_hdmac.c
+@@ -23,6 +23,7 @@
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
++#include <linux/jiffies.h>
+
+ #include "at_hdmac_regs.h"
+
+@@ -39,6 +40,8 @@
+ #define ATC_DEFAULT_CTRLA (0)
+ #define ATC_DEFAULT_CTRLB (ATC_SIF(MEM_IF) | ATC_DIF(MEM_IF))
+
++/* DMA timeout (10ms)*/
++#define DMA_TIMEOUT 10
+ /*
+ * Initial number of descriptors to allocate for each channel. This could
+ * be increased during dma usage.
+@@ -51,6 +54,8 @@ MODULE_PARM_DESC(init_nr_desc_per_channel,
+
+ /* prototypes */
+ static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx);
++static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
++ unsigned long arg);
+
+
+ /*----------------------------------------------------------------------*/
+@@ -229,6 +234,111 @@ static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first)
+ vdbg_dump_regs(atchan);
+ }
+
++/*
++ * atc_get_current_descriptors -
++ * locate the descriptor which equal to physical address in DSCR
++ * @atchan: the channel we want to start
++ * @dscr_addr: physical descriptor address in DSCR
++ */
++static struct at_desc *atc_get_current_descriptors(struct at_dma_chan *atchan,
++ u32 dscr_addr)
++{
++ struct at_desc *desc, *_desc, *child, *desc_cur = NULL;
++
++ list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) {
++
++ if (desc->lli.dscr == dscr_addr) {
++ desc_cur = desc;
++ break;
++ }
++
++ list_for_each_entry(child, &desc->tx_list, desc_node) {
++
++ if (child->lli.dscr == dscr_addr) {
++ desc_cur = child;
++ break;
++ }
++ }
++ }
++
++ return desc_cur;
++}
++
++/*
++ * atc_get_bytes_left -
++ * Get the number of bytes residue in dma buffer,
++ * the channel should be paused when calling this
++ * @chan: the channel we want to start
++ */
++static int atc_get_bytes_left(struct dma_chan *chan)
++{
++ struct at_dma_chan *atchan = to_at_dma_chan(chan);
++ struct at_dma *atdma = to_at_dma(chan->device);
++ int chan_id = atchan->chan_common.chan_id;
++ struct at_desc *desc_first = atc_first_active(atchan);
++ struct at_desc *desc_cur;
++ int ret = 0, count = 0;
++ unsigned long timeout = jiffies + msecs_to_jiffies(DMA_TIMEOUT);
++
++ /*
++ * Initialize necessary values in the first time.
++ * remain_desc record remain desc length.
++ */
++ if (atchan->remain_desc == 0)
++ /* First descriptor embedds the transaction length */
++ atchan->remain_desc = desc_first->len;
++
++start:
++ /* Channel should be paused before get residue */
++ if (!test_bit(ATC_IS_PAUSED, &atchan->status))
++ atc_control(chan, DMA_PAUSE, 0);
++ /*
++ * This happens when current descriptor transfer complete.
++ * The residual buffer size should reduce current descriptor length.
++ */
++ if (unlikely(test_bit(ATC_IS_BTC, &atchan->status))) {
++ clear_bit(ATC_IS_BTC, &atchan->status);
++ desc_cur = atc_get_current_descriptors(atchan,
++ channel_readl(atchan, DSCR));
++ if (!desc_cur) {
++ ret = -EINVAL;
++ goto out;
++ }
++ atchan->remain_desc -= (desc_cur->lli.ctrla & ATC_BTSIZE_MAX)
++ << (desc_first->tx_buswidth);
++ if (atchan->remain_desc < 0) {
++ ret = -EINVAL;
++ goto out;
++ } else
++ ret = atchan->remain_desc;
++ } else {
++ /*
++ * Get residual bytes when current
++ * descriptor transfer in progress.
++ */
++ count = (channel_readl(atchan, CTRLA) & ATC_BTSIZE_MAX)
++ << (desc_first->tx_buswidth);
++ ret = atchan->remain_desc - count;
++ }
++ /*
++ * Check fifo empty in pre-determined time, if not,
++ * restart a new taskelt to finish remain task.
++ */
++ if (!(dma_readl(atdma, CHSR) & AT_DMA_EMPT(chan_id))) {
++ if (time_before(jiffies, timeout)) {
++ goto start;
++ } else {
++ dev_vdbg(chan2dev(chan), "fifo is not empty, restart a new tasklet\n");
++ tasklet_schedule(&atchan->tasklet);
++ }
++ }
++out:
++ if (test_bit(ATC_IS_PAUSED, &atchan->status))
++ atc_control(chan, DMA_RESUME, 0);
++
++ return ret;
++}
++
+ /**
+ * atc_chain_complete - finish work for one transaction chain
+ * @atchan: channel we work on
+@@ -492,6 +602,8 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id)
+ /* Give information to tasklet */
+ set_bit(ATC_IS_ERROR, &atchan->status);
+ }
++ if (pending & AT_DMA_BTC(i))
++ set_bit(ATC_IS_BTC, &atchan->status);
+ tasklet_schedule(&atchan->tasklet);
+ ret = IRQ_HANDLED;
+ }
+@@ -621,6 +733,7 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
+ /* First descriptor of the chain embedds additional information */
+ first->txd.cookie = -EBUSY;
+ first->len = len;
++ first->tx_buswidth = src_width;
+
+ /* set end-of-link to the last link descriptor of list*/
+ set_desc_eol(desc);
+@@ -770,6 +883,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
+ /* First descriptor of the chain embedds additional information */
+ first->txd.cookie = -EBUSY;
+ first->len = total_len;
++ first->tx_buswidth = reg_width;
+
+ /* first link descriptor of list is responsible of flags */
+ first->txd.flags = flags; /* client is in control of this ack */
+@@ -892,6 +1006,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
+ /* First descriptor of the chain embedds additional information */
+ first->txd.cookie = -EBUSY;
+ first->len = buf_len;
++ first->tx_buswidth = reg_width;
+
+ return &first->txd;
+
+@@ -1015,41 +1130,43 @@ atc_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie,
+ struct dma_tx_state *txstate)
+ {
+- struct at_dma_chan *atchan = to_at_dma_chan(chan);
++ struct at_dma_chan *atchan = to_at_dma_chan(chan);
+ dma_cookie_t last_used;
+ dma_cookie_t last_complete;
+ unsigned long flags;
+ enum dma_status ret;
++ int bytes = 0;
+
+- spin_lock_irqsave(&atchan->lock, flags);
+
+ last_complete = atchan->completed_cookie;
+ last_used = chan->cookie;
+
+ ret = dma_async_is_complete(cookie, last_complete, last_used);
+- if (ret != DMA_SUCCESS) {
+- atc_cleanup_descriptors(atchan);
+
+- last_complete = atchan->completed_cookie;
+- last_used = chan->cookie;
++ if (ret == DMA_SUCCESS)
++ return ret;
++ /*
++ * There's no point calculating the residue if there's
++ * no txstate to store the value.
++ */
++ if (!txstate)
++ return DMA_ERROR;
+
+- ret = dma_async_is_complete(cookie, last_complete, last_used);
+- }
++ spin_lock_irqsave(&atchan->lock, flags);
+
+- spin_unlock_irqrestore(&atchan->lock, flags);
++ /* Get number of bytes left in the active transactions */
++ bytes = atc_get_bytes_left(chan);
+
+- if (ret != DMA_SUCCESS)
+- dma_set_tx_state(txstate, last_complete, last_used,
+- atc_first_active(atchan)->len);
+- else
+- dma_set_tx_state(txstate, last_complete, last_used, 0);
++ spin_unlock_irqrestore(&atchan->lock, flags);
+
+- if (test_bit(ATC_IS_PAUSED, &atchan->status))
+- ret = DMA_PAUSED;
++ if (unlikely(bytes < 0)) {
++ dev_vdbg(chan2dev(chan), "get residual bytes error\n");
++ return DMA_ERROR;
++ } else
++ dma_set_tx_state(txstate, last_complete, last_used, bytes);
+
+- dev_vdbg(chan2dev(chan), "tx_status %d: cookie = %d (d%d, u%d)\n",
+- ret, cookie, last_complete ? last_complete : 0,
+- last_used ? last_used : 0);
++ dev_vdbg(chan2dev(chan), "tx_status %d: cookie = %d residue = %d\n",
++ ret, cookie, bytes);
+
+ return ret;
+ }
+@@ -1135,6 +1252,7 @@ static int atc_alloc_chan_resources(struct dma_chan *chan)
+
+ spin_lock_irqsave(&atchan->lock, flags);
+ atchan->descs_allocated = i;
++ atchan->remain_desc = 0;
+ list_splice(&tmp_list, &atchan->free_list);
+ atchan->completed_cookie = chan->cookie = 1;
+ spin_unlock_irqrestore(&atchan->lock, flags);
+@@ -1177,6 +1295,7 @@ static void atc_free_chan_resources(struct dma_chan *chan)
+ list_splice_init(&atchan->free_list, &list);
+ atchan->descs_allocated = 0;
+ atchan->status = 0;
++ atchan->remain_desc = 0;
+
+ dev_vdbg(chan2dev(chan), "free_chan_resources: done\n");
+ }
+diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h
+index a29c698..e819051 100644
+--- a/drivers/dma/at_hdmac_regs.h
++++ b/drivers/dma/at_hdmac_regs.h
+@@ -161,6 +161,7 @@ struct at_lli {
+ * @txd: support for the async_tx api
+ * @desc_node: node on the channed descriptors list
+ * @len: total transaction bytecount
++ * @tx_buswidth: transmit buswidth
+ */
+ struct at_desc {
+ /* FIRST values the hardware uses */
+@@ -171,6 +172,7 @@ struct at_desc {
+ struct dma_async_tx_descriptor txd;
+ struct list_head desc_node;
+ size_t len;
++ u32 tx_buswidth;
+ };
+
+ static inline struct at_desc *
+@@ -190,6 +192,7 @@ txd_to_at_desc(struct dma_async_tx_descriptor *txd)
+ enum atc_status {
+ ATC_IS_ERROR = 0,
+ ATC_IS_PAUSED = 1,
++ ATC_IS_BTC = 2,
+ ATC_IS_CYCLIC = 24,
+ };
+
+@@ -205,6 +208,7 @@ enum atc_status {
+ * @save_cfg: configuration register that is saved on suspend/resume cycle
+ * @save_dscr: for cyclic operations, preserve next descriptor address in
+ * the cyclic list on suspend/resume cycle
++ * @save_len: to record dma buffer length
+ * @lock: serializes enqueue/dequeue operations to descriptors lists
+ * @completed_cookie: identifier for the most recently completed operation
+ * @active_list: list of descriptors dmaengine is being running on
+@@ -221,6 +225,7 @@ struct at_dma_chan {
+ struct tasklet_struct tasklet;
+ u32 save_cfg;
+ u32 save_dscr;
++ int remain_desc;
+
+ spinlock_t lock;
+
+--
+1.7.9.5
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0002-Serial-Configure-DMAC-configuration-register-for-usa.patch b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0002-Serial-Configure-DMAC-configuration-register-for-usa.patch
new file mode 100644
index 0000000..f1a3411
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0002-Serial-Configure-DMAC-configuration-register-for-usa.patch
@@ -0,0 +1,73 @@
+From 38a9a2980b7497a5d892fb1ce9247c114cf17cdf Mon Sep 17 00:00:00 2001
+From: Elen Song <elen.song@atmel.com>
+Date: Fri, 6 Jul 2012 13:35:40 +0800
+Subject: [PATCH 02/10] Serial: Configure DMAC configuration register for
+ usart 0
+
+Configure DMAC_CFG to enable lli for uart0
+enable uart0 dma rx
+
+Signed-off-by: Elen Song <elen.song@atmel.com>
+---
+ arch/arm/mach-at91/at91sam9x5_devices.c | 25 ++++++++++++++++++++++++-
+ arch/arm/mach-at91/include/mach/board.h | 1 +
+ 2 files changed, 25 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9x5_devices.c b/arch/arm/mach-at91/at91sam9x5_devices.c
+index cee42dc..048d86a 100644
+--- a/arch/arm/mach-at91/at91sam9x5_devices.c
++++ b/arch/arm/mach-at91/at91sam9x5_devices.c
+@@ -1583,7 +1583,7 @@ static struct resource usart0_resources[] = {
+
+ static struct atmel_uart_data usart0_data = {
+ .use_dma_tx = 1,
+- .use_dma_rx = 0, /* doesn't support */
++ .use_dma_rx = 1,
+ };
+
+ static u64 usart0_dmamask = DMA_BIT_MASK(32);
+@@ -1905,6 +1905,29 @@ void __init at91_add_device_serial(void)
+
+ pdata->dma_tx_slave = atslave;
+ }
++
++ if (pdata->use_dma_rx) {
++ struct at_dma_slave *arslave;
++
++ arslave = kzalloc(sizeof(struct at_dma_slave),
++ GFP_KERNEL);
++
++ /* DMA slave channel configuration */
++ if (peripheral_id == AT91SAM9X5_ID_USART0
++ || peripheral_id == AT91SAM9X5_ID_USART1
++ || peripheral_id == AT91SAM9X5_ID_UART0)
++ arslave->dma_dev = &at_hdmac0_device.dev;
++ else
++ arslave->dma_dev = &at_hdmac1_device.dev;
++
++ arslave->reg_width = DW_DMA_SLAVE_WIDTH_8BIT;
++ arslave->cfg = ATC_FIFOCFG_ENOUGHSPACE
++ | ATC_SRC_H2SEL_HW
++ | ATC_DST_H2SEL_SW
++ | AT_DMA_ID_USART0_RX; /*ATC_SRC_PER(peripheral_id);*/
++
++ pdata->dma_rx_slave = arslave;
++ }
+ #endif
+ platform_device_register(at91_usarts[i]);
+ }
+diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
+index 04dcec1..681688c 100644
+--- a/arch/arm/mach-at91/include/mach/board.h
++++ b/arch/arm/mach-at91/include/mach/board.h
+@@ -149,6 +149,7 @@ struct atmel_uart_data {
+ short use_dma_rx; /* use receive DMA? */
+ void __iomem *regs; /* virt. base address, if any */
+ struct at_dma_slave *dma_tx_slave;
++ struct at_dma_slave *dma_rx_slave;
+ struct serial_rs485 rs485; /* rs485 settings */
+ };
+ extern void __init at91_add_device_serial(void);
+--
+1.7.9.5
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0003-Configure-peripheral-id-and-enable-basic-usart.patch b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0003-Configure-peripheral-id-and-enable-basic-usart.patch
new file mode 100644
index 0000000..75e95d9
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0003-Configure-peripheral-id-and-enable-basic-usart.patch
@@ -0,0 +1,153 @@
+From 42b8165988e2f601c8a5c0076710bb41d6f154c2 Mon Sep 17 00:00:00 2001
+From: Elen Song <elen.song@atmel.com>
+Date: Mon, 22 Oct 2012 17:48:03 +0800
+Subject: [PATCH 03/10] Configure peripheral id and enable basic usart
+
+enable basic usart(usart0,1,2) on 9x5serial
+to register more usart, add code in board-sam9x5ek.c
+for example, to add AT91SAM9X5_ID_UART0
+you can add it in ek_map_io:at91_register_uart(AT91SAM9X5_ID_UART0, 3, 0)
+
+pay attention to some board do not have uart,
+we should not register them.
+
+Signed-off-by: Elen Song <elen.song@atmel.com>
+---
+ arch/arm/mach-at91/at91sam9x5_devices.c | 60 ++++++++++++++++++++++++--
+ arch/arm/mach-at91/board-sam9x5ek.c | 4 ++
+ arch/arm/mach-at91/include/mach/at91sam9x5.h | 4 ++
+ 3 files changed, 64 insertions(+), 4 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9x5_devices.c b/arch/arm/mach-at91/at91sam9x5_devices.c
+index 048d86a..26ecf47 100644
+--- a/arch/arm/mach-at91/at91sam9x5_devices.c
++++ b/arch/arm/mach-at91/at91sam9x5_devices.c
+@@ -1875,6 +1875,51 @@ void __init at91_set_serial_console(unsigned portnr)
+ atmel_default_console_device = at91_usarts[portnr];
+ }
+
++static int at91_set_peripheral_id(unsigned int id, unsigned int direction)
++{
++ unsigned int dst, src;
++ switch (id) {
++ case 0: /* DBGU */
++ dst = AT_DMA_ID_DBGU_TX;
++ src = AT_DMA_ID_DBGU_RX;
++ break;
++ case AT91SAM9X5_ID_USART0:
++ dst = AT_DMA_ID_USART0_TX;
++ src = AT_DMA_ID_USART0_RX;
++ break;
++ case AT91SAM9X5_ID_USART1:
++ dst = AT_DMA_ID_USART1_TX;
++ src = AT_DMA_ID_USART1_RX;
++ break;
++ case AT91SAM9X5_ID_USART2:
++ dst = AT_DMA_ID_USART2_TX;
++ src = AT_DMA_ID_USART2_RX;
++ break;
++ case AT91SAM9X5_ID_USART3:
++ dst = AT_DMA_ID_USART3_TX;
++ src = AT_DMA_ID_USART3_RX;
++ break;
++ case AT91SAM9X5_ID_UART0:
++ dst = AT_DMA_ID_UART0_TX;
++ src = AT_DMA_ID_UART0_RX;
++ break;
++ case AT91SAM9X5_ID_UART1:
++ dst = AT_DMA_ID_UART1_TX;
++ src = AT_DMA_ID_UART1_RX;
++ break;
++ default:
++ printk(KERN_ERR "usart %d unsupport!\n", id);
++ break;
++ }
++
++ if (direction == AT_DMA_TX)
++ return dst << 4;
++ if (direction == AT_DMA_RX)
++ return src;
++
++ return -EINVAL;
++}
++
+ void __init at91_add_device_serial(void)
+ {
+ int i;
+@@ -1887,8 +1932,10 @@ void __init at91_add_device_serial(void)
+
+ if (pdata->use_dma_tx) {
+ struct at_dma_slave *atslave;
+-
++ int dst;
+ atslave = kzalloc(sizeof(struct at_dma_slave), GFP_KERNEL);
++ dst = at91_set_peripheral_id(peripheral_id,
++ AT_DMA_TX);
+
+ /* DMA slave channel configuration */
+ if (peripheral_id == AT91SAM9X5_ID_USART0
+@@ -1901,14 +1948,16 @@ void __init at91_add_device_serial(void)
+ atslave->reg_width = DW_DMA_SLAVE_WIDTH_8BIT;
+ atslave->cfg = ATC_FIFOCFG_HALFFIFO
+ | ATC_SRC_H2SEL_SW | ATC_DST_H2SEL_HW
+- | (AT_DMA_ID_USART0_TX << 4); /*ATC_DST_PER(peripheral_id);*/
++ | dst;
++ /*ATC_DST_PER(peripheral_id);*/
++
+
+ pdata->dma_tx_slave = atslave;
+ }
+
+ if (pdata->use_dma_rx) {
+ struct at_dma_slave *arslave;
+-
++ int src;
+ arslave = kzalloc(sizeof(struct at_dma_slave),
+ GFP_KERNEL);
+
+@@ -1921,10 +1970,13 @@ void __init at91_add_device_serial(void)
+ arslave->dma_dev = &at_hdmac1_device.dev;
+
+ arslave->reg_width = DW_DMA_SLAVE_WIDTH_8BIT;
++ src = at91_set_peripheral_id(peripheral_id,
++ AT_DMA_RX);
+ arslave->cfg = ATC_FIFOCFG_ENOUGHSPACE
+ | ATC_SRC_H2SEL_HW
+ | ATC_DST_H2SEL_SW
+- | AT_DMA_ID_USART0_RX; /*ATC_SRC_PER(peripheral_id);*/
++ | src;
++ /*ATC_SRC_PER(peripheral_id);*/
+
+ pdata->dma_rx_slave = arslave;
+ }
+diff --git a/arch/arm/mach-at91/board-sam9x5ek.c b/arch/arm/mach-at91/board-sam9x5ek.c
+index 8c06040..cf72adb 100644
+--- a/arch/arm/mach-at91/board-sam9x5ek.c
++++ b/arch/arm/mach-at91/board-sam9x5ek.c
+@@ -55,6 +55,10 @@ static void __init ek_map_io(void)
+
+ /* USART0 on ttyS1. (Rx, Tx) */
+ at91_register_uart(AT91SAM9X5_ID_USART0, 1, 0);
++ /* USART1 on ttyS2. (Rx, Tx) */
++ at91_register_uart(AT91SAM9X5_ID_USART1, 2, 0);
++ /* USART2 on ttyS3. (Rx, Tx) */
++ at91_register_uart(AT91SAM9X5_ID_USART2, 3, 0);
+ }
+
+ /*
+diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5.h b/arch/arm/mach-at91/include/mach/at91sam9x5.h
+index 1219b32..529cbc3 100644
+--- a/arch/arm/mach-at91/include/mach/at91sam9x5.h
++++ b/arch/arm/mach-at91/include/mach/at91sam9x5.h
+@@ -176,4 +176,8 @@
+ #define AT_DMA_ID_USART3_TX 14
+ #define AT_DMA_ID_USART3_RX 15
+
++/* DMA peripheral_id direction */
++#define AT_DMA_TX 0
++#define AT_DMA_RX 1
++
+ #endif
+--
+1.7.9.5
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0004-Serial-Enable-Serial-cyclic-DMA-transfer.patch b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0004-Serial-Enable-Serial-cyclic-DMA-transfer.patch
new file mode 100644
index 0000000..4cba1b2
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0004-Serial-Enable-Serial-cyclic-DMA-transfer.patch
@@ -0,0 +1,399 @@
+From 29a3f150b069754fb4318e1a44f91f51f94fccf2 Mon Sep 17 00:00:00 2001
+From: Elen Song <elen.song@atmel.com>
+Date: Tue, 11 Dec 2012 18:38:55 +0800
+Subject: [PATCH 04/10] Serial: Enable Serial cyclic DMA transfer
+
+request a dma channle for serial rx,
+the channel is defined to be used for dma cyclic transfer,
+atmel_allocate_desc will allocate a cycle dma transfer after request channel,
+enable uart timeout in startup stage,
+when data successful receive, during the transfer interval,
+it will call timeout handler,
+the timeout handler will check the residual value,
+and insert the receive data into framework.
+
+Signed-off-by: Elen Song <elen.song@atmel.com>
+---
+ drivers/tty/serial/atmel_serial.c | 261 ++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 257 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
+index 205e496..b990594 100644
+--- a/drivers/tty/serial/atmel_serial.c
++++ b/drivers/tty/serial/atmel_serial.c
+@@ -130,7 +130,7 @@ struct atmel_uart_char {
+ u16 ch;
+ };
+
+-#define ATMEL_SERIAL_RINGSIZE 1024
++#define ATMEL_SERIAL_RINGSIZE 4096
+
+ /*
+ * We wrap our port structure around the generic uart_port.
+@@ -150,13 +150,19 @@ struct atmel_uart_port {
+ struct atmel_dma_buffer pdc_tx; /* PDC transmitter */
+
+ spinlock_t lock_tx; /* port lock */
++ spinlock_t lock_rx; /* port lock */
+ struct dma_chan *chan_tx;
++ struct dma_chan *chan_rx;
+ struct dma_async_tx_descriptor *desc_tx;
++ struct dma_async_tx_descriptor *desc_rx;
+ dma_cookie_t cookie_tx;
++ dma_cookie_t cookie_rx;
+
+ signed int xmit_head;
+ struct scatterlist sg_tx;
++ struct scatterlist sg_rx;
+ unsigned int sg_len_tx;
++ unsigned int sg_len_rx;
+
+ struct tasklet_struct tasklet;
+ unsigned int irq_status;
+@@ -213,13 +219,24 @@ static bool atmel_use_dma_tx(struct uart_port *port)
+
+ return atmel_port->use_dma_tx;
+ }
++
++static bool atmel_use_dma_rx(struct uart_port *port)
++{
++ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
++
++ return atmel_port->use_dma_rx;
++}
+ #else
+ static bool atmel_use_dma_tx(struct uart_port *port)
+ {
+ return false;
+ }
+-#endif
+
++static bool atmel_use_dma_rx(struct uart_port *port)
++{
++ return false;
++}
++#endif
+ /* Enable or disable the rs485 support */
+ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
+ {
+@@ -605,16 +622,38 @@ static void atmel_dma_tx_complete(void *arg)
+ spin_unlock_irqrestore(&port->lock, flags);
+ }
+
++
++static void atmel_dma_rx_complete(void *arg)
++{
++ struct uart_port *port = arg;
++ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
++
++ tasklet_schedule(&atmel_port->tasklet);
++}
++
+ static void atmel_tx_dma_release(struct atmel_uart_port *atmel_port)
+ {
+ struct dma_chan *chan = atmel_port->chan_tx;
+
+ atmel_port->chan_tx = NULL;
+ atmel_port->cookie_tx = -EINVAL;
++}
++
++static void atmel_rx_dma_release(struct atmel_uart_port *atmel_port)
++{
++ struct dma_chan *chan = atmel_port->chan_rx;
++ struct uart_port *port = &(atmel_port->uart);
++
+ if (chan) {
+ chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+ dma_release_channel(chan);
++ dma_unmap_sg(port->dev, &atmel_port->sg_rx, 1,
++ DMA_FROM_DEVICE);
+ }
++
++ atmel_port->desc_rx = NULL;
++ atmel_port->chan_rx = NULL;
++ atmel_port->cookie_rx = -EINVAL;
+ }
+
+ /*
+@@ -700,6 +739,79 @@ static void atmel_tx_dma(struct uart_port *port)
+ uart_write_wakeup(port);
+ }
+
++static void atmel_rx_dma_flip_buffer(struct uart_port *port,
++ char *buf, size_t count)
++{
++ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
++ struct tty_struct *tty = port->state->port.tty;
++
++ dma_sync_sg_for_cpu(port->dev,
++ &atmel_port->sg_rx,
++ 1,
++ DMA_FROM_DEVICE);
++
++ tty_insert_flip_string(tty, buf, count);
++
++ dma_sync_sg_for_device(port->dev,
++ &atmel_port->sg_rx,
++ 1,
++ DMA_FROM_DEVICE);
++ /*
++ * Drop the lock here since it might end up calling
++ * uart_start(), which takes the lock.
++ */
++ spin_unlock(&port->lock);
++ tty_flip_buffer_push(tty);
++ spin_lock(&port->lock);
++}
++
++
++static void atmel_rx_from_dma(struct uart_port *port)
++{
++ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
++ struct circ_buf *ring = &atmel_port->rx_ring;
++ struct dma_chan *chan = atmel_port->chan_rx;
++ struct dma_tx_state state;
++ enum dma_status dmastat;
++ size_t pending, count;
++
++
++ /* Reset the UART timeout early so that we don't miss one */
++ UART_PUT_CR(port, ATMEL_US_STTTO);
++ dmastat = chan->device->device_tx_status(chan,
++ atmel_port->cookie_rx,
++ &state);
++ /* Restart a new tasklet if DMA status is error */
++ if (dmastat == DMA_ERROR) {
++ dev_dbg(port->dev, "Get residue error, restart tasklet\n");
++ UART_PUT_IER(port, ATMEL_US_TIMEOUT);
++ tasklet_schedule(&atmel_port->tasklet);
++ return;
++ }
++ /* current transfer size should no larger than dma buffer */
++ pending = sg_dma_len(&atmel_port->sg_rx) - state.residue;
++ BUG_ON(pending > sg_dma_len(&atmel_port->sg_rx));
++
++ /*
++ * This will take the chars we have so far,
++ * ring->head will record the transfer size, only new bytes come
++ * will insert into the framework.
++ */
++ if (pending > ring->head) {
++ count = pending - ring->head;
++
++ atmel_rx_dma_flip_buffer(port, ring->buf + ring->head, count);
++
++ ring->head += count;
++ if (ring->head == sg_dma_len(&atmel_port->sg_rx))
++ ring->head = 0;
++
++ port->icount.rx += count;
++ }
++
++ UART_PUT_IER(port, ATMEL_US_TIMEOUT);
++}
++
+ static bool filter(struct dma_chan *chan, void *slave)
+ {
+ struct at_dma_slave *sl = slave;
+@@ -767,11 +879,87 @@ static void atmel_tx_request_dma(struct atmel_uart_port *atmel_port)
+ atmel_port->xmit_head = -1;
+ }
+ }
++
++static void atmel_rx_request_dma(struct atmel_uart_port *atmel_port)
++{
++ struct uart_port *port;
++ struct atmel_uart_data *pdata;
++ dma_cap_mask_t mask;
++ struct dma_chan *chan = NULL;
++ struct circ_buf *ring = &atmel_port->rx_ring;
++
++ if (atmel_port == NULL)
++ return;
++
++ port = &(atmel_port->uart);
++ pdata = (struct atmel_uart_data *)port->private_data;
++
++ if (!pdata)
++ goto chan_err;
++
++ dma_cap_zero(mask);
++ dma_cap_set(DMA_CYCLIC, mask);
++
++ if (atmel_use_dma_rx(port) && pdata->dma_rx_slave) {
++ pdata->dma_rx_slave->rx_reg = port->mapbase + ATMEL_US_RHR;
++ chan = dma_request_channel(mask, filter, pdata->dma_rx_slave);
++ if (chan == NULL)
++ goto chan_err;
++ dev_dbg(port->dev, "%s: RX: got channel %d\n",
++ __func__,
++ chan->chan_id);
++ }
++
++ if (chan) {
++ int nent;
++
++ spin_lock_init(&atmel_port->lock_rx);
++ atmel_port->chan_rx = chan;
++
++ sg_init_table(&atmel_port->sg_rx, 1);
++ /* UART circular tx buffer is an aligned page. */
++ BUG_ON((int)ring->buf & ~PAGE_MASK);
++ sg_set_page(&atmel_port->sg_rx,
++ virt_to_page(ring->buf),
++ ATMEL_SERIAL_RINGSIZE,
++ (int)ring->buf & ~PAGE_MASK);
++ nent = dma_map_sg(port->dev,
++ &atmel_port->sg_rx,
++ 1,
++ DMA_FROM_DEVICE);
++
++ if (!nent)
++ dev_dbg(port->dev, "need to release resource of dma\n");
++ else
++ dev_dbg(port->dev, "%s: mapped %d@%p to %x\n",
++ __func__,
++ sg_dma_len(&atmel_port->sg_rx),
++ ring->buf,
++ sg_dma_address(&atmel_port->sg_rx));
++
++ atmel_port->sg_len_rx = nent;
++
++ ring->head = 0;
++ ring->tail = 0;
++ }
++
++ return;
++
++chan_err:
++ dev_err(port->dev, "RX channel not available, switch to pio\n");
++ atmel_port->use_dma_rx = 0;
++ atmel_rx_dma_release(atmel_port);
++ return;
++}
+ #else
+ static void atmel_dma_tx_complete(void *arg) {}
++static void atmel_dma_rx_complete(void *arg) {}
+ static void atmel_tx_dma_release(struct atmel_uart_port *atmel_port) {}
++static void atmel_rx_dma_release(struct atmel_uart_port *atmel_port) {}
+ static void atmel_tx_dma(struct uart_port *port) {}
++static void atmel_rx_from_dma(struct uart_port *port) {}
+ static void atmel_tx_request_dma(struct atmel_uart_port *atmel_port) {}
++static void atmel_rx_request_dma(struct atmel_uart_port *atmel_port) {}
+ #endif
+
+ /*
+@@ -801,6 +989,17 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending)
+ atmel_pdc_rxerr(port, pending);
+ }
+
++ if (atmel_use_dma_rx(port)) {
++ if (pending & ATMEL_US_TIMEOUT) {
++ UART_PUT_IDR(port, ATMEL_US_TIMEOUT);
++ tasklet_schedule(&atmel_port->tasklet);
++ }
++
++ if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE |
++ ATMEL_US_FRAME | ATMEL_US_PARE))
++ atmel_pdc_rxerr(port, pending);
++ }
++
+ /* Interrupt receive */
+ if (pending & ATMEL_US_RXRDY)
+ atmel_rx_chars(port);
+@@ -1105,12 +1304,55 @@ static void atmel_tasklet_func(unsigned long data)
+
+ if (atmel_use_pdc_rx(port))
+ atmel_rx_from_pdc(port);
++ else if (atmel_use_dma_rx(port))
++ atmel_rx_from_dma(port);
+ else
+ atmel_rx_from_ring(port);
+
+ spin_unlock(&port->lock);
+ }
+
++static int atmel_allocate_desc(struct uart_port *port)
++{
++ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
++ struct dma_async_tx_descriptor *desc;
++ struct dma_chan *chan = atmel_port->chan_rx;
++
++ if (!chan) {
++ dev_err(port->dev, "No channel available\n");
++ goto err_dma;
++ }
++ /*
++ * Prepare a cyclic dma transfer, assign 2 descriptors,
++ * each one is half ring buffer size
++ */
++ desc = chan->device->device_prep_dma_cyclic(chan,
++ sg_dma_address(&atmel_port->sg_rx),
++ sg_dma_len(&atmel_port->sg_rx),
++ sg_dma_len(&atmel_port->sg_rx)/2,
++ DMA_FROM_DEVICE);
++
++ desc->callback = atmel_dma_rx_complete;
++ desc->callback_param = port;
++ atmel_port->desc_rx = desc;
++ atmel_port->cookie_rx = dmaengine_submit(desc);
++
++ async_tx_ack(atmel_port->desc_rx);
++
++ if (dma_submit_error(atmel_port->cookie_rx)) {
++ dev_err(port->dev, "Failed submitting Rx DMA descriptor\n");
++ goto err_dma;
++ }
++
++ return 0;
++
++err_dma:
++ dev_warn(port->dev, "Switch to PIO\n");
++ atmel_port->use_dma_rx = 0;
++ atmel_rx_dma_release(atmel_port);
++ return -EINVAL;
++}
++
+ /*
+ * Perform initialization and enable port for reception
+ */
+@@ -1191,6 +1433,10 @@ static int atmel_startup(struct uart_port *port)
+ if (atmel_use_dma_tx(port))
+ atmel_tx_request_dma(atmel_port);
+
++ if (atmel_use_dma_rx(port)) {
++ atmel_rx_request_dma(atmel_port);
++ atmel_allocate_desc(port);
++ }
+ /*
+ * If there is a specific "open" function (to register
+ * control line interrupts)
+@@ -1222,6 +1468,12 @@ static int atmel_startup(struct uart_port *port)
+ UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
+ /* enable PDC controller */
+ UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
++ } else if (atmel_use_dma_rx(port)) {
++ /* set UART timeout */
++ UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
++ UART_PUT_CR(port, ATMEL_US_STTTO);
++
++ UART_PUT_IER(port, ATMEL_US_TIMEOUT);
+ } else {
+ /* enable receive only */
+ UART_PUT_IER(port, ATMEL_US_RXRDY);
+@@ -1267,9 +1519,10 @@ static void atmel_shutdown(struct uart_port *port)
+ DMA_TO_DEVICE);
+ }
+
+- if (atmel_use_dma_tx(port)) {
++ if (atmel_use_dma_rx(port))
++ atmel_rx_dma_release(atmel_port);
++ if (atmel_use_dma_tx(port))
+ atmel_tx_dma_release(atmel_port);
+- }
+ /*
+ * Disable all interrupts, port and break condition.
+ */
+--
+1.7.9.5
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0005-Serial-AT91-Refine-tx-dma.patch b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0005-Serial-AT91-Refine-tx-dma.patch
new file mode 100644
index 0000000..7360893
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0005-Serial-AT91-Refine-tx-dma.patch
@@ -0,0 +1,167 @@
+From a5e9545cb6f9e171d8f015c661b9c8d7a84567e5 Mon Sep 17 00:00:00 2001
+From: Elen Song <elen.song@atmel.com>
+Date: Tue, 11 Dec 2012 18:44:45 +0800
+Subject: [PATCH 05/10] Serial: AT91: Refine tx dma
+
+remove useless part,
+refine tx request dma, swith to pio if channel is busy,
+refine tx dma, remove useless lock, terminate dma will transaction complete
+
+Signed-off-by: Elen Song <elen.song@atmel.com>
+---
+ drivers/tty/serial/atmel_serial.c | 60 ++++++++++++++++++-------------------
+ 1 file changed, 30 insertions(+), 30 deletions(-)
+
+diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
+index b990594..9013e6f 100644
+--- a/drivers/tty/serial/atmel_serial.c
++++ b/drivers/tty/serial/atmel_serial.c
+@@ -158,7 +158,6 @@ struct atmel_uart_port {
+ dma_cookie_t cookie_tx;
+ dma_cookie_t cookie_rx;
+
+- signed int xmit_head;
+ struct scatterlist sg_tx;
+ struct scatterlist sg_rx;
+ unsigned int sg_len_tx;
+@@ -596,10 +595,14 @@ static void atmel_dma_tx_complete(void *arg)
+ struct atmel_uart_port *atmel_port = arg;
+ struct uart_port *port = &atmel_port->uart;
+ struct circ_buf *xmit = &port->state->xmit;
++ struct dma_chan *chan = atmel_port->chan_tx;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+
++ if (chan)
++ chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
++
+ xmit->tail += sg_dma_len(&atmel_port->sg_tx);
+ xmit->tail &= UART_XMIT_SIZE - 1;
+
+@@ -634,7 +637,16 @@ static void atmel_dma_rx_complete(void *arg)
+ static void atmel_tx_dma_release(struct atmel_uart_port *atmel_port)
+ {
+ struct dma_chan *chan = atmel_port->chan_tx;
++ struct uart_port *port = &(atmel_port->uart);
++
++ if (chan) {
++ chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
++ dma_release_channel(chan);
++ dma_unmap_sg(port->dev, &atmel_port->sg_tx, 1,
++ DMA_TO_DEVICE);
++ }
+
++ atmel_port->desc_tx = NULL;
+ atmel_port->chan_tx = NULL;
+ atmel_port->cookie_tx = -EINVAL;
+ }
+@@ -667,13 +679,9 @@ static void atmel_tx_dma(struct uart_port *port)
+ struct dma_async_tx_descriptor *desc;
+ struct scatterlist *sg = &atmel_port->sg_tx;
+
+- spin_lock_irq(&atmel_port->lock_tx);
+ /* Make sure we have an idle channel */
+- if (atmel_port->desc_tx != NULL) {
+- spin_lock_irq(&atmel_port->lock_tx);
++ if (atmel_port->desc_tx != NULL)
+ return;
+- }
+- spin_unlock_irq(&atmel_port->lock_tx);
+
+ if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
+ /*
+@@ -683,23 +691,10 @@ static void atmel_tx_dma(struct uart_port *port)
+ * transmit till the end, and then the rest. Take the port lock to get a
+ * consistent xmit buffer state.
+ */
+- spin_lock_irq(&port->lock);
+- if (atmel_port->xmit_head != -1) {
+- if (atmel_port->xmit_head != xmit->head) {
+- atmel_port->xmit_head = xmit->head;
+- } else {
+- spin_unlock_irq(&port->lock);
+- return;
+- }
+- } else {
+- atmel_port->xmit_head = xmit->head;
+- }
+-
+ sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
+ sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1))
+ + sg->offset;
+ sg_dma_len(sg) = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+- spin_unlock_irq(&port->lock);
+
+ BUG_ON(!sg_dma_len(sg));
+
+@@ -707,22 +702,18 @@ static void atmel_tx_dma(struct uart_port *port)
+ sg, atmel_port->sg_len_tx, DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc) {
+- spin_unlock_irq(&port->lock);
+- printk (KERN_ERR "#### Error! Failed to send via dma!\n");
++ dev_err(port->dev, "Error! Failed to send via dma!\n");
+ return;
+ }
+
+ dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
+
+- spin_lock_irq(&port->lock);
+ atmel_port->desc_tx = desc;
+ desc->callback = atmel_dma_tx_complete;
+ desc->callback_param = atmel_port;
+- spin_unlock_irq(&port->lock);
+ atmel_port->cookie_tx = desc->tx_submit(desc);
+ if (atmel_port->cookie_tx < 0) {
+ dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n");
+- /* switch to PIO */
+ atmel_tx_dma_release(atmel_port);
+ return;
+ }
+@@ -837,10 +828,8 @@ static void atmel_tx_request_dma(struct atmel_uart_port *atmel_port)
+ port = &(atmel_port->uart);
+ pdata = (struct atmel_uart_data *)port->private_data;
+
+- if (!pdata) {
+- dev_notice(port->dev, "DMA not available, using PIO\n");
+- return;
+- }
++ if (!pdata)
++ goto chan_err;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+@@ -848,7 +837,11 @@ static void atmel_tx_request_dma(struct atmel_uart_port *atmel_port)
+ if (atmel_use_dma_tx(port) && pdata->dma_tx_slave) {
+ pdata->dma_tx_slave->tx_reg = port->mapbase + ATMEL_US_THR;
+ chan = dma_request_channel(mask, filter, pdata->dma_tx_slave);
+- dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan);
++ if (chan == NULL)
++ goto chan_err;
++ dev_dbg(port->dev, "%s: TX: got channel %d\n",
++ __func__,
++ chan->chan_id);
+ }
+
+ if (chan) {
+@@ -876,8 +869,15 @@ static void atmel_tx_request_dma(struct atmel_uart_port *atmel_port)
+ sg_dma_address(&atmel_port->sg_tx));
+
+ atmel_port->sg_len_tx = nent;
+- atmel_port->xmit_head = -1;
+ }
++
++ return;
++
++chan_err:
++ dev_err(port->dev, "TX channel not available, switch to pio\n");
++ atmel_port->use_dma_tx = 0;
++ atmel_tx_dma_release(atmel_port);
++ return;
+ }
+
+ static void atmel_rx_request_dma(struct atmel_uart_port *atmel_port)
+--
+1.7.9.5
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0006-Serial-AT91-refine-error-handler-in-probe-stage.patch b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0006-Serial-AT91-refine-error-handler-in-probe-stage.patch
new file mode 100644
index 0000000..b3581e3
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0006-Serial-AT91-refine-error-handler-in-probe-stage.patch
@@ -0,0 +1,70 @@
+From f4009ec3887c79e58f43c7c6010ae174d73ee662 Mon Sep 17 00:00:00 2001
+From: Elen Song <elen.song@atmel.com>
+Date: Tue, 11 Dec 2012 18:46:33 +0800
+Subject: [PATCH 06/10] Serial: AT91: refine error handler in probe stage
+
+Signed-off-by: Elen Song <elen.song@atmel.com>
+---
+ drivers/tty/serial/atmel_serial.c | 32 +++++++++++++++++++-------------
+ 1 file changed, 19 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
+index 9013e6f..65b2bb4 100644
+--- a/drivers/tty/serial/atmel_serial.c
++++ b/drivers/tty/serial/atmel_serial.c
+@@ -1390,15 +1390,10 @@ static int atmel_startup(struct uart_port *port)
+
+ pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL);
+ if (pdc->buf == NULL) {
+- if (i != 0) {
+- dma_unmap_single(port->dev,
+- atmel_port->pdc_rx[0].dma_addr,
+- PDC_BUFFER_SIZE,
+- DMA_FROM_DEVICE);
+- kfree(atmel_port->pdc_rx[0].buf);
+- }
+- free_irq(port->irq, port);
+- return -ENOMEM;
++ retval = -ENOMEM;
++ if (i != 0)
++ goto err_second_pdc_buffer;
++ goto err_pdc_buffer;
+ }
+ pdc->dma_addr = dma_map_single(port->dev,
+ pdc->buf,
+@@ -1443,10 +1438,8 @@ static int atmel_startup(struct uart_port *port)
+ */
+ if (atmel_open_hook) {
+ retval = atmel_open_hook(port);
+- if (retval) {
+- free_irq(port->irq, port);
+- return retval;
+- }
++ if (retval)
++ goto err_open_hook;
+ }
+
+ /* Save current CSR for comparison in atmel_tasklet_func() */
+@@ -1480,6 +1473,19 @@ static int atmel_startup(struct uart_port *port)
+ }
+
+ return 0;
++
++err_open_hook:
++err_second_pdc_buffer:
++ if (atmel_use_pdc_rx(port)) {
++ dma_unmap_single(port->dev,
++ atmel_port->pdc_rx[0].dma_addr,
++ PDC_BUFFER_SIZE,
++ DMA_FROM_DEVICE);
++ kfree(atmel_port->pdc_rx[0].buf);
++ }
++err_pdc_buffer:
++ free_irq(port->irq, port);
++ return retval;
+ }
+
+ /*
+--
+1.7.9.5
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0007-Serial-AT91-Add-dma-support-for-rs485-and-iso7816.patch b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0007-Serial-AT91-Add-dma-support-for-rs485-and-iso7816.patch
new file mode 100644
index 0000000..07b4508
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0007-Serial-AT91-Add-dma-support-for-rs485-and-iso7816.patch
@@ -0,0 +1,71 @@
+From df26bc6eeb017f49b0fee9a149f0f2e1d5a22cd6 Mon Sep 17 00:00:00 2001
+From: Elen Song <elen.song@atmel.com>
+Date: Tue, 6 Nov 2012 16:57:39 +0800
+Subject: [PATCH 07/10] Serial: AT91: Add dma support for rs485 and iso7816
+
+Add dma defination is atmel_start_tx, atmel_start_rx, atmel_stop_rx
+
+Signed-off-by: Elen Song <elen.song@atmel.com>
+---
+ drivers/tty/serial/atmel_serial.c | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
+index 65b2bb4..0133698 100644
+--- a/drivers/tty/serial/atmel_serial.c
++++ b/drivers/tty/serial/atmel_serial.c
+@@ -406,6 +406,11 @@ static void atmel_start_tx(struct uart_port *port)
+ UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
+ }
+
++ if (atmel_use_dma_tx(port)) {
++ if (atmel_port->rs485.flags & SER_RS485_ENABLED)
++ atmel_stop_rx(port);
++ }
++
+ /* Enable interrupts */
+ UART_PUT_IER(port, atmel_port->tx_done_mask);
+ }
+@@ -415,6 +420,9 @@ static void atmel_start_tx(struct uart_port *port)
+ */
+ static void atmel_start_rx(struct uart_port *port)
+ {
++ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
++ struct dma_chan *chan = atmel_port->chan_rx;
++
+ UART_PUT_CR(port, ATMEL_US_RSTSTA); /* reset status and receiver */
+
+ if (atmel_use_pdc_rx(port)) {
+@@ -422,6 +430,10 @@ static void atmel_start_rx(struct uart_port *port)
+ UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
+ port->read_status_mask);
+ UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
++ } else if (atmel_use_dma_rx(port)) {
++ /* resume dma transfer */
++ if (chan)
++ chan->device->device_control(chan, DMA_RESUME, 0);
+ } else {
+ UART_PUT_IER(port, ATMEL_US_RXRDY);
+ }
+@@ -432,11 +444,18 @@ static void atmel_start_rx(struct uart_port *port)
+ */
+ static void atmel_stop_rx(struct uart_port *port)
+ {
++ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
++ struct dma_chan *chan = atmel_port->chan_rx;
++
+ if (atmel_use_pdc_rx(port)) {
+ /* disable PDC receive */
+ UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS);
+ UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
+ port->read_status_mask);
++ } else if (atmel_use_dma_rx(port)) {
++ /* pause dma transfer */
++ if (chan)
++ chan->device->device_control(chan, DMA_PAUSE, 0);
+ } else {
+ UART_PUT_IDR(port, ATMEL_US_RXRDY);
+ }
+--
+1.7.9.5
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0008-Serial-AT91-remove-tx-dma-issue-pending.patch b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0008-Serial-AT91-remove-tx-dma-issue-pending.patch
new file mode 100644
index 0000000..edbf595
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0008-Serial-AT91-remove-tx-dma-issue-pending.patch
@@ -0,0 +1,32 @@
+From dd70a9fe2c0576be5cd6ee63d2d179bdbd164425 Mon Sep 17 00:00:00 2001
+From: Elen Song <elen.song@atmel.com>
+Date: Tue, 11 Dec 2012 18:59:50 +0800
+Subject: [PATCH 08/10] Serial: AT91: remove tx dma issue pending
+
+issue pending will cause dma complete callback execute if tx dma interrupt comes,
+when next tx interrupt happend before last dma complete callback,
+it will enable dma again, but the last dma assume dma is already closed,
+it will crash that driver found dma is enable when transaction finished.
+remove dma issue pending.
+
+Signed-off-by: Elen Song <elen.song@atmel.com>
+---
+ drivers/tty/serial/atmel_serial.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
+index 0133698..d253566 100644
+--- a/drivers/tty/serial/atmel_serial.c
++++ b/drivers/tty/serial/atmel_serial.c
+@@ -736,8 +736,6 @@ static void atmel_tx_dma(struct uart_port *port)
+ atmel_tx_dma_release(atmel_port);
+ return;
+ }
+-
+- dma_async_issue_pending(chan);
+ } else {
+ if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
+ /* DMA done, stop TX, start RX for RS485 */
+--
+1.7.9.5
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0009-Serial-AT91-Fix-DBGU-peripheral_id-wrong.patch b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0009-Serial-AT91-Fix-DBGU-peripheral_id-wrong.patch
new file mode 100644
index 0000000..63bb912
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0009-Serial-AT91-Fix-DBGU-peripheral_id-wrong.patch
@@ -0,0 +1,37 @@
+From 871a2b4a6974b7eba9da88bad95309d7555bd4db Mon Sep 17 00:00:00 2001
+From: Elen Song <elen.song@atmel.com>
+Date: Fri, 25 Jan 2013 16:15:17 +0800
+Subject: [PATCH 09/10] Serial:AT91: Fix DBGU peripheral_id wrong
+
+also fix warning.
+
+Signed-off-by: Elen Song <elen.song@atmel.com>
+---
+ arch/arm/mach-at91/at91sam9x5_devices.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9x5_devices.c b/arch/arm/mach-at91/at91sam9x5_devices.c
+index 26ecf47..c1e402d 100644
+--- a/arch/arm/mach-at91/at91sam9x5_devices.c
++++ b/arch/arm/mach-at91/at91sam9x5_devices.c
+@@ -1879,7 +1879,7 @@ static int at91_set_peripheral_id(unsigned int id, unsigned int direction)
+ {
+ unsigned int dst, src;
+ switch (id) {
+- case 0: /* DBGU */
++ case AT91_ID_SYS: /* DBGU */
+ dst = AT_DMA_ID_DBGU_TX;
+ src = AT_DMA_ID_DBGU_RX;
+ break;
+@@ -1908,6 +1908,8 @@ static int at91_set_peripheral_id(unsigned int id, unsigned int direction)
+ src = AT_DMA_ID_UART1_RX;
+ break;
+ default:
++ dst = 0;
++ src = 0;
+ printk(KERN_ERR "usart %d unsupport!\n", id);
+ break;
+ }
+--
+1.7.9.5
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0010-serial-at91-Make-DBGU-support-dma-and-pdc-transfer.patch b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0010-serial-at91-Make-DBGU-support-dma-and-pdc-transfer.patch
new file mode 100644
index 0000000..faf6098
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/0010-serial-at91-Make-DBGU-support-dma-and-pdc-transfer.patch
@@ -0,0 +1,183 @@
+From fd599168c0ebe37de73d2c6b1aac1399cd373cc6 Mon Sep 17 00:00:00 2001
+From: Elen Song <elen.song@atmel.com>
+Date: Fri, 25 Jan 2013 16:25:12 +0800
+Subject: [PATCH 10/10] serial:at91: Make DBGU support dma and pdc transfer
+
+Because the DBGU lack of receive timeout register, so we use a timer to trigger data receive.
+The DBGU physical address has been map to virtual address by mmu,
+so we use dbgu_resources to save DBGU physical address.
+
+Signed-off-by: Elen Song <elen.song@atmel.com>
+---
+ arch/arm/mach-at91/at91sam9x5_devices.c | 9 +++-
+ drivers/tty/serial/atmel_serial.c | 72 +++++++++++++++++++++++++------
+ 2 files changed, 66 insertions(+), 15 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9x5_devices.c b/arch/arm/mach-at91/at91sam9x5_devices.c
+index c1e402d..88d0ca4 100644
+--- a/arch/arm/mach-at91/at91sam9x5_devices.c
++++ b/arch/arm/mach-at91/at91sam9x5_devices.c
+@@ -1540,11 +1540,16 @@ static struct resource dbgu_resources[] = {
+ .end = AT91_ID_SYS,
+ .flags = IORESOURCE_IRQ,
+ },
++ [2] = {
++ .start = AT91_BASE_SYS + AT91_DBGU,
++ .end = AT91_BASE_SYS + AT91_DBGU + SZ_512 - 1,
++ .flags = IORESOURCE_MEM,
++ },
+ };
+
+ static struct atmel_uart_data dbgu_data = {
+- .use_dma_tx = 0,
+- .use_dma_rx = 0,
++ .use_dma_tx = 1,
++ .use_dma_rx = 1,
+ .regs = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
+ };
+
+diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
+index d253566..72610c8b 100644
+--- a/drivers/tty/serial/atmel_serial.c
++++ b/drivers/tty/serial/atmel_serial.c
+@@ -39,6 +39,7 @@
+ #include <linux/atmel_pdc.h>
+ #include <linux/atmel_serial.h>
+ #include <linux/uaccess.h>
++#include <linux/timer.h>
+
+ #include <asm/io.h>
+ #include <asm/ioctls.h>
+@@ -171,6 +172,8 @@ struct atmel_uart_port {
+
+ struct serial_rs485 rs485; /* rs485 settings */
+ unsigned int tx_done_mask;
++ struct timer_list uart_timer; /* dbgu timer */
++ resource_size_t dbgu_phybase; /* dbgu physical address */
+ };
+
+ static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
+@@ -852,7 +855,12 @@ static void atmel_tx_request_dma(struct atmel_uart_port *atmel_port)
+ dma_cap_set(DMA_SLAVE, mask);
+
+ if (atmel_use_dma_tx(port) && pdata->dma_tx_slave) {
+- pdata->dma_tx_slave->tx_reg = port->mapbase + ATMEL_US_THR;
++ if (port->line == 0)
++ pdata->dma_tx_slave->tx_reg = atmel_port->dbgu_phybase
++ + ATMEL_US_THR;
++ else
++ pdata->dma_tx_slave->tx_reg = port->mapbase
++ + ATMEL_US_THR;
+ chan = dma_request_channel(mask, filter, pdata->dma_tx_slave);
+ if (chan == NULL)
+ goto chan_err;
+@@ -918,7 +926,12 @@ static void atmel_rx_request_dma(struct atmel_uart_port *atmel_port)
+ dma_cap_set(DMA_CYCLIC, mask);
+
+ if (atmel_use_dma_rx(port) && pdata->dma_rx_slave) {
+- pdata->dma_rx_slave->rx_reg = port->mapbase + ATMEL_US_RHR;
++ if (port->line == 0)
++ pdata->dma_rx_slave->rx_reg = atmel_port->dbgu_phybase
++ + ATMEL_US_RHR;
++ else
++ pdata->dma_rx_slave->rx_reg = port->mapbase
++ + ATMEL_US_RHR;
+ chan = dma_request_channel(mask, filter, pdata->dma_rx_slave);
+ if (chan == NULL)
+ goto chan_err;
+@@ -1370,6 +1383,15 @@ err_dma:
+ return -EINVAL;
+ }
+
++static void atmel_uart_timer_callback(unsigned long data)
++{
++ struct uart_port *port = (void *)data;
++ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
++
++ tasklet_schedule(&atmel_port->tasklet);
++ mod_timer(&atmel_port->uart_timer, jiffies + uart_poll_timeout(port));
++}
++
+ /*
+ * Perform initialization and enable port for reception
+ */
+@@ -1472,18 +1494,34 @@ static int atmel_startup(struct uart_port *port)
+
+ if (atmel_use_pdc_rx(port)) {
+ /* set UART timeout */
+- UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
+- UART_PUT_CR(port, ATMEL_US_STTTO);
+-
+- UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
+- /* enable PDC controller */
+- UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
++ if (port->line == 0) {
++ setup_timer(&atmel_port->uart_timer,
++ atmel_uart_timer_callback,
++ (unsigned long)port);
++ mod_timer(&atmel_port->uart_timer,
++ jiffies + uart_poll_timeout(port));
++ } else {
++ UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
++ UART_PUT_CR(port, ATMEL_US_STTTO);
++
++ UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
++ }
++ /* enable PDC controller */
++ UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
+ } else if (atmel_use_dma_rx(port)) {
+ /* set UART timeout */
+- UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
+- UART_PUT_CR(port, ATMEL_US_STTTO);
+-
+- UART_PUT_IER(port, ATMEL_US_TIMEOUT);
++ if (port->line == 0) {
++ setup_timer(&atmel_port->uart_timer,
++ atmel_uart_timer_callback,
++ (unsigned long)port);
++ mod_timer(&atmel_port->uart_timer,
++ jiffies + uart_poll_timeout(port));
++ } else {
++ UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
++ UART_PUT_CR(port, ATMEL_US_STTTO);
++
++ UART_PUT_IER(port, ATMEL_US_TIMEOUT);
++ }
+ } else {
+ /* enable receive only */
+ UART_PUT_IER(port, ATMEL_US_RXRDY);
+@@ -1532,6 +1570,9 @@ static void atmel_shutdown(struct uart_port *port)
+ DMA_FROM_DEVICE);
+ kfree(pdc->buf);
+ }
++
++ if (port->line == 0)
++ del_timer_sync(&atmel_port->uart_timer);
+ }
+ if (atmel_use_pdc_tx(port)) {
+ struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+@@ -1542,8 +1583,11 @@ static void atmel_shutdown(struct uart_port *port)
+ DMA_TO_DEVICE);
+ }
+
+- if (atmel_use_dma_rx(port))
++ if (atmel_use_dma_rx(port)) {
+ atmel_rx_dma_release(atmel_port);
++ if (port->line == 0)
++ del_timer_sync(&atmel_port->uart_timer);
++ }
+ if (atmel_use_dma_tx(port))
+ atmel_tx_dma_release(atmel_port);
+ /*
+@@ -1945,6 +1989,8 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
+ port->mapbase = pdev->resource[0].start;
+ port->irq = pdev->resource[1].start;
+ port->private_data = data;
++ if (port->line == 0)
++ atmel_port->dbgu_phybase = pdev->resource[2].start;
+
+ tasklet_init(&atmel_port->tasklet, atmel_tasklet_func,
+ (unsigned long)port);
+--
+1.7.9.5
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/Change-log.txt b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/Change-log.txt
new file mode 100644
index 0000000..d14313c
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/Change-log.txt
@@ -0,0 +1,30 @@
+
+ The rc3 release patch :1st
+
+The rc4 release patch fix:
+1) lots of garbled characters showing up
+
+The rc5 release patch fix:
+1) Tx have CRC error.
+2) Both TX and RX can use 460800bps to transfer.
+
+
+The rc6 release patch fix:
+1) RTS/CTS switch will sometimes crashes in tx dma
+2) 460k may sometimes crashes while change rx ring buffer size.
+?
+
+The rc7 release patch fix:
+1) add bascic usart support
+
+The rc8 release patch fix:
+1) shutdown crash
+2) polling empty flag
+2) switching to pio when dma failed
+
+The rc9 release patch fix:
+1) tx may crash when transfer in high baudrate
+
+The 1.0 release patch add:
+1) DBGU dma and PDC support
+
diff --git a/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/how to apply.txt b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/how to apply.txt
new file mode 100644
index 0000000..8542bd1
--- /dev/null
+++ b/multitech/recipes/linux/linux-2.6.39.4/serial_dma_rx_at91sam9x5_1.0/how to apply.txt
@@ -0,0 +1,16 @@
+How to apply patch
+
+1. get source code from official site, if you have already gotten one, just skip to point 2.
+
+please refer to:
+http://www.at91.com/linux4sam/bin/view/Linux4SAM/SAM9x5Page#Linux4SAM_AT91SAM9x5_Experimenta
+
+2. apply uart patch:
+
+cd linux-2.6.39
+for p in serial_dma_rx_at91sam9x5_rc3/*.patch ; do patch -p1 < $p; done
+
+if you use git, you can also apply them by:
+
+git am 0001-DMA....and so on.
+
diff --git a/multitech/recipes/linux/linux_2.6.39.4.bb b/multitech/recipes/linux/linux_2.6.39.4.bb
index d0af5f7..2939bd9 100644
--- a/multitech/recipes/linux/linux_2.6.39.4.bb
+++ b/multitech/recipes/linux/linux_2.6.39.4.bb
@@ -1,11 +1,160 @@
require recipes/linux/linux.inc
-PR = "r1"
+# PR is set by MACHINE_KERNEL_PR in machine config
SRC_URI = " \
${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/linux-${PV}.tar.bz2;name=kernel \
+ "
+
+# 2.6.39-at91 patches from ftp://ftp.linux4sam.org/pub/linux/2.6.39-at91
+AT91SAM9X5_PATCHES = " \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0001-dmaengine-at_hdmac-modify-way-to-use-interrupts.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0002-dmaengine-at_hdmac-add-cyclic-DMA-operation-support.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0003-dmaengine-at_hdmac-debug-information-sg_len-for-prep.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0004-dmaengine-at_hdmac-remove-channel-status-testing-in-.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0005-dmaengine-at_hdmac-specialize-AHB-interfaces-to-opti.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0006-dmaengine-AT91SAM9X5-has-a-Atmel-AHB-DMA-engine.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0007-rtc-at91-workaround-for-5series-ES-chips.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0008-rtc-AT91SAM9X5-has-an-at91_rtc.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0009-ARM-at91-overall-definition-add-5series-support.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0010-ARM-at91-PMC-header-add-5series-support.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0011-ARM-at91-clock-add-5series-chip-family-support.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0012-ARM-at91-AT91SAM9x5-processors-and-EK-board-support.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0013-ARM-at91-provide-defconfig-for-at91sam9x5ek.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0014-usb-AT91SAM9X5-has-EHCI.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0015-ARM-at91-pio-add-new-PIO3a-features.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0016-usb-AT91SAM9X5-has-a-atmel_usba_udc-device.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0017-clocksource-tcb-add-support-for-32-bit-mode.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0018-mmc-atmel-mci-add-support-for-ARCH_AT91SAM9X5.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0019-serial-atmel-convert-to-use-dma-engine.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0020-video-atmel_lcdfb-add-support-for-AT91SAM9x5.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0021-video-atmel_lcdfb-The-output-bpp-should-not-change-a.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0022-input-atmel_tsadcc-add-support-for-ARCH_AT91SAM9X5.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0023-input-atmel_tsadcc-add-touch-screen-pressure-measure.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0024-input-atmel_tsadcc-enable-touchscreen-averaging-and-.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0025-input-atmel_tsadcc-add-ACR-register-and-change-trigg.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0026-MTD-atmel_nand-Add-PMECC-controller-support.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0027-MTD-atmel_nand-optimize-read-write-buffer-functions.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0028-spi-atmel_spi-trivial-change-some-comments.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0029-spi-atmel_spi-add-physical-base-address.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0030-spi-atmel_spi-call-unmapping-on-transfers-buffers.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0031-spi-atmel_spi-status-information-passed-through-cont.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0032-spi-atmel_spi-add-flag-to-controller-data-for-lock-o.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0033-spi-atmel_spi-add-dmaengine-support.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0034-net-can-allow-CAN_AT91-on-AT91SAM9X5.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0035-Input-qt1070-Add-MODULE_DEVICE_TABLE.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0036-Input-qt1070-trivial-fix-CHANGE-line-typo.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0037-Input-qt1070-add-power-management-suspend-resume.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0038-dmaengine-at_hdmac-clear-channel-status-on-channel-r.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0039-dmaengine-at_hdmac-set-residue-as-total-len-in-atc_t.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0040-dmaengine-at_hdmac-implement-pause-and-resume-in-atc.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0041-dmaengine-at_hdmac-pause-no-need-to-wait-for-FIFO-em.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0042-dmaengine-at_hdmac-replace-spin_lock-with-irqsave-va.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0043-dmaengine-at_hdmac-improve-power-management-routines.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0044-sound-atmel-pcm-trivial-typo-in-debug-comment.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0045-sound-atmel-pcm-trivial-typo-in-atmel_pcm_dma_params.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0046-dmaengine-at_hdmac-add-slave-config-operation.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0047-SPI-m25p80-add-serial-flash-IDs.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0048-sound-wm8731-rework-power-management.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0049-atmel-ssc-add-phybase-in-device-structure.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0050-atmel-ssc-dmaengine-usage-switch-depending-on-cpu.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0051-sound-atmel_ssc_dai-fix-ssc-error-path.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0052-sound-atmel_ssc_dai-atmel-pmc-adapt-to-dmaengine-usa.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0053-sound-sam9x5_wm8731-machine-driver-for-at91sam9x5-wm.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0054-mtd-atmel_nand-do-not-scream-while-using-PIO-instead.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0055-MMC-PM-suspend-resume-in-atmel-mci.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0056-ASoc-wm8731-fix-wm8731_check_osc-connected-condition.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0057-ASoc-sam9g20_wm8731-use-the-proper-SYSCKL-value.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0058-sound-atmel_ssc_dai-PM-actually-stopping-clock-on-su.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0059-ARM-at91-sam9x5-increase-CONSISTENT_DMA_SIZE.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0060-SPI-atmel_spi-add-bit-in-mode-register-to-prevent-ov.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0061-media-at91sam9x5-video-new-driver-for-the-high-end-o.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0062-can-at91_can-don-t-align-struct-definitions.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0063-can-at91_can-fix-comment-about-priv-tx_next.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0064-can-at91_can-don-t-copy-data-to-rx-ed-RTR-frames.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0065-can-at91_can-let-get_tx_-functions-return-unsigned-i.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0066-can-at91_can-directly-define-AT91_MB_RX_LAST.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0067-can-at91_can-rename-AT91_MB_RX_MASK-to-AT91_IRQ_MB_R.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0068-can-at91_can-convert-derived-mailbox-constants-into-.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0069-can-at91_can-add-id_table-and-convert-prime-mailbox-.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0070-can-at91_can-register-mb0-sysfs-entry-only-on-at91sa.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0071-can-at91_can-add-support-for-the-AT91SAM9X5-SOCs.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0072-media-V4L-videobuf2-memops-use-pr_debug-for-debug-me.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0073-video-atmelfb-initially-split-atmelfb-into-a-driver-.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0074-video-atmelfb-refactor-core-setup.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0075-video-atmelfb-refactor-start-stop.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0076-video-atmelfb-refactor-isr.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0077-video-atmelfb-refactor-backlight-routines.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0078-video-atmelfb-refactor-dma_update.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0079-video-atmelfb-refactor-LUT.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0080-video-atmelfb-refactor-limit_screeninfo.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0081-arm-at91-refactor-lcdc-includes.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0082-video-atmel_hlcdfb-add-new-driver.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0083-arm-at91-sam9x5-use-new-hlcdc-driver.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0084-arm-at91-sam9x5ek-use-16bpp-as-default-for-fb.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0085-create-platform-device-for-ovl1.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0086-WIP-add-clut-resource.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0087-video-atmel_lcdfb-add-error-msg-when-out-of-memory.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0088-Don-t-shortcut-vb2_reqbufs-in-case-the-format-change.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0089-at91-video-change-atmel-lcdfb-driver-selection-mode.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0090-sound-atmel_ssc_dai-add-a-missing-space-to-an-error-.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0091-at91-add-Atmel-Image-Sensor-Interface-ISI-support.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0092-add-isi-support-in-board-files.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0093-media-at91-add-dumb-set_parm.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0094-AT91-5series-add-ISI-device-and-board-support.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0095-AT91-board-remove-not-needed-comments.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0096-AT91-5series-update-defconfig.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0097-AT91-input-atmel_tsadcc-rework-irq-infrastructure-an.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0098-5series-Update-LCD-timings-to-avoid-flickering.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0099-atmel_lcdfb-change-pixel-clock-ratio-calculation.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0100-MTD-atmel_nand_pmecc-fix-warning-about-uninitialized.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0101-MTD-atmel_nand-fix-wrong-use-of-0-as-NULL.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0102-ASoC-wm8731-active-bit-and-OSC-management.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0103-AT91-at91sam9x5-add-can-clocks-to-9x25-chip.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0104-AT91-LCD-include-remove-not-needed-comment.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0105-AT91-5series-fix-SPI0-MCI1-ISI-pins-conflicts-in-boa.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0106-PMECC-Fix-bug-incorrect-register-address-for-remaind.patch \
+ file://2.6.39-at91-exp.2/2.6.39-at91-exp.2-0107-ARM-at91-add-smd-device-definition.patch \
+ file://serial_dma_rx_at91sam9x5_1.0/0001-DMA-AT91-Get-residual-bytes-in-dma-buffer.patch \
+ file://serial_dma_rx_at91sam9x5_1.0/0002-Serial-Configure-DMAC-configuration-register-for-usa.patch \
+ file://serial_dma_rx_at91sam9x5_1.0/0003-Configure-peripheral-id-and-enable-basic-usart.patch \
+ file://serial_dma_rx_at91sam9x5_1.0/0004-Serial-Enable-Serial-cyclic-DMA-transfer.patch \
+ file://serial_dma_rx_at91sam9x5_1.0/0005-Serial-AT91-Refine-tx-dma.patch \
+ file://serial_dma_rx_at91sam9x5_1.0/0006-Serial-AT91-refine-error-handler-in-probe-stage.patch \
+ file://serial_dma_rx_at91sam9x5_1.0/0007-Serial-AT91-Add-dma-support-for-rs485-and-iso7816.patch \
+ file://serial_dma_rx_at91sam9x5_1.0/0008-Serial-AT91-remove-tx-dma-issue-pending.patch \
+ file://serial_dma_rx_at91sam9x5_1.0/0009-Serial-AT91-Fix-DBGU-peripheral_id-wrong.patch \
+ file://serial_dma_rx_at91sam9x5_1.0/0010-serial-at91-Make-DBGU-support-dma-and-pdc-transfer.patch \
+ file://9x5_pmecc_2639/0001-Revert-MTD-atmel_nand-Add-PMECC-controller-support.patch \
+ file://9x5_pmecc_2639/0002-Revert-MTD-atmel_nand-optimize-read-write-buffer-fun.patch \
+ file://9x5_pmecc_2639/0003-mtd-at91-extract-hw-ecc-initialization-to-one-functi.patch \
+ file://9x5_pmecc_2639/0004-atmel_nand-add-PMECC-parameters-in-nand-structure.patch \
+ file://9x5_pmecc_2639/0005-mtd-at91-atmel_nand-add-Programmable-Multibit-ECC-co.patch \
+ file://9x5_pmecc_2639/0006-atmel_nand-port-to-2.6.39.-modify-function-definitio.patch \
+ file://9x5_pmecc_2639/0007-atmel_nand-pass-the-pmecc-parameter-from-board-file-.patch \
+ file://9x5_pmecc_2639/0008-atmel_nand-9x5ek-enable-PMECC-in-9x5ek-board.patch \
+ file://9x5_pmecc_2639/0009-atmel_nand-enable-dma-for-9x5ek.patch \
"
+SRC_URI_append_mtocgd3 = " \
+ ${AT91SAM9X5_PATCHES} \
+ file://defconfig \
+ file://linux-2.6.39.4-mach-at91-mtocgd3.patch \
+ file://linux-2.6.39.4-macb-force-link.patch \
+ file://linux-2.6.39.4-ledtrig-netdev.patch \
+ file://linux-2.6.39.4-at91sam9x5-extreset.patch \
+ file://linux-2.6.39.4-atmel-mci-force-detect.patch \
+ file://linux-2.6.39.4-wl12xx-sdio-irq.patch \
+ file://linux-2.6.35.14-at91-gpio-pullup.patch \
+ file://linux-2.6.32.3-atmel_spi.patch \
+ file://linux-2.6.32.3-at25.patch \
+ file://linux-2.6.39.4-atmel_serial_disable_hwhs.patch \
+ file://linux-2.6.39.4-at91sam9_wdt-10second-timeout.patch \
+ file://linux-2.6.35.14-option-zte.patch \
+ file://linux-2.6.39.4-option-telit.patch \
+ file://linux-2.6.38-sierra-1.7.40.patch \
+ "
+
SRC_URI_append_mt100eocg-pcie-dk = "file://defconfig \
file://linux-2.6.39.4-at91sam9260-reset.patch \
file://linux-2.6.39.4-mach-at91-mt100eocg-pcie-dk.patch \