aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-12-04 09:22:29 -0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-12-04 09:22:29 -0800
commitb5f72d1f70981e6f94668980bc50fd91acb4695b (patch)
tree174787ed4fa42d49e9bedec6daccf5c389e91ee3
parent12e057530821c9839d0d0272cdda555fb36869d1 (diff)
downloadltsi-kernel-b5f72d1f70981e6f94668980bc50fd91acb4695b.tar.gz
at91 patches added
-rw-r--r--patches.at91/0001-MAINTAINERS-add-entry-for-Atmel-isi-driver.patch32
-rw-r--r--patches.at91/0002-MAINTAINERS-add-entry-for-Atmel-touch-screen-ADC-con.patch31
-rw-r--r--patches.at91/0003-MAINTAINERS-add-entry-for-Atmel-DMA-driver.patch32
-rw-r--r--patches.at91/0004-MAINTAINERS-add-entry-for-Atmel-timer-counter-TC.patch34
-rw-r--r--patches.at91/0005-MAINTAINERS-remove-non-responding-web-link-for-atmel.patch27
-rw-r--r--patches.at91/0006-ARM-at91-change-AT91-Kconfig-entry-comment.patch28
-rw-r--r--patches.at91/0007-ARM-at91-Kconfig-change-at91sam9g45-entry.patch40
-rw-r--r--patches.at91/0008-ARM-at91-Kconfig-add-comment-to-at91sam9x5-family-en.patch33
-rw-r--r--patches.at91/0009-ARM-at91-Kconfig-add-clarifications-to-AT91SAM9M10G4.patch34
-rw-r--r--patches.at91/0010-ARM-at91-Kconfig-add-AT91SAM9x5-family-to-AT91_EARLY.patch26
-rw-r--r--patches.at91/0011-ARM-at91-Kconfig-website-link-for-AT91SAM9G20-EK.patch25
-rw-r--r--patches.at91/0012-rtc-Kconfig-remove-dependency-for-AT91-rtc-driver.patch30
-rw-r--r--patches.at91/0013-Input-Kconfig-remove-dependency-for-atmel_tsadcc-dri.patch35
-rw-r--r--patches.at91/0014-hwrng-Kconfig-remove-dependency-for-atmel-rng-driver.patch30
-rw-r--r--patches.at91/0015-ARM-at91-uncompress-Store-UART-address-in-a-variable.patch66
-rw-r--r--patches.at91/0016-ARM-at91-uncompress-autodetect-the-uart-to-use.patch494
-rw-r--r--patches.at91/0017-ARM-at91-drop-at91_set_serial_console.patch882
-rw-r--r--patches.at91/0018-ARM-at91-do-not-pin-mux-the-UARTs-in-init_early.patch1405
-rw-r--r--patches.at91/0019-ARM-at91-move-at91_init_leds-to-board-init.patch288
-rw-r--r--patches.at91/0020-ARM-at91-pm-select-memory-controler-at-runtime.patch117
-rw-r--r--patches.at91/0021-ARM-at91-add-SOC_AT91SAM9-kconfig-option-to-factoris.patch133
-rw-r--r--patches.at91/0022-ARN-at91-introduce-SOC_AT91xxx-define-to-allow-to-co.patch378
-rw-r--r--patches.at91/0023-ARM-at91-dt-do-not-specify-the-board-any-more.patch42
-rw-r--r--patches.at91/0024-ARM-at91-add-defconfig-for-device-tree.patch220
-rw-r--r--patches.at91/0025-ARM-at91-add-at91sam9260-DT-support.patch522
-rw-r--r--patches.at91/0026-arm-at91-add-Calao-TNY-A9260-and-TNY-A9G20-board-sup.patch165
-rw-r--r--patches.at91/0027-ARM-at91-add-at91sam9g20ek-boards-dt-support.patch253
-rw-r--r--patches.at91/0028-ARM-at91-USB-A926x-update-nand-partition.patch64
-rw-r--r--patches.at91/0029-ARM-at91-Calao-USB-A926x-factorize-common-binding-in.patch268
-rw-r--r--patches.at91/0030-ARM-at91-DT-add-Calao-USB-A9260-DT-support.patch57
-rw-r--r--patches.at91/0031-ARM-at91-standard-device-init-only-if-DT-is-not-popu.patch115
-rw-r--r--patches.at91/0032-ARM-at91-add-at91sam9263-DT-support.patch304
-rw-r--r--patches.at91/0033-ARM-at91-add-at91sam9263ek-DT-support.patch191
-rw-r--r--patches.at91/0034-ARM-at91-DT-add-Calao-USB-A9263-board-support.patch165
-rw-r--r--patches.at91/0035-ARM-at91-DT-add-Calao-TNY-A9263-board-support.patch131
-rw-r--r--patches.at91/0036-ARM-at91-add-kizbox-board-dt-support.patch176
-rw-r--r--patches.at91/0037-Ethernut-5-board-support.patch120
-rw-r--r--patches.at91/0038-ARM-at91-Add-machine-header-file-for-AT91SAM9N12-SoC.patch213
-rw-r--r--patches.at91/0039-ARM-at91-Add-machine-files-for-AT91SAM9N12-SoC.patch368
-rw-r--r--patches.at91/0040-ARM-at91-Add-DT-description-files-for-AT91SAM9N12-EK.patch338
-rw-r--r--patches.at91/0041-ARM-at91-remove-two-unused-headers.patch228
-rw-r--r--patches.at91/0042-ARM-at91-fix-at91_aic_write-macro.patch29
-rw-r--r--patches.at91/0043-USB-ohci-at91-use-resource_size-for-memory-io-resour.patch27
-rw-r--r--patches.at91/0044-USB-Kconfig-add-Atmel-usba-driver-entry.patch29
-rw-r--r--patches.at91/0045-ARM-at91-clock-fix-PLLA-overclock-warning.patch47
-rw-r--r--patches.at91/0046-ARM-at91-dts-remove-partial-parameter-in-at91sam9g25.patch29
-rw-r--r--patches.at91/0047-ARM-at91-set-i2c_board_info.type-to-ds1339-directly.patch33
-rw-r--r--patches.at91/0048-ARM-at91-defconfig-Remove-unaffected-config-option.patch123
-rw-r--r--patches.at91/0049-ARM-at91-fix-missing-interrupt-cells-on-gpio-control.patch207
-rw-r--r--patches.at91/0051-ARM-at91-missing-header-file-for-rtc-at91rm9200.c.patch28
-rw-r--r--patches.at91/0052-ASoC-atmel-ssc-include-linux-io.h-for-raw-io.patch37
-rw-r--r--patches.at91/0053-ARM-at91-aic-can-use-fast-eoi-handler-type.patch158
-rw-r--r--patches.at91/0054-ARM-at91-aic-add-dt-support-for-external-irqs.patch122
-rw-r--r--patches.at91/0055-ARM-at91-add-of-irq-priorities-support.patch883
-rw-r--r--patches.at91/0056-ARM-at91-remove-static-irq-priorities-for-sam9x5.patch69
-rw-r--r--patches.at91/0057-ARM-at91-at91-based-machines-specify-their-own-irq-h.patch903
-rw-r--r--patches.at91/0058-ARM-at91-sparse-irq-support.patch1578
-rw-r--r--patches.at91/0059-ARM-at91-remove-mach-irqs.h.patch53
-rw-r--r--patches.at91/0060-ARM-at91-add-AIC5-support.patch606
-rw-r--r--patches.at91/0061-dt-add-property-iteration-helpers.patch129
-rw-r--r--patches.at91/0062-ARM-at91-fix-new-build-errors.patch95
-rw-r--r--patches.at91/0063-dmaengine-at_hdmac-remove-some-at_dma_slave-comments.patch32
-rw-r--r--patches.at91/0064-dmaengine-at_hdmac-remove-ATC_DEFAULT_CTRLA-constant.patch66
-rw-r--r--patches.at91/0065-dmaengine-at_hdmac-take-maxburst-from-slave-configur.patch129
-rw-r--r--patches.at91/0066-dmaengine-at_hdmac-trivial-fix-comment-in-header.patch36
-rw-r--r--patches.at91/0069-AT91-Remove-fixed-mapping-for-AT91RM9200-ethernet.patch1121
-rw-r--r--patches.at91/0070-net-at91_ether-use-gpio_to_irq-for-phy-IRQ-line.patch62
-rw-r--r--patches.at91/0071-net-macb-manage-carrier-state-with-call-to-netif_car.patch67
-rw-r--r--patches.at91/0072-ALSA-atmel-ac97c-correct-the-unexpected-behavior-whe.patch35
-rw-r--r--patches.at91/0073-MTD-at91-extract-hw-ecc-initialization-to-one-functi.patch188
-rw-r--r--patches.at91/0074-MTD-at91-add-dt-parameters-for-Atmel-PMECC.patch157
-rw-r--r--patches.at91/0075-MTD-at91-atmel_nand-Update-driver-to-support-Program.patch959
-rw-r--r--patches.at91/0076-MTD-nand-add-return-value-for-write_page-write_page_.patch153
-rw-r--r--patches.at91/0077-MTD-atmel_nand-revet-the-oob_required-parameter-in-e.patch38
-rw-r--r--patches.at91/0078-MTD-atmel_nand-add-9x5-to-list-of-SoC-with-DMA.patch28
-rw-r--r--patches.at91/0079-MTD-atmel_nand-POI-fall-back-is-not-an-issue-change-.patch26
-rw-r--r--patches.at91/0080-MTD-atmel_nand-add-9n12-to-list-of-SoC-with-DMA.patch29
-rw-r--r--patches.at91/0081-input-atmel_tsadcc-add-support-for-ARCH_AT91SAM9X5.patch392
-rw-r--r--patches.at91/0082-input-atmel_tsadcc-add-touch-screen-pressure-measure.patch104
-rw-r--r--patches.at91/0083-input-atmel_tsadcc-enable-touchscreen-averaging-and-.patch77
-rw-r--r--patches.at91/0084-input-atmel_tsadcc-add-ACR-register-and-change-trigg.patch92
-rw-r--r--patches.at91/0085-AT91-input-atmel_tsadcc-rework-irq-infrastructure-an.patch168
-rw-r--r--patches.at91/0086-input-at91-add-tsadcc_data-for-9x5.patch27
-rw-r--r--patches.at91/0087-input-at91-add-dt-support-for-atmel-touch-screen-adc.patch157
-rw-r--r--patches.at91/0088-net-macb-Add-support-for-Gigabit-Ethernet-mode.patch85
-rw-r--r--patches.at91/0089-net-macb-memory-barriers-cleanup.patch96
-rw-r--r--patches.at91/0090-net-macb-change-debugging-messages.patch112
-rw-r--r--patches.at91/0091-net-macb-remove-macb_get_drvinfo.patch41
-rw-r--r--patches.at91/0092-net-macb-tx-status-is-more-than-8-bits-now.patch28
-rw-r--r--patches.at91/0093-net-macb-clean-up-ring-buffer-logic.patch409
-rw-r--r--patches.at91/0094-net-macb-ethtool-interface-add-register-dump-feature.patch88
-rw-r--r--patches.at91/0095-net-macb-better-manage-tx-errors.patch257
-rw-r--r--patches.at91/0096-net-macb-Offset-first-RX-buffer-by-two-bytes.patch94
-rw-r--r--patches.at91/0097-net-macb-GEM-DMA-configuration-register-update.patch71
-rw-r--r--patches.at91/0098-net-macb-Use-non-coherent-memory-for-rx-buffers.patch378
-rw-r--r--patches.at91/0099-phy-micrel-Use-proper-phy-in-gmac.patch49
-rw-r--r--patches.at91/0100-phy-micrel-we-need-to-register-ks8051-phy-for-emac.patch39
-rw-r--r--patches.at91/0101-usb-gadget-at91_udc-move-the-dereference-below-the-N.patch40
-rw-r--r--patches.at91/0103-USB-ohci-at91-fix-PIO-handling-in-relation-with-numb.patch41
-rw-r--r--patches.at91/0104-usb-gadget-at91_udc-Propagate-devicetree-to-gadget-d.patch28
-rw-r--r--patches.at91/0105-USB-ohci-at91.c-remove-err-usage.patch34
-rw-r--r--patches.at91/0107-media-video-atmel-isi-add-dumb-set_parm.patch42
-rw-r--r--patches.at91/0108-video-atmel_lcdfb-add-support-for-AT91SAM9x5.patch1810
-rw-r--r--patches.at91/0109-video-atmel_lcdfb-The-output-bpp-should-not-change-a.patch66
-rw-r--r--patches.at91/0110-video-atmelfb-initially-split-atmelfb-into-a-driver-.patch2643
-rw-r--r--patches.at91/0111-video-atmelfb-refactor-core-setup.patch403
-rw-r--r--patches.at91/0112-video-atmelfb-refactor-start-stop.patch196
-rw-r--r--patches.at91/0113-video-atmelfb-refactor-isr.patch154
-rw-r--r--patches.at91/0114-video-atmelfb-refactor-backlight-routines.patch256
-rw-r--r--patches.at91/0115-video-atmelfb-refactor-dma_update.patch211
-rw-r--r--patches.at91/0116-video-atmelfb-refactor-LUT.patch80
-rw-r--r--patches.at91/0117-video-atmelfb-refactor-limit_screeninfo.patch92
-rw-r--r--patches.at91/0118-arm-at91-refactor-lcdc-includes.patch804
-rw-r--r--patches.at91/0119-video-atmel_hlcdfb-add-new-driver.patch606
-rw-r--r--patches.at91/0120-WIP-add-clut-resource.patch167
-rw-r--r--patches.at91/0121-video-atmel_lcdfb-add-error-msg-when-out-of-memory.patch33
-rw-r--r--patches.at91/0122-video-atmel_lcdfb-HLCD-modifications.patch238
-rw-r--r--patches.at91/0123-atmel_lcdfb-change-pixel-clock-ratio-calculation.patch31
-rw-r--r--patches.at91/0124-media-at91sam9x5-video-new-driver-for-the-high-end-o.patch1498
-rw-r--r--patches.at91/0125-video-atmel_lcdfb-protect-bl_power-with-CONFIG_BACKL.patch112
-rw-r--r--patches.at91/0126-ARM-at91-9x5-modify-consistent-DMA-size.patch27
-rw-r--r--patches.at91/0127-video-atmel_lcdfb-adapt-to-all-IP-configurations.patch63
-rw-r--r--patches.at91/0128-media-at91sam9x5-video-cleanup-modifications.patch100
-rw-r--r--patches.at91/0129-media-at91sam9x5-video-align-DMA-descriptors-on-64-b.patch134
-rw-r--r--patches.at91/0130-media-at91sam9x5-video-change-scaling-factor-calcula.patch76
-rw-r--r--patches.at91/0131-media-at91sam9x5-video-add-device-tree-support.patch102
-rw-r--r--patches.at91/0132-ARM-at91-video-Atmel-HLCD-is-only-selected-by-newer-.patch59
-rw-r--r--patches.at91/0133-mmc-atmel-mci-the-r-w-proof-capability-lack-was-not-.patch208
-rw-r--r--patches.at91/0134-mmc-atmel-mci-change-the-state-machine-for-compatibi.patch469
-rw-r--r--patches.at91/0135-mmc-atmel-mci-add-support-for-version-lower-than-v2x.patch189
-rw-r--r--patches.at91/0136-mmc-atmel-mci-add-debug-logs.patch250
-rw-r--r--patches.at91/0137-mmc-atmel-mci-fix-data-timeout-issue.patch39
-rw-r--r--patches.at91/0138-ARM-at91-add-atmel-mci-support-for-chips-and-boards-.patch1554
-rw-r--r--patches.at91/0139-ARM-at91-defconfig-change-the-MCI-driver-to-use-in-d.patch140
-rw-r--r--patches.at91/0140-mmc-atmel-mci-fix-burst-chunk-size-modification.patch75
-rw-r--r--patches.at91/0141-mmc-atmel-mci-add-device-tree-support.patch212
-rw-r--r--patches.at91/0142-ARM-at91-add-clocks-for-DT-entries.patch83
-rw-r--r--patches.at91/0143-ARM-dts-add-nodes-for-atmel-hsmci-controllers-for-at.patch152
-rw-r--r--patches.at91/0144-ARM-dts-add-nodes-for-atmel-hsmci-controllers-for-at.patch163
-rw-r--r--patches.at91/0145-mmc-atmel-mci-remove-not-needed-DMA-capability-test.patch32
-rw-r--r--patches.at91/0146-ARM-at91-atmel-mci-remove-unused-setup_dma_addr-macr.patch39
-rw-r--r--patches.at91/0147-mmc-atmel-mci-remove-the-need-for-CONFIG_MMC_ATMELMC.patch57
-rw-r--r--patches.at91/0148-ARM-dts-fix-add-mmc-irq-priority.patch109
-rw-r--r--patches.at91/0149-mmc-atmel-mci-support-8-bit-buswidth.patch32
-rw-r--r--patches.at91/0150-mmc-atmel-mci-fix-incorrect-setting-of-host-data-to-.patch40
-rw-r--r--patches.at91/0151-mmc-block-fix-the-data-timeout-issue-with-ACMD22.patch71
-rw-r--r--patches.at91/0152-mmc-atmel-mci-modify-CLKDIV-displaying-in-debugfs.patch42
-rw-r--r--patches.at91/0153-mmc-atmel-mci-increase-dma-threshold.patch31
-rw-r--r--patches.at91/0154-mmc-atmel-mci-not-busy-flag-has-also-to-be-used-for-.patch56
-rw-r--r--patches.at91/0155-Replace-clk_lookup.con_id-with-clk_lookup.dev_id-ent.patch116
-rw-r--r--patches.at91/0156-i2c-at91-remove-old-polling-driver.patch432
-rw-r--r--patches.at91/0157-i2c-at91-add-new-driver.patch774
-rw-r--r--patches.at91/0158-arm-at91-G45-TWI-remove-open-drain-setting-for-twi-f.patch42
-rw-r--r--patches.at91/0159-ARM-at91-do-not-configure-at91sam9g10-twi-pio-as-ope.patch43
-rw-r--r--patches.at91/0160-i2c-at91-add-dt-support-to-i2c-at91.patch149
-rw-r--r--patches.at91/0161-ARM-at91-add-clocks-for-I2C-DT-entries.patch89
-rw-r--r--patches.at91/0162-ARM-dts-add-twi-nodes-for-atmel-SoCs.patch220
-rw-r--r--patches.at91/0163-ARM-dts-add-twi-nodes-for-atmel-boards.patch86
-rw-r--r--patches.at91/0164-i2c-at91-add-dma-support.patch504
-rw-r--r--patches.at91/0165-i2c-at91-backport-fix-for-devm_clk_get.patch45
-rw-r--r--patches.at91/0166-i2c-at91-add-dt-property-for-DMA-configuration.patch141
-rw-r--r--patches.at91/0167-ARM-at91-add-MCI-DMA-for-at91sam9x5.dtsi.patch35
-rw-r--r--patches.at91/0168-ARM-at91-add-i2c-and-qt1070-pin-muxing.patch34
-rw-r--r--patches.at91/0169-AT91-board-dt-add-mci-pinmux-for-9x5.patch48
-rw-r--r--patches.at91/0170-mtd-atmel_nand-add-4k-page-nand-flash-support-for-PM.patch32
-rw-r--r--patches.at91/0171-mtd-atmel_nand-incease-the-chip_delay-time-tR-for-su.patch30
-rw-r--r--patches.at91/0172-at91-9x5-add-DT-parameters-to-enable-PMECC.patch46
-rw-r--r--patches.at91/0173-ARM-at91-split-9x5-dts-dtsi-in-a-common-set-of-perip.patch124
-rw-r--r--patches.at91/0174-ARM-at91-9x5-family-add-at91sam9x25ek.dts.patch76
-rw-r--r--patches.at91/0175-ARM-at91-add-new-at91sam9g35ek.dts.patch109
-rw-r--r--patches.at91/0176-ARM-at91-add-pinmux-for-9x5-LCD.patch143
-rw-r--r--patches.at91/0177-ARM-at91-add-LCD-HEO-DT-entry-for-at91sam9x5.patch49
-rw-r--r--patches.at91/0178-AT91SAM9G45-add-crypto-peripherals.patch248
-rw-r--r--patches.at91/0179-crypto-add-Atmel-AES-driver.patch1369
-rw-r--r--patches.at91/0180-crypto-add-Atmel-DES-TDES-driver.patch1374
-rw-r--r--patches.at91/0181-crypto-add-Atmel-SHA1-SHA256-driver.patch1226
-rw-r--r--patches.at91/0182-crypto-add-atmel-test-driver.patch502
-rw-r--r--patches.at91/0183-crypto-add-new-tests-to-tcrypt.patch112
-rw-r--r--patches.at91/0184-AT91SAM9G45-crypto-same-platform-data-header-for-all.patch54
-rw-r--r--patches.at91/0185-AT91SAM9G45-dts-add-crypto-peripherals.patch65
-rw-r--r--patches.at91/0186-AT91SAM9N12-add-crypto-peripherals.patch90
-rw-r--r--patches.at91/0187-AT91SAM9N12-dts-add-crypto-peripherals.patch64
-rw-r--r--patches.at91/0188-crypto-Atmel-AES-add-device-tree-support.patch1070
-rw-r--r--patches.at91/0189-crypto-Atmel-TDES-add-device-tree-support.patch932
-rw-r--r--patches.at91/0190-crypto-Atmel-SHA-add-device-tree-support.patch1123
-rw-r--r--patches.at91/0191-crypto-Atmel-Test-add-SHA224-SHA384-and-SHA512-suppo.patch81
-rw-r--r--patches.at91/0192-pinctrl-core-device-tree-mapping-table-parsing-suppo.patch537
-rw-r--r--patches.at91/0193-pinctrl-fix-build-when-CONFIG_OF-CONFIG_PINCTRL.patch35
-rw-r--r--patches.at91/0194-pinctrl-fix-dangling-comment.patch29
-rw-r--r--patches.at91/0195-pinctrl-implement-devm_pinctrl_get-put.patch308
-rw-r--r--patches.at91/0196-pinctrl-add-pinctrl_provide_dummies-interface-for-pl.patch115
-rw-r--r--patches.at91/0197-pinctrl-remove-pinctrl_remove_gpio_range.patch103
-rw-r--r--patches.at91/0198-pinctrl-add-pinctrl_add_gpio_ranges-function.patch55
-rw-r--r--patches.at91/0199-pinctrl-support-gpio-request-deferred-probing.patch51
-rw-r--r--patches.at91/0200-pinctrl-propagate-map-validation-errors.patch38
-rw-r--r--patches.at91/0201-pinctrl-mark-non-EXPERIMENTAL.patch30
-rw-r--r--patches.at91/0202-pinctrl-implement-pinctrl-deferred-probing.patch82
-rw-r--r--patches.at91/0203-pinctrl-replace-list_-with-get_-_count.patch634
-rw-r--r--patches.at91/0204-pinctrl-show-pin-name-when-request-pins.patch40
-rw-r--r--patches.at91/0205-pinctrl-show-pin-name-for-pingroups-in-sysfs.patch106
-rw-r--r--patches.at91/0206-dt-add-of_get_child_count-helper-function.patch49
-rw-r--r--patches.at91/0207-arm-at91-use-macro-to-declare-soc-boot-data.patch191
-rw-r--r--patches.at91/0208-ARM-at91-gpio-implement-request.patch58
-rw-r--r--patches.at91/0209-at91-regroup-gpio-and-pinctrl-under-the-same-ranges.patch505
-rw-r--r--patches.at91/0210-arm-at91-at91sam9x5-fix-gpio-number-per-bank.patch166
-rw-r--r--patches.at91/0211-ARM-at91-add-dummies-pinctrl-for-non-dt-platform.patch34
-rw-r--r--patches.at91/0212-ARM-at91-add-pinctrl-support.patch1872
-rw-r--r--patches.at91/0213-arm-at91-dt-at91sam9-add-pinctrl-support.patch405
-rw-r--r--patches.at91/0214-tty-atmel_serial-add-pinctrl-support.patch49
-rw-r--r--patches.at91/0215-arm-at91-dt-sam9m10g45ek-use-rts-cts-pinctrl-group-f.patch27
-rw-r--r--patches.at91/0216-arm-at91-dt-sam9263ek-use-rts-cts-pinctrl-group-for-.patch27
-rw-r--r--patches.at91/0217-arm-at91-dt-sam9g20ek-use-rts-cts-dtr-dsr-dcd-ri-pin.patch33
-rw-r--r--patches.at91/0218-MTD-atmel-nand-fix-gpio-missing-request.patch86
-rw-r--r--patches.at91/0219-arm-at91-dt-at91sam9-add-nand-pinctrl-support.patch158
-rw-r--r--patches.at91/0220-MTD-atmel_nand-add-pinctrl-consumer-support.patch50
-rw-r--r--patches.at91/0221-pinctrl-at91-add-deglitch-debounce-pull-down-and-sch.patch194
-rw-r--r--patches.at91/0222-mtd-atmel_nand-fix-the-compile-error-which-miss-labe.patch50
-rw-r--r--patches.at91/0223-pinctrl-at91-fix-compatible-order.patch39
-rw-r--r--patches.at91/0224-pinctrl-at91-fix-gpio-irq-support.patch46
-rw-r--r--patches.at91/0225-i2c-at91-add-pinctrl.patch46
-rw-r--r--patches.at91/0226-media-atmel_isi-add-pinctrl.patch46
-rw-r--r--patches.at91/0227-mmc-at91-add-pinctrl.patch91
-rw-r--r--patches.at91/0228-video-atmel_lcdfb-add-pinctrl.patch47
-rw-r--r--patches.at91/0229-arm-at91sam9g45-add-missing-uart-pinctrl-node.patch132
-rw-r--r--patches.at91/0230-arm-at91sam9263-add-missing-uart-pinctrl-node.patch109
-rw-r--r--patches.at91/0231-arm-at91sam9260-add-missing-uart-pinctrl-node.patch182
-rw-r--r--patches.at91/0232-arm-at91sam9x5-sync-with-the-mainline.patch620
-rw-r--r--patches.at91/0233-ARM-at91-DT-add-i2c-mmc-nand-pinctrl-in-device-tree-.patch336
-rw-r--r--patches.at91/0234-at91sam9x5-add-lcd-pinctrl-support.patch69
-rw-r--r--patches.at91/0235-arm-at91sam9x5ek-drop-temporary-pinmux.patch72
-rw-r--r--patches.at91/0236-video-atmel-lcd-only-request-the-pinctrl-once.patch190
-rw-r--r--patches.at91/0237-ARM-at91-add-at91-3.4-trunk-contents.txt-file.patch91
-rw-r--r--patches.at91/0238-ARM-at91-add-defconfig-for-sam9x5-family.patch258
-rw-r--r--patches.at91/0239-MMC-atmel-mci-add-device-tree-property-for-configura.patch140
-rw-r--r--patches.at91/0240-pinctrl-at19-fix-typo-on-PULL_UP.patch26
-rw-r--r--patches.at91/0241-pinctrl-at91-fix-pull-down-support.patch40
-rw-r--r--patches.at91/0242-arm-at91sam9xcm-add-specific-nand-pinctrl.patch27
-rw-r--r--patches.at91/0243-pinctrl-at91-fix-debounce-support.patch28
-rw-r--r--patches.at91/0245-ARM-at91-dts-at91sam9g20ek_common-Fix-typos-in-butto.patch36
-rw-r--r--patches.at91/0246-ARM-at91-fix-external-interrupt-specification-in-boa.patch61
-rw-r--r--patches.at91/0248-ARM-at91-drop-duplicated-config-SOC_AT91SAM9-entry.patch43
-rw-r--r--patches.at91/0249-ARM-at91-fix-at91x40-build.patch33
-rw-r--r--patches.at91/0250-ARM-at91-fix-external-interrupts-in-non-DT-case.patch76
-rw-r--r--patches.at91/0251-ARM-at91-i2c-change-id-to-let-i2c-at91-work.patch154
-rw-r--r--patches.at91/0252-net-macb-align-ring-buffer-function-with-mainline.patch43
-rw-r--r--patches.at91/0253-net-macb-move-to-circ_buf-macros-and-fix-initial-con.patch90
-rw-r--r--series250
247 files changed, 54619 insertions, 0 deletions
diff --git a/patches.at91/0001-MAINTAINERS-add-entry-for-Atmel-isi-driver.patch b/patches.at91/0001-MAINTAINERS-add-entry-for-Atmel-isi-driver.patch
new file mode 100644
index 00000000000000..cf8199884a1106
--- /dev/null
+++ b/patches.at91/0001-MAINTAINERS-add-entry-for-Atmel-isi-driver.patch
@@ -0,0 +1,32 @@
+From f3bd6419099a0cfefc3b13cf95ba34015f06ffb3 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Fri, 23 Mar 2012 17:56:29 +0800
+Subject: MAINTAINERS: add entry for Atmel isi driver
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ MAINTAINERS | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index a60009d..c7c725e 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -1331,6 +1331,13 @@ M: Nicolas Ferre <nicolas.ferre@atmel.com>
+ S: Supported
+ F: drivers/tty/serial/atmel_serial.c
+
++ATMEL ISI DRIVER
++M: Josh Wu <josh.wu@atmel.com>
++L: linux-media@vger.kernel.org
++S: Supported
++F: drivers/media/video/atmel-isi.c
++F: include/media/atmel-isi.h
++
+ ATMEL LCDFB DRIVER
+ M: Nicolas Ferre <nicolas.ferre@atmel.com>
+ L: linux-fbdev@vger.kernel.org
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0002-MAINTAINERS-add-entry-for-Atmel-touch-screen-ADC-con.patch b/patches.at91/0002-MAINTAINERS-add-entry-for-Atmel-touch-screen-ADC-con.patch
new file mode 100644
index 00000000000000..d4a2238d683a4a
--- /dev/null
+++ b/patches.at91/0002-MAINTAINERS-add-entry-for-Atmel-touch-screen-ADC-con.patch
@@ -0,0 +1,31 @@
+From ef899cb1d2fda864b02a7efa424767981353f1b5 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Fri, 23 Mar 2012 17:56:55 +0800
+Subject: MAINTAINERS: add entry for Atmel touch screen ADC controller driver
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ MAINTAINERS | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index c7c725e..347df81 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -1355,6 +1355,12 @@ M: Nicolas Ferre <nicolas.ferre@atmel.com>
+ S: Supported
+ F: drivers/spi/spi-atmel.*
+
++ATMEL TSADCC DRIVER
++M: Josh Wu <josh.wu@atmel.com>
++L: linux-input@vger.kernel.org
++S: Supported
++F: drivers/input/touchscreen/atmel_tsadcc.c
++
+ ATMEL USBA UDC DRIVER
+ M: Nicolas Ferre <nicolas.ferre@atmel.com>
+ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0003-MAINTAINERS-add-entry-for-Atmel-DMA-driver.patch b/patches.at91/0003-MAINTAINERS-add-entry-for-Atmel-DMA-driver.patch
new file mode 100644
index 00000000000000..68b5ddaac06d69
--- /dev/null
+++ b/patches.at91/0003-MAINTAINERS-add-entry-for-Atmel-DMA-driver.patch
@@ -0,0 +1,32 @@
+From 2dd30cf629c3267c2925a9925b31addf1ef168b6 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 26 Mar 2012 15:50:36 +0200
+Subject: MAINTAINERS: add entry for Atmel DMA driver
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ MAINTAINERS | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 347df81..5d607d2 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -1331,6 +1331,14 @@ M: Nicolas Ferre <nicolas.ferre@atmel.com>
+ S: Supported
+ F: drivers/tty/serial/atmel_serial.c
+
++ATMEL DMA DRIVER
++M: Nicolas Ferre <nicolas.ferre@atmel.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Supported
++F: drivers/dma/at_hdmac.c
++F: drivers/dma/at_hdmac_regs.h
++F: arch/arm/mach-at91/include/mach/at_hdmac.h
++
+ ATMEL ISI DRIVER
+ M: Josh Wu <josh.wu@atmel.com>
+ L: linux-media@vger.kernel.org
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0004-MAINTAINERS-add-entry-for-Atmel-timer-counter-TC.patch b/patches.at91/0004-MAINTAINERS-add-entry-for-Atmel-timer-counter-TC.patch
new file mode 100644
index 00000000000000..3f2de362ad97d9
--- /dev/null
+++ b/patches.at91/0004-MAINTAINERS-add-entry-for-Atmel-timer-counter-TC.patch
@@ -0,0 +1,34 @@
+From 811046c42ca111ebc64328429ae035f48dddb2fd Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 26 Mar 2012 15:59:32 +0200
+Subject: MAINTAINERS: add entry for Atmel timer counter (TC)
+
+Add an entry for the Timer Counter (TC) library and the clocksource
+driver that is using this library.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ MAINTAINERS | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 5d607d2..54d18b0 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -1363,6 +1363,13 @@ M: Nicolas Ferre <nicolas.ferre@atmel.com>
+ S: Supported
+ F: drivers/spi/spi-atmel.*
+
++ATMEL Timer Counter (TC) AND CLOCKSOURCE DRIVERS
++M: Nicolas Ferre <nicolas.ferre@atmel.com>
++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
++S: Supported
++F: drivers/misc/atmel_tclib.c
++F: drivers/clocksource/tcb_clksrc.c
++
+ ATMEL TSADCC DRIVER
+ M: Josh Wu <josh.wu@atmel.com>
+ L: linux-input@vger.kernel.org
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0005-MAINTAINERS-remove-non-responding-web-link-for-atmel.patch b/patches.at91/0005-MAINTAINERS-remove-non-responding-web-link-for-atmel.patch
new file mode 100644
index 00000000000000..a516b9522b0d31
--- /dev/null
+++ b/patches.at91/0005-MAINTAINERS-remove-non-responding-web-link-for-atmel.patch
@@ -0,0 +1,27 @@
+From ff97bdd9bbdcd2f550b68c11d90a3e01873933c7 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 26 Mar 2012 16:11:19 +0200
+Subject: MAINTAINERS: remove non-responding web link for atmel_usba driver
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Cc: Haavard Skinnemoen <hskinnemoen@gmail.com>
+Cc: Hans-Christian Egtvedt <egtvedt@samfundet.no>
+---
+ MAINTAINERS | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 54d18b0..9c7e7ce 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -1379,7 +1379,6 @@ F: drivers/input/touchscreen/atmel_tsadcc.c
+ ATMEL USBA UDC DRIVER
+ M: Nicolas Ferre <nicolas.ferre@atmel.com>
+ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+-W: http://avr32linux.org/twiki/bin/view/Main/AtmelUsbDeviceDriver
+ S: Supported
+ F: drivers/usb/gadget/atmel_usba_udc.*
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0006-ARM-at91-change-AT91-Kconfig-entry-comment.patch b/patches.at91/0006-ARM-at91-change-AT91-Kconfig-entry-comment.patch
new file mode 100644
index 00000000000000..d84aa0d952cec3
--- /dev/null
+++ b/patches.at91/0006-ARM-at91-change-AT91-Kconfig-entry-comment.patch
@@ -0,0 +1,28 @@
+From cfcd98b36cbb2f074a06b1665727a72d3677ce64 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 15 Mar 2012 12:21:12 +0100
+Subject: ARM: at91: change AT91 Kconfig entry comment
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/Kconfig | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index 7a8660a..ddef021 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -340,8 +340,8 @@ config ARCH_AT91
+ select IRQ_DOMAIN
+ select NEED_MACH_IO_H if PCCARD
+ help
+- This enables support for systems based on the Atmel AT91RM9200,
+- AT91SAM9 processors.
++ This enables support for systems based on Atmel
++ AT91RM9200 and AT91SAM9* processors.
+
+ config ARCH_BCMRING
+ bool "Broadcom BCMRING"
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0007-ARM-at91-Kconfig-change-at91sam9g45-entry.patch b/patches.at91/0007-ARM-at91-Kconfig-change-at91sam9g45-entry.patch
new file mode 100644
index 00000000000000..a709d75a03e1f7
--- /dev/null
+++ b/patches.at91/0007-ARM-at91-Kconfig-change-at91sam9g45-entry.patch
@@ -0,0 +1,40 @@
+From 4b6fd2b781b2091e70dbfe0d3b3bf5ad70e9664b Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 15 Mar 2012 12:26:43 +0100
+Subject: ARM: at91/Kconfig: change at91sam9g45 entry
+
+The AT91SAM9G45 entry covers the whole family so we also add the AT91SAM9M10
+name and the "families" qualifier. Then, add a comment to explain which SoCs
+are supported by this entry: AT91SAM9G45, AT91SAM9G46 but also
+AT91SAM9M10 and AT91SAM9M11.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/Kconfig | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
+index 45db05d..dfbc2c5 100644
+--- a/arch/arm/mach-at91/Kconfig
++++ b/arch/arm/mach-at91/Kconfig
+@@ -89,13 +89,16 @@ config ARCH_AT91SAM9G20
+ select HAVE_NET_MACB
+
+ config ARCH_AT91SAM9G45
+- bool "AT91SAM9G45"
++ bool "AT91SAM9G45 or AT91SAM9M10 families"
+ select CPU_ARM926T
+ select GENERIC_CLOCKEVENTS
+ select HAVE_AT91_USART3
+ select HAVE_FB_ATMEL
+ select HAVE_NET_MACB
+ select HAVE_AT91_DBGU1
++ help
++ Select this if you are using one of Atmel's AT91SAM9G45 family SoC.
++ This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11.
+
+ config ARCH_AT91SAM9X5
+ bool "AT91SAM9x5 family"
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0008-ARM-at91-Kconfig-add-comment-to-at91sam9x5-family-en.patch b/patches.at91/0008-ARM-at91-Kconfig-add-comment-to-at91sam9x5-family-en.patch
new file mode 100644
index 00000000000000..02a7a09d9edefc
--- /dev/null
+++ b/patches.at91/0008-ARM-at91-Kconfig-add-comment-to-at91sam9x5-family-en.patch
@@ -0,0 +1,33 @@
+From 780545021feb2796b0595ebb300522c862bafc55 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 15 Mar 2012 12:48:41 +0100
+Subject: ARM: at91/Kconfig: add comment to at91sam9x5 family entry
+
+Add comment to make it clear that several SoC are supported by
+this generic entry.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/Kconfig | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
+index dfbc2c5..cad7a15 100644
+--- a/arch/arm/mach-at91/Kconfig
++++ b/arch/arm/mach-at91/Kconfig
+@@ -107,6 +107,12 @@ config ARCH_AT91SAM9X5
+ select HAVE_FB_ATMEL
+ select HAVE_NET_MACB
+ select HAVE_AT91_DBGU0
++ help
++ Select this if you are using one of Atmel's AT91SAM9x5 family SoC.
++ This means that your SAM9 name finishes with a '5' (except if it is
++ AT91SAM9G45!).
++ This support covers AT91SAM9G15, AT91SAM9G25, AT91SAM9X25, AT91SAM9G35
++ and AT91SAM9X35.
+
+ config ARCH_AT91X40
+ bool "AT91x40"
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0009-ARM-at91-Kconfig-add-clarifications-to-AT91SAM9M10G4.patch b/patches.at91/0009-ARM-at91-Kconfig-add-clarifications-to-AT91SAM9M10G4.patch
new file mode 100644
index 00000000000000..d5de31639952e9
--- /dev/null
+++ b/patches.at91/0009-ARM-at91-Kconfig-add-clarifications-to-AT91SAM9M10G4.patch
@@ -0,0 +1,34 @@
+From 2eb2471c5bf340e1057c2e5faba6d8b23f6f23e4 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 15 Mar 2012 12:57:03 +0100
+Subject: ARM: at91/Kconfig: add clarifications to AT91SAM9M10G45-EK entry
+
+Add clarifications about the SoCs that can be found on an AT91SAM9M10G45-EK
+board. Add also the web link to this board on Atmel's website.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/Kconfig | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
+index cad7a15..d2922a1 100644
+--- a/arch/arm/mach-at91/Kconfig
++++ b/arch/arm/mach-at91/Kconfig
+@@ -442,9 +442,10 @@ comment "AT91SAM9G45 Board Type"
+ config MACH_AT91SAM9M10G45EK
+ bool "Atmel AT91SAM9M10G45-EK Evaluation Kits"
+ help
+- Select this if you are using Atmel's AT91SAM9G45-EKES Evaluation Kit.
+- "ES" at the end of the name means that this board is an
+- Engineering Sample.
++ Select this if you are using Atmel's AT91SAM9M10G45-EK Evaluation Kit.
++ Those boards can be populated with any SoC of AT91SAM9G45 or AT91SAM9M10
++ families: AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11.
++ <http://www.atmel.com/tools/SAM9M10-G45-EK.aspx>
+
+ endif
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0010-ARM-at91-Kconfig-add-AT91SAM9x5-family-to-AT91_EARLY.patch b/patches.at91/0010-ARM-at91-Kconfig-add-AT91SAM9x5-family-to-AT91_EARLY.patch
new file mode 100644
index 00000000000000..48aedef8c2010e
--- /dev/null
+++ b/patches.at91/0010-ARM-at91-Kconfig-add-AT91SAM9x5-family-to-AT91_EARLY.patch
@@ -0,0 +1,26 @@
+From f46c2a68a6ad0d570c5c8894d8589cb91f0e2d5f Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 15 Mar 2012 13:49:21 +0100
+Subject: ARM: at91/Kconfig: add AT91SAM9x5 family to AT91_EARLY_DBGU0 entry
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
+index d2922a1..e0b8b10 100644
+--- a/arch/arm/mach-at91/Kconfig
++++ b/arch/arm/mach-at91/Kconfig
+@@ -529,7 +529,7 @@ choice
+ prompt "Select a UART for early kernel messages"
+
+ config AT91_EARLY_DBGU0
+- bool "DBGU on rm9200, 9260/9g20, 9261/9g10 and 9rl"
++ bool "DBGU on rm9200, 9260/9g20, 9261/9g10, 9rl and 9x5"
+ depends on HAVE_AT91_DBGU0
+
+ config AT91_EARLY_DBGU1
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0011-ARM-at91-Kconfig-website-link-for-AT91SAM9G20-EK.patch b/patches.at91/0011-ARM-at91-Kconfig-website-link-for-AT91SAM9G20-EK.patch
new file mode 100644
index 00000000000000..f43f496e1e49d1
--- /dev/null
+++ b/patches.at91/0011-ARM-at91-Kconfig-website-link-for-AT91SAM9G20-EK.patch
@@ -0,0 +1,25 @@
+From 761e63c4d6f8cbf48f12bc90aff9083eefb37e2c Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 15 Mar 2012 13:56:44 +0100
+Subject: ARM: at91/Kconfig: website link for AT91SAM9G20-EK
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
+index e0b8b10..8acc164 100644
+--- a/arch/arm/mach-at91/Kconfig
++++ b/arch/arm/mach-at91/Kconfig
+@@ -373,6 +373,7 @@ config MACH_AT91SAM9G20EK_2MMC
+ Select this if you are using an Atmel AT91SAM9G20-EK Evaluation Kit
+ with 2 SD/MMC Slots. This is the case for AT91SAM9G20-EK rev. C and
+ onwards.
++ <http://www.atmel.com/tools/SAM9G20-EK.aspx>
+
+ config MACH_CPU9G20
+ bool "Eukrea CPU9G20 board"
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0012-rtc-Kconfig-remove-dependency-for-AT91-rtc-driver.patch b/patches.at91/0012-rtc-Kconfig-remove-dependency-for-AT91-rtc-driver.patch
new file mode 100644
index 00000000000000..dd918d05e054b5
--- /dev/null
+++ b/patches.at91/0012-rtc-Kconfig-remove-dependency-for-AT91-rtc-driver.patch
@@ -0,0 +1,30 @@
+From aa2c1a9a69b0a74992d2e4d129f69f58c9b9c433 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 15 Mar 2012 14:38:09 +0100
+Subject: rtc: Kconfig: remove dependency for AT91 rtc driver
+
+This will allow to select this driver for newer SoCs.
+Keep dependency on AT91 because of the use of an header
+file located in include/mach directory.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/rtc/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
+index 8c8377d..4161bfe 100644
+--- a/drivers/rtc/Kconfig
++++ b/drivers/rtc/Kconfig
+@@ -838,7 +838,7 @@ 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_AT91
+ help
+ Driver for the internal RTC (Realtime Clock) module found on
+ Atmel AT91RM9200's and some AT91SAM9 chips. On AT91SAM9 chips
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0013-Input-Kconfig-remove-dependency-for-atmel_tsadcc-dri.patch b/patches.at91/0013-Input-Kconfig-remove-dependency-for-atmel_tsadcc-dri.patch
new file mode 100644
index 00000000000000..f79ccb33435eb2
--- /dev/null
+++ b/patches.at91/0013-Input-Kconfig-remove-dependency-for-atmel_tsadcc-dri.patch
@@ -0,0 +1,35 @@
+From 3f06a6301f2cba15b6e6f60283c5910f6383ed3f Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 15 Mar 2012 16:02:02 +0100
+Subject: Input: Kconfig: remove dependency for atmel_tsadcc driver
+
+This will allow to select this driver for newer SoCs.
+Keep dependency on AT91 because of the use of an header
+file located in include/mach directory.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Dmitry Torokhov <dtor@mail.ru>
+---
+ drivers/input/touchscreen/Kconfig | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
+index 2a21419..75838d7 100644
+--- a/drivers/input/touchscreen/Kconfig
++++ b/drivers/input/touchscreen/Kconfig
+@@ -489,10 +489,10 @@ config TOUCHSCREEN_TI_TSCADC
+
+ config TOUCHSCREEN_ATMEL_TSADCC
+ tristate "Atmel Touchscreen Interface"
+- depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
++ depends on ARCH_AT91
+ help
+ Say Y here if you have a 4-wire touchscreen connected to the
+- ADC Controller on your Atmel SoC (such as the AT91SAM9RL).
++ ADC Controller on your Atmel SoC.
+
+ If unsure, say N.
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0014-hwrng-Kconfig-remove-dependency-for-atmel-rng-driver.patch b/patches.at91/0014-hwrng-Kconfig-remove-dependency-for-atmel-rng-driver.patch
new file mode 100644
index 00000000000000..b2703f828ca404
--- /dev/null
+++ b/patches.at91/0014-hwrng-Kconfig-remove-dependency-for-atmel-rng-driver.patch
@@ -0,0 +1,30 @@
+From 3511638f3d8c7369a85592a17b186482c1057b99 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 15 Mar 2012 16:10:59 +0100
+Subject: hwrng: Kconfig: remove dependency for atmel-rng driver
+
+This will allow to select this driver for newer SoCs. Make sure to
+keep dependency on HAVE_CLK to avoid breaking other machines.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
+---
+ drivers/char/hw_random/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
+index 0689bf6..b2402eb 100644
+--- a/drivers/char/hw_random/Kconfig
++++ b/drivers/char/hw_random/Kconfig
+@@ -62,7 +62,7 @@ config HW_RANDOM_AMD
+
+ config HW_RANDOM_ATMEL
+ tristate "Atmel Random Number Generator support"
+- depends on HW_RANDOM && ARCH_AT91SAM9G45
++ depends on HW_RANDOM && HAVE_CLK
+ default HW_RANDOM
+ ---help---
+ This driver provides kernel-side support for the Random Number
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0015-ARM-at91-uncompress-Store-UART-address-in-a-variable.patch b/patches.at91/0015-ARM-at91-uncompress-Store-UART-address-in-a-variable.patch
new file mode 100644
index 00000000000000..bc6a6391476218
--- /dev/null
+++ b/patches.at91/0015-ARM-at91-uncompress-Store-UART-address-in-a-variable.patch
@@ -0,0 +1,66 @@
+From d100869e11a7ed455412896d44314a81a386ed42 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Wed, 15 Feb 2012 18:35:40 +0800
+Subject: ARM: at91: uncompress Store UART address in a variable
+
+This will allow a future change to auto-detect which UART to use.
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/include/mach/uncompress.h | 20 +++++++++++---------
+ 1 file changed, 11 insertions(+), 9 deletions(-)
+
+diff --git a/arch/arm/mach-at91/include/mach/uncompress.h b/arch/arm/mach-at91/include/mach/uncompress.h
+index 4218647..d985af7 100644
+--- a/arch/arm/mach-at91/include/mach/uncompress.h
++++ b/arch/arm/mach-at91/include/mach/uncompress.h
+@@ -43,6 +43,14 @@
+ #define UART_OFFSET AT91_USART5
+ #endif
+
++void __iomem *at91_uart;
++
++static inline void arch_decomp_setup(void)
++{
++#ifdef UART_OFFSET
++ at91_uart = (void __iomem *) UART_OFFSET; /* physical address */
++#endif
++}
+ /*
+ * The following code assumes the serial port has already been
+ * initialized by the bootloader. If you didn't setup a port in
+@@ -53,27 +61,21 @@
+ static void putc(int c)
+ {
+ #ifdef UART_OFFSET
+- void __iomem *sys = (void __iomem *) UART_OFFSET; /* physical address */
+-
+- while (!(__raw_readl(sys + ATMEL_US_CSR) & ATMEL_US_TXRDY))
++ while (!(__raw_readl(at91_uart + ATMEL_US_CSR) & ATMEL_US_TXRDY))
+ barrier();
+- __raw_writel(c, sys + ATMEL_US_THR);
++ __raw_writel(c, at91_uart + ATMEL_US_THR);
+ #endif
+ }
+
+ static inline void flush(void)
+ {
+ #ifdef UART_OFFSET
+- void __iomem *sys = (void __iomem *) UART_OFFSET; /* physical address */
+-
+ /* wait for transmission to complete */
+- while (!(__raw_readl(sys + ATMEL_US_CSR) & ATMEL_US_TXEMPTY))
++ while (!(__raw_readl(at91_uart + ATMEL_US_CSR) & ATMEL_US_TXEMPTY))
+ barrier();
+ #endif
+ }
+
+-#define arch_decomp_setup()
+-
+ #define arch_decomp_wdog()
+
+ #endif
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0016-ARM-at91-uncompress-autodetect-the-uart-to-use.patch b/patches.at91/0016-ARM-at91-uncompress-autodetect-the-uart-to-use.patch
new file mode 100644
index 00000000000000..b54384b26e4b9c
--- /dev/null
+++ b/patches.at91/0016-ARM-at91-uncompress-autodetect-the-uart-to-use.patch
@@ -0,0 +1,494 @@
+From e740a739f469c0128ad12bf8388cdb69bdccc005 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Wed, 15 Feb 2012 18:44:40 +0800
+Subject: ARM: at91: uncompress: autodetect the uart to use
+
+This will now autodetect the first uart enabled by the bootloader
+and will use it for uncompress. This will still assume that the bootloader
+configured it (pins and clock).
+
+This also allows to include all soc headers together.
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/Kconfig | 53 --------
+ arch/arm/mach-at91/include/mach/at91rm9200.h | 5 -
+ arch/arm/mach-at91/include/mach/at91sam9260.h | 7 --
+ arch/arm/mach-at91/include/mach/at91sam9261.h | 4 -
+ arch/arm/mach-at91/include/mach/at91sam9263.h | 4 -
+ arch/arm/mach-at91/include/mach/at91sam9g45.h | 5 -
+ arch/arm/mach-at91/include/mach/at91sam9rl.h | 5 -
+ arch/arm/mach-at91/include/mach/at91sam9x5.h | 8 --
+ arch/arm/mach-at91/include/mach/hardware.h | 16 +--
+ arch/arm/mach-at91/include/mach/uncompress.h | 170 ++++++++++++++++++++++----
+ 10 files changed, 148 insertions(+), 129 deletions(-)
+
+diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
+index 8acc164..885fdb9 100644
+--- a/arch/arm/mach-at91/Kconfig
++++ b/arch/arm/mach-at91/Kconfig
+@@ -9,15 +9,6 @@ config HAVE_AT91_DBGU0
+ config HAVE_AT91_DBGU1
+ bool
+
+-config HAVE_AT91_USART3
+- bool
+-
+-config HAVE_AT91_USART4
+- bool
+-
+-config HAVE_AT91_USART5
+- bool
+-
+ config AT91_SAM9_ALT_RESET
+ bool
+ default !ARCH_AT91X40
+@@ -36,16 +27,12 @@ config ARCH_AT91RM9200
+ select CPU_ARM920T
+ select GENERIC_CLOCKEVENTS
+ select HAVE_AT91_DBGU0
+- select HAVE_AT91_USART3
+
+ config ARCH_AT91SAM9260
+ bool "AT91SAM9260 or AT91SAM9XE"
+ select CPU_ARM926T
+ select GENERIC_CLOCKEVENTS
+ select HAVE_AT91_DBGU0
+- select HAVE_AT91_USART3
+- select HAVE_AT91_USART4
+- select HAVE_AT91_USART5
+ select HAVE_NET_MACB
+
+ config ARCH_AT91SAM9261
+@@ -74,7 +61,6 @@ config ARCH_AT91SAM9RL
+ bool "AT91SAM9RL"
+ select CPU_ARM926T
+ select GENERIC_CLOCKEVENTS
+- select HAVE_AT91_USART3
+ select HAVE_FB_ATMEL
+ select HAVE_AT91_DBGU0
+
+@@ -83,16 +69,12 @@ config ARCH_AT91SAM9G20
+ select CPU_ARM926T
+ select GENERIC_CLOCKEVENTS
+ select HAVE_AT91_DBGU0
+- select HAVE_AT91_USART3
+- select HAVE_AT91_USART4
+- select HAVE_AT91_USART5
+ select HAVE_NET_MACB
+
+ config ARCH_AT91SAM9G45
+ bool "AT91SAM9G45 or AT91SAM9M10 families"
+ select CPU_ARM926T
+ select GENERIC_CLOCKEVENTS
+- select HAVE_AT91_USART3
+ select HAVE_FB_ATMEL
+ select HAVE_NET_MACB
+ select HAVE_AT91_DBGU1
+@@ -526,41 +508,6 @@ config AT91_TIMER_HZ
+ system clock (of at least several MHz), rounding is less of a
+ problem so it can be safer to use a decimal values like 100.
+
+-choice
+- prompt "Select a UART for early kernel messages"
+-
+-config AT91_EARLY_DBGU0
+- bool "DBGU on rm9200, 9260/9g20, 9261/9g10, 9rl and 9x5"
+- depends on HAVE_AT91_DBGU0
+-
+-config AT91_EARLY_DBGU1
+- bool "DBGU on 9263 and 9g45"
+- depends on HAVE_AT91_DBGU1
+-
+-config AT91_EARLY_USART0
+- bool "USART0"
+-
+-config AT91_EARLY_USART1
+- bool "USART1"
+-
+-config AT91_EARLY_USART2
+- bool "USART2"
+- depends on ! ARCH_AT91X40
+-
+-config AT91_EARLY_USART3
+- bool "USART3"
+- depends on HAVE_AT91_USART3
+-
+-config AT91_EARLY_USART4
+- bool "USART4"
+- depends on HAVE_AT91_USART4
+-
+-config AT91_EARLY_USART5
+- bool "USART5"
+- depends on HAVE_AT91_USART5
+-
+-endchoice
+-
+ endmenu
+
+ endif
+diff --git a/arch/arm/mach-at91/include/mach/at91rm9200.h b/arch/arm/mach-at91/include/mach/at91rm9200.h
+index 603e6aa..e67317c 100644
+--- a/arch/arm/mach-at91/include/mach/at91rm9200.h
++++ b/arch/arm/mach-at91/include/mach/at91rm9200.h
+@@ -88,11 +88,6 @@
+ #define AT91RM9200_BASE_RTC 0xfffffe00 /* Real-Time Clock */
+ #define AT91RM9200_BASE_MC 0xffffff00 /* Memory Controllers */
+
+-#define AT91_USART0 AT91RM9200_BASE_US0
+-#define AT91_USART1 AT91RM9200_BASE_US1
+-#define AT91_USART2 AT91RM9200_BASE_US2
+-#define AT91_USART3 AT91RM9200_BASE_US3
+-
+ /*
+ * Internal Memory.
+ */
+diff --git a/arch/arm/mach-at91/include/mach/at91sam9260.h b/arch/arm/mach-at91/include/mach/at91sam9260.h
+index 08ae9af..416c7b6 100644
+--- a/arch/arm/mach-at91/include/mach/at91sam9260.h
++++ b/arch/arm/mach-at91/include/mach/at91sam9260.h
+@@ -95,13 +95,6 @@
+ #define AT91SAM9260_BASE_WDT 0xfffffd40
+ #define AT91SAM9260_BASE_GPBR 0xfffffd50
+
+-#define AT91_USART0 AT91SAM9260_BASE_US0
+-#define AT91_USART1 AT91SAM9260_BASE_US1
+-#define AT91_USART2 AT91SAM9260_BASE_US2
+-#define AT91_USART3 AT91SAM9260_BASE_US3
+-#define AT91_USART4 AT91SAM9260_BASE_US4
+-#define AT91_USART5 AT91SAM9260_BASE_US5
+-
+
+ /*
+ * Internal Memory.
+diff --git a/arch/arm/mach-at91/include/mach/at91sam9261.h b/arch/arm/mach-at91/include/mach/at91sam9261.h
+index 44fbdc1..a041406 100644
+--- a/arch/arm/mach-at91/include/mach/at91sam9261.h
++++ b/arch/arm/mach-at91/include/mach/at91sam9261.h
+@@ -79,10 +79,6 @@
+ #define AT91SAM9261_BASE_WDT 0xfffffd40
+ #define AT91SAM9261_BASE_GPBR 0xfffffd50
+
+-#define AT91_USART0 AT91SAM9261_BASE_US0
+-#define AT91_USART1 AT91SAM9261_BASE_US1
+-#define AT91_USART2 AT91SAM9261_BASE_US2
+-
+
+ /*
+ * Internal Memory.
+diff --git a/arch/arm/mach-at91/include/mach/at91sam9263.h b/arch/arm/mach-at91/include/mach/at91sam9263.h
+index d96cbb2..d201029 100644
+--- a/arch/arm/mach-at91/include/mach/at91sam9263.h
++++ b/arch/arm/mach-at91/include/mach/at91sam9263.h
+@@ -95,10 +95,6 @@
+ #define AT91SAM9263_BASE_RTT1 0xfffffd50
+ #define AT91SAM9263_BASE_GPBR 0xfffffd60
+
+-#define AT91_USART0 AT91SAM9263_BASE_US0
+-#define AT91_USART1 AT91SAM9263_BASE_US1
+-#define AT91_USART2 AT91SAM9263_BASE_US2
+-
+ #define AT91_SMC AT91_SMC0
+
+ /*
+diff --git a/arch/arm/mach-at91/include/mach/at91sam9g45.h b/arch/arm/mach-at91/include/mach/at91sam9g45.h
+index d052abc..3a4da24 100644
+--- a/arch/arm/mach-at91/include/mach/at91sam9g45.h
++++ b/arch/arm/mach-at91/include/mach/at91sam9g45.h
+@@ -106,11 +106,6 @@
+ #define AT91SAM9G45_BASE_RTC 0xfffffdb0
+ #define AT91SAM9G45_BASE_GPBR 0xfffffd60
+
+-#define AT91_USART0 AT91SAM9G45_BASE_US0
+-#define AT91_USART1 AT91SAM9G45_BASE_US1
+-#define AT91_USART2 AT91SAM9G45_BASE_US2
+-#define AT91_USART3 AT91SAM9G45_BASE_US3
+-
+ /*
+ * Internal Memory.
+ */
+diff --git a/arch/arm/mach-at91/include/mach/at91sam9rl.h b/arch/arm/mach-at91/include/mach/at91sam9rl.h
+index e0073eb..a15db56 100644
+--- a/arch/arm/mach-at91/include/mach/at91sam9rl.h
++++ b/arch/arm/mach-at91/include/mach/at91sam9rl.h
+@@ -89,11 +89,6 @@
+ #define AT91SAM9RL_BASE_GPBR 0xfffffd60
+ #define AT91SAM9RL_BASE_RTC 0xfffffe00
+
+-#define AT91_USART0 AT91SAM9RL_BASE_US0
+-#define AT91_USART1 AT91SAM9RL_BASE_US1
+-#define AT91_USART2 AT91SAM9RL_BASE_US2
+-#define AT91_USART3 AT91SAM9RL_BASE_US3
+-
+
+ /*
+ * Internal Memory.
+diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5.h b/arch/arm/mach-at91/include/mach/at91sam9x5.h
+index 88e43d5..c75ee19 100644
+--- a/arch/arm/mach-at91/include/mach/at91sam9x5.h
++++ b/arch/arm/mach-at91/include/mach/at91sam9x5.h
+@@ -55,14 +55,6 @@
+ #define AT91SAM9X5_BASE_USART2 0xf8024000
+
+ /*
+- * Base addresses for early serial code (uncompress.h)
+- */
+-#define AT91_DBGU AT91_BASE_DBGU0
+-#define AT91_USART0 AT91SAM9X5_BASE_USART0
+-#define AT91_USART1 AT91SAM9X5_BASE_USART1
+-#define AT91_USART2 AT91SAM9X5_BASE_USART2
+-
+-/*
+ * Internal Memory.
+ */
+ #define AT91SAM9X5_SRAM_BASE 0x00300000 /* Internal SRAM base address */
+diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h
+index e9e29a6..3a01f8f 100644
+--- a/arch/arm/mach-at91/include/mach/hardware.h
++++ b/arch/arm/mach-at91/include/mach/hardware.h
+@@ -22,27 +22,17 @@
+ /* 9263, 9g45 */
+ #define AT91_BASE_DBGU1 0xffffee00
+
+-#if defined(CONFIG_ARCH_AT91RM9200)
++#if defined(CONFIG_ARCH_AT91X40)
++#include <mach/at91x40.h>
++#else
+ #include <mach/at91rm9200.h>
+-#elif defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20)
+ #include <mach/at91sam9260.h>
+-#elif defined(CONFIG_ARCH_AT91SAM9261) || defined(CONFIG_ARCH_AT91SAM9G10)
+ #include <mach/at91sam9261.h>
+-#elif defined(CONFIG_ARCH_AT91SAM9263)
+ #include <mach/at91sam9263.h>
+-#elif defined(CONFIG_ARCH_AT91SAM9RL)
+ #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_AT91X40)
+-#include <mach/at91x40.h>
+-#else
+-#error "Unsupported AT91 processor"
+-#endif
+
+-#if !defined(CONFIG_ARCH_AT91X40)
+ /*
+ * On all at91 except rm9200 and x40 have the System Controller starts
+ * at address 0xffffc000 and has a size of 16KiB.
+diff --git a/arch/arm/mach-at91/include/mach/uncompress.h b/arch/arm/mach-at91/include/mach/uncompress.h
+index d985af7..6f6118d 100644
+--- a/arch/arm/mach-at91/include/mach/uncompress.h
++++ b/arch/arm/mach-at91/include/mach/uncompress.h
+@@ -1,7 +1,8 @@
+ /*
+ * arch/arm/mach-at91/include/mach/uncompress.h
+ *
+- * Copyright (C) 2003 SAN People
++ * Copyright (C) 2003 SAN People
++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.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
+@@ -25,32 +26,149 @@
+ #include <linux/atmel_serial.h>
+ #include <mach/hardware.h>
+
+-#if defined(CONFIG_AT91_EARLY_DBGU0)
+-#define UART_OFFSET AT91_BASE_DBGU0
+-#elif defined(CONFIG_AT91_EARLY_DBGU1)
+-#define UART_OFFSET AT91_BASE_DBGU1
+-#elif defined(CONFIG_AT91_EARLY_USART0)
+-#define UART_OFFSET AT91_USART0
+-#elif defined(CONFIG_AT91_EARLY_USART1)
+-#define UART_OFFSET AT91_USART1
+-#elif defined(CONFIG_AT91_EARLY_USART2)
+-#define UART_OFFSET AT91_USART2
+-#elif defined(CONFIG_AT91_EARLY_USART3)
+-#define UART_OFFSET AT91_USART3
+-#elif defined(CONFIG_AT91_EARLY_USART4)
+-#define UART_OFFSET AT91_USART4
+-#elif defined(CONFIG_AT91_EARLY_USART5)
+-#define UART_OFFSET AT91_USART5
+-#endif
++#include <mach/at91_dbgu.h>
++#include <mach/cpu.h>
+
+ void __iomem *at91_uart;
+
++#if !defined(CONFIG_ARCH_AT91X40)
++static const u32 uarts_rm9200[] = {
++ AT91_BASE_DBGU0,
++ AT91RM9200_BASE_US0,
++ AT91RM9200_BASE_US1,
++ AT91RM9200_BASE_US2,
++ AT91RM9200_BASE_US3,
++ 0,
++};
++
++static const u32 uarts_sam9260[] = {
++ AT91_BASE_DBGU0,
++ AT91SAM9260_BASE_US0,
++ AT91SAM9260_BASE_US1,
++ AT91SAM9260_BASE_US2,
++ AT91SAM9260_BASE_US3,
++ AT91SAM9260_BASE_US4,
++ AT91SAM9260_BASE_US5,
++ 0,
++};
++
++static const u32 uarts_sam9261[] = {
++ AT91_BASE_DBGU0,
++ AT91SAM9261_BASE_US0,
++ AT91SAM9261_BASE_US1,
++ AT91SAM9261_BASE_US2,
++ 0,
++};
++
++static const u32 uarts_sam9263[] = {
++ AT91_BASE_DBGU1,
++ AT91SAM9263_BASE_US0,
++ AT91SAM9263_BASE_US1,
++ AT91SAM9263_BASE_US2,
++ 0,
++};
++
++static const u32 uarts_sam9g45[] = {
++ AT91_BASE_DBGU1,
++ AT91SAM9G45_BASE_US0,
++ AT91SAM9G45_BASE_US1,
++ AT91SAM9G45_BASE_US2,
++ AT91SAM9G45_BASE_US3,
++ 0,
++};
++
++static const u32 uarts_sam9rl[] = {
++ AT91_BASE_DBGU0,
++ AT91SAM9RL_BASE_US0,
++ AT91SAM9RL_BASE_US1,
++ AT91SAM9RL_BASE_US2,
++ AT91SAM9RL_BASE_US3,
++ 0,
++};
++
++static const u32 uarts_sam9x5[] = {
++ AT91_BASE_DBGU0,
++ AT91SAM9X5_BASE_USART0,
++ AT91SAM9X5_BASE_USART1,
++ AT91SAM9X5_BASE_USART2,
++ 0,
++};
++
++static inline const u32* decomp_soc_detect(u32 dbgu_base)
++{
++ u32 cidr, socid;
++
++ cidr = __raw_readl(dbgu_base + AT91_DBGU_CIDR);
++ socid = cidr & ~AT91_CIDR_VERSION;
++
++ switch (socid) {
++ case ARCH_ID_AT91RM9200:
++ return uarts_rm9200;
++
++ case ARCH_ID_AT91SAM9G20:
++ case ARCH_ID_AT91SAM9260:
++ return uarts_sam9260;
++
++ case ARCH_ID_AT91SAM9261:
++ return uarts_sam9261;
++
++ case ARCH_ID_AT91SAM9263:
++ return uarts_sam9263;
++
++ case ARCH_ID_AT91SAM9G45:
++ return uarts_sam9g45;
++
++ case ARCH_ID_AT91SAM9RL64:
++ return uarts_sam9rl;
++
++ case ARCH_ID_AT91SAM9X5:
++ return uarts_sam9x5;
++ }
++
++ /* at91sam9g10 */
++ if ((cidr & ~AT91_CIDR_EXT) == ARCH_ID_AT91SAM9G10) {
++ return uarts_sam9261;
++ }
++ /* at91sam9xe */
++ else if ((cidr & AT91_CIDR_ARCH) == ARCH_FAMILY_AT91SAM9XE) {
++ return uarts_sam9260;
++ }
++
++ return NULL;
++}
++
+ static inline void arch_decomp_setup(void)
+ {
+-#ifdef UART_OFFSET
+- at91_uart = (void __iomem *) UART_OFFSET; /* physical address */
+-#endif
++ int i = 0;
++ const u32* usarts;
++
++ usarts = decomp_soc_detect(AT91_BASE_DBGU0);
++
++ if (!usarts)
++ usarts = decomp_soc_detect(AT91_BASE_DBGU1);
++ if (!usarts) {
++ at91_uart = NULL;
++ return;
++ }
++
++ do {
++ /* physical address */
++ at91_uart = (void __iomem *)usarts[i];
++
++ if (__raw_readl(at91_uart + ATMEL_US_BRGR))
++ return;
++ i++;
++ } while (usarts[i]);
++
++ at91_uart = NULL;
+ }
++#else
++static inline void arch_decomp_setup(void)
++{
++ at91_uart = NULL;
++}
++#endif
++
+ /*
+ * The following code assumes the serial port has already been
+ * initialized by the bootloader. If you didn't setup a port in
+@@ -60,20 +178,22 @@ static inline void arch_decomp_setup(void)
+ */
+ static void putc(int c)
+ {
+-#ifdef UART_OFFSET
++ if (!at91_uart)
++ return;
++
+ while (!(__raw_readl(at91_uart + ATMEL_US_CSR) & ATMEL_US_TXRDY))
+ barrier();
+ __raw_writel(c, at91_uart + ATMEL_US_THR);
+-#endif
+ }
+
+ static inline void flush(void)
+ {
+-#ifdef UART_OFFSET
++ if (!at91_uart)
++ return;
++
+ /* wait for transmission to complete */
+ while (!(__raw_readl(at91_uart + ATMEL_US_CSR) & ATMEL_US_TXEMPTY))
+ barrier();
+-#endif
+ }
+
+ #define arch_decomp_wdog()
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0017-ARM-at91-drop-at91_set_serial_console.patch b/patches.at91/0017-ARM-at91-drop-at91_set_serial_console.patch
new file mode 100644
index 00000000000000..d394110e4a3018
--- /dev/null
+++ b/patches.at91/0017-ARM-at91-drop-at91_set_serial_console.patch
@@ -0,0 +1,882 @@
+From 9e4b59887ceab4e5a9a311f91da86196106c75c1 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Thu, 5 Apr 2012 13:43:40 +0800
+Subject: ARM: at91: drop at91_set_serial_console
+
+at91_set_serial_console is used to define the default console of linux.
+This is already manage by the cmdline. And if the boot loader can not be
+modified you can still set it by enabling the CONFIG_CMDLINE_EXTEND option.
+And then the command-line arguments provided by the boot loader will be
+appended to the default kernel command string.
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/at91rm9200.c | 12 ------------
+ arch/arm/mach-at91/at91rm9200_devices.c | 12 ------------
+ arch/arm/mach-at91/at91sam9260.c | 12 ------------
+ arch/arm/mach-at91/at91sam9260_devices.c | 12 ------------
+ arch/arm/mach-at91/at91sam9261.c | 12 ------------
+ arch/arm/mach-at91/at91sam9261_devices.c | 12 ------------
+ arch/arm/mach-at91/at91sam9263.c | 12 ------------
+ arch/arm/mach-at91/at91sam9263_devices.c | 12 ------------
+ arch/arm/mach-at91/at91sam9g45.c | 12 ------------
+ arch/arm/mach-at91/at91sam9g45_devices.c | 12 ------------
+ arch/arm/mach-at91/at91sam9rl.c | 12 ------------
+ arch/arm/mach-at91/at91sam9rl_devices.c | 12 ------------
+ arch/arm/mach-at91/board-1arm.c | 3 ---
+ arch/arm/mach-at91/board-afeb-9260v1.c | 3 ---
+ arch/arm/mach-at91/board-cam60.c | 3 ---
+ arch/arm/mach-at91/board-carmeva.c | 3 ---
+ arch/arm/mach-at91/board-cpu9krea.c | 3 ---
+ arch/arm/mach-at91/board-cpuat91.c | 3 ---
+ arch/arm/mach-at91/board-csb337.c | 3 ---
+ arch/arm/mach-at91/board-csb637.c | 3 ---
+ arch/arm/mach-at91/board-eb9200.c | 3 ---
+ arch/arm/mach-at91/board-ecbat91.c | 3 ---
+ arch/arm/mach-at91/board-eco920.c | 3 ---
+ arch/arm/mach-at91/board-flexibity.c | 3 ---
+ arch/arm/mach-at91/board-foxg20.c | 3 ---
+ arch/arm/mach-at91/board-kafa.c | 3 ---
+ arch/arm/mach-at91/board-kb9202.c | 3 ---
+ arch/arm/mach-at91/board-neocore926.c | 3 ---
+ arch/arm/mach-at91/board-picotux200.c | 3 ---
+ arch/arm/mach-at91/board-qil-a9260.c | 4 ----
+ arch/arm/mach-at91/board-rm9200dk.c | 3 ---
+ arch/arm/mach-at91/board-rm9200ek.c | 3 ---
+ arch/arm/mach-at91/board-rsi-ews.c | 3 ---
+ arch/arm/mach-at91/board-sam9-l9260.c | 3 ---
+ arch/arm/mach-at91/board-sam9260ek.c | 3 ---
+ arch/arm/mach-at91/board-sam9261ek.c | 3 ---
+ arch/arm/mach-at91/board-sam9263ek.c | 3 ---
+ arch/arm/mach-at91/board-sam9g20ek.c | 3 ---
+ arch/arm/mach-at91/board-sam9m10g45ek.c | 3 ---
+ arch/arm/mach-at91/board-sam9rlek.c | 3 ---
+ arch/arm/mach-at91/board-snapper9260.c | 1 -
+ arch/arm/mach-at91/board-stamp9g20.c | 3 ---
+ arch/arm/mach-at91/board-usb-a926x.c | 3 ---
+ arch/arm/mach-at91/board-yl-9200.c | 3 ---
+ arch/arm/mach-at91/generic.h | 11 -----------
+ arch/arm/mach-at91/include/mach/board.h | 1 -
+ 46 files changed, 251 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
+index 364c193..d50da1a 100644
+--- a/arch/arm/mach-at91/at91rm9200.c
++++ b/arch/arm/mach-at91/at91rm9200.c
+@@ -258,18 +258,6 @@ static void __init at91rm9200_register_clocks(void)
+ clk_register(&pck3);
+ }
+
+-static struct clk_lookup console_clock_lookup;
+-
+-void __init at91rm9200_set_console_clock(int id)
+-{
+- if (id >= ARRAY_SIZE(usart_clocks_lookups))
+- return;
+-
+- console_clock_lookup.con_id = "usart";
+- console_clock_lookup.clk = usart_clocks_lookups[id].clk;
+- clkdev_add(&console_clock_lookup);
+-}
+-
+ /* --------------------------------------------------------------------
+ * GPIO
+ * -------------------------------------------------------------------- */
+diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
+index 05774e5..99affb5 100644
+--- a/arch/arm/mach-at91/at91rm9200_devices.c
++++ b/arch/arm/mach-at91/at91rm9200_devices.c
+@@ -1152,14 +1152,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
+ at91_uarts[portnr] = pdev;
+ }
+
+-void __init at91_set_serial_console(unsigned portnr)
+-{
+- if (portnr < ATMEL_MAX_UART) {
+- atmel_default_console_device = at91_uarts[portnr];
+- at91rm9200_set_console_clock(at91_uarts[portnr]->id);
+- }
+-}
+-
+ void __init at91_add_device_serial(void)
+ {
+ int i;
+@@ -1168,13 +1160,9 @@ void __init at91_add_device_serial(void)
+ if (at91_uarts[i])
+ platform_device_register(at91_uarts[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
+
+diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
+index 46f7742..a27bbec 100644
+--- a/arch/arm/mach-at91/at91sam9260.c
++++ b/arch/arm/mach-at91/at91sam9260.c
+@@ -268,18 +268,6 @@ static void __init at91sam9260_register_clocks(void)
+ clk_register(&pck1);
+ }
+
+-static struct clk_lookup console_clock_lookup;
+-
+-void __init at91sam9260_set_console_clock(int id)
+-{
+- if (id >= ARRAY_SIZE(usart_clocks_lookups))
+- return;
+-
+- console_clock_lookup.con_id = "usart";
+- console_clock_lookup.clk = usart_clocks_lookups[id].clk;
+- clkdev_add(&console_clock_lookup);
+-}
+-
+ /* --------------------------------------------------------------------
+ * GPIO
+ * -------------------------------------------------------------------- */
+diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
+index 5652dde..ad00fe9 100644
+--- a/arch/arm/mach-at91/at91sam9260_devices.c
++++ b/arch/arm/mach-at91/at91sam9260_devices.c
+@@ -1229,14 +1229,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
+ at91_uarts[portnr] = pdev;
+ }
+
+-void __init at91_set_serial_console(unsigned portnr)
+-{
+- if (portnr < ATMEL_MAX_UART) {
+- atmel_default_console_device = at91_uarts[portnr];
+- at91sam9260_set_console_clock(at91_uarts[portnr]->id);
+- }
+-}
+-
+ void __init at91_add_device_serial(void)
+ {
+ int i;
+@@ -1245,13 +1237,9 @@ void __init at91_add_device_serial(void)
+ if (at91_uarts[i])
+ platform_device_register(at91_uarts[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
+
+diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
+index 7de81e6..c77d503 100644
+--- a/arch/arm/mach-at91/at91sam9261.c
++++ b/arch/arm/mach-at91/at91sam9261.c
+@@ -239,18 +239,6 @@ static void __init at91sam9261_register_clocks(void)
+ clk_register(&hck1);
+ }
+
+-static struct clk_lookup console_clock_lookup;
+-
+-void __init at91sam9261_set_console_clock(int id)
+-{
+- if (id >= ARRAY_SIZE(usart_clocks_lookups))
+- return;
+-
+- console_clock_lookup.con_id = "usart";
+- console_clock_lookup.clk = usart_clocks_lookups[id].clk;
+- clkdev_add(&console_clock_lookup);
+-}
+-
+ /* --------------------------------------------------------------------
+ * GPIO
+ * -------------------------------------------------------------------- */
+diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
+index 4db961a..9295e90 100644
+--- a/arch/arm/mach-at91/at91sam9261_devices.c
++++ b/arch/arm/mach-at91/at91sam9261_devices.c
+@@ -1051,14 +1051,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
+ at91_uarts[portnr] = pdev;
+ }
+
+-void __init at91_set_serial_console(unsigned portnr)
+-{
+- if (portnr < ATMEL_MAX_UART) {
+- atmel_default_console_device = at91_uarts[portnr];
+- at91sam9261_set_console_clock(at91_uarts[portnr]->id);
+- }
+-}
+-
+ void __init at91_add_device_serial(void)
+ {
+ int i;
+@@ -1067,13 +1059,9 @@ void __init at91_add_device_serial(void)
+ if (at91_uarts[i])
+ platform_device_register(at91_uarts[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
+
+diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
+index ef301be..7fae365 100644
+--- a/arch/arm/mach-at91/at91sam9263.c
++++ b/arch/arm/mach-at91/at91sam9263.c
+@@ -255,18 +255,6 @@ static void __init at91sam9263_register_clocks(void)
+ clk_register(&pck3);
+ }
+
+-static struct clk_lookup console_clock_lookup;
+-
+-void __init at91sam9263_set_console_clock(int id)
+-{
+- if (id >= ARRAY_SIZE(usart_clocks_lookups))
+- return;
+-
+- console_clock_lookup.con_id = "usart";
+- console_clock_lookup.clk = usart_clocks_lookups[id].clk;
+- clkdev_add(&console_clock_lookup);
+-}
+-
+ /* --------------------------------------------------------------------
+ * GPIO
+ * -------------------------------------------------------------------- */
+diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
+index fe99206..dfe5bc0 100644
+--- a/arch/arm/mach-at91/at91sam9263_devices.c
++++ b/arch/arm/mach-at91/at91sam9263_devices.c
+@@ -1461,14 +1461,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
+ at91_uarts[portnr] = pdev;
+ }
+
+-void __init at91_set_serial_console(unsigned portnr)
+-{
+- if (portnr < ATMEL_MAX_UART) {
+- atmel_default_console_device = at91_uarts[portnr];
+- at91sam9263_set_console_clock(at91_uarts[portnr]->id);
+- }
+-}
+-
+ void __init at91_add_device_serial(void)
+ {
+ int i;
+@@ -1477,13 +1469,9 @@ void __init at91_add_device_serial(void)
+ if (at91_uarts[i])
+ platform_device_register(at91_uarts[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
+
+diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
+index d222f83..f205449 100644
+--- a/arch/arm/mach-at91/at91sam9g45.c
++++ b/arch/arm/mach-at91/at91sam9g45.c
+@@ -288,18 +288,6 @@ static void __init at91sam9g45_register_clocks(void)
+ clk_register(&pck1);
+ }
+
+-static struct clk_lookup console_clock_lookup;
+-
+-void __init at91sam9g45_set_console_clock(int id)
+-{
+- if (id >= ARRAY_SIZE(usart_clocks_lookups))
+- return;
+-
+- console_clock_lookup.con_id = "usart";
+- console_clock_lookup.clk = usart_clocks_lookups[id].clk;
+- clkdev_add(&console_clock_lookup);
+-}
+-
+ /* --------------------------------------------------------------------
+ * GPIO
+ * -------------------------------------------------------------------- */
+diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
+index 6b008ae..db2f88c2 100644
+--- a/arch/arm/mach-at91/at91sam9g45_devices.c
++++ b/arch/arm/mach-at91/at91sam9g45_devices.c
+@@ -1741,14 +1741,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
+ at91_uarts[portnr] = pdev;
+ }
+
+-void __init at91_set_serial_console(unsigned portnr)
+-{
+- if (portnr < ATMEL_MAX_UART) {
+- atmel_default_console_device = at91_uarts[portnr];
+- at91sam9g45_set_console_clock(at91_uarts[portnr]->id);
+- }
+-}
+-
+ void __init at91_add_device_serial(void)
+ {
+ int i;
+@@ -1757,13 +1749,9 @@ void __init at91_add_device_serial(void)
+ if (at91_uarts[i])
+ platform_device_register(at91_uarts[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
+
+diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
+index d9f2774..e420085 100644
+--- a/arch/arm/mach-at91/at91sam9rl.c
++++ b/arch/arm/mach-at91/at91sam9rl.c
+@@ -232,18 +232,6 @@ static void __init at91sam9rl_register_clocks(void)
+ clk_register(&pck1);
+ }
+
+-static struct clk_lookup console_clock_lookup;
+-
+-void __init at91sam9rl_set_console_clock(int id)
+-{
+- if (id >= ARRAY_SIZE(usart_clocks_lookups))
+- return;
+-
+- console_clock_lookup.con_id = "usart";
+- console_clock_lookup.clk = usart_clocks_lookups[id].clk;
+- clkdev_add(&console_clock_lookup);
+-}
+-
+ /* --------------------------------------------------------------------
+ * GPIO
+ * -------------------------------------------------------------------- */
+diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
+index fe4ae22..9c0b148 100644
+--- a/arch/arm/mach-at91/at91sam9rl_devices.c
++++ b/arch/arm/mach-at91/at91sam9rl_devices.c
+@@ -1192,14 +1192,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
+ at91_uarts[portnr] = pdev;
+ }
+
+-void __init at91_set_serial_console(unsigned portnr)
+-{
+- if (portnr < ATMEL_MAX_UART) {
+- atmel_default_console_device = at91_uarts[portnr];
+- at91sam9rl_set_console_clock(at91_uarts[portnr]->id);
+- }
+-}
+-
+ void __init at91_add_device_serial(void)
+ {
+ int i;
+@@ -1208,13 +1200,9 @@ void __init at91_add_device_serial(void)
+ if (at91_uarts[i])
+ platform_device_register(at91_uarts[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
+
+diff --git a/arch/arm/mach-at91/board-1arm.c b/arch/arm/mach-at91/board-1arm.c
+index 2628384..f43ad91 100644
+--- a/arch/arm/mach-at91/board-1arm.c
++++ b/arch/arm/mach-at91/board-1arm.c
+@@ -58,9 +58,6 @@ static void __init onearm_init_early(void)
+ at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+ | ATMEL_UART_RI);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ static struct macb_platform_data __initdata onearm_eth_data = {
+diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c
+index 161efba..7c7c682 100644
+--- a/arch/arm/mach-at91/board-afeb-9260v1.c
++++ b/arch/arm/mach-at91/board-afeb-9260v1.c
+@@ -65,9 +65,6 @@ static void __init afeb9260_init_early(void)
+ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+ at91_register_uart(AT91SAM9260_ID_US1, 2,
+ ATMEL_UART_CTS | ATMEL_UART_RTS);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ /*
+diff --git a/arch/arm/mach-at91/board-cam60.c b/arch/arm/mach-at91/board-cam60.c
+index c6d44ee..871717d 100644
+--- a/arch/arm/mach-at91/board-cam60.c
++++ b/arch/arm/mach-at91/board-cam60.c
+@@ -52,9 +52,6 @@ static void __init cam60_init_early(void)
+
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ /*
+diff --git a/arch/arm/mach-at91/board-carmeva.c b/arch/arm/mach-at91/board-carmeva.c
+index 59d9cf9..168b3fa 100644
+--- a/arch/arm/mach-at91/board-carmeva.c
++++ b/arch/arm/mach-at91/board-carmeva.c
+@@ -52,9 +52,6 @@ static void __init carmeva_init_early(void)
+ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+ | ATMEL_UART_RI);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ static struct macb_platform_data __initdata carmeva_eth_data = {
+diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c
+index 5f3680e..4073e30 100644
+--- a/arch/arm/mach-at91/board-cpu9krea.c
++++ b/arch/arm/mach-at91/board-cpu9krea.c
+@@ -77,9 +77,6 @@ static void __init cpu9krea_init_early(void)
+
+ /* USART5 on ttyS6. (Rx, Tx) */
+ at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ /*
+diff --git a/arch/arm/mach-at91/board-cpuat91.c b/arch/arm/mach-at91/board-cpuat91.c
+index e094cc8..76c62ed 100644
+--- a/arch/arm/mach-at91/board-cpuat91.c
++++ b/arch/arm/mach-at91/board-cpuat91.c
+@@ -78,9 +78,6 @@ static void __init cpuat91_init_early(void)
+ /* USART3 on ttyS4 (Rx, Tx, CTS, RTS) */
+ at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_CTS |
+ ATMEL_UART_RTS);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ static struct macb_platform_data __initdata cpuat91_eth_data = {
+diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
+index 1a1547b..d984435 100644
+--- a/arch/arm/mach-at91/board-csb337.c
++++ b/arch/arm/mach-at91/board-csb337.c
+@@ -53,9 +53,6 @@ static void __init csb337_init_early(void)
+
+ /* DBGU on ttyS0 */
+ at91_register_uart(0, 0, 0);
+-
+- /* make console=ttyS0 the default */
+- at91_set_serial_console(0);
+ }
+
+ static struct macb_platform_data __initdata csb337_eth_data = {
+diff --git a/arch/arm/mach-at91/board-csb637.c b/arch/arm/mach-at91/board-csb637.c
+index f650bf3..0c9935d 100644
+--- a/arch/arm/mach-at91/board-csb637.c
++++ b/arch/arm/mach-at91/board-csb637.c
+@@ -47,9 +47,6 @@ static void __init csb637_init_early(void)
+
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+-
+- /* make console=ttyS0 (ie, DBGU) the default */
+- at91_set_serial_console(0);
+ }
+
+ static struct macb_platform_data __initdata csb637_eth_data = {
+diff --git a/arch/arm/mach-at91/board-eb9200.c b/arch/arm/mach-at91/board-eb9200.c
+index d302ca3..a189b9f 100644
+--- a/arch/arm/mach-at91/board-eb9200.c
++++ b/arch/arm/mach-at91/board-eb9200.c
+@@ -55,9 +55,6 @@ static void __init eb9200_init_early(void)
+
+ /* USART2 on ttyS2. (Rx, Tx) - IRDA */
+ at91_register_uart(AT91RM9200_ID_US2, 2, 0);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ static struct macb_platform_data __initdata eb9200_eth_data = {
+diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c
+index 69966ce..307c530 100644
+--- a/arch/arm/mach-at91/board-ecbat91.c
++++ b/arch/arm/mach-at91/board-ecbat91.c
+@@ -59,9 +59,6 @@ static void __init ecb_at91init_early(void)
+
+ /* USART0 on ttyS1. (Rx & Tx only) */
+ at91_register_uart(AT91RM9200_ID_US0, 1, 0);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ static struct macb_platform_data __initdata ecb_at91eth_data = {
+diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c
+index f23aabe..7df6a9b 100644
+--- a/arch/arm/mach-at91/board-eco920.c
++++ b/arch/arm/mach-at91/board-eco920.c
+@@ -43,9 +43,6 @@ static void __init eco920_init_early(void)
+
+ /* DBGU on ttyS0. (Rx & Tx only */
+ at91_register_uart(0, 0, 0);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ static struct macb_platform_data __initdata eco920_eth_data = {
+diff --git a/arch/arm/mach-at91/board-flexibity.c b/arch/arm/mach-at91/board-flexibity.c
+index 1815152..6dcc962 100644
+--- a/arch/arm/mach-at91/board-flexibity.c
++++ b/arch/arm/mach-at91/board-flexibity.c
+@@ -44,9 +44,6 @@ static void __init flexibity_init_early(void)
+
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ /* USB Host port */
+diff --git a/arch/arm/mach-at91/board-foxg20.c b/arch/arm/mach-at91/board-foxg20.c
+index caf017f..bb07807 100644
+--- a/arch/arm/mach-at91/board-foxg20.c
++++ b/arch/arm/mach-at91/board-foxg20.c
+@@ -93,9 +93,6 @@ static void __init foxg20_init_early(void)
+ /* USART5 on ttyS6. (Rx & Tx only) */
+ at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
+
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+-
+ /* Set the internal pull-up resistor on DRXD */
+ at91_set_A_periph(AT91_PIN_PB14, 1);
+
+diff --git a/arch/arm/mach-at91/board-kafa.c b/arch/arm/mach-at91/board-kafa.c
+index efde1b2..3e858ed 100644
+--- a/arch/arm/mach-at91/board-kafa.c
++++ b/arch/arm/mach-at91/board-kafa.c
+@@ -56,9 +56,6 @@ static void __init kafa_init_early(void)
+
+ /* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */
+ at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ static struct macb_platform_data __initdata kafa_eth_data = {
+diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c
+index 59b92aa..ccbc8be 100644
+--- a/arch/arm/mach-at91/board-kb9202.c
++++ b/arch/arm/mach-at91/board-kb9202.c
+@@ -65,9 +65,6 @@ static void __init kb9202_init_early(void)
+
+ /* USART3 on ttyS3 (Rx, Tx, CTS, RTS) - RS485 (optional) */
+ at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ static struct macb_platform_data __initdata kb9202_eth_data = {
+diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
+index 57d5f6a..c456fdc 100644
+--- a/arch/arm/mach-at91/board-neocore926.c
++++ b/arch/arm/mach-at91/board-neocore926.c
+@@ -61,9 +61,6 @@ static void __init neocore926_init_early(void)
+
+ /* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */
+ at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ /*
+diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c
+index 59e35dd..4ca56cd 100644
+--- a/arch/arm/mach-at91/board-picotux200.c
++++ b/arch/arm/mach-at91/board-picotux200.c
+@@ -56,9 +56,6 @@ static void __init picotux200_init_early(void)
+ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+ | ATMEL_UART_RI);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ static struct macb_platform_data __initdata picotux200_eth_data = {
+diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c
+index b6ed5ed..189d3fe 100644
+--- a/arch/arm/mach-at91/board-qil-a9260.c
++++ b/arch/arm/mach-at91/board-qil-a9260.c
+@@ -66,10 +66,6 @@ static void __init ek_init_early(void)
+
+ /* USART2 on ttyS3. (Rx, Tx, CTS, RTS) */
+ at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
+-
+- /* set serial console to ttyS1 (ie, USART0) */
+- at91_set_serial_console(1);
+-
+ }
+
+ /*
+diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c
+index 01332aa..d5ce630 100644
+--- a/arch/arm/mach-at91/board-rm9200dk.c
++++ b/arch/arm/mach-at91/board-rm9200dk.c
+@@ -61,9 +61,6 @@ static void __init dk_init_early(void)
+ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+ | ATMEL_UART_RI);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ static struct macb_platform_data __initdata dk_eth_data = {
+diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c
+index b2e4fe2..e96d5f5 100644
+--- a/arch/arm/mach-at91/board-rm9200ek.c
++++ b/arch/arm/mach-at91/board-rm9200ek.c
+@@ -61,9 +61,6 @@ static void __init ek_init_early(void)
+ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+ | ATMEL_UART_RI);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ static struct macb_platform_data __initdata ek_eth_data = {
+diff --git a/arch/arm/mach-at91/board-rsi-ews.c b/arch/arm/mach-at91/board-rsi-ews.c
+index af0750f..2c84463 100644
+--- a/arch/arm/mach-at91/board-rsi-ews.c
++++ b/arch/arm/mach-at91/board-rsi-ews.c
+@@ -52,9 +52,6 @@ static void __init rsi_ews_init_early(void)
+ /* USART3 on ttyS4. (Rx, Tx, RTS) */
+ /* RS485 communication */
+ at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_RTS);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ /*
+diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c
+index e8b116b..dee44cb 100644
+--- a/arch/arm/mach-at91/board-sam9-l9260.c
++++ b/arch/arm/mach-at91/board-sam9-l9260.c
+@@ -62,9 +62,6 @@ static void __init ek_init_early(void)
+
+ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */
+ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ /*
+diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
+index d5aec55..6da17b5 100644
+--- a/arch/arm/mach-at91/board-sam9260ek.c
++++ b/arch/arm/mach-at91/board-sam9260ek.c
+@@ -65,9 +65,6 @@ static void __init ek_init_early(void)
+
+ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ /*
+diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
+index 065fed3..950c20b 100644
+--- a/arch/arm/mach-at91/board-sam9261ek.c
++++ b/arch/arm/mach-at91/board-sam9261ek.c
+@@ -64,9 +64,6 @@ static void __init ek_init_early(void)
+
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ /*
+diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
+index 2ffe50f..4424873 100644
+--- a/arch/arm/mach-at91/board-sam9263ek.c
++++ b/arch/arm/mach-at91/board-sam9263ek.c
+@@ -63,9 +63,6 @@ static void __init ek_init_early(void)
+
+ /* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */
+ at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ /*
+diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
+index 8923ec9..05f8467 100644
+--- a/arch/arm/mach-at91/board-sam9g20ek.c
++++ b/arch/arm/mach-at91/board-sam9g20ek.c
+@@ -76,9 +76,6 @@ static void __init ek_init_early(void)
+
+ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ /*
+diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
+index c88e908..be2ca19 100644
+--- a/arch/arm/mach-at91/board-sam9m10g45ek.c
++++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
+@@ -60,9 +60,6 @@ static void __init ek_init_early(void)
+ /* USART0 not connected on the -EK board */
+ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+ at91_register_uart(AT91SAM9G45_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ /*
+diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
+index b109ce2..23f383a 100644
+--- a/arch/arm/mach-at91/board-sam9rlek.c
++++ b/arch/arm/mach-at91/board-sam9rlek.c
+@@ -48,9 +48,6 @@ static void __init ek_init_early(void)
+
+ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */
+ at91_register_uart(AT91SAM9RL_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ /*
+diff --git a/arch/arm/mach-at91/board-snapper9260.c b/arch/arm/mach-at91/board-snapper9260.c
+index ebc9d01..1a6774a 100644
+--- a/arch/arm/mach-at91/board-snapper9260.c
++++ b/arch/arm/mach-at91/board-snapper9260.c
+@@ -46,7 +46,6 @@ static void __init snapper9260_init_early(void)
+
+ /* Debug on ttyS0 */
+ at91_register_uart(0, 0, 0);
+- at91_set_serial_console(0);
+
+ at91_register_uart(AT91SAM9260_ID_US0, 1,
+ ATMEL_UART_CTS | ATMEL_UART_RTS);
+diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c
+index 7640049..38a7ca5 100644
+--- a/arch/arm/mach-at91/board-stamp9g20.c
++++ b/arch/arm/mach-at91/board-stamp9g20.c
+@@ -39,9 +39,6 @@ void __init stamp9g20_init_early(void)
+
+ /* DGBU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ static void __init stamp9g20evb_init_early(void)
+diff --git a/arch/arm/mach-at91/board-usb-a926x.c b/arch/arm/mach-at91/board-usb-a926x.c
+index b7483a3..ee482eb 100644
+--- a/arch/arm/mach-at91/board-usb-a926x.c
++++ b/arch/arm/mach-at91/board-usb-a926x.c
+@@ -56,9 +56,6 @@ static void __init ek_init_early(void)
+
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ /*
+diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c
+index 38dd279..e94a04e 100644
+--- a/arch/arm/mach-at91/board-yl-9200.c
++++ b/arch/arm/mach-at91/board-yl-9200.c
+@@ -75,9 +75,6 @@ static void __init yl9200_init_early(void)
+
+ /* USART3 on ttyS3. (Rx, Tx, RTS - RS485 interface) */
+ at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_RTS);
+-
+- /* set serial console to ttyS0 (ie, DBGU) */
+- at91_set_serial_console(0);
+ }
+
+ /*
+diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
+index dd9b346..0a60bf8 100644
+--- a/arch/arm/mach-at91/generic.h
++++ b/arch/arm/mach-at91/generic.h
+@@ -40,17 +40,6 @@ extern struct sys_timer at91sam926x_timer;
+ extern struct sys_timer at91x40_timer;
+
+ /* Clocks */
+-/*
+- * function to specify the clock of the default console. As we do not
+- * use the device/driver bus, the dev_name is not intialize. So we need
+- * to link the clock to a specific con_id only "usart"
+- */
+-extern void __init at91rm9200_set_console_clock(int id);
+-extern void __init at91sam9260_set_console_clock(int id);
+-extern void __init at91sam9261_set_console_clock(int id);
+-extern void __init at91sam9263_set_console_clock(int id);
+-extern void __init at91sam9rl_set_console_clock(int id);
+-extern void __init at91sam9g45_set_console_clock(int id);
+ #ifdef CONFIG_AT91_PMC_UNIT
+ extern int __init at91_clock_init(unsigned long main_clock);
+ extern int __init at91_dt_clock_init(void);
+diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
+index 49a8211..369afc2 100644
+--- a/arch/arm/mach-at91/include/mach/board.h
++++ b/arch/arm/mach-at91/include/mach/board.h
+@@ -121,7 +121,6 @@ extern void __init at91_add_device_spi(struct spi_board_info *devices, int nr_de
+ #define ATMEL_UART_RI 0x20
+
+ extern void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins);
+-extern void __init at91_set_serial_console(unsigned portnr);
+
+ extern struct platform_device *atmel_default_console_device;
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0018-ARM-at91-do-not-pin-mux-the-UARTs-in-init_early.patch b/patches.at91/0018-ARM-at91-do-not-pin-mux-the-UARTs-in-init_early.patch
new file mode 100644
index 00000000000000..7e4cfed4a69939
--- /dev/null
+++ b/patches.at91/0018-ARM-at91-do-not-pin-mux-the-UARTs-in-init_early.patch
@@ -0,0 +1,1405 @@
+From 01175552b5bdf3438fa9bb6acbbfa5498414d2ab Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Thu, 5 Apr 2012 14:14:28 +0800
+Subject: ARM: at91: do not pin mux the UARTs in init_early
+
+There is no need to pinmux the UART so early in the kernel.
+Move it to the board init.
+
+This will also allow to finally move the gpio driver to platform device/driver.
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/board-1arm.c | 21 +++++-----
+ arch/arm/mach-at91/board-afeb-9260v1.c | 25 ++++++------
+ arch/arm/mach-at91/board-cam60.c | 5 +--
+ arch/arm/mach-at91/board-carmeva.c | 15 ++++----
+ arch/arm/mach-at91/board-cpu9krea.c | 49 ++++++++++++------------
+ arch/arm/mach-at91/board-cpuat91.c | 37 +++++++++---------
+ arch/arm/mach-at91/board-csb337.c | 5 +--
+ arch/arm/mach-at91/board-csb637.c | 5 +--
+ arch/arm/mach-at91/board-eb9200.c | 21 +++++-----
+ arch/arm/mach-at91/board-ecbat91.c | 11 +++---
+ arch/arm/mach-at91/board-eco920.c | 5 +--
+ arch/arm/mach-at91/board-flexibity.c | 5 +--
+ arch/arm/mach-at91/board-foxg20.c | 68 ++++++++++++++++-----------------
+ arch/arm/mach-at91/board-gsia18s.c | 63 +++++++++++++++---------------
+ arch/arm/mach-at91/board-kafa.c | 11 +++---
+ arch/arm/mach-at91/board-kb9202.c | 23 ++++++-----
+ arch/arm/mach-at91/board-neocore926.c | 11 +++---
+ arch/arm/mach-at91/board-pcontrol-g20.c | 21 +++++-----
+ arch/arm/mach-at91/board-picotux200.c | 15 ++++----
+ arch/arm/mach-at91/board-qil-a9260.c | 27 +++++++------
+ arch/arm/mach-at91/board-rm9200dk.c | 15 ++++----
+ arch/arm/mach-at91/board-rm9200ek.c | 15 ++++----
+ arch/arm/mach-at91/board-rsi-ews.c | 27 +++++++------
+ arch/arm/mach-at91/board-sam9-l9260.c | 21 +++++-----
+ arch/arm/mach-at91/board-sam9260ek.c | 21 +++++-----
+ arch/arm/mach-at91/board-sam9261ek.c | 5 +--
+ arch/arm/mach-at91/board-sam9263ek.c | 11 +++---
+ arch/arm/mach-at91/board-sam9g20ek.c | 21 +++++-----
+ arch/arm/mach-at91/board-sam9m10g45ek.c | 13 +++----
+ arch/arm/mach-at91/board-sam9rlek.c | 11 +++---
+ arch/arm/mach-at91/board-snapper9260.c | 17 ++++-----
+ arch/arm/mach-at91/board-stamp9g20.c | 61 ++++++++++++-----------------
+ arch/arm/mach-at91/board-usb-a926x.c | 5 +--
+ arch/arm/mach-at91/board-yl-9200.c | 27 +++++++------
+ 34 files changed, 333 insertions(+), 380 deletions(-)
+
+diff --git a/arch/arm/mach-at91/board-1arm.c b/arch/arm/mach-at91/board-1arm.c
+index f43ad91..271f994 100644
+--- a/arch/arm/mach-at91/board-1arm.c
++++ b/arch/arm/mach-at91/board-1arm.c
+@@ -47,17 +47,6 @@ static void __init onearm_init_early(void)
+
+ /* Initialize processor: 18.432 MHz crystal */
+ at91_initialize(18432000);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */
+- at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
+-
+- /* USART1 on ttyS2 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+- at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS
+- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+- | ATMEL_UART_RI);
+ }
+
+ static struct macb_platform_data __initdata onearm_eth_data = {
+@@ -79,6 +68,16 @@ static struct at91_udc_data __initdata onearm_udc_data = {
+ static void __init onearm_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */
++ at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
++
++ /* USART1 on ttyS2 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
++ at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS
++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
++ | ATMEL_UART_RI);
+ at91_add_device_serial();
+ /* Ethernet */
+ at91_add_device_eth(&onearm_eth_data);
+diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c
+index 7c7c682..b7d8aa7 100644
+--- a/arch/arm/mach-at91/board-afeb-9260v1.c
++++ b/arch/arm/mach-at91/board-afeb-9260v1.c
+@@ -52,19 +52,6 @@ static void __init afeb9260_init_early(void)
+ {
+ /* Initialize processor: 18.432 MHz crystal */
+ at91_initialize(18432000);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+- at91_register_uart(AT91SAM9260_ID_US0, 1,
+- ATMEL_UART_CTS | ATMEL_UART_RTS
+- | ATMEL_UART_DTR | ATMEL_UART_DSR
+- | ATMEL_UART_DCD | ATMEL_UART_RI);
+-
+- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+- at91_register_uart(AT91SAM9260_ID_US1, 2,
+- ATMEL_UART_CTS | ATMEL_UART_RTS);
+ }
+
+ /*
+@@ -180,6 +167,18 @@ static struct at91_cf_data afeb9260_cf_data = {
+ static void __init afeb9260_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
++ at91_register_uart(AT91SAM9260_ID_US0, 1,
++ ATMEL_UART_CTS | ATMEL_UART_RTS
++ | ATMEL_UART_DTR | ATMEL_UART_DSR
++ | ATMEL_UART_DCD | ATMEL_UART_RI);
++
++ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
++ at91_register_uart(AT91SAM9260_ID_US1, 2,
++ ATMEL_UART_CTS | ATMEL_UART_RTS);
+ at91_add_device_serial();
+ /* USB Host */
+ at91_add_device_usbh(&afeb9260_usbh_data);
+diff --git a/arch/arm/mach-at91/board-cam60.c b/arch/arm/mach-at91/board-cam60.c
+index 871717d..29d3ef0 100644
+--- a/arch/arm/mach-at91/board-cam60.c
++++ b/arch/arm/mach-at91/board-cam60.c
+@@ -49,9 +49,6 @@ static void __init cam60_init_early(void)
+ {
+ /* Initialize processor: 10 MHz crystal */
+ at91_initialize(10000000);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+ }
+
+ /*
+@@ -172,6 +169,8 @@ static void __init cam60_add_device_nand(void)
+ static void __init cam60_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
+ at91_add_device_serial();
+ /* SPI */
+ at91_add_device_spi(cam60_spi_devices, ARRAY_SIZE(cam60_spi_devices));
+diff --git a/arch/arm/mach-at91/board-carmeva.c b/arch/arm/mach-at91/board-carmeva.c
+index 168b3fa..44328a6 100644
+--- a/arch/arm/mach-at91/board-carmeva.c
++++ b/arch/arm/mach-at91/board-carmeva.c
+@@ -44,14 +44,6 @@ static void __init carmeva_init_early(void)
+ {
+ /* Initialize processor: 20.000 MHz crystal */
+ at91_initialize(20000000);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+- | ATMEL_UART_RI);
+ }
+
+ static struct macb_platform_data __initdata carmeva_eth_data = {
+@@ -136,6 +128,13 @@ static struct gpio_led carmeva_leds[] = {
+ static void __init carmeva_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
++ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
++ | ATMEL_UART_RI);
+ at91_add_device_serial();
+ /* Ethernet */
+ at91_add_device_eth(&carmeva_eth_data);
+diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c
+index 4073e30..69951ec 100644
+--- a/arch/arm/mach-at91/board-cpu9krea.c
++++ b/arch/arm/mach-at91/board-cpu9krea.c
+@@ -52,31 +52,6 @@ static void __init cpu9krea_init_early(void)
+ {
+ /* Initialize processor: 18.432 MHz crystal */
+ at91_initialize(18432000);
+-
+- /* DGBU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS |
+- ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DSR |
+- ATMEL_UART_DCD | ATMEL_UART_RI);
+-
+- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS |
+- ATMEL_UART_RTS);
+-
+- /* USART2 on ttyS3. (Rx, Tx, RTS, CTS) */
+- at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS |
+- ATMEL_UART_RTS);
+-
+- /* USART3 on ttyS4. (Rx, Tx) */
+- at91_register_uart(AT91SAM9260_ID_US3, 4, 0);
+-
+- /* USART4 on ttyS5. (Rx, Tx) */
+- at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
+-
+- /* USART5 on ttyS6. (Rx, Tx) */
+- at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
+ }
+
+ /*
+@@ -349,6 +324,30 @@ static void __init cpu9krea_board_init(void)
+ /* NOR */
+ cpu9krea_add_device_nor();
+ /* Serial */
++ /* DGBU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
++ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS |
++ ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DSR |
++ ATMEL_UART_DCD | ATMEL_UART_RI);
++
++ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
++ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS |
++ ATMEL_UART_RTS);
++
++ /* USART2 on ttyS3. (Rx, Tx, RTS, CTS) */
++ at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS |
++ ATMEL_UART_RTS);
++
++ /* USART3 on ttyS4. (Rx, Tx) */
++ at91_register_uart(AT91SAM9260_ID_US3, 4, 0);
++
++ /* USART4 on ttyS5. (Rx, Tx) */
++ at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
++
++ /* USART5 on ttyS6. (Rx, Tx) */
++ at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
+ at91_add_device_serial();
+ /* USB Host */
+ at91_add_device_usbh(&cpu9krea_usbh_data);
+diff --git a/arch/arm/mach-at91/board-cpuat91.c b/arch/arm/mach-at91/board-cpuat91.c
+index 76c62ed..895cf2d 100644
+--- a/arch/arm/mach-at91/board-cpuat91.c
++++ b/arch/arm/mach-at91/board-cpuat91.c
+@@ -59,25 +59,6 @@ static void __init cpuat91_init_early(void)
+
+ /* Initialize processor: 18.432 MHz crystal */
+ at91_initialize(18432000);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */
+- at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS |
+- ATMEL_UART_RTS);
+-
+- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+- at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS |
+- ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DSR |
+- ATMEL_UART_DCD | ATMEL_UART_RI);
+-
+- /* USART2 on ttyS3 (Rx, Tx) */
+- at91_register_uart(AT91RM9200_ID_US2, 3, 0);
+-
+- /* USART3 on ttyS4 (Rx, Tx, CTS, RTS) */
+- at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_CTS |
+- ATMEL_UART_RTS);
+ }
+
+ static struct macb_platform_data __initdata cpuat91_eth_data = {
+@@ -158,6 +139,24 @@ static struct platform_device *platform_devices[] __initdata = {
+ static void __init cpuat91_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */
++ at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS |
++ ATMEL_UART_RTS);
++
++ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
++ at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS |
++ ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DSR |
++ ATMEL_UART_DCD | ATMEL_UART_RI);
++
++ /* USART2 on ttyS3 (Rx, Tx) */
++ at91_register_uart(AT91RM9200_ID_US2, 3, 0);
++
++ /* USART3 on ttyS4 (Rx, Tx, CTS, RTS) */
++ at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_CTS |
++ ATMEL_UART_RTS);
+ at91_add_device_serial();
+ /* LEDs. */
+ at91_gpio_leds(cpuat91_leds, ARRAY_SIZE(cpuat91_leds));
+diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
+index d984435..ad7f9f0 100644
+--- a/arch/arm/mach-at91/board-csb337.c
++++ b/arch/arm/mach-at91/board-csb337.c
+@@ -50,9 +50,6 @@ static void __init csb337_init_early(void)
+
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
+-
+- /* DBGU on ttyS0 */
+- at91_register_uart(0, 0, 0);
+ }
+
+ static struct macb_platform_data __initdata csb337_eth_data = {
+@@ -226,6 +223,8 @@ static struct gpio_led csb_leds[] = {
+ static void __init csb337_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0 */
++ at91_register_uart(0, 0, 0);
+ at91_add_device_serial();
+ /* Ethernet */
+ at91_add_device_eth(&csb337_eth_data);
+diff --git a/arch/arm/mach-at91/board-csb637.c b/arch/arm/mach-at91/board-csb637.c
+index 0c9935d..7c8b05a 100644
+--- a/arch/arm/mach-at91/board-csb637.c
++++ b/arch/arm/mach-at91/board-csb637.c
+@@ -44,9 +44,6 @@ static void __init csb637_init_early(void)
+ {
+ /* Initialize processor: 3.6864 MHz crystal */
+ at91_initialize(3686400);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+ }
+
+ static struct macb_platform_data __initdata csb637_eth_data = {
+@@ -115,6 +112,8 @@ static void __init csb637_board_init(void)
+ /* LED(s) */
+ at91_gpio_leds(csb_leds, ARRAY_SIZE(csb_leds));
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
+ at91_add_device_serial();
+ /* Ethernet */
+ at91_add_device_eth(&csb637_eth_data);
+diff --git a/arch/arm/mach-at91/board-eb9200.c b/arch/arm/mach-at91/board-eb9200.c
+index a189b9f..bd10172 100644
+--- a/arch/arm/mach-at91/board-eb9200.c
++++ b/arch/arm/mach-at91/board-eb9200.c
+@@ -44,17 +44,6 @@ static void __init eb9200_init_early(void)
+ {
+ /* Initialize processor: 18.432 MHz crystal */
+ at91_initialize(18432000);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+- | ATMEL_UART_RI);
+-
+- /* USART2 on ttyS2. (Rx, Tx) - IRDA */
+- at91_register_uart(AT91RM9200_ID_US2, 2, 0);
+ }
+
+ static struct macb_platform_data __initdata eb9200_eth_data = {
+@@ -98,6 +87,16 @@ static struct i2c_board_info __initdata eb9200_i2c_devices[] = {
+ static void __init eb9200_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
++ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
++ | ATMEL_UART_RI);
++
++ /* USART2 on ttyS2. (Rx, Tx) - IRDA */
++ at91_register_uart(AT91RM9200_ID_US2, 2, 0);
+ at91_add_device_serial();
+ /* Ethernet */
+ at91_add_device_eth(&eb9200_eth_data);
+diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c
+index 307c530..2510825 100644
+--- a/arch/arm/mach-at91/board-ecbat91.c
++++ b/arch/arm/mach-at91/board-ecbat91.c
+@@ -53,12 +53,6 @@ static void __init ecb_at91init_early(void)
+
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PC7, AT91_PIN_PC7);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART0 on ttyS1. (Rx & Tx only) */
+- at91_register_uart(AT91RM9200_ID_US0, 1, 0);
+ }
+
+ static struct macb_platform_data __initdata ecb_at91eth_data = {
+@@ -149,6 +143,11 @@ static struct spi_board_info __initdata ecb_at91spi_devices[] = {
+ static void __init ecb_at91board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART0 on ttyS1. (Rx & Tx only) */
++ at91_register_uart(AT91RM9200_ID_US0, 1, 0);
+ at91_add_device_serial();
+
+ /* Ethernet */
+diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c
+index 7df6a9b..bebeae8 100644
+--- a/arch/arm/mach-at91/board-eco920.c
++++ b/arch/arm/mach-at91/board-eco920.c
+@@ -40,9 +40,6 @@ static void __init eco920_init_early(void)
+
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
+-
+- /* DBGU on ttyS0. (Rx & Tx only */
+- at91_register_uart(0, 0, 0);
+ }
+
+ static struct macb_platform_data __initdata eco920_eth_data = {
+@@ -100,6 +97,8 @@ static struct spi_board_info eco920_spi_devices[] = {
+
+ static void __init eco920_board_init(void)
+ {
++ /* DBGU on ttyS0. (Rx & Tx only */
++ at91_register_uart(0, 0, 0);
+ at91_add_device_serial();
+ at91_add_device_eth(&eco920_eth_data);
+ at91_add_device_usbh(&eco920_usbh_data);
+diff --git a/arch/arm/mach-at91/board-flexibity.c b/arch/arm/mach-at91/board-flexibity.c
+index 6dcc962..47658f7 100644
+--- a/arch/arm/mach-at91/board-flexibity.c
++++ b/arch/arm/mach-at91/board-flexibity.c
+@@ -41,9 +41,6 @@ static void __init flexibity_init_early(void)
+ {
+ /* Initialize processor: 18.432 MHz crystal */
+ at91_initialize(18432000);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+ }
+
+ /* USB Host port */
+@@ -140,6 +137,8 @@ static struct gpio_led flexibity_leds[] = {
+ static void __init flexibity_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
+ at91_add_device_serial();
+ /* USB Host */
+ at91_add_device_usbh(&flexibity_usbh_data);
+diff --git a/arch/arm/mach-at91/board-foxg20.c b/arch/arm/mach-at91/board-foxg20.c
+index bb07807..33411e6 100644
+--- a/arch/arm/mach-at91/board-foxg20.c
++++ b/arch/arm/mach-at91/board-foxg20.c
+@@ -61,41 +61,6 @@ static void __init foxg20_init_early(void)
+ {
+ /* Initialize processor: 18.432 MHz crystal */
+ at91_initialize(18432000);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+- at91_register_uart(AT91SAM9260_ID_US0, 1,
+- ATMEL_UART_CTS
+- | ATMEL_UART_RTS
+- | ATMEL_UART_DTR
+- | ATMEL_UART_DSR
+- | ATMEL_UART_DCD
+- | ATMEL_UART_RI);
+-
+- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+- at91_register_uart(AT91SAM9260_ID_US1, 2,
+- ATMEL_UART_CTS
+- | ATMEL_UART_RTS);
+-
+- /* USART2 on ttyS3. (Rx & Tx only) */
+- at91_register_uart(AT91SAM9260_ID_US2, 3, 0);
+-
+- /* USART3 on ttyS4. (Rx, Tx, RTS, CTS) */
+- at91_register_uart(AT91SAM9260_ID_US3, 4,
+- ATMEL_UART_CTS
+- | ATMEL_UART_RTS);
+-
+- /* USART4 on ttyS5. (Rx & Tx only) */
+- at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
+-
+- /* USART5 on ttyS6. (Rx & Tx only) */
+- at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
+-
+- /* Set the internal pull-up resistor on DRXD */
+- at91_set_A_periph(AT91_PIN_PB14, 1);
+-
+ }
+
+ /*
+@@ -238,6 +203,39 @@ static struct i2c_board_info __initdata foxg20_i2c_devices[] = {
+ static void __init foxg20_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
++ at91_register_uart(AT91SAM9260_ID_US0, 1,
++ ATMEL_UART_CTS
++ | ATMEL_UART_RTS
++ | ATMEL_UART_DTR
++ | ATMEL_UART_DSR
++ | ATMEL_UART_DCD
++ | ATMEL_UART_RI);
++
++ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
++ at91_register_uart(AT91SAM9260_ID_US1, 2,
++ ATMEL_UART_CTS
++ | ATMEL_UART_RTS);
++
++ /* USART2 on ttyS3. (Rx & Tx only) */
++ at91_register_uart(AT91SAM9260_ID_US2, 3, 0);
++
++ /* USART3 on ttyS4. (Rx, Tx, RTS, CTS) */
++ at91_register_uart(AT91SAM9260_ID_US3, 4,
++ ATMEL_UART_CTS
++ | ATMEL_UART_RTS);
++
++ /* USART4 on ttyS5. (Rx & Tx only) */
++ at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
++
++ /* USART5 on ttyS6. (Rx & Tx only) */
++ at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
++
++ /* Set the internal pull-up resistor on DRXD */
++ at91_set_A_periph(AT91_PIN_PB14, 1);
+ at91_add_device_serial();
+ /* USB Host */
+ at91_add_device_usbh(&foxg20_usbh_data);
+diff --git a/arch/arm/mach-at91/board-gsia18s.c b/arch/arm/mach-at91/board-gsia18s.c
+index 230e719..3e0dfa6 100644
+--- a/arch/arm/mach-at91/board-gsia18s.c
++++ b/arch/arm/mach-at91/board-gsia18s.c
+@@ -41,38 +41,6 @@
+ static void __init gsia18s_init_early(void)
+ {
+ stamp9g20_init_early();
+-
+- /*
+- * USART0 on ttyS1 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI).
+- * Used for Internal Analog Modem.
+- */
+- at91_register_uart(AT91SAM9260_ID_US0, 1,
+- ATMEL_UART_CTS | ATMEL_UART_RTS |
+- ATMEL_UART_DTR | ATMEL_UART_DSR |
+- ATMEL_UART_DCD | ATMEL_UART_RI);
+- /*
+- * USART1 on ttyS2 (Rx, Tx, CTS, RTS).
+- * Used for GPS or WiFi or Data stream.
+- */
+- at91_register_uart(AT91SAM9260_ID_US1, 2,
+- ATMEL_UART_CTS | ATMEL_UART_RTS);
+- /*
+- * USART2 on ttyS3 (Rx, Tx, CTS, RTS).
+- * Used for External Modem.
+- */
+- at91_register_uart(AT91SAM9260_ID_US2, 3,
+- ATMEL_UART_CTS | ATMEL_UART_RTS);
+- /*
+- * USART3 on ttyS4 (Rx, Tx, RTS).
+- * Used for RS-485.
+- */
+- at91_register_uart(AT91SAM9260_ID_US3, 4, ATMEL_UART_RTS);
+-
+- /*
+- * USART4 on ttyS5 (Rx, Tx).
+- * Used for TRX433 Radio Module.
+- */
+- at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
+ }
+
+ /*
+@@ -558,6 +526,37 @@ static int __init gsia18s_power_off_init(void)
+
+ static void __init gsia18s_board_init(void)
+ {
++ /*
++ * USART0 on ttyS1 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI).
++ * Used for Internal Analog Modem.
++ */
++ at91_register_uart(AT91SAM9260_ID_US0, 1,
++ ATMEL_UART_CTS | ATMEL_UART_RTS |
++ ATMEL_UART_DTR | ATMEL_UART_DSR |
++ ATMEL_UART_DCD | ATMEL_UART_RI);
++ /*
++ * USART1 on ttyS2 (Rx, Tx, CTS, RTS).
++ * Used for GPS or WiFi or Data stream.
++ */
++ at91_register_uart(AT91SAM9260_ID_US1, 2,
++ ATMEL_UART_CTS | ATMEL_UART_RTS);
++ /*
++ * USART2 on ttyS3 (Rx, Tx, CTS, RTS).
++ * Used for External Modem.
++ */
++ at91_register_uart(AT91SAM9260_ID_US2, 3,
++ ATMEL_UART_CTS | ATMEL_UART_RTS);
++ /*
++ * USART3 on ttyS4 (Rx, Tx, RTS).
++ * Used for RS-485.
++ */
++ at91_register_uart(AT91SAM9260_ID_US3, 4, ATMEL_UART_RTS);
++
++ /*
++ * USART4 on ttyS5 (Rx, Tx).
++ * Used for TRX433 Radio Module.
++ */
++ at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
+ stamp9g20_board_init();
+ at91_add_device_usbh(&usbh_data);
+ at91_add_device_udc(&udc_data);
+diff --git a/arch/arm/mach-at91/board-kafa.c b/arch/arm/mach-at91/board-kafa.c
+index 3e858ed..f46b3eb 100644
+--- a/arch/arm/mach-at91/board-kafa.c
++++ b/arch/arm/mach-at91/board-kafa.c
+@@ -50,12 +50,6 @@ static void __init kafa_init_early(void)
+
+ /* Set up the LEDs */
+ at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */
+- at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
+ }
+
+ static struct macb_platform_data __initdata kafa_eth_data = {
+@@ -77,6 +71,11 @@ static struct at91_udc_data __initdata kafa_udc_data = {
+ static void __init kafa_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */
++ at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
+ at91_add_device_serial();
+ /* Ethernet */
+ at91_add_device_eth(&kafa_eth_data);
+diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c
+index ccbc8be..e71b9e1 100644
+--- a/arch/arm/mach-at91/board-kb9202.c
++++ b/arch/arm/mach-at91/board-kb9202.c
+@@ -53,18 +53,6 @@ static void __init kb9202_init_early(void)
+
+ /* Set up the LEDs */
+ at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART0 on ttyS1 (Rx & Tx only) */
+- at91_register_uart(AT91RM9200_ID_US0, 1, 0);
+-
+- /* USART1 on ttyS2 (Rx & Tx only) - IRDA (optional) */
+- at91_register_uart(AT91RM9200_ID_US1, 2, 0);
+-
+- /* USART3 on ttyS3 (Rx, Tx, CTS, RTS) - RS485 (optional) */
+- at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
+ }
+
+ static struct macb_platform_data __initdata kb9202_eth_data = {
+@@ -113,6 +101,17 @@ static struct atmel_nand_data __initdata kb9202_nand_data = {
+ static void __init kb9202_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART0 on ttyS1 (Rx & Tx only) */
++ at91_register_uart(AT91RM9200_ID_US0, 1, 0);
++
++ /* USART1 on ttyS2 (Rx & Tx only) - IRDA (optional) */
++ at91_register_uart(AT91RM9200_ID_US1, 2, 0);
++
++ /* USART3 on ttyS3 (Rx, Tx, CTS, RTS) - RS485 (optional) */
++ at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
+ at91_add_device_serial();
+ /* Ethernet */
+ at91_add_device_eth(&kb9202_eth_data);
+diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
+index c456fdc..d2f4cc1 100644
+--- a/arch/arm/mach-at91/board-neocore926.c
++++ b/arch/arm/mach-at91/board-neocore926.c
+@@ -55,12 +55,6 @@ static void __init neocore926_init_early(void)
+ {
+ /* Initialize processor: 20 MHz crystal */
+ at91_initialize(20000000);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */
+- at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
+ }
+
+ /*
+@@ -338,6 +332,11 @@ static struct ac97c_platform_data neocore926_ac97_data = {
+ static void __init neocore926_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */
++ at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
+ at91_add_device_serial();
+
+ /* USB Host */
+diff --git a/arch/arm/mach-at91/board-pcontrol-g20.c b/arch/arm/mach-at91/board-pcontrol-g20.c
+index b4a12fc..7fe6383 100644
+--- a/arch/arm/mach-at91/board-pcontrol-g20.c
++++ b/arch/arm/mach-at91/board-pcontrol-g20.c
+@@ -40,17 +40,6 @@
+ static void __init pcontrol_g20_init_early(void)
+ {
+ stamp9g20_init_early();
+-
+- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) piggyback A2 */
+- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS
+- | ATMEL_UART_RTS);
+-
+- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) isolated RS485 X5 */
+- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS
+- | ATMEL_UART_RTS);
+-
+- /* USART2 on ttyS3. (Rx, Tx) 9bit-Bus Multidrop-mode X4 */
+- at91_register_uart(AT91SAM9260_ID_US4, 3, 0);
+ }
+
+ static struct sam9_smc_config __initdata pcontrol_smc_config[2] = { {
+@@ -199,6 +188,16 @@ static struct spi_board_info pcontrol_g20_spi_devices[] = {
+
+ static void __init pcontrol_g20_board_init(void)
+ {
++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) piggyback A2 */
++ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS
++ | ATMEL_UART_RTS);
++
++ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) isolated RS485 X5 */
++ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS
++ | ATMEL_UART_RTS);
++
++ /* USART2 on ttyS3. (Rx, Tx) 9bit-Bus Multidrop-mode X4 */
++ at91_register_uart(AT91SAM9260_ID_US4, 3, 0);
+ stamp9g20_board_init();
+ at91_add_device_usbh(&usbh_data);
+ at91_add_device_eth(&macb_data);
+diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c
+index 4ca56cd..b45c0a5 100644
+--- a/arch/arm/mach-at91/board-picotux200.c
++++ b/arch/arm/mach-at91/board-picotux200.c
+@@ -48,14 +48,6 @@ static void __init picotux200_init_early(void)
+ {
+ /* Initialize processor: 18.432 MHz crystal */
+ at91_initialize(18432000);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+- | ATMEL_UART_RI);
+ }
+
+ static struct macb_platform_data __initdata picotux200_eth_data = {
+@@ -103,6 +95,13 @@ static struct platform_device picotux200_flash = {
+ static void __init picotux200_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
++ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
++ | ATMEL_UART_RI);
+ at91_add_device_serial();
+ /* Ethernet */
+ at91_add_device_eth(&picotux200_eth_data);
+diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c
+index 189d3fe..0c61bf0 100644
+--- a/arch/arm/mach-at91/board-qil-a9260.c
++++ b/arch/arm/mach-at91/board-qil-a9260.c
+@@ -52,20 +52,6 @@ static void __init ek_init_early(void)
+ {
+ /* Initialize processor: 12.000 MHz crystal */
+ at91_initialize(12000000);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+- | ATMEL_UART_RI);
+-
+- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */
+- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
+-
+- /* USART2 on ttyS3. (Rx, Tx, CTS, RTS) */
+- at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
+ }
+
+ /*
+@@ -231,6 +217,19 @@ static struct gpio_led ek_leds[] = {
+ static void __init ek_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
++ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
++ | ATMEL_UART_RI);
++
++ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */
++ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
++
++ /* USART2 on ttyS3. (Rx, Tx, CTS, RTS) */
++ at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
+ at91_add_device_serial();
+ /* USB Host */
+ at91_add_device_usbh(&ek_usbh_data);
+diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c
+index d5ce630..4a0b097 100644
+--- a/arch/arm/mach-at91/board-rm9200dk.c
++++ b/arch/arm/mach-at91/board-rm9200dk.c
+@@ -53,14 +53,6 @@ static void __init dk_init_early(void)
+
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+- | ATMEL_UART_RI);
+ }
+
+ static struct macb_platform_data __initdata dk_eth_data = {
+@@ -188,6 +180,13 @@ static struct gpio_led dk_leds[] = {
+ static void __init dk_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
++ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
++ | ATMEL_UART_RI);
+ at91_add_device_serial();
+ /* Ethernet */
+ at91_add_device_eth(&dk_eth_data);
+diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c
+index e96d5f5..6fa54ac 100644
+--- a/arch/arm/mach-at91/board-rm9200ek.c
++++ b/arch/arm/mach-at91/board-rm9200ek.c
+@@ -53,14 +53,6 @@ static void __init ek_init_early(void)
+
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+- | ATMEL_UART_RI);
+ }
+
+ static struct macb_platform_data __initdata ek_eth_data = {
+@@ -159,6 +151,13 @@ static struct gpio_led ek_leds[] = {
+ static void __init ek_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
++ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
++ | ATMEL_UART_RI);
+ at91_add_device_serial();
+ /* Ethernet */
+ at91_add_device_eth(&ek_eth_data);
+diff --git a/arch/arm/mach-at91/board-rsi-ews.c b/arch/arm/mach-at91/board-rsi-ews.c
+index 2c84463..10d8730 100644
+--- a/arch/arm/mach-at91/board-rsi-ews.c
++++ b/arch/arm/mach-at91/board-rsi-ews.c
+@@ -38,20 +38,6 @@ static void __init rsi_ews_init_early(void)
+
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PB6, AT91_PIN_PB9);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- /* This one is for debugging */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+- /* Dialin/-out modem interface */
+- at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS
+- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+- | ATMEL_UART_RI);
+-
+- /* USART3 on ttyS4. (Rx, Tx, RTS) */
+- /* RS485 communication */
+- at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_RTS);
+ }
+
+ /*
+@@ -202,6 +188,19 @@ static struct platform_device rsiews_nor_flash = {
+ static void __init rsi_ews_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ /* This one is for debugging */
++ at91_register_uart(0, 0, 0);
++
++ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
++ /* Dialin/-out modem interface */
++ at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS
++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
++ | ATMEL_UART_RI);
++
++ /* USART3 on ttyS4. (Rx, Tx, RTS) */
++ /* RS485 communication */
++ at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_RTS);
+ at91_add_device_serial();
+ at91_set_gpio_output(AT91_PIN_PA21, 0);
+ /* Ethernet */
+diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c
+index dee44cb..5343dab 100644
+--- a/arch/arm/mach-at91/board-sam9-l9260.c
++++ b/arch/arm/mach-at91/board-sam9-l9260.c
+@@ -51,17 +51,6 @@ static void __init ek_init_early(void)
+
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PA9, AT91_PIN_PA6);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+- | ATMEL_UART_RI);
+-
+- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */
+- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
+ }
+
+ /*
+@@ -182,6 +171,16 @@ static struct at91_mmc_data __initdata ek_mmc_data = {
+ static void __init ek_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
++ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
++ | ATMEL_UART_RI);
++
++ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */
++ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
+ at91_add_device_serial();
+ /* USB Host */
+ at91_add_device_usbh(&ek_usbh_data);
+diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
+index 6da17b5..7b3c391 100644
+--- a/arch/arm/mach-at91/board-sam9260ek.c
++++ b/arch/arm/mach-at91/board-sam9260ek.c
+@@ -54,17 +54,6 @@ static void __init ek_init_early(void)
+ {
+ /* Initialize processor: 18.432 MHz crystal */
+ at91_initialize(18432000);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+- | ATMEL_UART_RI);
+-
+- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
+ }
+
+ /*
+@@ -317,6 +306,16 @@ static void __init ek_add_device_buttons(void) {}
+ static void __init ek_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
++ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
++ | ATMEL_UART_RI);
++
++ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
++ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
+ at91_add_device_serial();
+ /* USB Host */
+ at91_add_device_usbh(&ek_usbh_data);
+diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
+index 950c20b..de1ed46 100644
+--- a/arch/arm/mach-at91/board-sam9261ek.c
++++ b/arch/arm/mach-at91/board-sam9261ek.c
+@@ -61,9 +61,6 @@ static void __init ek_init_early(void)
+
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PA13, AT91_PIN_PA14);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+ }
+
+ /*
+@@ -575,6 +572,8 @@ static struct gpio_led ek_leds[] = {
+ static void __init ek_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
+ at91_add_device_serial();
+ /* USB Host */
+ at91_add_device_usbh(&ek_usbh_data);
+diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
+index 4424873..983cb98 100644
+--- a/arch/arm/mach-at91/board-sam9263ek.c
++++ b/arch/arm/mach-at91/board-sam9263ek.c
+@@ -57,12 +57,6 @@ static void __init ek_init_early(void)
+ {
+ /* Initialize processor: 16.367 MHz crystal */
+ at91_initialize(16367660);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */
+- at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
+ }
+
+ /*
+@@ -409,6 +403,11 @@ static struct at91_can_data ek_can_data = {
+ static void __init ek_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */
++ at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
+ at91_add_device_serial();
+ /* USB Host */
+ at91_add_device_usbh(&ek_usbh_data);
+diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
+index 05f8467..3d61553 100644
+--- a/arch/arm/mach-at91/board-sam9g20ek.c
++++ b/arch/arm/mach-at91/board-sam9g20ek.c
+@@ -65,17 +65,6 @@ static void __init ek_init_early(void)
+ {
+ /* Initialize processor: 18.432 MHz crystal */
+ at91_initialize(18432000);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+- | ATMEL_UART_RI);
+-
+- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
+ }
+
+ /*
+@@ -369,6 +358,16 @@ static struct i2c_board_info __initdata ek_i2c_devices[] = {
+ static void __init ek_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
++ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
++ | ATMEL_UART_RI);
++
++ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
++ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
+ at91_add_device_serial();
+ /* USB Host */
+ at91_add_device_usbh(&ek_usbh_data);
+diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
+index be2ca19..9a87f0b 100644
+--- a/arch/arm/mach-at91/board-sam9m10g45ek.c
++++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
+@@ -53,13 +53,6 @@ static void __init ek_init_early(void)
+ {
+ /* Initialize processor: 12.000 MHz crystal */
+ at91_initialize(12000000);
+-
+- /* DGBU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART0 not connected on the -EK board */
+- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+- at91_register_uart(AT91SAM9G45_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
+ }
+
+ /*
+@@ -454,6 +447,12 @@ static struct platform_device *devices[] __initdata = {
+ static void __init ek_board_init(void)
+ {
+ /* Serial */
++ /* DGBU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART0 not connected on the -EK board */
++ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
++ at91_register_uart(AT91SAM9G45_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
+ at91_add_device_serial();
+ /* USB HS Host */
+ at91_add_device_usbh_ohci(&ek_usbh_hs_data);
+diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
+index 23f383a..be3239f 100644
+--- a/arch/arm/mach-at91/board-sam9rlek.c
++++ b/arch/arm/mach-at91/board-sam9rlek.c
+@@ -42,12 +42,6 @@ static void __init ek_init_early(void)
+ {
+ /* Initialize processor: 12.000 MHz crystal */
+ at91_initialize(12000000);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */
+- at91_register_uart(AT91SAM9RL_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
+ }
+
+ /*
+@@ -293,6 +287,11 @@ static void __init ek_add_device_buttons(void) {}
+ static void __init ek_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */
++ at91_register_uart(AT91SAM9RL_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
+ at91_add_device_serial();
+ /* USB HS */
+ at91_add_device_usba(&ek_usba_udc_data);
+diff --git a/arch/arm/mach-at91/board-snapper9260.c b/arch/arm/mach-at91/board-snapper9260.c
+index 1a6774a..9d446f1 100644
+--- a/arch/arm/mach-at91/board-snapper9260.c
++++ b/arch/arm/mach-at91/board-snapper9260.c
+@@ -43,15 +43,6 @@
+ static void __init snapper9260_init_early(void)
+ {
+ at91_initialize(18432000);
+-
+- /* Debug on ttyS0 */
+- at91_register_uart(0, 0, 0);
+-
+- at91_register_uart(AT91SAM9260_ID_US0, 1,
+- ATMEL_UART_CTS | ATMEL_UART_RTS);
+- at91_register_uart(AT91SAM9260_ID_US1, 2,
+- ATMEL_UART_CTS | ATMEL_UART_RTS);
+- at91_register_uart(AT91SAM9260_ID_US2, 3, 0);
+ }
+
+ static struct at91_usbh_data __initdata snapper9260_usbh_data = {
+@@ -167,6 +158,14 @@ static void __init snapper9260_board_init(void)
+ snapper9260_i2c_isl1208.irq = gpio_to_irq(AT91_PIN_PA31);
+ i2c_register_board_info(0, &snapper9260_i2c_isl1208, 1);
+
++ /* Debug on ttyS0 */
++ at91_register_uart(0, 0, 0);
++
++ at91_register_uart(AT91SAM9260_ID_US0, 1,
++ ATMEL_UART_CTS | ATMEL_UART_RTS);
++ at91_register_uart(AT91SAM9260_ID_US1, 2,
++ ATMEL_UART_CTS | ATMEL_UART_RTS);
++ at91_register_uart(AT91SAM9260_ID_US2, 3, 0);
+ at91_add_device_serial();
+ at91_add_device_usbh(&snapper9260_usbh_data);
+ at91_add_device_udc(&snapper9260_udc_data);
+diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c
+index 38a7ca5..ee86f9d 100644
+--- a/arch/arm/mach-at91/board-stamp9g20.c
++++ b/arch/arm/mach-at91/board-stamp9g20.c
+@@ -36,41 +36,6 @@ void __init stamp9g20_init_early(void)
+ {
+ /* Initialize processor: 18.432 MHz crystal */
+ at91_initialize(18432000);
+-
+- /* DGBU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-}
+-
+-static void __init stamp9g20evb_init_early(void)
+-{
+- stamp9g20_init_early();
+-
+- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+- | ATMEL_UART_DTR | ATMEL_UART_DSR
+- | ATMEL_UART_DCD | ATMEL_UART_RI);
+-}
+-
+-static void __init portuxg20_init_early(void)
+-{
+- stamp9g20_init_early();
+-
+- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+- | ATMEL_UART_DTR | ATMEL_UART_DSR
+- | ATMEL_UART_DCD | ATMEL_UART_RI);
+-
+- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */
+- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
+-
+- /* USART2 on ttyS3. (Rx, Tx, CTS, RTS) */
+- at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
+-
+- /* USART4 on ttyS5. (Rx, Tx only) */
+- at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
+-
+- /* USART5 on ttyS6. (Rx, Tx only) */
+- at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
+ }
+
+ /*
+@@ -251,6 +216,8 @@ void add_w1(void)
+ void __init stamp9g20_board_init(void)
+ {
+ /* Serial */
++ /* DGBU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
+ at91_add_device_serial();
+ /* NAND */
+ add_device_nand();
+@@ -266,6 +233,22 @@ void __init stamp9g20_board_init(void)
+
+ static void __init portuxg20_board_init(void)
+ {
++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
++ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
++ | ATMEL_UART_DTR | ATMEL_UART_DSR
++ | ATMEL_UART_DCD | ATMEL_UART_RI);
++
++ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */
++ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
++
++ /* USART2 on ttyS3. (Rx, Tx, CTS, RTS) */
++ at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
++
++ /* USART4 on ttyS5. (Rx, Tx only) */
++ at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
++
++ /* USART5 on ttyS6. (Rx, Tx only) */
++ at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
+ stamp9g20_board_init();
+ /* USB Host */
+ at91_add_device_usbh(&usbh_data);
+@@ -283,6 +266,10 @@ static void __init portuxg20_board_init(void)
+
+ static void __init stamp9g20evb_board_init(void)
+ {
++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
++ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
++ | ATMEL_UART_DTR | ATMEL_UART_DSR
++ | ATMEL_UART_DCD | ATMEL_UART_RI);
+ stamp9g20_board_init();
+ /* USB Host */
+ at91_add_device_usbh(&usbh_data);
+@@ -300,7 +287,7 @@ MACHINE_START(PORTUXG20, "taskit PortuxG20")
+ /* Maintainer: taskit GmbH */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
+- .init_early = portuxg20_init_early,
++ .init_early = stamp9g20_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = portuxg20_board_init,
+ MACHINE_END
+@@ -309,7 +296,7 @@ MACHINE_START(STAMP9G20, "taskit Stamp9G20")
+ /* Maintainer: taskit GmbH */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
+- .init_early = stamp9g20evb_init_early,
++ .init_early = stamp9g20_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = stamp9g20evb_board_init,
+ MACHINE_END
+diff --git a/arch/arm/mach-at91/board-usb-a926x.c b/arch/arm/mach-at91/board-usb-a926x.c
+index ee482eb..332ecd4 100644
+--- a/arch/arm/mach-at91/board-usb-a926x.c
++++ b/arch/arm/mach-at91/board-usb-a926x.c
+@@ -53,9 +53,6 @@ static void __init ek_init_early(void)
+ {
+ /* Initialize processor: 12.00 MHz crystal */
+ at91_initialize(12000000);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+ }
+
+ /*
+@@ -322,6 +319,8 @@ static void __init ek_add_device_leds(void)
+ static void __init ek_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
+ at91_add_device_serial();
+ /* USB Host */
+ at91_add_device_usbh(&ek_usbh_data);
+diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c
+index e94a04e..db8d25c 100644
+--- a/arch/arm/mach-at91/board-yl-9200.c
++++ b/arch/arm/mach-at91/board-yl-9200.c
+@@ -61,20 +61,6 @@ static void __init yl9200_init_early(void)
+
+ /* Setup the LEDs D2=PB17 (timer), D3=PB16 (cpu) */
+ at91_init_leds(AT91_PIN_PB16, AT91_PIN_PB17);
+-
+- /* DBGU on ttyS0. (Rx & Tx only) */
+- at91_register_uart(0, 0, 0);
+-
+- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+- | ATMEL_UART_RI);
+-
+- /* USART0 on ttyS2. (Rx & Tx only to JP3) */
+- at91_register_uart(AT91RM9200_ID_US0, 2, 0);
+-
+- /* USART3 on ttyS3. (Rx, Tx, RTS - RS485 interface) */
+- at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_RTS);
+ }
+
+ /*
+@@ -558,6 +544,19 @@ void __init yl9200_add_device_video(void) {}
+ static void __init yl9200_board_init(void)
+ {
+ /* Serial */
++ /* DBGU on ttyS0. (Rx & Tx only) */
++ at91_register_uart(0, 0, 0);
++
++ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
++ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
++ | ATMEL_UART_RI);
++
++ /* USART0 on ttyS2. (Rx & Tx only to JP3) */
++ at91_register_uart(AT91RM9200_ID_US0, 2, 0);
++
++ /* USART3 on ttyS3. (Rx, Tx, RTS - RS485 interface) */
++ at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_RTS);
+ at91_add_device_serial();
+ /* Ethernet */
+ at91_add_device_eth(&yl9200_eth_data);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0019-ARM-at91-move-at91_init_leds-to-board-init.patch b/patches.at91/0019-ARM-at91-move-at91_init_leds-to-board-init.patch
new file mode 100644
index 00000000000000..4e75d7d4ff617b
--- /dev/null
+++ b/patches.at91/0019-ARM-at91-move-at91_init_leds-to-board-init.patch
@@ -0,0 +1,288 @@
+From 0543012c6006a0638654943130daae637f764d5a Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Thu, 5 Apr 2012 14:27:57 +0800
+Subject: ARM: at91: move at91_init_leds to board init
+
+This will also allow to finally move the gpio driver to platform device/driver.
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/board-csb337.c | 5 ++---
+ arch/arm/mach-at91/board-ecbat91.c | 6 +++---
+ arch/arm/mach-at91/board-eco920.c | 5 ++---
+ arch/arm/mach-at91/board-kafa.c | 6 +++---
+ arch/arm/mach-at91/board-kb9202.c | 6 +++---
+ arch/arm/mach-at91/board-rm9200dk.c | 6 +++---
+ arch/arm/mach-at91/board-rm9200ek.c | 6 +++---
+ arch/arm/mach-at91/board-rsi-ews.c | 6 +++---
+ arch/arm/mach-at91/board-sam9-l9260.c | 6 +++---
+ arch/arm/mach-at91/board-sam9261ek.c | 6 +++---
+ arch/arm/mach-at91/board-yl-9200.c | 6 +++---
+ 11 files changed, 31 insertions(+), 33 deletions(-)
+
+diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
+index ad7f9f0..cd81336 100644
+--- a/arch/arm/mach-at91/board-csb337.c
++++ b/arch/arm/mach-at91/board-csb337.c
+@@ -47,9 +47,6 @@ static void __init csb337_init_early(void)
+ {
+ /* Initialize processor: 3.6864 MHz crystal */
+ at91_initialize(3686400);
+-
+- /* Setup the LEDs */
+- at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
+ }
+
+ static struct macb_platform_data __initdata csb337_eth_data = {
+@@ -222,6 +219,8 @@ static struct gpio_led csb_leds[] = {
+
+ static void __init csb337_board_init(void)
+ {
++ /* Setup the LEDs */
++ at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
+ /* Serial */
+ /* DBGU on ttyS0 */
+ at91_register_uart(0, 0, 0);
+diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c
+index 2510825..89cc372 100644
+--- a/arch/arm/mach-at91/board-ecbat91.c
++++ b/arch/arm/mach-at91/board-ecbat91.c
+@@ -50,9 +50,6 @@ static void __init ecb_at91init_early(void)
+
+ /* Initialize processor: 18.432 MHz crystal */
+ at91_initialize(18432000);
+-
+- /* Setup the LEDs */
+- at91_init_leds(AT91_PIN_PC7, AT91_PIN_PC7);
+ }
+
+ static struct macb_platform_data __initdata ecb_at91eth_data = {
+@@ -142,6 +139,9 @@ static struct spi_board_info __initdata ecb_at91spi_devices[] = {
+
+ static void __init ecb_at91board_init(void)
+ {
++ /* Setup the LEDs */
++ at91_init_leds(AT91_PIN_PC7, AT91_PIN_PC7);
++
+ /* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c
+index bebeae8..558546c 100644
+--- a/arch/arm/mach-at91/board-eco920.c
++++ b/arch/arm/mach-at91/board-eco920.c
+@@ -37,9 +37,6 @@ static void __init eco920_init_early(void)
+ at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
+
+ at91_initialize(18432000);
+-
+- /* Setup the LEDs */
+- at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
+ }
+
+ static struct macb_platform_data __initdata eco920_eth_data = {
+@@ -97,6 +94,8 @@ static struct spi_board_info eco920_spi_devices[] = {
+
+ static void __init eco920_board_init(void)
+ {
++ /* Setup the LEDs */
++ at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
+ /* DBGU on ttyS0. (Rx & Tx only */
+ at91_register_uart(0, 0, 0);
+ at91_add_device_serial();
+diff --git a/arch/arm/mach-at91/board-kafa.c b/arch/arm/mach-at91/board-kafa.c
+index f46b3eb..f260657 100644
+--- a/arch/arm/mach-at91/board-kafa.c
++++ b/arch/arm/mach-at91/board-kafa.c
+@@ -47,9 +47,6 @@ static void __init kafa_init_early(void)
+
+ /* Initialize processor: 18.432 MHz crystal */
+ at91_initialize(18432000);
+-
+- /* Set up the LEDs */
+- at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4);
+ }
+
+ static struct macb_platform_data __initdata kafa_eth_data = {
+@@ -70,6 +67,9 @@ static struct at91_udc_data __initdata kafa_udc_data = {
+
+ static void __init kafa_board_init(void)
+ {
++ /* Set up the LEDs */
++ at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4);
++
+ /* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c
+index e71b9e1..ba39db5 100644
+--- a/arch/arm/mach-at91/board-kb9202.c
++++ b/arch/arm/mach-at91/board-kb9202.c
+@@ -50,9 +50,6 @@ static void __init kb9202_init_early(void)
+
+ /* Initialize processor: 10 MHz crystal */
+ at91_initialize(10000000);
+-
+- /* Set up the LEDs */
+- at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18);
+ }
+
+ static struct macb_platform_data __initdata kb9202_eth_data = {
+@@ -100,6 +97,9 @@ static struct atmel_nand_data __initdata kb9202_nand_data = {
+
+ static void __init kb9202_board_init(void)
+ {
++ /* Set up the LEDs */
++ at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18);
++
+ /* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c
+index 4a0b097..afd7a47 100644
+--- a/arch/arm/mach-at91/board-rm9200dk.c
++++ b/arch/arm/mach-at91/board-rm9200dk.c
+@@ -50,9 +50,6 @@ static void __init dk_init_early(void)
+ {
+ /* Initialize processor: 18.432 MHz crystal */
+ at91_initialize(18432000);
+-
+- /* Setup the LEDs */
+- at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
+ }
+
+ static struct macb_platform_data __initdata dk_eth_data = {
+@@ -179,6 +176,9 @@ static struct gpio_led dk_leds[] = {
+
+ static void __init dk_board_init(void)
+ {
++ /* Setup the LEDs */
++ at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
++
+ /* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c
+index 6fa54ac..2b15b8a 100644
+--- a/arch/arm/mach-at91/board-rm9200ek.c
++++ b/arch/arm/mach-at91/board-rm9200ek.c
+@@ -50,9 +50,6 @@ static void __init ek_init_early(void)
+ {
+ /* Initialize processor: 18.432 MHz crystal */
+ at91_initialize(18432000);
+-
+- /* Setup the LEDs */
+- at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2);
+ }
+
+ static struct macb_platform_data __initdata ek_eth_data = {
+@@ -150,6 +147,9 @@ static struct gpio_led ek_leds[] = {
+
+ static void __init ek_board_init(void)
+ {
++ /* Setup the LEDs */
++ at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2);
++
+ /* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+diff --git a/arch/arm/mach-at91/board-rsi-ews.c b/arch/arm/mach-at91/board-rsi-ews.c
+index 10d8730..24ab9be 100644
+--- a/arch/arm/mach-at91/board-rsi-ews.c
++++ b/arch/arm/mach-at91/board-rsi-ews.c
+@@ -35,9 +35,6 @@ static void __init rsi_ews_init_early(void)
+ {
+ /* Initialize processor: 18.432 MHz crystal */
+ at91_initialize(18432000);
+-
+- /* Setup the LEDs */
+- at91_init_leds(AT91_PIN_PB6, AT91_PIN_PB9);
+ }
+
+ /*
+@@ -187,6 +184,9 @@ static struct platform_device rsiews_nor_flash = {
+ */
+ static void __init rsi_ews_board_init(void)
+ {
++ /* Setup the LEDs */
++ at91_init_leds(AT91_PIN_PB6, AT91_PIN_PB9);
++
+ /* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ /* This one is for debugging */
+diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c
+index 5343dab..cdd21f2 100644
+--- a/arch/arm/mach-at91/board-sam9-l9260.c
++++ b/arch/arm/mach-at91/board-sam9-l9260.c
+@@ -48,9 +48,6 @@ static void __init ek_init_early(void)
+ {
+ /* Initialize processor: 18.432 MHz crystal */
+ at91_initialize(18432000);
+-
+- /* Setup the LEDs */
+- at91_init_leds(AT91_PIN_PA9, AT91_PIN_PA6);
+ }
+
+ /*
+@@ -170,6 +167,9 @@ static struct at91_mmc_data __initdata ek_mmc_data = {
+
+ static void __init ek_board_init(void)
+ {
++ /* Setup the LEDs */
++ at91_init_leds(AT91_PIN_PA9, AT91_PIN_PA6);
++
+ /* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
+index de1ed46..2736453 100644
+--- a/arch/arm/mach-at91/board-sam9261ek.c
++++ b/arch/arm/mach-at91/board-sam9261ek.c
+@@ -58,9 +58,6 @@ static void __init ek_init_early(void)
+ {
+ /* Initialize processor: 18.432 MHz crystal */
+ at91_initialize(18432000);
+-
+- /* Setup the LEDs */
+- at91_init_leds(AT91_PIN_PA13, AT91_PIN_PA14);
+ }
+
+ /*
+@@ -571,6 +568,9 @@ static struct gpio_led ek_leds[] = {
+
+ static void __init ek_board_init(void)
+ {
++ /* Setup the LEDs */
++ at91_init_leds(AT91_PIN_PA13, AT91_PIN_PA14);
++
+ /* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c
+index db8d25c..d56665e 100644
+--- a/arch/arm/mach-at91/board-yl-9200.c
++++ b/arch/arm/mach-at91/board-yl-9200.c
+@@ -58,9 +58,6 @@ static void __init yl9200_init_early(void)
+
+ /* Initialize processor: 18.432 MHz crystal */
+ at91_initialize(18432000);
+-
+- /* Setup the LEDs D2=PB17 (timer), D3=PB16 (cpu) */
+- at91_init_leds(AT91_PIN_PB16, AT91_PIN_PB17);
+ }
+
+ /*
+@@ -543,6 +540,9 @@ void __init yl9200_add_device_video(void) {}
+
+ static void __init yl9200_board_init(void)
+ {
++ /* Setup the LEDs D2=PB17 (timer), D3=PB16 (cpu) */
++ at91_init_leds(AT91_PIN_PB16, AT91_PIN_PB17);
++
+ /* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0020-ARM-at91-pm-select-memory-controler-at-runtime.patch b/patches.at91/0020-ARM-at91-pm-select-memory-controler-at-runtime.patch
new file mode 100644
index 00000000000000..23c7bb32643968
--- /dev/null
+++ b/patches.at91/0020-ARM-at91-pm-select-memory-controler-at-runtime.patch
@@ -0,0 +1,117 @@
+From e7d4df4ef74b1ed11a0e2037bc5cbe8123cf258d Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Mon, 13 Feb 2012 14:58:30 +0800
+Subject: ARM: at91: pm select memory controler at runtime
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+[nicolas.ferre@atmel.com: add cpuidle modification]
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/cpuidle.c | 8 +++++++-
+ arch/arm/mach-at91/pm.c | 12 ++++++++----
+ arch/arm/mach-at91/pm.h | 13 -------------
+ 3 files changed, 15 insertions(+), 18 deletions(-)
+
+diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c
+index ece1f9a..0c63815 100644
+--- a/arch/arm/mach-at91/cpuidle.c
++++ b/arch/arm/mach-at91/cpuidle.c
+@@ -21,6 +21,7 @@
+ #include <linux/export.h>
+ #include <asm/proc-fns.h>
+ #include <asm/cpuidle.h>
++#include <mach/cpu.h>
+
+ #include "pm.h"
+
+@@ -33,7 +34,12 @@ static int at91_enter_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+ {
+- at91_standby();
++ if (cpu_is_at91rm9200())
++ at91rm9200_standby();
++ else if (cpu_is_at91sam9g45())
++ at91sam9g45_standby();
++ else
++ at91sam9_standby();
+
+ return index;
+ }
+diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
+index f630250..1bfaad6 100644
+--- a/arch/arm/mach-at91/pm.c
++++ b/arch/arm/mach-at91/pm.c
+@@ -261,7 +261,12 @@ static int at91_pm_enter(suspend_state_t state)
+ * For ARM 926 based chips, this requirement is weaker
+ * as at91sam9 can access a RAM in self-refresh mode.
+ */
+- at91_standby();
++ if (cpu_is_at91rm9200())
++ at91rm9200_standby();
++ else if (cpu_is_at91sam9g45())
++ at91sam9g45_standby();
++ else
++ at91sam9_standby();
+ break;
+
+ case PM_SUSPEND_ON:
+@@ -307,10 +312,9 @@ static int __init at91_pm_init(void)
+
+ pr_info("AT91: Power Management%s\n", (slow_clock ? " (with slow clock mode)" : ""));
+
+-#ifdef CONFIG_ARCH_AT91RM9200
+ /* AT91RM9200 SDRAM low-power mode cannot be used with self-refresh. */
+- at91_ramc_write(0, AT91RM9200_SDRAMC_LPR, 0);
+-#endif
++ if (cpu_is_at91rm9200())
++ at91_ramc_write(0, AT91RM9200_SDRAMC_LPR, 0);
+
+ suspend_set_ops(&at91_pm_ops);
+
+diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h
+index 89f56f3..1b4865e 100644
+--- a/arch/arm/mach-at91/pm.h
++++ b/arch/arm/mach-at91/pm.h
+@@ -12,7 +12,6 @@
+ #define __ARCH_ARM_MACH_AT91_PM
+
+ #include <mach/at91_ramc.h>
+-#ifdef CONFIG_ARCH_AT91RM9200
+ #include <mach/at91rm9200_sdramc.h>
+
+ /*
+@@ -43,10 +42,6 @@ static inline void at91rm9200_standby(void)
+ "r" (lpr));
+ }
+
+-#define at91_standby at91rm9200_standby
+-
+-#elif defined(CONFIG_ARCH_AT91SAM9G45)
+-
+ /* We manage both DDRAM/SDRAM controllers, we need more than one value to
+ * remember.
+ */
+@@ -75,10 +70,6 @@ static inline void at91sam9g45_standby(void)
+ at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1);
+ }
+
+-#define at91_standby at91sam9g45_standby
+-
+-#else
+-
+ #ifdef CONFIG_ARCH_AT91SAM9263
+ /*
+ * FIXME either or both the SDRAM controllers (EB0, EB1) might be in use;
+@@ -102,8 +93,4 @@ static inline void at91sam9_standby(void)
+ at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr);
+ }
+
+-#define at91_standby at91sam9_standby
+-
+-#endif
+-
+ #endif
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0021-ARM-at91-add-SOC_AT91SAM9-kconfig-option-to-factoris.patch b/patches.at91/0021-ARM-at91-add-SOC_AT91SAM9-kconfig-option-to-factoris.patch
new file mode 100644
index 00000000000000..3d2ea6f94e1a5a
--- /dev/null
+++ b/patches.at91/0021-ARM-at91-add-SOC_AT91SAM9-kconfig-option-to-factoris.patch
@@ -0,0 +1,133 @@
+From 54af5dc6fcc90243d7d161c83f2c94cb1ef67697 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Fri, 6 Apr 2012 13:04:04 +0800
+Subject: ARM: at91: add SOC_AT91SAM9 kconfig option to factorise select
+
+This will allow to simplify the switch to multi soc in the same kernel.
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/Kconfig | 29 +++++++++++++----------------
+ arch/arm/mach-at91/Makefile | 17 +++++++++--------
+ 2 files changed, 22 insertions(+), 24 deletions(-)
+
+diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
+index 885fdb9..40e31c7 100644
+--- a/arch/arm/mach-at91/Kconfig
++++ b/arch/arm/mach-at91/Kconfig
+@@ -17,6 +17,11 @@ config AT91_SAM9G45_RESET
+ bool
+ default !ARCH_AT91X40
+
++config SOC_AT91SAM9
++ bool
++ select GENERIC_CLOCKEVENTS
++ select CPU_ARM926T
++
+ menu "Atmel AT91 System-on-Chip"
+
+ choice
+@@ -30,51 +35,44 @@ config ARCH_AT91RM9200
+
+ config ARCH_AT91SAM9260
+ bool "AT91SAM9260 or AT91SAM9XE"
+- select CPU_ARM926T
+- select GENERIC_CLOCKEVENTS
++ select SOC_AT91SAM9
+ select HAVE_AT91_DBGU0
+ select HAVE_NET_MACB
+
+ config ARCH_AT91SAM9261
+ bool "AT91SAM9261"
+- select CPU_ARM926T
+- select GENERIC_CLOCKEVENTS
++ select SOC_AT91SAM9
+ select HAVE_FB_ATMEL
+ select HAVE_AT91_DBGU0
+
+ config ARCH_AT91SAM9G10
+ bool "AT91SAM9G10"
+- select CPU_ARM926T
+- select GENERIC_CLOCKEVENTS
++ select SOC_AT91SAM9
+ select HAVE_AT91_DBGU0
+ select HAVE_FB_ATMEL
+
+ config ARCH_AT91SAM9263
+ bool "AT91SAM9263"
+- select CPU_ARM926T
+- select GENERIC_CLOCKEVENTS
++ select SOC_AT91SAM9
+ select HAVE_FB_ATMEL
+ select HAVE_NET_MACB
+ select HAVE_AT91_DBGU1
+
+ config ARCH_AT91SAM9RL
+ bool "AT91SAM9RL"
+- select CPU_ARM926T
+- select GENERIC_CLOCKEVENTS
++ select SOC_AT91SAM9
+ select HAVE_FB_ATMEL
+ select HAVE_AT91_DBGU0
+
+ config ARCH_AT91SAM9G20
+ bool "AT91SAM9G20"
+- select CPU_ARM926T
+- select GENERIC_CLOCKEVENTS
++ select SOC_AT91SAM9
+ select HAVE_AT91_DBGU0
+ select HAVE_NET_MACB
+
+ config ARCH_AT91SAM9G45
+ bool "AT91SAM9G45 or AT91SAM9M10 families"
+- select CPU_ARM926T
+- select GENERIC_CLOCKEVENTS
++ select SOC_AT91SAM9
+ select HAVE_FB_ATMEL
+ select HAVE_NET_MACB
+ select HAVE_AT91_DBGU1
+@@ -84,8 +82,7 @@ config ARCH_AT91SAM9G45
+
+ config ARCH_AT91SAM9X5
+ bool "AT91SAM9x5 family"
+- select CPU_ARM926T
+- select GENERIC_CLOCKEVENTS
++ select SOC_AT91SAM9
+ select HAVE_FB_ATMEL
+ select HAVE_NET_MACB
+ select HAVE_AT91_DBGU0
+diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
+index 8512e53..d97d0f4 100644
+--- a/arch/arm/mach-at91/Makefile
++++ b/arch/arm/mach-at91/Makefile
+@@ -10,17 +10,18 @@ obj- :=
+ obj-$(CONFIG_AT91_PMC_UNIT) += clock.o
+ obj-$(CONFIG_AT91_SAM9_ALT_RESET) += at91sam9_alt_reset.o
+ obj-$(CONFIG_AT91_SAM9G45_RESET) += at91sam9g45_reset.o
++obj-$(CONFIG_SOC_AT91SAM9) += at91sam926x_time.o sam9_smc.o
+
+ # CPU-specific support
+ obj-$(CONFIG_ARCH_AT91RM9200) += at91rm9200.o at91rm9200_time.o at91rm9200_devices.o
+-obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o
+-obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o
+-obj-$(CONFIG_ARCH_AT91SAM9G10) += at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o
+-obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam926x_time.o at91sam9263_devices.o sam9_smc.o
+-obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o sam9_smc.o
+-obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.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 sam9_smc.o
++obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260.o at91sam9260_devices.o
++obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261.o at91sam9261_devices.o
++obj-$(CONFIG_ARCH_AT91SAM9G10) += at91sam9261.o at91sam9261_devices.o
++obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam9263_devices.o
++obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl.o at91sam9rl_devices.o
++obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam9260_devices.o
++obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam9g45_devices.o
++obj-$(CONFIG_ARCH_AT91SAM9X5) += at91sam9x5.o
+ obj-$(CONFIG_ARCH_AT91X40) += at91x40.o at91x40_time.o
+
+ # AT91RM9200 board-specific support
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0022-ARN-at91-introduce-SOC_AT91xxx-define-to-allow-to-co.patch b/patches.at91/0022-ARN-at91-introduce-SOC_AT91xxx-define-to-allow-to-co.patch
new file mode 100644
index 00000000000000..13ba82bd936635
--- /dev/null
+++ b/patches.at91/0022-ARN-at91-introduce-SOC_AT91xxx-define-to-allow-to-co.patch
@@ -0,0 +1,378 @@
+From 420a99e1110afb0a9a2fd8ac6e1c18ba2136002e Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Fri, 6 Apr 2012 11:51:50 +0800
+Subject: ARN: at91: introduce SOC_AT91xxx define to allow to compile SoC core
+ support
+
+We can now compile all SoC core support together and DT boards.
+We still can not compile together the non DT board.
+So We keep the ARCH_AT91xxx for the non DT board and for backward defconfig
+compatibility. This will enable the plaform_device ressources.
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/configs/at91rm9200_defconfig | 1 +
+ arch/arm/mach-at91/Kconfig | 91 ++++++++++++++++++++++++-----------
+ arch/arm/mach-at91/Makefile | 25 ++++++----
+ arch/arm/mach-at91/include/mach/cpu.h | 28 +++++------
+ arch/arm/mach-at91/pm.h | 2 +-
+ arch/arm/mach-at91/pm_slowclock.S | 2 +-
+ arch/arm/mach-at91/soc.h | 14 +++---
+ 7 files changed, 101 insertions(+), 62 deletions(-)
+
+diff --git a/arch/arm/configs/at91rm9200_defconfig b/arch/arm/configs/at91rm9200_defconfig
+index bbe4e1a..d54e2ac 100644
+--- a/arch/arm/configs/at91rm9200_defconfig
++++ b/arch/arm/configs/at91rm9200_defconfig
+@@ -14,6 +14,7 @@ CONFIG_MODULE_SRCVERSION_ALL=y
+ # CONFIG_BLK_DEV_BSG is not set
+ # CONFIG_IOSCHED_CFQ is not set
+ CONFIG_ARCH_AT91=y
++CONFIG_ARCH_AT91RM9200=y
+ CONFIG_MACH_ONEARM=y
+ CONFIG_ARCH_AT91RM9200DK=y
+ CONFIG_MACH_AT91RM9200EK=y
+diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
+index 40e31c7..98a42f3 100644
+--- a/arch/arm/mach-at91/Kconfig
++++ b/arch/arm/mach-at91/Kconfig
+@@ -24,68 +24,66 @@ config SOC_AT91SAM9
+
+ menu "Atmel AT91 System-on-Chip"
+
+-choice
+- prompt "Atmel AT91 Processor"
++comment "Atmel AT91 Processor"
+
+-config ARCH_AT91RM9200
++config SOC_AT91SAM9
++ bool
++ select CPU_ARM926T
++ select AT91_SAM9_TIME
++ select AT91_SAM9_SMC
++
++config SOC_AT91RM9200
+ bool "AT91RM9200"
+ select CPU_ARM920T
+ select GENERIC_CLOCKEVENTS
+ select HAVE_AT91_DBGU0
+
+-config ARCH_AT91SAM9260
+- bool "AT91SAM9260 or AT91SAM9XE"
++config SOC_AT91SAM9260
++ bool "AT91SAM9260, AT91SAM9XE or AT91SAM9G20"
+ select SOC_AT91SAM9
+ select HAVE_AT91_DBGU0
+ select HAVE_NET_MACB
++ help
++ Select this if you are using one of Atmel's AT91SAM9260, AT91SAM9XE
++ or AT91SAM9G20 SoC.
+
+-config ARCH_AT91SAM9261
+- bool "AT91SAM9261"
+- select SOC_AT91SAM9
+- select HAVE_FB_ATMEL
+- select HAVE_AT91_DBGU0
+-
+-config ARCH_AT91SAM9G10
+- bool "AT91SAM9G10"
++config SOC_AT91SAM9261
++ bool "AT91SAM9261 or AT91SAM9G10"
+ select SOC_AT91SAM9
+ select HAVE_AT91_DBGU0
+ select HAVE_FB_ATMEL
++ help
++ Select this if you are using one of Atmel's AT91SAM9261 or AT91SAM9G10 SoC.
+
+-config ARCH_AT91SAM9263
++config SOC_AT91SAM9263
+ bool "AT91SAM9263"
+ select SOC_AT91SAM9
++ select HAVE_AT91_DBGU1
+ select HAVE_FB_ATMEL
+ select HAVE_NET_MACB
+- select HAVE_AT91_DBGU1
+
+-config ARCH_AT91SAM9RL
++config SOC_AT91SAM9RL
+ bool "AT91SAM9RL"
+ select SOC_AT91SAM9
+- select HAVE_FB_ATMEL
+ select HAVE_AT91_DBGU0
++ select HAVE_FB_ATMEL
+
+-config ARCH_AT91SAM9G20
+- bool "AT91SAM9G20"
+- select SOC_AT91SAM9
+- select HAVE_AT91_DBGU0
+- select HAVE_NET_MACB
+-
+-config ARCH_AT91SAM9G45
++config SOC_AT91SAM9G45
+ bool "AT91SAM9G45 or AT91SAM9M10 families"
+ select SOC_AT91SAM9
++ select HAVE_AT91_DBGU1
+ select HAVE_FB_ATMEL
+ select HAVE_NET_MACB
+- select HAVE_AT91_DBGU1
+ help
+ Select this if you are using one of Atmel's AT91SAM9G45 family SoC.
+ This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11.
+
+-config ARCH_AT91SAM9X5
++config SOC_AT91SAM9X5
+ bool "AT91SAM9x5 family"
+ select SOC_AT91SAM9
++ select HAVE_AT91_DBGU0
+ select HAVE_FB_ATMEL
+ select HAVE_NET_MACB
+- select HAVE_AT91_DBGU0
+ help
+ Select this if you are using one of Atmel's AT91SAM9x5 family SoC.
+ This means that your SAM9 name finishes with a '5' (except if it is
+@@ -93,8 +91,47 @@ config ARCH_AT91SAM9X5
+ This support covers AT91SAM9G15, AT91SAM9G25, AT91SAM9X25, AT91SAM9G35
+ and AT91SAM9X35.
+
++choice
++ prompt "Atmel AT91 Processor Devices for non DT boards"
++
++config ARCH_AT91_NONE
++ bool "None"
++
++config ARCH_AT91RM9200
++ bool "AT91RM9200"
++ select SOC_AT91RM9200
++
++config ARCH_AT91SAM9260
++ bool "AT91SAM9260 or AT91SAM9XE"
++ select SOC_AT91SAM9260
++
++config ARCH_AT91SAM9261
++ bool "AT91SAM9261"
++ select SOC_AT91SAM9261
++
++config ARCH_AT91SAM9G10
++ bool "AT91SAM9G10"
++ select SOC_AT91SAM9261
++
++config ARCH_AT91SAM9263
++ bool "AT91SAM9263"
++ select SOC_AT91SAM9263
++
++config ARCH_AT91SAM9RL
++ bool "AT91SAM9RL"
++ select SOC_AT91SAM9RL
++
++config ARCH_AT91SAM9G20
++ bool "AT91SAM9G20"
++ select SOC_AT91SAM9260
++
++config ARCH_AT91SAM9G45
++ bool "AT91SAM9G45"
++ select SOC_AT91SAM9G45
++
+ config ARCH_AT91X40
+ bool "AT91x40"
++ depends on !MMU
+ select ARCH_USES_GETTIMEOFFSET
+
+ endchoice
+diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
+index d97d0f4..79d0f60 100644
+--- a/arch/arm/mach-at91/Makefile
++++ b/arch/arm/mach-at91/Makefile
+@@ -13,15 +13,22 @@ obj-$(CONFIG_AT91_SAM9G45_RESET) += at91sam9g45_reset.o
+ obj-$(CONFIG_SOC_AT91SAM9) += at91sam926x_time.o sam9_smc.o
+
+ # CPU-specific support
+-obj-$(CONFIG_ARCH_AT91RM9200) += at91rm9200.o at91rm9200_time.o at91rm9200_devices.o
+-obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260.o at91sam9260_devices.o
+-obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261.o at91sam9261_devices.o
+-obj-$(CONFIG_ARCH_AT91SAM9G10) += at91sam9261.o at91sam9261_devices.o
+-obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam9263_devices.o
+-obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl.o at91sam9rl_devices.o
+-obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam9260_devices.o
+-obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam9g45_devices.o
+-obj-$(CONFIG_ARCH_AT91SAM9X5) += at91sam9x5.o
++obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o at91rm9200_time.o
++obj-$(CONFIG_SOC_AT91SAM9260) += at91sam9260.o
++obj-$(CONFIG_SOC_AT91SAM9261) += at91sam9261.o
++obj-$(CONFIG_SOC_AT91SAM9263) += at91sam9263.o
++obj-$(CONFIG_SOC_AT91SAM9G45) += at91sam9g45.o
++obj-$(CONFIG_SOC_AT91SAM9X5) += at91sam9x5.o
++obj-$(CONFIG_SOC_AT91SAM9RL) += at91sam9rl.o
++
++obj-$(CONFIG_ARCH_AT91RM9200) += at91rm9200_devices.o
++obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260_devices.o
++obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261_devices.o
++obj-$(CONFIG_ARCH_AT91SAM9G10) += at91sam9261_devices.o
++obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263_devices.o
++obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl_devices.o
++obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260_devices.o
++obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45_devices.o
+ obj-$(CONFIG_ARCH_AT91X40) += at91x40.o at91x40_time.o
+
+ # AT91RM9200 board-specific support
+diff --git a/arch/arm/mach-at91/include/mach/cpu.h b/arch/arm/mach-at91/include/mach/cpu.h
+index 0118c33..73d2fd2 100644
+--- a/arch/arm/mach-at91/include/mach/cpu.h
++++ b/arch/arm/mach-at91/include/mach/cpu.h
+@@ -54,6 +54,7 @@
+ #define ARCH_REVISON_9200_BGA (0 << 0)
+ #define ARCH_REVISON_9200_PQFP (1 << 0)
+
++#ifndef __ASSEMBLY__
+ enum at91_soc_type {
+ /* 920T */
+ AT91_SOC_RM9200,
+@@ -106,7 +107,7 @@ static inline int at91_soc_is_detected(void)
+ return at91_soc_initdata.type != AT91_SOC_NONE;
+ }
+
+-#ifdef CONFIG_ARCH_AT91RM9200
++#ifdef CONFIG_SOC_AT91RM9200
+ #define cpu_is_at91rm9200() (at91_soc_initdata.type == AT91_SOC_RM9200)
+ #define cpu_is_at91rm9200_bga() (at91_soc_initdata.subtype == AT91_SOC_RM9200_BGA)
+ #define cpu_is_at91rm9200_pqfp() (at91_soc_initdata.subtype == AT91_SOC_RM9200_PQFP)
+@@ -116,45 +117,37 @@ static inline int at91_soc_is_detected(void)
+ #define cpu_is_at91rm9200_pqfp() (0)
+ #endif
+
+-#ifdef CONFIG_ARCH_AT91SAM9260
++#ifdef CONFIG_SOC_AT91SAM9260
+ #define cpu_is_at91sam9xe() (at91_soc_initdata.subtype == AT91_SOC_SAM9XE)
+ #define cpu_is_at91sam9260() (at91_soc_initdata.type == AT91_SOC_SAM9260)
++#define cpu_is_at91sam9g20() (at91_soc_initdata.type == AT91_SOC_SAM9G20)
+ #else
+ #define cpu_is_at91sam9xe() (0)
+ #define cpu_is_at91sam9260() (0)
+-#endif
+-
+-#ifdef CONFIG_ARCH_AT91SAM9G20
+-#define cpu_is_at91sam9g20() (at91_soc_initdata.type == AT91_SOC_SAM9G20)
+-#else
+ #define cpu_is_at91sam9g20() (0)
+ #endif
+
+-#ifdef CONFIG_ARCH_AT91SAM9261
++#ifdef CONFIG_SOC_AT91SAM9261
+ #define cpu_is_at91sam9261() (at91_soc_initdata.type == AT91_SOC_SAM9261)
+-#else
+-#define cpu_is_at91sam9261() (0)
+-#endif
+-
+-#ifdef CONFIG_ARCH_AT91SAM9G10
+ #define cpu_is_at91sam9g10() (at91_soc_initdata.type == AT91_SOC_SAM9G10)
+ #else
++#define cpu_is_at91sam9261() (0)
+ #define cpu_is_at91sam9g10() (0)
+ #endif
+
+-#ifdef CONFIG_ARCH_AT91SAM9263
++#ifdef CONFIG_SOC_AT91SAM9263
+ #define cpu_is_at91sam9263() (at91_soc_initdata.type == AT91_SOC_SAM9263)
+ #else
+ #define cpu_is_at91sam9263() (0)
+ #endif
+
+-#ifdef CONFIG_ARCH_AT91SAM9RL
++#ifdef CONFIG_SOC_AT91SAM9RL
+ #define cpu_is_at91sam9rl() (at91_soc_initdata.type == AT91_SOC_SAM9RL)
+ #else
+ #define cpu_is_at91sam9rl() (0)
+ #endif
+
+-#ifdef CONFIG_ARCH_AT91SAM9G45
++#ifdef CONFIG_SOC_AT91SAM9G45
+ #define cpu_is_at91sam9g45() (at91_soc_initdata.type == AT91_SOC_SAM9G45)
+ #define cpu_is_at91sam9g45es() (at91_soc_initdata.subtype == AT91_SOC_SAM9G45ES)
+ #define cpu_is_at91sam9m10() (at91_soc_initdata.subtype == AT91_SOC_SAM9M10)
+@@ -168,7 +161,7 @@ static inline int at91_soc_is_detected(void)
+ #define cpu_is_at91sam9m11() (0)
+ #endif
+
+-#ifdef CONFIG_ARCH_AT91SAM9X5
++#ifdef CONFIG_SOC_AT91SAM9X5
+ #define cpu_is_at91sam9x5() (at91_soc_initdata.type == AT91_SOC_SAM9X5)
+ #define cpu_is_at91sam9g15() (at91_soc_initdata.subtype == AT91_SOC_SAM9G15)
+ #define cpu_is_at91sam9g35() (at91_soc_initdata.subtype == AT91_SOC_SAM9G35)
+@@ -189,5 +182,6 @@ static inline int at91_soc_is_detected(void)
+ * definitions may reduce clutter in common drivers.
+ */
+ #define cpu_is_at32ap7000() (0)
++#endif /* __ASSEMBLY__ */
+
+ #endif /* __MACH_CPU_H__ */
+diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h
+index 1b4865e..38f467c 100644
+--- a/arch/arm/mach-at91/pm.h
++++ b/arch/arm/mach-at91/pm.h
+@@ -70,7 +70,7 @@ static inline void at91sam9g45_standby(void)
+ at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1);
+ }
+
+-#ifdef CONFIG_ARCH_AT91SAM9263
++#ifdef CONFIG_SOC_AT91SAM9263
+ /*
+ * FIXME either or both the SDRAM controllers (EB0, EB1) might be in use;
+ * handle those cases both here and in the Suspend-To-RAM support.
+diff --git a/arch/arm/mach-at91/pm_slowclock.S b/arch/arm/mach-at91/pm_slowclock.S
+index db54521..098c28d 100644
+--- a/arch/arm/mach-at91/pm_slowclock.S
++++ b/arch/arm/mach-at91/pm_slowclock.S
+@@ -18,7 +18,7 @@
+ #include <mach/at91_ramc.h>
+
+
+-#ifdef CONFIG_ARCH_AT91SAM9263
++#ifdef CONFIG_SOC_AT91SAM9263
+ /*
+ * FIXME either or both the SDRAM controllers (EB0, EB1) might be in use;
+ * handle those cases both here and in the Suspend-To-RAM support.
+diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h
+index 5db4aa4..683dddf 100644
+--- a/arch/arm/mach-at91/soc.h
++++ b/arch/arm/mach-at91/soc.h
+@@ -26,30 +26,30 @@ static inline int at91_soc_is_enabled(void)
+ return at91_boot_soc.init != NULL;
+ }
+
+-#if !defined(CONFIG_ARCH_AT91RM9200)
++#if !defined(CONFIG_SOC_AT91RM9200)
+ #define at91rm9200_soc at91_boot_soc
+ #endif
+
+-#if !(defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20))
++#if !defined(CONFIG_SOC_AT91SAM9260)
+ #define at91sam9260_soc at91_boot_soc
+ #endif
+
+-#if !(defined(CONFIG_ARCH_AT91SAM9261) || defined(CONFIG_ARCH_AT91SAM9G10))
++#if !defined(CONFIG_SOC_AT91SAM9261)
+ #define at91sam9261_soc at91_boot_soc
+ #endif
+
+-#if !defined(CONFIG_ARCH_AT91SAM9263)
++#if !defined(CONFIG_SOC_AT91SAM9263)
+ #define at91sam9263_soc at91_boot_soc
+ #endif
+
+-#if !defined(CONFIG_ARCH_AT91SAM9G45)
++#if !defined(CONFIG_SOC_AT91SAM9G45)
+ #define at91sam9g45_soc at91_boot_soc
+ #endif
+
+-#if !defined(CONFIG_ARCH_AT91SAM9RL)
++#if !defined(CONFIG_SOC_AT91SAM9RL)
+ #define at91sam9rl_soc at91_boot_soc
+ #endif
+
+-#if !defined(CONFIG_ARCH_AT91SAM9X5)
++#if !defined(CONFIG_SOC_AT91SAM9X5)
+ #define at91sam9x5_soc at91_boot_soc
+ #endif
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0023-ARM-at91-dt-do-not-specify-the-board-any-more.patch b/patches.at91/0023-ARM-at91-dt-do-not-specify-the-board-any-more.patch
new file mode 100644
index 00000000000000..5f968506f6d997
--- /dev/null
+++ b/patches.at91/0023-ARM-at91-dt-do-not-specify-the-board-any-more.patch
@@ -0,0 +1,42 @@
+From 77a5977e7fdc175bb1963143b80ad2a74cf3d9b8 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Thu, 1 Mar 2012 14:47:44 +0800
+Subject: ARM: at91/dt: do not specify the board any more
+
+This will allow to add any board to a compiled kernel by just passing the DTB.
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/board-dt.c | 8 +-------
+ 1 file changed, 1 insertion(+), 7 deletions(-)
+
+diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
+index c18d4d3..a1fce05 100644
+--- a/arch/arm/mach-at91/board-dt.c
++++ b/arch/arm/mach-at91/board-dt.c
+@@ -1,10 +1,6 @@
+ /*
+ * Setup code for AT91SAM Evaluation Kits with Device Tree support
+ *
+- * Covers: * AT91SAM9G45-EKES board
+- * * AT91SAM9M10-EKES board
+- * * AT91SAM9M10G45-EK board
+- *
+ * Copyright (C) 2011 Atmel,
+ * 2011 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+@@ -49,9 +45,7 @@ static void __init at91_dt_device_init(void)
+ }
+
+ static const char *at91_dt_board_compat[] __initdata = {
+- "atmel,at91sam9m10g45ek",
+- "atmel,at91sam9x5ek",
+- "calao,usb-a9g20",
++ "atmel,at91sam9",
+ NULL
+ };
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0024-ARM-at91-add-defconfig-for-device-tree.patch b/patches.at91/0024-ARM-at91-add-defconfig-for-device-tree.patch
new file mode 100644
index 00000000000000..9ae95597c5db5f
--- /dev/null
+++ b/patches.at91/0024-ARM-at91-add-defconfig-for-device-tree.patch
@@ -0,0 +1,220 @@
+From 73aa3911713fc739b9213475b4ff86d85d80d113 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Sun, 8 Apr 2012 17:40:06 +0200
+Subject: ARM: at91: add defconfig for device tree
+
+This will enable all current SoC support on DT (9260, 9g20, 9g45 family
+and 9x5 family).
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/configs/at91_dt_defconfig | 196 +++++++++++++++++++++++++++++++++++++
+ 1 file changed, 196 insertions(+)
+ create mode 100644 arch/arm/configs/at91_dt_defconfig
+
+diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig
+new file mode 100644
+index 0000000..67bc571
+--- /dev/null
++++ b/arch/arm/configs/at91_dt_defconfig
+@@ -0,0 +1,196 @@
++CONFIG_EXPERIMENTAL=y
++# CONFIG_LOCALVERSION_AUTO is not set
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_LOG_BUF_SHIFT=14
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_EMBEDDED=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_SOC_AT91SAM9260=y
++CONFIG_SOC_AT91SAM9263=y
++CONFIG_SOC_AT91SAM9G45=y
++CONFIG_SOC_AT91SAM9X5=y
++CONFIG_MACH_AT91SAM_DT=y
++CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
++CONFIG_AT91_TIMER_HZ=128
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++CONFIG_LEDS=y
++CONFIG_LEDS_CPU=y
++CONFIG_UACCESS_WITH_MEMCPY=y
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_ARM_APPENDED_DTB=y
++CONFIG_ARM_ATAG_DTB_COMPAT=y
++CONFIG_CMDLINE="mem=128M console=ttyS0,115200 initrd=0x21100000,25165824 root=/dev/ram0 rw"
++CONFIG_KEXEC=y
++CONFIG_AUTO_ZRELADDR=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_PNP=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_DIAG is not set
++CONFIG_IPV6=y
++# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET6_XFRM_MODE_BEET is not set
++CONFIG_IPV6_SIT_6RD=y
++# CONFIG_WIRELESS is not set
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++# CONFIG_STANDALONE is not set
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_MTD=y
++CONFIG_MTD_CMDLINE_PARTS=y
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++CONFIG_MTD_NAND=y
++CONFIG_MTD_NAND_ATMEL=y
++CONFIG_MTD_UBI=y
++CONFIG_MTD_UBI_GLUEBI=y
++CONFIG_PROC_DEVICETREE=y
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=4
++CONFIG_BLK_DEV_RAM_SIZE=8192
++CONFIG_ATMEL_PWM=y
++CONFIG_ATMEL_TCLIB=y
++CONFIG_EEPROM_93CX6=m
++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_MACB=y
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_VENDOR_CHELSIO is not set
++# CONFIG_NET_VENDOR_FARADAY is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++CONFIG_DAVICOM_PHY=y
++CONFIG_MICREL_PHY=y
++# CONFIG_WLAN is not set
++CONFIG_INPUT_POLLDEV=y
++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=480
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=272
++CONFIG_INPUT_JOYDEV=y
++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_SERIO is not set
++CONFIG_LEGACY_PTY_COUNT=4
++CONFIG_SERIAL_ATMEL=y
++CONFIG_SERIAL_ATMEL_CONSOLE=y
++CONFIG_HW_RANDOM=y
++CONFIG_I2C=y
++CONFIG_I2C_GPIO=y
++CONFIG_SPI=y
++CONFIG_SPI_ATMEL=y
++# CONFIG_HWMON is not set
++CONFIG_WATCHDOG=y
++CONFIG_AT91SAM9X_WATCHDOG=y
++CONFIG_SSB=m
++CONFIG_FB=y
++CONFIG_FB_MODE_HELPERS=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_FRAMEBUFFER_CONSOLE=y
++CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
++CONFIG_FONTS=y
++CONFIG_FONT_8x8=y
++CONFIG_FONT_ACORN_8x8=y
++CONFIG_FONT_MINI_4x6=y
++CONFIG_LOGO=y
++# CONFIG_HID_SUPPORT is not set
++CONFIG_USB=y
++CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
++CONFIG_USB_DEVICEFS=y
++# CONFIG_USB_DEVICE_CLASS is not set
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_ACM=y
++CONFIG_USB_STORAGE=y
++CONFIG_USB_SERIAL=y
++CONFIG_USB_SERIAL_GENERIC=y
++CONFIG_USB_SERIAL_FTDI_SIO=y
++CONFIG_USB_SERIAL_PL2303=y
++CONFIG_USB_GADGET=y
++CONFIG_USB_AT91=m
++CONFIG_USB_ATMEL_USBA=m
++CONFIG_USB_ETH=m
++CONFIG_USB_GADGETFS=m
++CONFIG_USB_CDC_COMPOSITE=m
++CONFIG_USB_G_ACM_MS=m
++CONFIG_USB_G_MULTI=m
++CONFIG_USB_G_MULTI_CDC=y
++CONFIG_MMC=y
++CONFIG_MMC_ATMELMCI=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_RTC_DRV_AT91SAM9=y
++CONFIG_DMADEVICES=y
++# CONFIG_IOMMU_SUPPORT is not set
++CONFIG_EXT2_FS=y
++CONFIG_FANOTIFY=y
++CONFIG_VFAT_FS=y
++CONFIG_TMPFS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++CONFIG_ROOT_NFS=y
++CONFIG_NLS_CODEPAGE_437=y
++CONFIG_NLS_CODEPAGE_850=y
++CONFIG_NLS_ISO8859_1=y
++CONFIG_STRIP_ASM_SYMS=y
++CONFIG_DEBUG_FS=y
++# CONFIG_SCHED_DEBUG is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++# CONFIG_FTRACE is not set
++CONFIG_DEBUG_USER=y
++CONFIG_CRYPTO=y
++CONFIG_CRYPTO_ECB=y
++CONFIG_CRYPTO_AES=y
++CONFIG_CRYPTO_ARC4=y
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++CONFIG_CRYPTO_USER_API_HASH=m
++CONFIG_CRYPTO_USER_API_SKCIPHER=m
++# CONFIG_CRYPTO_HW is not set
++CONFIG_CRC_CCITT=m
++CONFIG_CRC_ITU_T=m
++CONFIG_CRC7=m
++CONFIG_AVERAGE=y
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0025-ARM-at91-add-at91sam9260-DT-support.patch b/patches.at91/0025-ARM-at91-add-at91sam9260-DT-support.patch
new file mode 100644
index 00000000000000..48bd9750d284f7
--- /dev/null
+++ b/patches.at91/0025-ARM-at91-add-at91sam9260-DT-support.patch
@@ -0,0 +1,522 @@
+From d795dab6d067cd5734cd7af4b67634f3b3961bd7 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Mon, 9 Apr 2012 19:26:33 +0800
+Subject: ARM: at91: add at91sam9260 DT support
+
+The at91sam9260 and at91sam9g20 share most of the same IP.
+So udpate the node property in the at91sam9g20 only.
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9260.dtsi | 238 +++++++++++++++++++++++++++++++++++++
+ arch/arm/boot/dts/at91sam9g20.dtsi | 226 +----------------------------------
+ arch/arm/mach-at91/Makefile.boot | 1 +
+ 3 files changed, 242 insertions(+), 223 deletions(-)
+ create mode 100644 arch/arm/boot/dts/at91sam9260.dtsi
+
+diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
+new file mode 100644
+index 0000000..f4605ff
+--- /dev/null
++++ b/arch/arm/boot/dts/at91sam9260.dtsi
+@@ -0,0 +1,238 @@
++/*
++ * at91sam9260.dtsi - Device Tree Include file for AT91SAM9260 family SoC
++ *
++ * Copyright (C) 2011 Atmel,
++ * 2011 Nicolas Ferre <nicolas.ferre@atmel.com>,
++ * 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
++ *
++ * Licensed under GPLv2 or later.
++ */
++
++/include/ "skeleton.dtsi"
++
++/ {
++ model = "Atmel AT91SAM9260 family SoC";
++ compatible = "atmel,at91sam9260";
++ interrupt-parent = <&aic>;
++
++ aliases {
++ serial0 = &dbgu;
++ serial1 = &usart0;
++ serial2 = &usart1;
++ serial3 = &usart2;
++ serial4 = &usart3;
++ serial5 = &usart4;
++ serial6 = &usart5;
++ gpio0 = &pioA;
++ gpio1 = &pioB;
++ gpio2 = &pioC;
++ tcb0 = &tcb0;
++ tcb1 = &tcb1;
++ };
++ cpus {
++ cpu@0 {
++ compatible = "arm,arm926ejs";
++ };
++ };
++
++ memory {
++ reg = <0x20000000 0x04000000>;
++ };
++
++ ahb {
++ compatible = "simple-bus";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges;
++
++ apb {
++ compatible = "simple-bus";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges;
++
++ aic: interrupt-controller@fffff000 {
++ #interrupt-cells = <2>;
++ compatible = "atmel,at91rm9200-aic";
++ interrupt-controller;
++ reg = <0xfffff000 0x200>;
++ };
++
++ ramc0: ramc@ffffea00 {
++ compatible = "atmel,at91sam9260-sdramc";
++ reg = <0xffffea00 0x200>;
++ };
++
++ pmc: pmc@fffffc00 {
++ compatible = "atmel,at91rm9200-pmc";
++ reg = <0xfffffc00 0x100>;
++ };
++
++ rstc@fffffd00 {
++ compatible = "atmel,at91sam9260-rstc";
++ reg = <0xfffffd00 0x10>;
++ };
++
++ shdwc@fffffd10 {
++ compatible = "atmel,at91sam9260-shdwc";
++ reg = <0xfffffd10 0x10>;
++ };
++
++ pit: timer@fffffd30 {
++ compatible = "atmel,at91sam9260-pit";
++ reg = <0xfffffd30 0xf>;
++ interrupts = <1 4>;
++ };
++
++ tcb0: timer@fffa0000 {
++ compatible = "atmel,at91rm9200-tcb";
++ reg = <0xfffa0000 0x100>;
++ interrupts = <17 4 18 4 19 4>;
++ };
++
++ tcb1: timer@fffdc000 {
++ compatible = "atmel,at91rm9200-tcb";
++ reg = <0xfffdc000 0x100>;
++ interrupts = <26 4 27 4 28 4>;
++ };
++
++ pioA: gpio@fffff400 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff400 0x100>;
++ interrupts = <2 4>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ };
++
++ pioB: gpio@fffff600 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff600 0x100>;
++ interrupts = <3 4>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ };
++
++ pioC: gpio@fffff800 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff800 0x100>;
++ interrupts = <4 4>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ };
++
++ dbgu: serial@fffff200 {
++ compatible = "atmel,at91sam9260-usart";
++ reg = <0xfffff200 0x200>;
++ interrupts = <1 4>;
++ status = "disabled";
++ };
++
++ usart0: serial@fffb0000 {
++ compatible = "atmel,at91sam9260-usart";
++ reg = <0xfffb0000 0x200>;
++ interrupts = <6 4>;
++ atmel,use-dma-rx;
++ atmel,use-dma-tx;
++ status = "disabled";
++ };
++
++ usart1: serial@fffb4000 {
++ compatible = "atmel,at91sam9260-usart";
++ reg = <0xfffb4000 0x200>;
++ interrupts = <7 4>;
++ atmel,use-dma-rx;
++ atmel,use-dma-tx;
++ status = "disabled";
++ };
++
++ usart2: serial@fffb8000 {
++ compatible = "atmel,at91sam9260-usart";
++ reg = <0xfffb8000 0x200>;
++ interrupts = <8 4>;
++ atmel,use-dma-rx;
++ atmel,use-dma-tx;
++ status = "disabled";
++ };
++
++ usart3: serial@fffd0000 {
++ compatible = "atmel,at91sam9260-usart";
++ reg = <0xfffd0000 0x200>;
++ interrupts = <23 4>;
++ atmel,use-dma-rx;
++ atmel,use-dma-tx;
++ status = "disabled";
++ };
++
++ usart4: serial@fffd4000 {
++ compatible = "atmel,at91sam9260-usart";
++ reg = <0xfffd4000 0x200>;
++ interrupts = <24 4>;
++ atmel,use-dma-rx;
++ atmel,use-dma-tx;
++ status = "disabled";
++ };
++
++ usart5: serial@fffd8000 {
++ compatible = "atmel,at91sam9260-usart";
++ reg = <0xfffd8000 0x200>;
++ interrupts = <25 4>;
++ atmel,use-dma-rx;
++ atmel,use-dma-tx;
++ status = "disabled";
++ };
++
++ macb0: ethernet@fffc4000 {
++ compatible = "cdns,at32ap7000-macb", "cdns,macb";
++ reg = <0xfffc4000 0x100>;
++ interrupts = <21 4>;
++ status = "disabled";
++ };
++
++ usb1: gadget@fffa4000 {
++ compatible = "atmel,at91rm9200-udc";
++ reg = <0xfffa4000 0x4000>;
++ interrupts = <10 4>;
++ status = "disabled";
++ };
++ };
++
++ nand0: nand@40000000 {
++ compatible = "atmel,at91rm9200-nand";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ reg = <0x40000000 0x10000000
++ 0xffffe800 0x200
++ >;
++ atmel,nand-addr-offset = <21>;
++ atmel,nand-cmd-offset = <22>;
++ gpios = <&pioC 13 0
++ &pioC 14 0
++ 0
++ >;
++ status = "disabled";
++ };
++
++ usb0: ohci@00500000 {
++ compatible = "atmel,at91rm9200-ohci", "usb-ohci";
++ reg = <0x00500000 0x100000>;
++ interrupts = <20 4>;
++ status = "disabled";
++ };
++ };
++
++ i2c@0 {
++ compatible = "i2c-gpio";
++ gpios = <&pioA 23 0 /* sda */
++ &pioA 24 0 /* scl */
++ >;
++ i2c-gpio,sda-open-drain;
++ i2c-gpio,scl-open-drain;
++ i2c-gpio,delay-us = <2>; /* ~100 kHz */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++};
+diff --git a/arch/arm/boot/dts/at91sam9g20.dtsi b/arch/arm/boot/dts/at91sam9g20.dtsi
+index 773ef48..0eb1a75 100644
+--- a/arch/arm/boot/dts/at91sam9g20.dtsi
++++ b/arch/arm/boot/dts/at91sam9g20.dtsi
+@@ -1,238 +1,18 @@
+ /*
+ * at91sam9g20.dtsi - Device Tree Include file for AT91SAM9G20 family SoC
+ *
+- * Copyright (C) 2011 Atmel,
+- * 2011 Nicolas Ferre <nicolas.ferre@atmel.com>,
+- * 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+- * Licensed under GPLv2 or later.
++ * Licensed under GPLv2.
+ */
+
+-/include/ "skeleton.dtsi"
++/include/ "at91sam9260.dtsi"
+
+ / {
+ model = "Atmel AT91SAM9G20 family SoC";
+ compatible = "atmel,at91sam9g20";
+- interrupt-parent = <&aic>;
+-
+- aliases {
+- serial0 = &dbgu;
+- serial1 = &usart0;
+- serial2 = &usart1;
+- serial3 = &usart2;
+- serial4 = &usart3;
+- serial5 = &usart4;
+- serial6 = &usart5;
+- gpio0 = &pioA;
+- gpio1 = &pioB;
+- gpio2 = &pioC;
+- tcb0 = &tcb0;
+- tcb1 = &tcb1;
+- };
+- cpus {
+- cpu@0 {
+- compatible = "arm,arm926ejs";
+- };
+- };
+
+ memory {
+ reg = <0x20000000 0x08000000>;
+ };
+-
+- ahb {
+- compatible = "simple-bus";
+- #address-cells = <1>;
+- #size-cells = <1>;
+- ranges;
+-
+- apb {
+- compatible = "simple-bus";
+- #address-cells = <1>;
+- #size-cells = <1>;
+- ranges;
+-
+- aic: interrupt-controller@fffff000 {
+- #interrupt-cells = <2>;
+- compatible = "atmel,at91rm9200-aic";
+- interrupt-controller;
+- reg = <0xfffff000 0x200>;
+- };
+-
+- ramc0: ramc@ffffea00 {
+- compatible = "atmel,at91sam9260-sdramc";
+- reg = <0xffffea00 0x200>;
+- };
+-
+- pmc: pmc@fffffc00 {
+- compatible = "atmel,at91rm9200-pmc";
+- reg = <0xfffffc00 0x100>;
+- };
+-
+- rstc@fffffd00 {
+- compatible = "atmel,at91sam9260-rstc";
+- reg = <0xfffffd00 0x10>;
+- };
+-
+- shdwc@fffffd10 {
+- compatible = "atmel,at91sam9260-shdwc";
+- reg = <0xfffffd10 0x10>;
+- };
+-
+- pit: timer@fffffd30 {
+- compatible = "atmel,at91sam9260-pit";
+- reg = <0xfffffd30 0xf>;
+- interrupts = <1 4>;
+- };
+-
+- tcb0: timer@fffa0000 {
+- compatible = "atmel,at91rm9200-tcb";
+- reg = <0xfffa0000 0x100>;
+- interrupts = <17 4 18 4 19 4>;
+- };
+-
+- tcb1: timer@fffdc000 {
+- compatible = "atmel,at91rm9200-tcb";
+- reg = <0xfffdc000 0x100>;
+- interrupts = <26 4 27 4 28 4>;
+- };
+-
+- pioA: gpio@fffff400 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff400 0x100>;
+- interrupts = <2 4>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- };
+-
+- pioB: gpio@fffff600 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff600 0x100>;
+- interrupts = <3 4>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- };
+-
+- pioC: gpio@fffff800 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff800 0x100>;
+- interrupts = <4 4>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- };
+-
+- dbgu: serial@fffff200 {
+- compatible = "atmel,at91sam9260-usart";
+- reg = <0xfffff200 0x200>;
+- interrupts = <1 4>;
+- status = "disabled";
+- };
+-
+- usart0: serial@fffb0000 {
+- compatible = "atmel,at91sam9260-usart";
+- reg = <0xfffb0000 0x200>;
+- interrupts = <6 4>;
+- atmel,use-dma-rx;
+- atmel,use-dma-tx;
+- status = "disabled";
+- };
+-
+- usart1: serial@fffb4000 {
+- compatible = "atmel,at91sam9260-usart";
+- reg = <0xfffb4000 0x200>;
+- interrupts = <7 4>;
+- atmel,use-dma-rx;
+- atmel,use-dma-tx;
+- status = "disabled";
+- };
+-
+- usart2: serial@fffb8000 {
+- compatible = "atmel,at91sam9260-usart";
+- reg = <0xfffb8000 0x200>;
+- interrupts = <8 4>;
+- atmel,use-dma-rx;
+- atmel,use-dma-tx;
+- status = "disabled";
+- };
+-
+- usart3: serial@fffd0000 {
+- compatible = "atmel,at91sam9260-usart";
+- reg = <0xfffd0000 0x200>;
+- interrupts = <23 4>;
+- atmel,use-dma-rx;
+- atmel,use-dma-tx;
+- status = "disabled";
+- };
+-
+- usart4: serial@fffd4000 {
+- compatible = "atmel,at91sam9260-usart";
+- reg = <0xfffd4000 0x200>;
+- interrupts = <24 4>;
+- atmel,use-dma-rx;
+- atmel,use-dma-tx;
+- status = "disabled";
+- };
+-
+- usart5: serial@fffd8000 {
+- compatible = "atmel,at91sam9260-usart";
+- reg = <0xfffd8000 0x200>;
+- interrupts = <25 4>;
+- atmel,use-dma-rx;
+- atmel,use-dma-tx;
+- status = "disabled";
+- };
+-
+- macb0: ethernet@fffc4000 {
+- compatible = "cdns,at32ap7000-macb", "cdns,macb";
+- reg = <0xfffc4000 0x100>;
+- interrupts = <21 4>;
+- status = "disabled";
+- };
+-
+- usb1: gadget@fffa4000 {
+- compatible = "atmel,at91rm9200-udc";
+- reg = <0xfffa4000 0x4000>;
+- interrupts = <10 4>;
+- status = "disabled";
+- };
+- };
+-
+- nand0: nand@40000000 {
+- compatible = "atmel,at91rm9200-nand";
+- #address-cells = <1>;
+- #size-cells = <1>;
+- reg = <0x40000000 0x10000000
+- 0xffffe800 0x200
+- >;
+- atmel,nand-addr-offset = <21>;
+- atmel,nand-cmd-offset = <22>;
+- gpios = <&pioC 13 0
+- &pioC 14 0
+- 0
+- >;
+- status = "disabled";
+- };
+-
+- usb0: ohci@00500000 {
+- compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+- reg = <0x00500000 0x100000>;
+- interrupts = <20 4>;
+- status = "disabled";
+- };
+- };
+-
+- i2c@0 {
+- compatible = "i2c-gpio";
+- gpios = <&pioA 23 0 /* sda */
+- &pioA 24 0 /* scl */
+- >;
+- i2c-gpio,sda-open-drain;
+- i2c-gpio,scl-open-drain;
+- i2c-gpio,delay-us = <2>; /* ~100 kHz */
+- #address-cells = <1>;
+- #size-cells = <0>;
+- status = "disabled";
+- };
+ };
+diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
+index 0da66ca..0c2336c 100644
+--- a/arch/arm/mach-at91/Makefile.boot
++++ b/arch/arm/mach-at91/Makefile.boot
+@@ -14,6 +14,7 @@ initrd_phys-y := 0x20410000
+ endif
+
+ # Keep dtb files sorted alphabetically for each SoC
++# sam9260
+ # sam9g20
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9g20.dtb
+ # sam9g45
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0026-arm-at91-add-Calao-TNY-A9260-and-TNY-A9G20-board-sup.patch b/patches.at91/0026-arm-at91-add-Calao-TNY-A9260-and-TNY-A9G20-board-sup.patch
new file mode 100644
index 00000000000000..002aa44882393f
--- /dev/null
+++ b/patches.at91/0026-arm-at91-add-Calao-TNY-A9260-and-TNY-A9G20-board-sup.patch
@@ -0,0 +1,165 @@
+From 735aea5075e405af25ecdaea8a00091fa0b45c29 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Mon, 30 Jan 2012 23:45:52 +0800
+Subject: arm: at91: add Calao TNY-A9260 and TNY-A9G20 board support
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/tny_a9260.dts | 15 ++++++
+ arch/arm/boot/dts/tny_a9260_common.dtsi | 83 +++++++++++++++++++++++++++++++++
+ arch/arm/boot/dts/tny_a9g20.dts | 15 ++++++
+ arch/arm/mach-at91/Makefile.boot | 2 +
+ 4 files changed, 115 insertions(+)
+ create mode 100644 arch/arm/boot/dts/tny_a9260.dts
+ create mode 100644 arch/arm/boot/dts/tny_a9260_common.dtsi
+ create mode 100644 arch/arm/boot/dts/tny_a9g20.dts
+
+diff --git a/arch/arm/boot/dts/tny_a9260.dts b/arch/arm/boot/dts/tny_a9260.dts
+new file mode 100644
+index 0000000..367a16d
+--- /dev/null
++++ b/arch/arm/boot/dts/tny_a9260.dts
+@@ -0,0 +1,15 @@
++/*
++ * tny_a9260.dts - Device Tree file for Caloa TNY A9260 board
++ *
++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
++ *
++ * Licensed under GPLv2.
++ */
++/dts-v1/;
++/include/ "at91sam9260.dtsi"
++/include/ "tny_a9260_common.dtsi"
++
++/ {
++ model = "Calao TNY A9260";
++ compatible = "calao,tny-a9260", "atmel,at91sam9260", "atmel,at91sam9";
++};
+diff --git a/arch/arm/boot/dts/tny_a9260_common.dtsi b/arch/arm/boot/dts/tny_a9260_common.dtsi
+new file mode 100644
+index 0000000..0e6d3de
+--- /dev/null
++++ b/arch/arm/boot/dts/tny_a9260_common.dtsi
+@@ -0,0 +1,83 @@
++/*
++ * tny_a9260_common.dtsi - Device Tree file for Caloa TNY A926x board
++ *
++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
++ *
++ * Licensed under GPLv2.
++ */
++
++/ {
++ chosen {
++ bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock6 rw rootfstype=ubifs";
++ };
++
++ memory {
++ reg = <0x20000000 0x4000000>;
++ };
++
++ clocks {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges;
++
++ main_clock: clock@0 {
++ compatible = "atmel,osc", "fixed-clock";
++ clock-frequency = <12000000>;
++ };
++ };
++
++ ahb {
++ apb {
++ dbgu: serial@fffff200 {
++ status = "okay";
++ };
++ };
++
++ nand0: nand@40000000 {
++ nand-bus-width = <8>;
++ nand-ecc-mode = "soft";
++ nand-on-flash-bbt;
++ status = "okay";
++
++ at91bootstrap@0 {
++ label = "at91bootstrap";
++ reg = <0x0 0x20000>;
++ };
++
++ barebox@20000 {
++ label = "barebox";
++ reg = <0x20000 0x40000>;
++ };
++
++ bareboxenv@60000 {
++ label = "bareboxenv";
++ reg = <0x60000 0x20000>;
++ };
++
++ bareboxenv2@80000 {
++ label = "bareboxenv2";
++ reg = <0x80000 0x20000>;
++ };
++
++ oftree@80000 {
++ label = "oftree";
++ reg = <0xa0000 0x20000>;
++ };
++
++ kernel@a0000 {
++ label = "kernel";
++ reg = <0xc0000 0x400000>;
++ };
++
++ rootfs@4a0000 {
++ label = "rootfs";
++ reg = <0x4c0000 0x7800000>;
++ };
++
++ data@7ca0000 {
++ label = "data";
++ reg = <0x7cc0000 0x8340000>;
++ };
++ };
++ };
++};
+diff --git a/arch/arm/boot/dts/tny_a9g20.dts b/arch/arm/boot/dts/tny_a9g20.dts
+new file mode 100644
+index 0000000..e1ab64c
+--- /dev/null
++++ b/arch/arm/boot/dts/tny_a9g20.dts
+@@ -0,0 +1,15 @@
++/*
++ * tny_a9g20.dts - Device Tree file for Caloa TNY A9G20 board
++ *
++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
++ *
++ * Licensed under GPLv2.
++ */
++/dts-v1/;
++/include/ "at91sam9g20.dtsi"
++/include/ "tny_a9260_common.dtsi"
++
++/ {
++ model = "Calao TNY A9G20";
++ compatible = "calao,tny-a9g20", "atmel,at91sam9g20", "atmel,at91sam9";
++};
+diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
+index 0c2336c..bdf9841 100644
+--- a/arch/arm/mach-at91/Makefile.boot
++++ b/arch/arm/mach-at91/Makefile.boot
+@@ -15,7 +15,9 @@ endif
+
+ # Keep dtb files sorted alphabetically for each SoC
+ # sam9260
++dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9260.dtb
+ # sam9g20
++dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9g20.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9g20.dtb
+ # sam9g45
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0027-ARM-at91-add-at91sam9g20ek-boards-dt-support.patch b/patches.at91/0027-ARM-at91-add-at91sam9g20ek-boards-dt-support.patch
new file mode 100644
index 00000000000000..73d1a909e38bed
--- /dev/null
+++ b/patches.at91/0027-ARM-at91-add-at91sam9g20ek-boards-dt-support.patch
@@ -0,0 +1,253 @@
+From a72c0834c3f846f3fe9f2c782c8d6a67df258458 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Mon, 13 Feb 2012 00:54:47 +0800
+Subject: ARM: at91: add at91sam9g20ek boards dt support
+
+Add both board revision support 1mmc and 2mmc and use a dtsi for common part.
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9g20ek.dts | 29 ++++++
+ arch/arm/boot/dts/at91sam9g20ek_2mmc.dts | 29 ++++++
+ arch/arm/boot/dts/at91sam9g20ek_common.dtsi | 142 ++++++++++++++++++++++++++++
+ arch/arm/mach-at91/Makefile.boot | 2 +
+ 4 files changed, 202 insertions(+)
+ create mode 100644 arch/arm/boot/dts/at91sam9g20ek.dts
+ create mode 100644 arch/arm/boot/dts/at91sam9g20ek_2mmc.dts
+ create mode 100644 arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+
+diff --git a/arch/arm/boot/dts/at91sam9g20ek.dts b/arch/arm/boot/dts/at91sam9g20ek.dts
+new file mode 100644
+index 0000000..e5324bf
+--- /dev/null
++++ b/arch/arm/boot/dts/at91sam9g20ek.dts
+@@ -0,0 +1,29 @@
++/*
++ * at91sam9g20ek.dts - Device Tree file for Atmel at91sam9g20ek board
++ *
++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
++ *
++ * Licensed under GPLv2.
++ */
++/dts-v1/;
++/include/ "at91sam9g20ek_common.dtsi"
++
++/ {
++ model = "Atmel at91sam9g20ek";
++ compatible = "atmel,at91sam9g20ek", "atmel,at91sam9g20", "atmel,at91sam9";
++
++ leds {
++ compatible = "gpio-leds";
++
++ ds1 {
++ label = "ds1";
++ gpios = <&pioA 9 0>;
++ linux,default-trigger = "heartbeat";
++ };
++
++ ds5 {
++ label = "ds5";
++ gpios = <&pioA 6 1>;
++ };
++ };
++};
+diff --git a/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts b/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts
+new file mode 100644
+index 0000000..f1b2e14
+--- /dev/null
++++ b/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts
+@@ -0,0 +1,29 @@
++/*
++ * at91sam9g20ek_2mmc.dts - Device Tree file for Atmel at91sam9g20ek 2 MMC board
++ *
++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
++ *
++ * Licensed under GPLv2.
++ */
++/dts-v1/;
++/include/ "at91sam9g20ek_common.dtsi"
++
++/ {
++ model = "Atmel at91sam9g20ek 2 mmc";
++ compatible = "atmel,at91sam9g20ek_2mmc", "atmel,at91sam9g20", "atmel,at91sam9";
++
++ leds {
++ compatible = "gpio-leds";
++
++ ds1 {
++ label = "ds1";
++ gpios = <&pioB 9 0>;
++ linux,default-trigger = "heartbeat";
++ };
++
++ ds5 {
++ label = "ds5";
++ gpios = <&pioB 8 1>;
++ };
++ };
++};
+diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+new file mode 100644
+index 0000000..b06c0db
+--- /dev/null
++++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+@@ -0,0 +1,142 @@
++/*
++ * at91sam9g20ek_common.dtsi - Device Tree file for Atmel at91sam9g20ek board
++ *
++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
++ *
++ * Licensed under GPLv2.
++ */
++/include/ "at91sam9g20.dtsi"
++
++/ {
++
++ chosen {
++ bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs";
++ };
++
++ memory {
++ reg = <0x20000000 0x4000000>;
++ };
++
++ clocks {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges;
++
++ main_clock: clock@0 {
++ compatible = "atmel,osc", "fixed-clock";
++ clock-frequency = <18432000>;
++ };
++ };
++
++ ahb {
++ apb {
++ dbgu: serial@fffff200 {
++ status = "okay";
++ };
++
++ usart0: serial@fffb0000 {
++ status = "okay";
++ };
++
++ usart1: serial@fffb4000 {
++ status = "okay";
++ };
++
++ macb0: ethernet@fffc4000 {
++ phy-mode = "rmii";
++ status = "okay";
++ };
++
++ usb1: gadget@fffa4000 {
++ atmel,vbus-gpio = <&pioC 5 0>;
++ status = "okay";
++ };
++ };
++
++ nand0: nand@40000000 {
++ nand-bus-width = <8>;
++ nand-ecc-mode = "soft";
++ nand-on-flash-bbt;
++ status = "okay";
++
++ at91bootstrap@0 {
++ label = "at91bootstrap";
++ reg = <0x0 0x20000>;
++ };
++
++ barebox@20000 {
++ label = "barebox";
++ reg = <0x20000 0x40000>;
++ };
++
++ bareboxenv@60000 {
++ label = "bareboxenv";
++ reg = <0x60000 0x20000>;
++ };
++
++ bareboxenv2@80000 {
++ label = "bareboxenv2";
++ reg = <0x80000 0x20000>;
++ };
++
++ oftree@80000 {
++ label = "oftree";
++ reg = <0xa0000 0x20000>;
++ };
++
++ kernel@a0000 {
++ label = "kernel";
++ reg = <0xc0000 0x400000>;
++ };
++
++ rootfs@4a0000 {
++ label = "rootfs";
++ reg = <0x4c0000 0x7800000>;
++ };
++
++ data@7ca0000 {
++ label = "data";
++ reg = <0x7cc0000 0x8340000>;
++ };
++ };
++
++ usb0: ohci@00500000 {
++ num-ports = <2>;
++ status = "okay";
++ };
++ };
++
++ i2c@0 {
++ status = "okay";
++
++ 24c512@50 {
++ compatible = "24c512";
++ reg = <0x50>;
++ };
++
++ wm8731@1b {
++ compatible = "wm8731";
++ reg = <0x1b>;
++ };
++ };
++
++ gpio_keys {
++ compatible = "gpio-keys";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ btn3 {
++ label = "Buttin 3";
++ gpios = <&pioA 30 1>;
++ linux,code = <0x103>;
++ gpio-key,wakeup;
++ };
++
++ btn4 {
++ label = "Buttin 4";
++ gpios = <&pioA 31 1>;
++ linux,code = <0x104>;
++ gpio-key,wakeup;
++ };
++ };
++};
+diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
+index bdf9841..30d6c10 100644
+--- a/arch/arm/mach-at91/Makefile.boot
++++ b/arch/arm/mach-at91/Makefile.boot
+@@ -17,6 +17,8 @@ endif
+ # sam9260
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9260.dtb
+ # sam9g20
++dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek.dtb
++dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek_2mmc.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9g20.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9g20.dtb
+ # sam9g45
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0028-ARM-at91-USB-A926x-update-nand-partition.patch b/patches.at91/0028-ARM-at91-USB-A926x-update-nand-partition.patch
new file mode 100644
index 00000000000000..d8029a144ce828
--- /dev/null
+++ b/patches.at91/0028-ARM-at91-USB-A926x-update-nand-partition.patch
@@ -0,0 +1,64 @@
+From b2b5334c32e6c1c8c0333279e4ee9600b3d4d34a Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Wed, 11 Apr 2012 23:40:31 +0800
+Subject: ARM: at91: USB A926x update nand partition
+
+We now store the dtb in a nand partition.
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/usb_a9g20.dts | 11 ++++++++---
+ arch/arm/mach-at91/board-usb-a926x.c | 4 ++++
+ 2 files changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/boot/dts/usb_a9g20.dts b/arch/arm/boot/dts/usb_a9g20.dts
+index 7c2399c..0f88ec8 100644
+--- a/arch/arm/boot/dts/usb_a9g20.dts
++++ b/arch/arm/boot/dts/usb_a9g20.dts
+@@ -74,19 +74,24 @@
+ reg = <0x80000 0x20000>;
+ };
+
++ oftree@80000 {
++ label = "oftree";
++ reg = <0xa0000 0x20000>;
++ };
++
+ kernel@a0000 {
+ label = "kernel";
+- reg = <0xa0000 0x400000>;
++ reg = <0xc0000 0x400000>;
+ };
+
+ rootfs@4a0000 {
+ label = "rootfs";
+- reg = <0x4a0000 0x7800000>;
++ reg = <0x4c0000 0x7800000>;
+ };
+
+ data@7ca0000 {
+ label = "data";
+- reg = <0x7ca0000 0x8360000>;
++ reg = <0x7cc0000 0x8340000>;
+ };
+ };
+
+diff --git a/arch/arm/mach-at91/board-usb-a926x.c b/arch/arm/mach-at91/board-usb-a926x.c
+index 332ecd4..95393fc 100644
+--- a/arch/arm/mach-at91/board-usb-a926x.c
++++ b/arch/arm/mach-at91/board-usb-a926x.c
+@@ -172,6 +172,10 @@ static struct mtd_partition __initdata ek_nand_partition[] = {
+ .offset = MTDPART_OFS_NXTBLK,
+ .size = SZ_128K,
+ }, {
++ .name = "oftree",
++ .offset = MTDPART_OFS_NXTBLK,
++ .size = SZ_128K,
++ }, {
+ .name = "kernel",
+ .offset = MTDPART_OFS_NXTBLK,
+ .size = 4 * SZ_1M,
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0029-ARM-at91-Calao-USB-A926x-factorize-common-binding-in.patch b/patches.at91/0029-ARM-at91-Calao-USB-A926x-factorize-common-binding-in.patch
new file mode 100644
index 00000000000000..d3b4a11e21ff0e
--- /dev/null
+++ b/patches.at91/0029-ARM-at91-Calao-USB-A926x-factorize-common-binding-in.patch
@@ -0,0 +1,268 @@
+From 23f3c5a2f5746c2e1eca2364ea6fb3d3e4515cf3 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Wed, 11 Apr 2012 23:42:44 +0800
+Subject: ARM: at91: Calao USB A926x factorize common binding in
+ usb_a9260_common
+
+This will simplify the adding of the A9260.
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/usb_a9260_common.dtsi | 117 ++++++++++++++++++++++++++++++++
+ arch/arm/boot/dts/usb_a9g20.dts | 107 +----------------------------
+ 2 files changed, 118 insertions(+), 106 deletions(-)
+ create mode 100644 arch/arm/boot/dts/usb_a9260_common.dtsi
+
+diff --git a/arch/arm/boot/dts/usb_a9260_common.dtsi b/arch/arm/boot/dts/usb_a9260_common.dtsi
+new file mode 100644
+index 0000000..e70d229
+--- /dev/null
++++ b/arch/arm/boot/dts/usb_a9260_common.dtsi
+@@ -0,0 +1,117 @@
++/*
++ * usb_a926x.dts - Device Tree file for Caloa USB A926x board
++ *
++ * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
++ *
++ * Licensed under GPLv2 or later.
++ */
++
++/ {
++ clocks {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges;
++
++ main_clock: clock@0 {
++ compatible = "atmel,osc", "fixed-clock";
++ clock-frequency = <12000000>;
++ };
++ };
++
++ ahb {
++ apb {
++ dbgu: serial@fffff200 {
++ status = "okay";
++ };
++
++ macb0: ethernet@fffc4000 {
++ phy-mode = "rmii";
++ status = "okay";
++ };
++
++ usb1: gadget@fffa4000 {
++ atmel,vbus-gpio = <&pioC 5 0>;
++ status = "okay";
++ };
++ };
++
++ nand0: nand@40000000 {
++ nand-bus-width = <8>;
++ nand-ecc-mode = "soft";
++ nand-on-flash-bbt;
++ status = "okay";
++
++ at91bootstrap@0 {
++ label = "at91bootstrap";
++ reg = <0x0 0x20000>;
++ };
++
++ barebox@20000 {
++ label = "barebox";
++ reg = <0x20000 0x40000>;
++ };
++
++ bareboxenv@60000 {
++ label = "bareboxenv";
++ reg = <0x60000 0x20000>;
++ };
++
++ bareboxenv2@80000 {
++ label = "bareboxenv2";
++ reg = <0x80000 0x20000>;
++ };
++
++ oftree@80000 {
++ label = "oftree";
++ reg = <0xa0000 0x20000>;
++ };
++
++ kernel@a0000 {
++ label = "kernel";
++ reg = <0xc0000 0x400000>;
++ };
++
++ rootfs@4a0000 {
++ label = "rootfs";
++ reg = <0x4c0000 0x7800000>;
++ };
++
++ data@7ca0000 {
++ label = "data";
++ reg = <0x7cc0000 0x8340000>;
++ };
++ };
++
++ usb0: ohci@00500000 {
++ num-ports = <2>;
++ status = "okay";
++ };
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ user_led {
++ label = "user_led";
++ gpios = <&pioB 21 1>;
++ linux,default-trigger = "heartbeat";
++ };
++ };
++
++ gpio_keys {
++ compatible = "gpio-keys";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ user_pb {
++ label = "user_pb";
++ gpios = <&pioB 10 1>;
++ linux,code = <28>;
++ gpio-key,wakeup;
++ };
++ };
++
++ i2c@0 {
++ status = "okay";
++ };
++};
+diff --git a/arch/arm/boot/dts/usb_a9g20.dts b/arch/arm/boot/dts/usb_a9g20.dts
+index 0f88ec8..2dacb16c 100644
+--- a/arch/arm/boot/dts/usb_a9g20.dts
++++ b/arch/arm/boot/dts/usb_a9g20.dts
+@@ -7,6 +7,7 @@
+ */
+ /dts-v1/;
+ /include/ "at91sam9g20.dtsi"
++/include/ "usb_a9260_common.dtsi"
+
+ / {
+ model = "Calao USB A9G20";
+@@ -20,113 +21,7 @@
+ reg = <0x20000000 0x4000000>;
+ };
+
+- clocks {
+- #address-cells = <1>;
+- #size-cells = <1>;
+- ranges;
+-
+- main_clock: clock@0 {
+- compatible = "atmel,osc", "fixed-clock";
+- clock-frequency = <12000000>;
+- };
+- };
+-
+- ahb {
+- apb {
+- dbgu: serial@fffff200 {
+- status = "okay";
+- };
+-
+- macb0: ethernet@fffc4000 {
+- phy-mode = "rmii";
+- status = "okay";
+- };
+-
+- usb1: gadget@fffa4000 {
+- atmel,vbus-gpio = <&pioC 5 0>;
+- status = "okay";
+- };
+- };
+-
+- nand0: nand@40000000 {
+- nand-bus-width = <8>;
+- nand-ecc-mode = "soft";
+- nand-on-flash-bbt;
+- status = "okay";
+-
+- at91bootstrap@0 {
+- label = "at91bootstrap";
+- reg = <0x0 0x20000>;
+- };
+-
+- barebox@20000 {
+- label = "barebox";
+- reg = <0x20000 0x40000>;
+- };
+-
+- bareboxenv@60000 {
+- label = "bareboxenv";
+- reg = <0x60000 0x20000>;
+- };
+-
+- bareboxenv2@80000 {
+- label = "bareboxenv2";
+- reg = <0x80000 0x20000>;
+- };
+-
+- oftree@80000 {
+- label = "oftree";
+- reg = <0xa0000 0x20000>;
+- };
+-
+- kernel@a0000 {
+- label = "kernel";
+- reg = <0xc0000 0x400000>;
+- };
+-
+- rootfs@4a0000 {
+- label = "rootfs";
+- reg = <0x4c0000 0x7800000>;
+- };
+-
+- data@7ca0000 {
+- label = "data";
+- reg = <0x7cc0000 0x8340000>;
+- };
+- };
+-
+- usb0: ohci@00500000 {
+- num-ports = <2>;
+- status = "okay";
+- };
+- };
+-
+- leds {
+- compatible = "gpio-leds";
+-
+- user_led {
+- label = "user_led";
+- gpios = <&pioB 21 1>;
+- linux,default-trigger = "heartbeat";
+- };
+- };
+-
+- gpio_keys {
+- compatible = "gpio-keys";
+- #address-cells = <1>;
+- #size-cells = <0>;
+-
+- user_pb {
+- label = "user_pb";
+- gpios = <&pioB 10 1>;
+- linux,code = <28>;
+- gpio-key,wakeup;
+- };
+- };
+-
+ i2c@0 {
+- status = "okay";
+-
+ rv3029c2@56 {
+ compatible = "rv3029c2";
+ reg = <0x56>;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0030-ARM-at91-DT-add-Calao-USB-A9260-DT-support.patch b/patches.at91/0030-ARM-at91-DT-add-Calao-USB-A9260-DT-support.patch
new file mode 100644
index 00000000000000..e3259ae532e1d9
--- /dev/null
+++ b/patches.at91/0030-ARM-at91-DT-add-Calao-USB-A9260-DT-support.patch
@@ -0,0 +1,57 @@
+From 83be7b15e8dea5beb4d3299835b79347c3148fd2 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Mon, 9 Apr 2012 14:43:34 +0800
+Subject: ARM: at91: DT: add Calao USB A9260 DT support
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/usb_a9260.dts | 23 +++++++++++++++++++++++
+ arch/arm/mach-at91/Makefile.boot | 1 +
+ 2 files changed, 24 insertions(+)
+ create mode 100644 arch/arm/boot/dts/usb_a9260.dts
+
+diff --git a/arch/arm/boot/dts/usb_a9260.dts b/arch/arm/boot/dts/usb_a9260.dts
+new file mode 100644
+index 0000000..2962160
+--- /dev/null
++++ b/arch/arm/boot/dts/usb_a9260.dts
+@@ -0,0 +1,23 @@
++/*
++ * usb_a9260.dts - Device Tree file for Caloa USB A9260 board
++ *
++ * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
++ *
++ * Licensed under GPLv2 or later.
++ */
++/dts-v1/;
++/include/ "at91sam9260.dtsi"
++/include/ "usb_a9260_common.dtsi"
++
++/ {
++ model = "Calao USB A9260";
++ compatible = "calao,usb-a9260", "atmel,at91sam9260", "atmel,at91sam9";
++
++ chosen {
++ bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs";
++ };
++
++ memory {
++ reg = <0x20000000 0x4000000>;
++ };
++};
+diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
+index 30d6c10..b2ac536 100644
+--- a/arch/arm/mach-at91/Makefile.boot
++++ b/arch/arm/mach-at91/Makefile.boot
+@@ -16,6 +16,7 @@ endif
+ # Keep dtb files sorted alphabetically for each SoC
+ # sam9260
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9260.dtb
++dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9260.dtb
+ # sam9g20
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek_2mmc.dtb
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0031-ARM-at91-standard-device-init-only-if-DT-is-not-popu.patch b/patches.at91/0031-ARM-at91-standard-device-init-only-if-DT-is-not-popu.patch
new file mode 100644
index 00000000000000..f27c8142d2baf0
--- /dev/null
+++ b/patches.at91/0031-ARM-at91-standard-device-init-only-if-DT-is-not-popu.patch
@@ -0,0 +1,115 @@
+From 07e34d884cb904668fe1e413fe10958a65de3c57 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Tue, 28 Feb 2012 15:23:43 +0800
+Subject: ARM: at91: standard device init only if DT is not populated.
+
+This will avoid the CONFIG_OF on the *_devices.c as this file is deprecated
+for DT support.
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/at91sam9260_devices.c | 20 +++-----------------
+ arch/arm/mach-at91/at91sam9g45_devices.c | 30 ++++--------------------------
+ 2 files changed, 7 insertions(+), 43 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
+index ad00fe9..d556de1 100644
+--- a/arch/arm/mach-at91/at91sam9260_devices.c
++++ b/arch/arm/mach-at91/at91sam9260_devices.c
+@@ -702,25 +702,8 @@ static struct platform_device at91sam9260_tcb1_device = {
+ .num_resources = ARRAY_SIZE(tcb1_resources),
+ };
+
+-#if defined(CONFIG_OF)
+-static struct of_device_id tcb_ids[] = {
+- { .compatible = "atmel,at91rm9200-tcb" },
+- { /*sentinel*/ }
+-};
+-#endif
+-
+ static void __init at91_add_device_tc(void)
+ {
+-#if defined(CONFIG_OF)
+- struct device_node *np;
+-
+- np = of_find_matching_node(NULL, tcb_ids);
+- if (np) {
+- of_node_put(np);
+- return;
+- }
+-#endif
+-
+ platform_device_register(&at91sam9260_tcb0_device);
+ platform_device_register(&at91sam9260_tcb1_device);
+ }
+@@ -1364,6 +1347,9 @@ void __init at91_add_device_cf(struct at91_cf_data * data) {}
+ */
+ static int __init at91_add_standard_devices(void)
+ {
++ if (of_have_populated_dt())
++ return 0;
++
+ at91_add_device_rtt();
+ at91_add_device_watchdog();
+ at91_add_device_tc();
+diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
+index db2f88c2..35bd42d 100644
+--- a/arch/arm/mach-at91/at91sam9g45_devices.c
++++ b/arch/arm/mach-at91/at91sam9g45_devices.c
+@@ -69,15 +69,7 @@ static struct platform_device at_hdmac_device = {
+
+ void __init at91_add_device_hdmac(void)
+ {
+-#if defined(CONFIG_OF)
+- struct device_node *of_node =
+- of_find_node_by_name(NULL, "dma-controller");
+-
+- if (of_node)
+- of_node_put(of_node);
+- else
+-#endif
+- platform_device_register(&at_hdmac_device);
++ platform_device_register(&at_hdmac_device);
+ }
+ #else
+ void __init at91_add_device_hdmac(void) {}
+@@ -1094,25 +1086,8 @@ static struct platform_device at91sam9g45_tcb1_device = {
+ .num_resources = ARRAY_SIZE(tcb1_resources),
+ };
+
+-#if defined(CONFIG_OF)
+-static struct of_device_id tcb_ids[] = {
+- { .compatible = "atmel,at91rm9200-tcb" },
+- { /*sentinel*/ }
+-};
+-#endif
+-
+ static void __init at91_add_device_tc(void)
+ {
+-#if defined(CONFIG_OF)
+- struct device_node *np;
+-
+- np = of_find_matching_node(NULL, tcb_ids);
+- if (np) {
+- of_node_put(np);
+- return;
+- }
+-#endif
+-
+ platform_device_register(&at91sam9g45_tcb0_device);
+ platform_device_register(&at91sam9g45_tcb1_device);
+ }
+@@ -1763,6 +1738,9 @@ void __init at91_add_device_serial(void) {}
+ */
+ static int __init at91_add_standard_devices(void)
+ {
++ if (of_have_populated_dt())
++ return 0;
++
+ at91_add_device_hdmac();
+ at91_add_device_rtc();
+ at91_add_device_rtt();
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0032-ARM-at91-add-at91sam9263-DT-support.patch b/patches.at91/0032-ARM-at91-add-at91sam9263-DT-support.patch
new file mode 100644
index 00000000000000..c624252fec8306
--- /dev/null
+++ b/patches.at91/0032-ARM-at91-add-at91sam9263-DT-support.patch
@@ -0,0 +1,304 @@
+From 6703c4d1f42cf346f9a6f5f174f46c01ece33c90 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Sun, 26 Feb 2012 19:12:43 +0800
+Subject: ARM: at91: add at91sam9263 DT support
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9263.dtsi | 220 +++++++++++++++++++++++++++++++
+ arch/arm/mach-at91/at91sam9263.c | 10 ++
+ arch/arm/mach-at91/at91sam9263_devices.c | 20 +++
+ 3 files changed, 250 insertions(+)
+ create mode 100644 arch/arm/boot/dts/at91sam9263.dtsi
+
+diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
+new file mode 100644
+index 0000000..0209913
+--- /dev/null
++++ b/arch/arm/boot/dts/at91sam9263.dtsi
+@@ -0,0 +1,220 @@
++/*
++ * at91sam9263.dtsi - Device Tree Include file for AT91SAM9263 family SoC
++ *
++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
++ *
++ * Licensed under GPLv2 only.
++ */
++
++/include/ "skeleton.dtsi"
++
++/ {
++ model = "Atmel AT91SAM9263 family SoC";
++ compatible = "atmel,at91sam9263";
++ interrupt-parent = <&aic>;
++
++ aliases {
++ serial0 = &dbgu;
++ serial1 = &usart0;
++ serial2 = &usart1;
++ serial3 = &usart2;
++ gpio0 = &pioA;
++ gpio1 = &pioB;
++ gpio2 = &pioC;
++ gpio3 = &pioD;
++ gpio4 = &pioE;
++ tcb0 = &tcb0;
++ };
++ cpus {
++ cpu@0 {
++ compatible = "arm,arm926ejs";
++ };
++ };
++
++ memory {
++ reg = <0x20000000 0x08000000>;
++ };
++
++ ahb {
++ compatible = "simple-bus";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges;
++
++ apb {
++ compatible = "simple-bus";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges;
++
++ aic: interrupt-controller@fffff000 {
++ #interrupt-cells = <2>;
++ compatible = "atmel,at91rm9200-aic";
++ interrupt-controller;
++ reg = <0xfffff000 0x200>;
++ };
++
++ pmc: pmc@fffffc00 {
++ compatible = "atmel,at91rm9200-pmc";
++ reg = <0xfffffc00 0x100>;
++ };
++
++ ramc: ramc@ffffe200 {
++ compatible = "atmel,at91sam9260-sdramc";
++ reg = <0xffffe200 0x200
++ 0xffffe800 0x200>;
++ };
++
++ pit: timer@fffffd30 {
++ compatible = "atmel,at91sam9260-pit";
++ reg = <0xfffffd30 0xf>;
++ interrupts = <1 4>;
++ };
++
++ tcb0: timer@fff7c000 {
++ compatible = "atmel,at91rm9200-tcb";
++ reg = <0xfff7c000 0x100>;
++ interrupts = <19 4>;
++ };
++
++ rstc@fffffd00 {
++ compatible = "atmel,at91sam9260-rstc";
++ reg = <0xfffffd00 0x10>;
++ };
++
++ shdwc@fffffd10 {
++ compatible = "atmel,at91sam9260-shdwc";
++ reg = <0xfffffd10 0x10>;
++ };
++
++ pioA: gpio@fffff200 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff200 0x100>;
++ interrupts = <2 4>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ };
++
++ pioB: gpio@fffff400 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff400 0x100>;
++ interrupts = <3 4>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ };
++
++ pioC: gpio@fffff600 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff600 0x100>;
++ interrupts = <4 4>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ };
++
++ pioD: gpio@fffff800 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff800 0x100>;
++ interrupts = <4 4>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ };
++
++ pioE: gpio@fffffa00 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffffa00 0x100>;
++ interrupts = <4 4>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ };
++
++ dbgu: serial@ffffee00 {
++ compatible = "atmel,at91sam9260-usart";
++ reg = <0xffffee00 0x200>;
++ interrupts = <1 4>;
++ status = "disabled";
++ };
++
++ usart0: serial@fff8c000 {
++ compatible = "atmel,at91sam9260-usart";
++ reg = <0xfff8c000 0x200>;
++ interrupts = <7 4>;
++ atmel,use-dma-rx;
++ atmel,use-dma-tx;
++ status = "disabled";
++ };
++
++ usart1: serial@fff90000 {
++ compatible = "atmel,at91sam9260-usart";
++ reg = <0xfff90000 0x200>;
++ interrupts = <8 4>;
++ atmel,use-dma-rx;
++ atmel,use-dma-tx;
++ status = "disabled";
++ };
++
++ usart2: serial@fff94000 {
++ compatible = "atmel,at91sam9260-usart";
++ reg = <0xfff94000 0x200>;
++ interrupts = <9 4>;
++ atmel,use-dma-rx;
++ atmel,use-dma-tx;
++ status = "disabled";
++ };
++
++ macb0: ethernet@fffbc000 {
++ compatible = "cdns,at32ap7000-macb", "cdns,macb";
++ reg = <0xfffbc000 0x100>;
++ interrupts = <21 4>;
++ status = "disabled";
++ };
++
++ usb1: gadget@fff78000 {
++ compatible = "atmel,at91rm9200-udc";
++ reg = <0xfff78000 0x4000>;
++ interrupts = <24 4>;
++ status = "disabled";
++ };
++ };
++
++ nand0: nand@40000000 {
++ compatible = "atmel,at91rm9200-nand";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ reg = <0x40000000 0x10000000
++ 0xffffe000 0x200
++ >;
++ atmel,nand-addr-offset = <21>;
++ atmel,nand-cmd-offset = <22>;
++ gpios = <&pioA 22 0
++ &pioD 15 0
++ 0
++ >;
++ status = "disabled";
++ };
++
++ usb0: ohci@00a00000 {
++ compatible = "atmel,at91rm9200-ohci", "usb-ohci";
++ reg = <0x00a00000 0x100000>;
++ interrupts = <29 4>;
++ status = "disabled";
++ };
++ };
++
++ i2c@0 {
++ compatible = "i2c-gpio";
++ gpios = <&pioB 4 0 /* sda */
++ &pioB 5 0 /* scl */
++ >;
++ i2c-gpio,sda-open-drain;
++ i2c-gpio,scl-open-drain;
++ i2c-gpio,delay-us = <2>; /* ~100 kHz */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++};
+diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
+index 7fae365..ed91c7e 100644
+--- a/arch/arm/mach-at91/at91sam9263.c
++++ b/arch/arm/mach-at91/at91sam9263.c
+@@ -199,6 +199,16 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_ID("pioC", &pioCDE_clk),
+ CLKDEV_CON_ID("pioD", &pioCDE_clk),
+ CLKDEV_CON_ID("pioE", &pioCDE_clk),
++ /* more usart lookup table for DT entries */
++ CLKDEV_CON_DEV_ID("usart", "ffffee00.serial", &mck),
++ CLKDEV_CON_DEV_ID("usart", "fff8c000.serial", &usart0_clk),
++ CLKDEV_CON_DEV_ID("usart", "fff90000.serial", &usart1_clk),
++ CLKDEV_CON_DEV_ID("usart", "fff94000.serial", &usart2_clk),
++ /* more tc lookup table for DT entries */
++ CLKDEV_CON_DEV_ID("t0_clk", "fff7c000.timer", &tcb_clk),
++ CLKDEV_CON_DEV_ID("hclk", "a00000.ohci", &ohci_clk),
++ CLKDEV_CON_DEV_ID("spi_clk", "fffa4000.spi", &spi0_clk),
++ CLKDEV_CON_DEV_ID("spi_clk", "fffa8000.spi", &spi1_clk),
+ };
+
+ static struct clk_lookup usart_clocks_lookups[] = {
+diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
+index dfe5bc0..175e000 100644
+--- a/arch/arm/mach-at91/at91sam9263_devices.c
++++ b/arch/arm/mach-at91/at91sam9263_devices.c
+@@ -953,8 +953,25 @@ static struct platform_device at91sam9263_tcb_device = {
+ .num_resources = ARRAY_SIZE(tcb_resources),
+ };
+
++#if defined(CONFIG_OF)
++static struct of_device_id tcb_ids[] = {
++ { .compatible = "atmel,at91rm9200-tcb" },
++ { /*sentinel*/ }
++};
++#endif
++
+ static void __init at91_add_device_tc(void)
+ {
++#if defined(CONFIG_OF)
++ struct device_node *np;
++
++ np = of_find_matching_node(NULL, tcb_ids);
++ if (np) {
++ of_node_put(np);
++ return;
++ }
++#endif
++
+ platform_device_register(&at91sam9263_tcb_device);
+ }
+ #else
+@@ -1483,6 +1500,9 @@ void __init at91_add_device_serial(void) {}
+ */
+ static int __init at91_add_standard_devices(void)
+ {
++ if (of_have_populated_dt())
++ return 0;
++
+ at91_add_device_rtt();
+ at91_add_device_watchdog();
+ at91_add_device_tc();
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0033-ARM-at91-add-at91sam9263ek-DT-support.patch b/patches.at91/0033-ARM-at91-add-at91sam9263ek-DT-support.patch
new file mode 100644
index 00000000000000..7b9c30e1b7b634
--- /dev/null
+++ b/patches.at91/0033-ARM-at91-add-at91sam9263ek-DT-support.patch
@@ -0,0 +1,191 @@
+From 57fab5b53e9cf05574fffd706373b62713eb616c Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Sun, 26 Feb 2012 19:12:43 +0800
+Subject: ARM: at91: add at91sam9263ek DT support
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9263ek.dts | 156 ++++++++++++++++++++++++++++++++++++
+ arch/arm/mach-at91/Makefile.boot | 2 +
+ 2 files changed, 158 insertions(+)
+ create mode 100644 arch/arm/boot/dts/at91sam9263ek.dts
+
+diff --git a/arch/arm/boot/dts/at91sam9263ek.dts b/arch/arm/boot/dts/at91sam9263ek.dts
+new file mode 100644
+index 0000000..f86ac4b
+--- /dev/null
++++ b/arch/arm/boot/dts/at91sam9263ek.dts
+@@ -0,0 +1,156 @@
++/*
++ * at91sam9263ek.dts - Device Tree file for Atmel at91sam9263 reference board
++ *
++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
++ *
++ * Licensed under GPLv2 only
++ */
++/dts-v1/;
++/include/ "at91sam9263.dtsi"
++
++/ {
++ model = "Atmel at91sam9263ek";
++ compatible = "atmel,at91sam9263ek", "atmel,at91sam9263", "atmel,at91sam9";
++
++ chosen {
++ bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs";
++ };
++
++ memory {
++ reg = <0x20000000 0x4000000>;
++ };
++
++ clocks {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges;
++
++ main_clock: clock@0 {
++ compatible = "atmel,osc", "fixed-clock";
++ clock-frequency = <16367660>;
++ };
++ };
++
++ ahb {
++ apb {
++ dbgu: serial@ffffee00 {
++ status = "okay";
++ };
++
++ usart0: serial@fff8c000 {
++ status = "okay";
++ };
++
++ macb0: ethernet@fffbc000 {
++ phy-mode = "rmii";
++ status = "okay";
++ };
++
++ usb1: gadget@fff78000 {
++ atmel,vbus-gpio = <&pioA 25 0>;
++ status = "okay";
++ };
++ };
++
++ nand0: nand@40000000 {
++ nand-bus-width = <8>;
++ nand-ecc-mode = "soft";
++ nand-on-flash-bbt = <1>;
++ status = "okay";
++
++ at91bootstrap@0 {
++ label = "at91bootstrap";
++ reg = <0x0 0x20000>;
++ };
++
++ barebox@20000 {
++ label = "barebox";
++ reg = <0x20000 0x40000>;
++ };
++
++ bareboxenv@60000 {
++ label = "bareboxenv";
++ reg = <0x60000 0x20000>;
++ };
++
++ bareboxenv2@80000 {
++ label = "bareboxenv2";
++ reg = <0x80000 0x20000>;
++ };
++
++ oftree@80000 {
++ label = "oftree";
++ reg = <0xa0000 0x20000>;
++ };
++
++ kernel@a0000 {
++ label = "kernel";
++ reg = <0xc0000 0x400000>;
++ };
++
++ rootfs@4a0000 {
++ label = "rootfs";
++ reg = <0x4c0000 0x7800000>;
++ };
++
++ data@7ca0000 {
++ label = "data";
++ reg = <0x7cc0000 0x8340000>;
++ };
++ };
++
++ usb0: ohci@00a00000 {
++ num-ports = <2>;
++ status = "okay";
++ atmel,vbus-gpio = <&pioA 24 0
++ &pioA 21 0
++ >;
++ };
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ d3 {
++ label = "d3";
++ gpios = <&pioB 7 0>;
++ linux,default-trigger = "heartbeat";
++ };
++
++ d2 {
++ label = "d2";
++ gpios = <&pioC 29 1>;
++ linux,default-trigger = "nand-disk";
++ };
++ };
++
++ gpio_keys {
++ compatible = "gpio-keys";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ left_click {
++ label = "left_click";
++ gpios = <&pioC 5 1>;
++ linux,code = <272>;
++ gpio-key,wakeup;
++ };
++
++ right_click {
++ label = "right_click";
++ gpios = <&pioC 4 1>;
++ linux,code = <273>;
++ gpio-key,wakeup;
++ };
++ };
++
++ i2c@0 {
++ status = "okay";
++
++ 24c512@50 {
++ compatible = "24c512";
++ reg = <0x50>;
++ pagesize = <128>;
++ };
++ };
++};
+diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
+index b2ac536..0c6e0e9 100644
+--- a/arch/arm/mach-at91/Makefile.boot
++++ b/arch/arm/mach-at91/Makefile.boot
+@@ -17,6 +17,8 @@ endif
+ # sam9260
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9260.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9260.dtb
++# sam9263
++dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9263ek.dtb
+ # sam9g20
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek_2mmc.dtb
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0034-ARM-at91-DT-add-Calao-USB-A9263-board-support.patch b/patches.at91/0034-ARM-at91-DT-add-Calao-USB-A9263-board-support.patch
new file mode 100644
index 00000000000000..5ad367b549f0de
--- /dev/null
+++ b/patches.at91/0034-ARM-at91-DT-add-Calao-USB-A9263-board-support.patch
@@ -0,0 +1,165 @@
+From 6c84b391e098cad2350f661ebffd8b8d4f6b8981 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Thu, 12 Apr 2012 18:01:33 +0800
+Subject: ARM: at91: DT: add Calao USB A9263 board support
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/usb_a9263.dts | 131 +++++++++++++++++++++++++++++++++++++++
+ arch/arm/mach-at91/Makefile.boot | 1 +
+ 2 files changed, 132 insertions(+)
+ create mode 100644 arch/arm/boot/dts/usb_a9263.dts
+
+diff --git a/arch/arm/boot/dts/usb_a9263.dts b/arch/arm/boot/dts/usb_a9263.dts
+new file mode 100644
+index 0000000..6fe05cc
+--- /dev/null
++++ b/arch/arm/boot/dts/usb_a9263.dts
+@@ -0,0 +1,131 @@
++/*
++ * usb_a9263.dts - Device Tree file for Caloa USB A9293 board
++ *
++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
++ *
++ * Licensed under GPLv2 only
++ */
++/dts-v1/;
++/include/ "at91sam9263.dtsi"
++
++/ {
++ model = "Calao USB A9263";
++ compatible = "atmel,usb-a9263", "atmel,at91sam9263", "atmel,at91sam9";
++
++ chosen {
++ bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs";
++ };
++
++ memory {
++ reg = <0x20000000 0x4000000>;
++ };
++
++ clocks {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges;
++
++ main_clock: clock@0 {
++ compatible = "atmel,osc", "fixed-clock";
++ clock-frequency = <12000000>;
++ };
++ };
++
++ ahb {
++ apb {
++ dbgu: serial@ffffee00 {
++ status = "okay";
++ };
++
++ macb0: ethernet@fffbc000 {
++ phy-mode = "rmii";
++ status = "okay";
++ };
++
++ usb1: gadget@fff78000 {
++ atmel,vbus-gpio = <&pioB 11 0>;
++ status = "okay";
++ };
++
++ };
++
++ nand0: nand@40000000 {
++ nand-bus-width = <8>;
++ nand-ecc-mode = "soft";
++ nand-on-flash-bbt;
++ status = "okay";
++
++ at91bootstrap@0 {
++ label = "at91bootstrap";
++ reg = <0x0 0x20000>;
++ };
++
++ barebox@20000 {
++ label = "barebox";
++ reg = <0x20000 0x40000>;
++ };
++
++ bareboxenv@60000 {
++ label = "bareboxenv";
++ reg = <0x60000 0x20000>;
++ };
++
++ bareboxenv2@80000 {
++ label = "bareboxenv2";
++ reg = <0x80000 0x20000>;
++ };
++
++ oftree@80000 {
++ label = "oftree";
++ reg = <0xa0000 0x20000>;
++ };
++
++ kernel@a0000 {
++ label = "kernel";
++ reg = <0xc0000 0x400000>;
++ };
++
++ rootfs@4a0000 {
++ label = "rootfs";
++ reg = <0x4c0000 0x7800000>;
++ };
++
++ data@7ca0000 {
++ label = "data";
++ reg = <0x7cc0000 0x8340000>;
++ };
++ };
++
++ usb0: ohci@00a00000 {
++ num-ports = <2>;
++ status = "okay";
++ };
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ user_led {
++ label = "user_led";
++ gpios = <&pioB 21 0>;
++ linux,default-trigger = "heartbeat";
++ };
++ };
++
++ gpio_keys {
++ compatible = "gpio-keys";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ user_pb {
++ label = "user_pb";
++ gpios = <&pioB 10 1>;
++ linux,code = <28>;
++ gpio-key,wakeup;
++ };
++ };
++
++ i2c@0 {
++ status = "okay";
++ };
++};
+diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
+index 0c6e0e9..7f0a5cb 100644
+--- a/arch/arm/mach-at91/Makefile.boot
++++ b/arch/arm/mach-at91/Makefile.boot
+@@ -19,6 +19,7 @@ dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9260.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9260.dtb
+ # sam9263
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9263ek.dtb
++dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9263.dtb
+ # sam9g20
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek_2mmc.dtb
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0035-ARM-at91-DT-add-Calao-TNY-A9263-board-support.patch b/patches.at91/0035-ARM-at91-DT-add-Calao-TNY-A9263-board-support.patch
new file mode 100644
index 00000000000000..1cdfb9cc6dc58b
--- /dev/null
+++ b/patches.at91/0035-ARM-at91-DT-add-Calao-TNY-A9263-board-support.patch
@@ -0,0 +1,131 @@
+From 242797da12e5e34231572f9d5472ab2f80bbc301 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Thu, 12 Apr 2012 18:47:32 +0800
+Subject: ARM: at91: DT: add Calao TNY A9263 board support
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/tny_a9263.dts | 97 ++++++++++++++++++++++++++++++++++++++++
+ arch/arm/mach-at91/Makefile.boot | 1 +
+ 2 files changed, 98 insertions(+)
+ create mode 100644 arch/arm/boot/dts/tny_a9263.dts
+
+diff --git a/arch/arm/boot/dts/tny_a9263.dts b/arch/arm/boot/dts/tny_a9263.dts
+new file mode 100644
+index 0000000..dee9c57
+--- /dev/null
++++ b/arch/arm/boot/dts/tny_a9263.dts
+@@ -0,0 +1,97 @@
++/*
++ * usb_a9263.dts - Device Tree file for Caloa USB A9293 board
++ *
++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
++ *
++ * Licensed under GPLv2 only
++ */
++/dts-v1/;
++/include/ "at91sam9263.dtsi"
++
++/ {
++ model = "Calao TNY A9263";
++ compatible = "atmel,tny-a9263", "atmel,at91sam9263", "atmel,at91sam9";
++
++ chosen {
++ bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs";
++ };
++
++ memory {
++ reg = <0x20000000 0x4000000>;
++ };
++
++ clocks {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges;
++
++ main_clock: clock@0 {
++ compatible = "atmel,osc", "fixed-clock";
++ clock-frequency = <12000000>;
++ };
++ };
++
++ ahb {
++ apb {
++ dbgu: serial@ffffee00 {
++ status = "okay";
++ };
++
++ usb1: gadget@fff78000 {
++ atmel,vbus-gpio = <&pioB 11 0>;
++ status = "okay";
++ };
++ };
++
++ nand0: nand@40000000 {
++ nand-bus-width = <8>;
++ nand-ecc-mode = "soft";
++ nand-on-flash-bbt;
++ status = "okay";
++
++ at91bootstrap@0 {
++ label = "at91bootstrap";
++ reg = <0x0 0x20000>;
++ };
++
++ barebox@20000 {
++ label = "barebox";
++ reg = <0x20000 0x40000>;
++ };
++
++ bareboxenv@60000 {
++ label = "bareboxenv";
++ reg = <0x60000 0x20000>;
++ };
++
++ bareboxenv2@80000 {
++ label = "bareboxenv2";
++ reg = <0x80000 0x20000>;
++ };
++
++ oftree@80000 {
++ label = "oftree";
++ reg = <0xa0000 0x20000>;
++ };
++
++ kernel@a0000 {
++ label = "kernel";
++ reg = <0xc0000 0x400000>;
++ };
++
++ rootfs@4a0000 {
++ label = "rootfs";
++ reg = <0x4c0000 0x7800000>;
++ };
++
++ data@7ca0000 {
++ label = "data";
++ reg = <0x7cc0000 0x8340000>;
++ };
++ };
++ };
++
++ i2c@0 {
++ status = "okay";
++ };
++};
+diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
+index 7f0a5cb..618fc5b 100644
+--- a/arch/arm/mach-at91/Makefile.boot
++++ b/arch/arm/mach-at91/Makefile.boot
+@@ -19,6 +19,7 @@ dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9260.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9260.dtb
+ # sam9263
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9263ek.dtb
++dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9263.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9263.dtb
+ # sam9g20
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek.dtb
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0036-ARM-at91-add-kizbox-board-dt-support.patch b/patches.at91/0036-ARM-at91-add-kizbox-board-dt-support.patch
new file mode 100644
index 00000000000000..c6646e562f124d
--- /dev/null
+++ b/patches.at91/0036-ARM-at91-add-kizbox-board-dt-support.patch
@@ -0,0 +1,176 @@
+From 1dd636835a243a050417ff1c10f221ef545d5ab0 Mon Sep 17 00:00:00 2001
+From: Boris BREZILLON <linux-arm@overkiz.com>
+Date: Fri, 20 Apr 2012 14:37:50 +0200
+Subject: ARM: at91: add kizbox board dt support.
+
+This patch adds support for the kizbox board (based on at91sam9g20 SoC)
+
+Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/boot/dts/kizbox.dts | 138 +++++++++++++++++++++++++++++++++++++++
+ arch/arm/mach-at91/Makefile.boot | 1 +
+ 2 files changed, 139 insertions(+)
+ create mode 100644 arch/arm/boot/dts/kizbox.dts
+
+diff --git a/arch/arm/boot/dts/kizbox.dts b/arch/arm/boot/dts/kizbox.dts
+new file mode 100644
+index 0000000..e8814fe
+--- /dev/null
++++ b/arch/arm/boot/dts/kizbox.dts
+@@ -0,0 +1,138 @@
++/*
++ * kizbox.dts - Device Tree file for Overkiz Kizbox board
++ *
++ * Copyright (C) 2012 Boris BREZILLON <linux-arm@overkiz.com>
++ *
++ * Licensed under GPLv2.
++ */
++/dts-v1/;
++/include/ "at91sam9g20.dtsi"
++
++/ {
++
++ model = "Overkiz kizbox";
++ compatible = "overkiz,kizbox", "atmel,at91sam9g20", "atmel,at91sam9";
++
++ chosen {
++ bootargs = "panic=5 ubi.mtd=1 rootfstype=ubifs root=ubi0:root";
++ };
++
++ memory {
++ reg = <0x20000000 0x2000000>;
++ };
++
++ clocks {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges;
++
++ main_clock: clock@0 {
++ compatible = "atmel,osc", "fixed-clock";
++ clock-frequency = <18432000>;
++ };
++ };
++
++ ahb {
++ apb {
++ dbgu: serial@fffff200 {
++ status = "okay";
++ };
++
++ usart0: serial@fffb0000 {
++ status = "okay";
++ };
++
++ usart1: serial@fffb4000 {
++ status = "okay";
++ };
++
++ macb0: ethernet@fffc4000 {
++ phy-mode = "mii";
++ status = "okay";
++ };
++
++ };
++
++ nand0: nand@40000000 {
++ nand-bus-width = <8>;
++ nand-ecc-mode = "soft";
++ status = "okay";
++
++ bootloaderkernel@0 {
++ label = "bootloader-kernel";
++ reg = <0x0 0xc0000>;
++ };
++
++ ubi@c0000 {
++ label = "ubi";
++ reg = <0xc0000 0x7f40000>;
++ };
++
++ };
++
++ usb0: ohci@00500000 {
++ num-ports = <1>;
++ status = "okay";
++ };
++ };
++
++ i2c@0 {
++ status = "okay";
++
++ pcf8563@51 {
++ /* nxp pcf8563 rtc */
++ compatible = "nxp,pcf8563";
++ reg = <0x51>;
++ };
++
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ led1g {
++ label = "led1:green";
++ gpios = <&pioB 0 1>;
++ linux,default-trigger = "none";
++ };
++
++ led1r {
++ label = "led1:red";
++ gpios = <&pioB 1 1>;
++ linux,default-trigger = "none";
++ };
++
++ led2g {
++ label = "led2:green";
++ gpios = <&pioB 2 1>;
++ linux,default-trigger = "none";
++ default-state = "on";
++ };
++
++ led2r {
++ label = "led2:red";
++ gpios = <&pioB 3 1>;
++ linux,default-trigger = "none";
++ };
++ };
++
++ gpio_keys {
++ compatible = "gpio-keys";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ reset {
++ label = "reset";
++ gpios = <&pioB 30 1>;
++ linux,code = <0x100>;
++ gpio-key,wakeup;
++ };
++
++ mode {
++ label = "mode";
++ gpios = <&pioB 31 1>;
++ linux,code = <0x101>;
++ gpio-key,wakeup;
++ };
++ };
++};
+\ No newline at end of file
+diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
+index 618fc5b..99e8097 100644
+--- a/arch/arm/mach-at91/Makefile.boot
++++ b/arch/arm/mach-at91/Makefile.boot
+@@ -24,6 +24,7 @@ dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9263.dtb
+ # sam9g20
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek_2mmc.dtb
++dtb-$(CONFIG_MACH_AT91SAM_DT) += kizbox.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9g20.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9g20.dtb
+ # sam9g45
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0037-Ethernut-5-board-support.patch b/patches.at91/0037-Ethernut-5-board-support.patch
new file mode 100644
index 00000000000000..a3b9b10843482e
--- /dev/null
+++ b/patches.at91/0037-Ethernut-5-board-support.patch
@@ -0,0 +1,120 @@
+From 6d9ded2c6183d8098f852b2a5dcd18454f9de0e7 Mon Sep 17 00:00:00 2001
+From: Tim Schendekehl <tim.schendekehl@egnite.de>
+Date: Tue, 24 Apr 2012 18:47:59 +0200
+Subject: Ethernut 5 board support
+
+Add support for the Ethernut 5 open hardware design, based
+on Atmel's AT91SAM9XE512 SoC.
+
+Signed-off-by: Tim Schendekehl <tim.schendekehl@egnite.de>
+---
+ arch/arm/boot/dts/ethernut5.dts | 84 ++++++++++++++++++++++++++++++++++++++++
+ arch/arm/mach-at91/Makefile.boot | 1 +
+ 2 files changed, 85 insertions(+)
+ create mode 100644 arch/arm/boot/dts/ethernut5.dts
+
+diff --git a/arch/arm/boot/dts/ethernut5.dts b/arch/arm/boot/dts/ethernut5.dts
+new file mode 100644
+index 0000000..1ea9d34
+--- /dev/null
++++ b/arch/arm/boot/dts/ethernut5.dts
+@@ -0,0 +1,84 @@
++/*
++ * ethernut5.dts - Device Tree file for Ethernut 5 board
++ *
++ * Copyright (C) 2012 egnite GmbH <info@egnite.de>
++ *
++ * Licensed under GPLv2.
++ */
++/dts-v1/;
++/include/ "at91sam9260.dtsi"
++
++/ {
++ model = "Ethernut 5";
++ compatible = "egnite,ethernut5", "atmel,at91sam9260", "atmel,at91sam9";
++
++ chosen {
++ bootargs = "console=ttyS0,115200 root=/dev/mtdblock0 rw rootfstype=jffs2";
++ };
++
++ memory {
++ reg = <0x20000000 0x08000000>;
++ };
++
++ ahb {
++ apb {
++ dbgu: serial@fffff200 {
++ status = "okay";
++ };
++
++ usart0: serial@fffb0000 {
++ status = "okay";
++ };
++
++ usart1: serial@fffb4000 {
++ status = "okay";
++ };
++
++ macb0: ethernet@fffc4000 {
++ phy-mode = "rmii";
++ status = "okay";
++ };
++
++ usb1: gadget@fffa4000 {
++ atmel,vbus-gpio = <&pioC 5 0>;
++ status = "okay";
++ };
++ };
++
++ nand0: nand@40000000 {
++ nand-bus-width = <8>;
++ nand-ecc-mode = "soft";
++ nand-on-flash-bbt;
++ status = "okay";
++
++ gpios = <0
++ &pioC 14 0
++ 0
++ >;
++
++ root@0 {
++ label = "root";
++ reg = <0x0 0x08000000>;
++ };
++
++ data@20000 {
++ label = "data";
++ reg = <0x08000000 0x38000000>;
++ };
++ };
++
++ usb0: ohci@00500000 {
++ num-ports = <2>;
++ status = "okay";
++ };
++ };
++
++ i2c@0 {
++ status = "okay";
++
++ pcf8563@50 {
++ compatible = "nxp,pcf8563";
++ reg = <0x51>;
++ };
++ };
++};
+diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
+index 99e8097..c03417d 100644
+--- a/arch/arm/mach-at91/Makefile.boot
++++ b/arch/arm/mach-at91/Makefile.boot
+@@ -15,6 +15,7 @@ endif
+
+ # Keep dtb files sorted alphabetically for each SoC
+ # sam9260
++dtb-$(CONFIG_MACH_AT91SAM_DT) += ethernut5.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9260.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9260.dtb
+ # sam9263
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0038-ARM-at91-Add-machine-header-file-for-AT91SAM9N12-SoC.patch b/patches.at91/0038-ARM-at91-Add-machine-header-file-for-AT91SAM9N12-SoC.patch
new file mode 100644
index 00000000000000..dc6f319c3282b6
--- /dev/null
+++ b/patches.at91/0038-ARM-at91-Add-machine-header-file-for-AT91SAM9N12-SoC.patch
@@ -0,0 +1,213 @@
+From 771d02d8690db4118b239f864edca3d80d1c163f Mon Sep 17 00:00:00 2001
+From: Hong Xu <hong.xu@atmel.com>
+Date: Tue, 17 Apr 2012 14:26:30 +0800
+Subject: ARM: at91: Add machine header file for AT91SAM9N12 SoC
+
+Signed-off-by: Hong Xu <hong.xu@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/mach-at91/include/mach/at91sam9n12.h | 60 ++++++++++++++++++++++
+ .../mach-at91/include/mach/at91sam9n12_matrix.h | 53 +++++++++++++++++++
+ arch/arm/mach-at91/include/mach/cpu.h | 10 ++++
+ arch/arm/mach-at91/include/mach/hardware.h | 1 +
+ arch/arm/mach-at91/soc.h | 5 ++
+ 5 files changed, 129 insertions(+)
+ create mode 100644 arch/arm/mach-at91/include/mach/at91sam9n12.h
+ create mode 100644 arch/arm/mach-at91/include/mach/at91sam9n12_matrix.h
+
+diff --git a/arch/arm/mach-at91/include/mach/at91sam9n12.h b/arch/arm/mach-at91/include/mach/at91sam9n12.h
+new file mode 100644
+index 0000000..d374b87
+--- /dev/null
++++ b/arch/arm/mach-at91/include/mach/at91sam9n12.h
+@@ -0,0 +1,60 @@
++/*
++ * SoC specific header file for the AT91SAM9N12
++ *
++ * Copyright (C) 2012 Atmel Corporation
++ *
++ * Common definitions, based on AT91SAM9N12 SoC datasheet
++ *
++ * Licensed under GPLv2 or later
++ */
++
++#ifndef _AT91SAM9N12_H_
++#define _AT91SAM9N12_H_
++
++/*
++ * Peripheral identifiers/interrupts.
++ */
++#define AT91SAM9N12_ID_PIOAB 2 /* Parallel I/O Controller A and B */
++#define AT91SAM9N12_ID_PIOCD 3 /* Parallel I/O Controller C and D */
++#define AT91SAM9N12_ID_FUSE 4 /* FUSE Controller */
++#define AT91SAM9N12_ID_USART0 5 /* USART 0 */
++#define AT91SAM9N12_ID_USART1 6 /* USART 1 */
++#define AT91SAM9N12_ID_USART2 7 /* USART 2 */
++#define AT91SAM9N12_ID_USART3 8 /* USART 3 */
++#define AT91SAM9N12_ID_TWI0 9 /* Two-Wire Interface 0 */
++#define AT91SAM9N12_ID_TWI1 10 /* Two-Wire Interface 1 */
++#define AT91SAM9N12_ID_MCI 12 /* High Speed Multimedia Card Interface */
++#define AT91SAM9N12_ID_SPI0 13 /* Serial Peripheral Interface 0 */
++#define AT91SAM9N12_ID_SPI1 14 /* Serial Peripheral Interface 1 */
++#define AT91SAM9N12_ID_UART0 15 /* UART 0 */
++#define AT91SAM9N12_ID_UART1 16 /* UART 1 */
++#define AT91SAM9N12_ID_TCB 17 /* Timer Counter 0, 1, 2, 3, 4 and 5 */
++#define AT91SAM9N12_ID_PWM 18 /* Pulse Width Modulation Controller */
++#define AT91SAM9N12_ID_ADC 19 /* ADC Controller */
++#define AT91SAM9N12_ID_DMA 20 /* DMA Controller */
++#define AT91SAM9N12_ID_UHP 22 /* USB Host High Speed */
++#define AT91SAM9N12_ID_UDP 23 /* USB Device High Speed */
++#define AT91SAM9N12_ID_LCDC 25 /* LCD Controller */
++#define AT91SAM9N12_ID_ISI 25 /* Image Sensor Interface */
++#define AT91SAM9N12_ID_SSC 28 /* Synchronous Serial Controller */
++#define AT91SAM9N12_ID_TRNG 30 /* TRNG */
++#define AT91SAM9N12_ID_IRQ0 31 /* Advanced Interrupt Controller */
++
++/*
++ * User Peripheral physical base addresses.
++ */
++#define AT91SAM9N12_BASE_USART0 0xf801c000
++#define AT91SAM9N12_BASE_USART1 0xf8020000
++#define AT91SAM9N12_BASE_USART2 0xf8024000
++#define AT91SAM9N12_BASE_USART3 0xf8028000
++
++/*
++ * Internal Memory.
++ */
++#define AT91SAM9N12_SRAM_BASE 0x00300000 /* Internal SRAM base address */
++#define AT91SAM9N12_SRAM_SIZE SZ_32K /* Internal SRAM size (32Kb) */
++
++#define AT91SAM9N12_ROM_BASE 0x00100000 /* Internal ROM base address */
++#define AT91SAM9N12_ROM_SIZE SZ_128K /* Internal ROM size (128Kb) */
++
++#endif
+diff --git a/arch/arm/mach-at91/include/mach/at91sam9n12_matrix.h b/arch/arm/mach-at91/include/mach/at91sam9n12_matrix.h
+new file mode 100644
+index 0000000..40060cd
+--- /dev/null
++++ b/arch/arm/mach-at91/include/mach/at91sam9n12_matrix.h
+@@ -0,0 +1,53 @@
++/*
++ * Matrix-centric header file for the AT91SAM9N12
++ *
++ * Copyright (C) 2012 Atmel Corporation.
++ *
++ * Only EBI related registers.
++ * Write Protect register definitions may be useful.
++ *
++ * Licensed under GPLv2 or later.
++ */
++
++#ifndef _AT91SAM9N12_MATRIX_H_
++#define _AT91SAM9N12_MATRIX_H_
++
++#define AT91_MATRIX_EBICSA (AT91_MATRIX + 0x118) /* 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_VDDIOMSEL (1 << 16) /* Memory voltage selection */
++#define AT91_MATRIX_EBI_VDDIOMSEL_1_8V (0 << 16)
++#define AT91_MATRIX_EBI_VDDIOMSEL_3_3V (1 << 16)
++#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_EBI_DDR_IOSR (1 << 18) /* DDR2 dedicated port I/O slew rate selection */
++#define AT91_MATRIX_EBI_DDR_IOSR_REDUCED (0 << 18)
++#define AT91_MATRIX_EBI_DDR_IOSR_NORMAL (1 << 18)
++#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
+diff --git a/arch/arm/mach-at91/include/mach/cpu.h b/arch/arm/mach-at91/include/mach/cpu.h
+index 73d2fd2..b6504c1 100644
+--- a/arch/arm/mach-at91/include/mach/cpu.h
++++ b/arch/arm/mach-at91/include/mach/cpu.h
+@@ -25,6 +25,7 @@
+ #define ARCH_ID_AT91SAM9G45MRL 0x819b05a2 /* aka 9G45-ES2 & non ES lots */
+ #define ARCH_ID_AT91SAM9G45ES 0x819b05a1 /* 9G45-ES (Engineering Sample) */
+ #define ARCH_ID_AT91SAM9X5 0x819a05a0
++#define ARCH_ID_AT91SAM9N12 0x819a07a0
+
+ #define ARCH_ID_AT91SAM9XE128 0x329973a0
+ #define ARCH_ID_AT91SAM9XE256 0x329a93a0
+@@ -71,6 +72,9 @@ enum at91_soc_type {
+ /* SAM9X5 */
+ AT91_SOC_SAM9X5,
+
++ /* SAM9N12 */
++ AT91_SOC_SAM9N12,
++
+ /* Unknown type */
+ AT91_SOC_NONE
+ };
+@@ -177,6 +181,12 @@ static inline int at91_soc_is_detected(void)
+ #define cpu_is_at91sam9x25() (0)
+ #endif
+
++#ifdef CONFIG_SOC_AT91SAM9N12
++#define cpu_is_at91sam9n12() (at91_soc_initdata.type == AT91_SOC_SAM9N12)
++#else
++#define cpu_is_at91sam9n12() (0)
++#endif
++
+ /*
+ * Since this is ARM, we will never run on any AVR32 CPU. But these
+ * definitions may reduce clutter in common drivers.
+diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h
+index 3a01f8f..24b46bd 100644
+--- a/arch/arm/mach-at91/include/mach/hardware.h
++++ b/arch/arm/mach-at91/include/mach/hardware.h
+@@ -32,6 +32,7 @@
+ #include <mach/at91sam9rl.h>
+ #include <mach/at91sam9g45.h>
+ #include <mach/at91sam9x5.h>
++#include <mach/at91sam9n12.h>
+
+ /*
+ * On all at91 except rm9200 and x40 have the System Controller starts
+diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h
+index 683dddf..a9cfeb1 100644
+--- a/arch/arm/mach-at91/soc.h
++++ b/arch/arm/mach-at91/soc.h
+@@ -20,6 +20,7 @@ extern struct at91_init_soc at91sam9263_soc;
+ extern struct at91_init_soc at91sam9g45_soc;
+ extern struct at91_init_soc at91sam9rl_soc;
+ extern struct at91_init_soc at91sam9x5_soc;
++extern struct at91_init_soc at91sam9n12_soc;
+
+ static inline int at91_soc_is_enabled(void)
+ {
+@@ -53,3 +54,7 @@ static inline int at91_soc_is_enabled(void)
+ #if !defined(CONFIG_SOC_AT91SAM9X5)
+ #define at91sam9x5_soc at91_boot_soc
+ #endif
++
++#if !defined(CONFIG_SOC_AT91SAM9N12)
++#define at91sam9n12_soc at91_boot_soc
++#endif
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0039-ARM-at91-Add-machine-files-for-AT91SAM9N12-SoC.patch b/patches.at91/0039-ARM-at91-Add-machine-files-for-AT91SAM9N12-SoC.patch
new file mode 100644
index 00000000000000..c5a453488e8e14
--- /dev/null
+++ b/patches.at91/0039-ARM-at91-Add-machine-files-for-AT91SAM9N12-SoC.patch
@@ -0,0 +1,368 @@
+From 37b8c7ad2aa24a15b778cff614913c63b7e5c505 Mon Sep 17 00:00:00 2001
+From: Hong Xu <hong.xu@atmel.com>
+Date: Tue, 17 Apr 2012 14:26:31 +0800
+Subject: ARM: at91: Add machine files for AT91SAM9N12 SoC
+
+Signed-off-by: Hong Xu <hong.xu@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/mach-at91/Kconfig | 8 ++
+ arch/arm/mach-at91/Makefile | 1 +
+ arch/arm/mach-at91/Makefile.boot | 2 +
+ arch/arm/mach-at91/at91sam9n12.c | 233 +++++++++++++++++++++++++++++++++++++++
+ arch/arm/mach-at91/clock.c | 15 ++-
+ arch/arm/mach-at91/setup.c | 6 +
+ 6 files changed, 260 insertions(+), 5 deletions(-)
+ create mode 100644 arch/arm/mach-at91/at91sam9n12.c
+
+diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
+index 98a42f3..19505c0 100644
+--- a/arch/arm/mach-at91/Kconfig
++++ b/arch/arm/mach-at91/Kconfig
+@@ -91,6 +91,14 @@ config SOC_AT91SAM9X5
+ This support covers AT91SAM9G15, AT91SAM9G25, AT91SAM9X25, AT91SAM9G35
+ and AT91SAM9X35.
+
++config SOC_AT91SAM9N12
++ bool "AT91SAM9N12 family"
++ select SOC_AT91SAM9
++ select HAVE_AT91_DBGU0
++ select HAVE_FB_ATMEL
++ help
++ Select this if you are using Atmel's AT91SAM9N12 SoC.
++
+ choice
+ prompt "Atmel AT91 Processor Devices for non DT boards"
+
+diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
+index 79d0f60..3bb7a51 100644
+--- a/arch/arm/mach-at91/Makefile
++++ b/arch/arm/mach-at91/Makefile
+@@ -18,6 +18,7 @@ obj-$(CONFIG_SOC_AT91SAM9260) += at91sam9260.o
+ obj-$(CONFIG_SOC_AT91SAM9261) += at91sam9261.o
+ obj-$(CONFIG_SOC_AT91SAM9263) += at91sam9263.o
+ obj-$(CONFIG_SOC_AT91SAM9G45) += at91sam9g45.o
++obj-$(CONFIG_SOC_AT91SAM9N12) += at91sam9n12.o
+ obj-$(CONFIG_SOC_AT91SAM9X5) += at91sam9x5.o
+ obj-$(CONFIG_SOC_AT91SAM9RL) += at91sam9rl.o
+
+diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
+index c03417d..9e84fe4 100644
+--- a/arch/arm/mach-at91/Makefile.boot
++++ b/arch/arm/mach-at91/Makefile.boot
+@@ -30,5 +30,7 @@ dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9g20.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9g20.dtb
+ # sam9g45
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb
++# sam9n12
++dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9n12ek.dtb
+ # sam9x5
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g25ek.dtb
+diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
+new file mode 100644
+index 0000000..0849466
+--- /dev/null
++++ b/arch/arm/mach-at91/at91sam9n12.c
+@@ -0,0 +1,233 @@
++/*
++ * SoC specific setup code for the AT91SAM9N12
++ *
++ * Copyright (C) 2012 Atmel Corporation.
++ *
++ * Licensed under GPLv2 or later.
++ */
++
++#include <linux/module.h>
++#include <linux/dma-mapping.h>
++
++#include <asm/irq.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <mach/at91sam9n12.h>
++#include <mach/at91_pmc.h>
++#include <mach/cpu.h>
++#include <mach/board.h>
++
++#include "soc.h"
++#include "generic.h"
++#include "clock.h"
++#include "sam9_smc.h"
++
++/* --------------------------------------------------------------------
++ * Clocks
++ * -------------------------------------------------------------------- */
++
++/*
++ * The peripheral clocks.
++ */
++static struct clk pioAB_clk = {
++ .name = "pioAB_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_PIOAB,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk pioCD_clk = {
++ .name = "pioCD_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_PIOCD,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk usart0_clk = {
++ .name = "usart0_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_USART0,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk usart1_clk = {
++ .name = "usart1_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_USART1,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk usart2_clk = {
++ .name = "usart2_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_USART2,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk usart3_clk = {
++ .name = "usart3_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_USART3,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk twi0_clk = {
++ .name = "twi0_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_TWI0,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk twi1_clk = {
++ .name = "twi1_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_TWI1,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk mmc_clk = {
++ .name = "mci_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_MCI,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk spi0_clk = {
++ .name = "spi0_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_SPI0,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk spi1_clk = {
++ .name = "spi1_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_SPI1,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk uart0_clk = {
++ .name = "uart0_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_UART0,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk uart1_clk = {
++ .name = "uart1_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_UART1,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk tcb_clk = {
++ .name = "tcb_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_TCB,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk pwm_clk = {
++ .name = "pwm_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_PWM,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk adc_clk = {
++ .name = "adc_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_ADC,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk dma_clk = {
++ .name = "dma_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_DMA,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk uhp_clk = {
++ .name = "uhp",
++ .pmc_mask = 1 << AT91SAM9N12_ID_UHP,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk udp_clk = {
++ .name = "udp_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_UDP,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk lcdc_clk = {
++ .name = "lcdc_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_LCDC,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk ssc_clk = {
++ .name = "ssc_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_SSC,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++
++static struct clk *periph_clocks[] __initdata = {
++ &pioAB_clk,
++ &pioCD_clk,
++ &usart0_clk,
++ &usart1_clk,
++ &usart2_clk,
++ &usart3_clk,
++ &twi0_clk,
++ &twi1_clk,
++ &mmc_clk,
++ &spi0_clk,
++ &spi1_clk,
++ &lcdc_clk,
++ &uart0_clk,
++ &uart1_clk,
++ &tcb_clk,
++ &pwm_clk,
++ &adc_clk,
++ &dma_clk,
++ &uhp_clk,
++ &udp_clk,
++ &ssc_clk,
++};
++
++static struct clk_lookup periph_clocks_lookups[] = {
++ /* lookup table for DT entries */
++ CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
++ CLKDEV_CON_DEV_ID("usart", "f801c000.serial", &usart0_clk),
++ CLKDEV_CON_DEV_ID("usart", "f8020000.serial", &usart1_clk),
++ CLKDEV_CON_DEV_ID("usart", "f8024000.serial", &usart2_clk),
++ CLKDEV_CON_DEV_ID("usart", "f8028000.serial", &usart3_clk),
++ CLKDEV_CON_DEV_ID("t0_clk", "f8008000.timer", &tcb_clk),
++ CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb_clk),
++ CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma_clk),
++ CLKDEV_CON_ID("pioA", &pioAB_clk),
++ CLKDEV_CON_ID("pioB", &pioAB_clk),
++ CLKDEV_CON_ID("pioC", &pioCD_clk),
++ CLKDEV_CON_ID("pioD", &pioCD_clk),
++ /* additional fake clock for macb_hclk */
++ CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &uhp_clk),
++ CLKDEV_CON_DEV_ID("ohci_clk", "500000.ohci", &uhp_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 at91sam9n12_register_clocks(void)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
++ clk_register(periph_clocks[i]);
++ clk_register(&pck0);
++ clk_register(&pck1);
++
++ clkdev_add_table(periph_clocks_lookups,
++ ARRAY_SIZE(periph_clocks_lookups));
++
++}
++
++/* --------------------------------------------------------------------
++ * AT91SAM9N12 processor initialization
++ * -------------------------------------------------------------------- */
++
++static void __init at91sam9n12_map_io(void)
++{
++ at91_init_sram(0, AT91SAM9N12_SRAM_BASE, AT91SAM9N12_SRAM_SIZE);
++}
++
++void __init at91sam9n12_initialize(void)
++{
++ at91_extern_irq = (1 << AT91SAM9N12_ID_IRQ0);
++
++ /* Register GPIO subsystem (using DT) */
++ at91_gpio_init(NULL, 0);
++}
++
++struct at91_init_soc __initdata at91sam9n12_soc = {
++ .map_io = at91sam9n12_map_io,
++ .register_clocks = at91sam9n12_register_clocks,
++ .init = at91sam9n12_initialize,
++};
+diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c
+index 6b69282..de2ec6b 100644
+--- a/arch/arm/mach-at91/clock.c
++++ b/arch/arm/mach-at91/clock.c
+@@ -58,13 +58,15 @@ EXPORT_SYMBOL_GPL(at91_pmc_base);
+
+ #define cpu_has_800M_plla() ( cpu_is_at91sam9g20() \
+ || cpu_is_at91sam9g45() \
+- || cpu_is_at91sam9x5())
++ || cpu_is_at91sam9x5() \
++ || cpu_is_at91sam9n12())
+
+ #define cpu_has_300M_plla() (cpu_is_at91sam9g10())
+
+ #define cpu_has_pllb() (!(cpu_is_at91sam9rl() \
+ || cpu_is_at91sam9g45() \
+- || cpu_is_at91sam9x5()))
++ || cpu_is_at91sam9x5() \
++ || cpu_is_at91sam9n12()))
+
+ #define cpu_has_upll() (cpu_is_at91sam9g45() \
+ || cpu_is_at91sam9x5())
+@@ -78,12 +80,15 @@ EXPORT_SYMBOL_GPL(at91_pmc_base);
+ || cpu_is_at91sam9x5()))
+
+ #define cpu_has_plladiv2() (cpu_is_at91sam9g45() \
+- || cpu_is_at91sam9x5())
++ || cpu_is_at91sam9x5() \
++ || cpu_is_at91sam9n12())
+
+ #define cpu_has_mdiv3() (cpu_is_at91sam9g45() \
+- || cpu_is_at91sam9x5())
++ || cpu_is_at91sam9x5() \
++ || cpu_is_at91sam9n12())
+
+-#define cpu_has_alt_prescaler() (cpu_is_at91sam9x5())
++#define cpu_has_alt_prescaler() (cpu_is_at91sam9x5() \
++ || cpu_is_at91sam9n12())
+
+ static LIST_HEAD(clocks);
+ static DEFINE_SPINLOCK(clk_lock);
+diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
+index f44a2e7..944bffb 100644
+--- a/arch/arm/mach-at91/setup.c
++++ b/arch/arm/mach-at91/setup.c
+@@ -143,6 +143,11 @@ static void __init soc_detect(u32 dbgu_base)
+ at91_soc_initdata.type = AT91_SOC_SAM9X5;
+ at91_boot_soc = at91sam9x5_soc;
+ break;
++
++ case ARCH_ID_AT91SAM9N12:
++ at91_soc_initdata.type = AT91_SOC_SAM9N12;
++ at91_boot_soc = at91sam9n12_soc;
++ break;
+ }
+
+ /* at91sam9g10 */
+@@ -210,6 +215,7 @@ static const char *soc_name[] = {
+ [AT91_SOC_SAM9G45] = "at91sam9g45",
+ [AT91_SOC_SAM9RL] = "at91sam9rl",
+ [AT91_SOC_SAM9X5] = "at91sam9x5",
++ [AT91_SOC_SAM9N12] = "at91sam9n12",
+ [AT91_SOC_NONE] = "Unknown"
+ };
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0040-ARM-at91-Add-DT-description-files-for-AT91SAM9N12-EK.patch b/patches.at91/0040-ARM-at91-Add-DT-description-files-for-AT91SAM9N12-EK.patch
new file mode 100644
index 00000000000000..b84646a52eb98a
--- /dev/null
+++ b/patches.at91/0040-ARM-at91-Add-DT-description-files-for-AT91SAM9N12-EK.patch
@@ -0,0 +1,338 @@
+From 2fc9a0d7df19f33a08242efb22d64e8d3d0280de Mon Sep 17 00:00:00 2001
+From: Hong Xu <hong.xu@atmel.com>
+Date: Tue, 17 Apr 2012 14:26:29 +0800
+Subject: ARM: at91: Add DT description files for AT91SAM9N12-EK
+
+Added AT91SAM9N12 SoC DT file, as well as the board definition
+.dts file for AT91SAM9N12-EK.
+
+Signed-off-by: Hong Xu <hong.xu@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/boot/dts/at91sam9n12.dtsi | 221 ++++++++++++++++++++++++++++++++++++
+ arch/arm/boot/dts/at91sam9n12ek.dts | 84 ++++++++++++++
+ 2 files changed, 305 insertions(+)
+ create mode 100644 arch/arm/boot/dts/at91sam9n12.dtsi
+ create mode 100644 arch/arm/boot/dts/at91sam9n12ek.dts
+
+diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
+new file mode 100644
+index 0000000..cb84de7
+--- /dev/null
++++ b/arch/arm/boot/dts/at91sam9n12.dtsi
+@@ -0,0 +1,221 @@
++/*
++ * at91sam9n12.dtsi - Device Tree include file for AT91SAM9N12 SoC
++ *
++ * Copyright (C) 2012 Atmel,
++ * 2012 Hong Xu <hong.xu@atmel.com>
++ *
++ * Licensed under GPLv2 or later.
++ */
++
++/include/ "skeleton.dtsi"
++
++/ {
++ model = "Atmel AT91SAM9N12 SoC";
++ compatible = "atmel,at91sam9n12";
++ interrupt-parent = <&aic>;
++
++ aliases {
++ serial0 = &dbgu;
++ serial1 = &usart0;
++ serial2 = &usart1;
++ serial3 = &usart2;
++ serial4 = &usart3;
++ gpio0 = &pioA;
++ gpio1 = &pioB;
++ gpio2 = &pioC;
++ gpio3 = &pioD;
++ tcb0 = &tcb0;
++ tcb1 = &tcb1;
++ };
++ cpus {
++ cpu@0 {
++ compatible = "arm,arm926ejs";
++ };
++ };
++
++ memory {
++ reg = <0x20000000 0x10000000>;
++ };
++
++ ahb {
++ compatible = "simple-bus";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges;
++
++ apb {
++ compatible = "simple-bus";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges;
++
++ aic: interrupt-controller@fffff000 {
++ #interrupt-cells = <2>;
++ compatible = "atmel,at91rm9200-aic";
++ interrupt-controller;
++ reg = <0xfffff000 0x200>;
++ };
++
++ ramc0: ramc@ffffe800 {
++ compatible = "atmel,at91sam9g45-ddramc";
++ reg = <0xffffe800 0x200>;
++ };
++
++ pmc: pmc@fffffc00 {
++ compatible = "atmel,at91rm9200-pmc";
++ reg = <0xfffffc00 0x100>;
++ };
++
++ rstc@fffffe00 {
++ compatible = "atmel,at91sam9g45-rstc";
++ reg = <0xfffffe00 0x10>;
++ };
++
++ pit: timer@fffffe30 {
++ compatible = "atmel,at91sam9260-pit";
++ reg = <0xfffffe30 0xf>;
++ interrupts = <1 4>;
++ };
++
++ shdwc@fffffe10 {
++ compatible = "atmel,at91sam9x5-shdwc";
++ reg = <0xfffffe10 0x10>;
++ };
++
++ tcb0: timer@f8008000 {
++ compatible = "atmel,at91sam9x5-tcb";
++ reg = <0xf8008000 0x100>;
++ interrupts = <17 4>;
++ };
++
++ tcb1: timer@f800c000 {
++ compatible = "atmel,at91sam9x5-tcb";
++ reg = <0xf800c000 0x100>;
++ interrupts = <17 4>;
++ };
++
++ dma: dma-controller@ffffec00 {
++ compatible = "atmel,at91sam9g45-dma";
++ reg = <0xffffec00 0x200>;
++ interrupts = <20 4>;
++ };
++
++ pioA: gpio@fffff400 {
++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
++ reg = <0xfffff400 0x100>;
++ interrupts = <2 4>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ };
++
++ pioB: gpio@fffff600 {
++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
++ reg = <0xfffff600 0x100>;
++ interrupts = <2 4>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ };
++
++ pioC: gpio@fffff800 {
++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
++ reg = <0xfffff800 0x100>;
++ interrupts = <3 4>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ };
++
++ pioD: gpio@fffffa00 {
++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
++ reg = <0xfffffa00 0x100>;
++ interrupts = <3 4>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ };
++
++ dbgu: serial@fffff200 {
++ compatible = "atmel,at91sam9260-usart";
++ reg = <0xfffff200 0x200>;
++ interrupts = <1 4>;
++ status = "disabled";
++ };
++
++ usart0: serial@f801c000 {
++ compatible = "atmel,at91sam9260-usart";
++ reg = <0xf801c000 0x4000>;
++ interrupts = <5 4>;
++ atmel,use-dma-rx;
++ atmel,use-dma-tx;
++ status = "disabled";
++ };
++
++ usart1: serial@f8020000 {
++ compatible = "atmel,at91sam9260-usart";
++ reg = <0xf8020000 0x4000>;
++ interrupts = <6 4>;
++ atmel,use-dma-rx;
++ atmel,use-dma-tx;
++ status = "disabled";
++ };
++
++ usart2: serial@f8024000 {
++ compatible = "atmel,at91sam9260-usart";
++ reg = <0xf8024000 0x4000>;
++ interrupts = <7 4>;
++ atmel,use-dma-rx;
++ atmel,use-dma-tx;
++ status = "disabled";
++ };
++
++ usart3: serial@f8028000 {
++ compatible = "atmel,at91sam9260-usart";
++ reg = <0xf8028000 0x4000>;
++ interrupts = <8 4>;
++ atmel,use-dma-rx;
++ atmel,use-dma-tx;
++ status = "disabled";
++ };
++ };
++
++ nand0: nand@40000000 {
++ compatible = "atmel,at91rm9200-nand";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ reg = < 0x40000000 0x10000000
++ 0xffffe000 0x00000600
++ 0xffffe600 0x00000200
++ 0x00100000 0x00100000
++ >;
++ atmel,nand-addr-offset = <21>;
++ atmel,nand-cmd-offset = <22>;
++ gpios = <&pioD 5 0
++ &pioD 4 0
++ 0
++ >;
++ status = "disabled";
++ };
++
++ usb0: ohci@00500000 {
++ compatible = "atmel,at91rm9200-ohci", "usb-ohci";
++ reg = <0x00500000 0x00100000>;
++ interrupts = <22 4>;
++ status = "disabled";
++ };
++ };
++
++ i2c@0 {
++ compatible = "i2c-gpio";
++ gpios = <&pioA 30 0 /* sda */
++ &pioA 31 0 /* scl */
++ >;
++ i2c-gpio,sda-open-drain;
++ i2c-gpio,scl-open-drain;
++ i2c-gpio,delay-us = <2>; /* ~100 kHz */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++};
+diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts
+new file mode 100644
+index 0000000..f4e43e3
+--- /dev/null
++++ b/arch/arm/boot/dts/at91sam9n12ek.dts
+@@ -0,0 +1,84 @@
++/*
++ * at91sam9n12ek.dts - Device Tree file for AT91SAM9N12-EK board
++ *
++ * Copyright (C) 2012 Atmel,
++ * 2012 Hong Xu <hong.xu@atmel.com>
++ *
++ * Licensed under GPLv2 or later.
++ */
++/dts-v1/;
++/include/ "at91sam9n12.dtsi"
++
++/ {
++ model = "Atmel AT91SAM9N12-EK";
++ compatible = "atmel,at91sam9n12ek", "atmel,at91sam9n12", "atmel,at91sam9";
++
++ chosen {
++ bootargs = "mem=128M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=jffs2";
++ };
++
++ memory {
++ reg = <0x20000000 0x10000000>;
++ };
++
++ clocks {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges;
++
++ main_clock: clock@0 {
++ compatible = "atmel,osc", "fixed-clock";
++ clock-frequency = <16000000>;
++ };
++ };
++
++ ahb {
++ apb {
++ dbgu: serial@fffff200 {
++ status = "okay";
++ };
++ };
++
++ nand0: nand@40000000 {
++ nand-bus-width = <8>;
++ nand-ecc-mode = "soft";
++ nand-on-flash-bbt;
++ status = "okay";
++ };
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ d8 {
++ label = "d8";
++ gpios = <&pioB 4 1>;
++ linux,default-trigger = "mmc0";
++ };
++
++ d9 {
++ label = "d6";
++ gpios = <&pioB 5 1>;
++ linux,default-trigger = "nand-disk";
++ };
++
++ d10 {
++ label = "d7";
++ gpios = <&pioB 6 0>;
++ linux,default-trigger = "heartbeat";
++ };
++ };
++
++ gpio_keys {
++ compatible = "gpio-keys";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ enter {
++ label = "Enter";
++ gpios = <&pioB 4 1>;
++ linux,code = <28>;
++ gpio-key,wakeup;
++ };
++ };
++};
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0041-ARM-at91-remove-two-unused-headers.patch b/patches.at91/0041-ARM-at91-remove-two-unused-headers.patch
new file mode 100644
index 00000000000000..a118d5ff83b62f
--- /dev/null
+++ b/patches.at91/0041-ARM-at91-remove-two-unused-headers.patch
@@ -0,0 +1,228 @@
+From 2d672820ba5d6f2b3be8f73decfc00d4994af6ba Mon Sep 17 00:00:00 2001
+From: Paul Bolle <pebolle@tiscali.nl>
+Date: Thu, 7 Jun 2012 12:18:46 +0200
+Subject: ARM: at91: remove two unused headers
+
+Commit 82c583e3ae31ffa76d1280197274cc1e1cde3179 ("AT91RM9200 hardware
+headers") introduced arch/arm/mach-at91/include/mach/at91_spi.h and
+arch/arm/mach-at91/include/mach/at91_ssc.h. (These files were called
+at91rm9200_spi.h and at91rm9200_ssc.h then.) That commit was added in
+the v2.6.18 development cycle.
+
+Nothing includes them now and nothing uses the named constants they
+provide. (There's no way these named constants could be used unless
+these files were included somehow.) It actually seems these two headers
+have never been used since they were added to the tree. They can safely
+be removed.
+
+Signed-off-by: Paul Bolle <pebolle@tiscali.nl>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/include/mach/at91_spi.h | 81 ----------------------
+ arch/arm/mach-at91/include/mach/at91_ssc.h | 106 -----------------------------
+ 2 files changed, 187 deletions(-)
+ delete mode 100644 arch/arm/mach-at91/include/mach/at91_spi.h
+ delete mode 100644 arch/arm/mach-at91/include/mach/at91_ssc.h
+
+diff --git a/arch/arm/mach-at91/include/mach/at91_spi.h b/arch/arm/mach-at91/include/mach/at91_spi.h
+deleted file mode 100644
+index 2f6ba0c..0000000
+--- a/arch/arm/mach-at91/include/mach/at91_spi.h
++++ /dev/null
+@@ -1,81 +0,0 @@
+-/*
+- * arch/arm/mach-at91/include/mach/at91_spi.h
+- *
+- * Copyright (C) 2005 Ivan Kokshaysky
+- * Copyright (C) SAN People
+- *
+- * Serial Peripheral Interface (SPI) registers.
+- * Based on AT91RM9200 datasheet revision E.
+- *
+- * 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 AT91_SPI_H
+-#define AT91_SPI_H
+-
+-#define AT91_SPI_CR 0x00 /* Control Register */
+-#define AT91_SPI_SPIEN (1 << 0) /* SPI Enable */
+-#define AT91_SPI_SPIDIS (1 << 1) /* SPI Disable */
+-#define AT91_SPI_SWRST (1 << 7) /* SPI Software Reset */
+-#define AT91_SPI_LASTXFER (1 << 24) /* Last Transfer [SAM9261 only] */
+-
+-#define AT91_SPI_MR 0x04 /* Mode Register */
+-#define AT91_SPI_MSTR (1 << 0) /* Master/Slave Mode */
+-#define AT91_SPI_PS (1 << 1) /* Peripheral Select */
+-#define AT91_SPI_PS_FIXED (0 << 1)
+-#define AT91_SPI_PS_VARIABLE (1 << 1)
+-#define AT91_SPI_PCSDEC (1 << 2) /* Chip Select Decode */
+-#define AT91_SPI_DIV32 (1 << 3) /* Clock Selection [AT91RM9200 only] */
+-#define AT91_SPI_MODFDIS (1 << 4) /* Mode Fault Detection */
+-#define AT91_SPI_LLB (1 << 7) /* Local Loopback Enable */
+-#define AT91_SPI_PCS (0xf << 16) /* Peripheral Chip Select */
+-#define AT91_SPI_DLYBCS (0xff << 24) /* Delay Between Chip Selects */
+-
+-#define AT91_SPI_RDR 0x08 /* Receive Data Register */
+-#define AT91_SPI_RD (0xffff << 0) /* Receive Data */
+-#define AT91_SPI_PCS (0xf << 16) /* Peripheral Chip Select */
+-
+-#define AT91_SPI_TDR 0x0c /* Transmit Data Register */
+-#define AT91_SPI_TD (0xffff << 0) /* Transmit Data */
+-#define AT91_SPI_PCS (0xf << 16) /* Peripheral Chip Select */
+-#define AT91_SPI_LASTXFER (1 << 24) /* Last Transfer [SAM9261 only] */
+-
+-#define AT91_SPI_SR 0x10 /* Status Register */
+-#define AT91_SPI_RDRF (1 << 0) /* Receive Data Register Full */
+-#define AT91_SPI_TDRE (1 << 1) /* Transmit Data Register Full */
+-#define AT91_SPI_MODF (1 << 2) /* Mode Fault Error */
+-#define AT91_SPI_OVRES (1 << 3) /* Overrun Error Status */
+-#define AT91_SPI_ENDRX (1 << 4) /* End of RX buffer */
+-#define AT91_SPI_ENDTX (1 << 5) /* End of TX buffer */
+-#define AT91_SPI_RXBUFF (1 << 6) /* RX Buffer Full */
+-#define AT91_SPI_TXBUFE (1 << 7) /* TX Buffer Empty */
+-#define AT91_SPI_NSSR (1 << 8) /* NSS Rising [SAM9261 only] */
+-#define AT91_SPI_TXEMPTY (1 << 9) /* Transmission Register Empty [SAM9261 only] */
+-#define AT91_SPI_SPIENS (1 << 16) /* SPI Enable Status */
+-
+-#define AT91_SPI_IER 0x14 /* Interrupt Enable Register */
+-#define AT91_SPI_IDR 0x18 /* Interrupt Disable Register */
+-#define AT91_SPI_IMR 0x1c /* Interrupt Mask Register */
+-
+-#define AT91_SPI_CSR(n) (0x30 + ((n) * 4)) /* Chip Select Registers 0-3 */
+-#define AT91_SPI_CPOL (1 << 0) /* Clock Polarity */
+-#define AT91_SPI_NCPHA (1 << 1) /* Clock Phase */
+-#define AT91_SPI_CSAAT (1 << 3) /* Chip Select Active After Transfer [SAM9261 only] */
+-#define AT91_SPI_BITS (0xf << 4) /* Bits Per Transfer */
+-#define AT91_SPI_BITS_8 (0 << 4)
+-#define AT91_SPI_BITS_9 (1 << 4)
+-#define AT91_SPI_BITS_10 (2 << 4)
+-#define AT91_SPI_BITS_11 (3 << 4)
+-#define AT91_SPI_BITS_12 (4 << 4)
+-#define AT91_SPI_BITS_13 (5 << 4)
+-#define AT91_SPI_BITS_14 (6 << 4)
+-#define AT91_SPI_BITS_15 (7 << 4)
+-#define AT91_SPI_BITS_16 (8 << 4)
+-#define AT91_SPI_SCBR (0xff << 8) /* Serial Clock Baud Rate */
+-#define AT91_SPI_DLYBS (0xff << 16) /* Delay before SPCK */
+-#define AT91_SPI_DLYBCT (0xff << 24) /* Delay between Consecutive Transfers */
+-
+-#endif
+diff --git a/arch/arm/mach-at91/include/mach/at91_ssc.h b/arch/arm/mach-at91/include/mach/at91_ssc.h
+deleted file mode 100644
+index a81114c..0000000
+--- a/arch/arm/mach-at91/include/mach/at91_ssc.h
++++ /dev/null
+@@ -1,106 +0,0 @@
+-/*
+- * arch/arm/mach-at91/include/mach/at91_ssc.h
+- *
+- * Copyright (C) SAN People
+- *
+- * Serial Synchronous Controller (SSC) registers.
+- * Based on AT91RM9200 datasheet revision E.
+- *
+- * 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 AT91_SSC_H
+-#define AT91_SSC_H
+-
+-#define AT91_SSC_CR 0x00 /* Control Register */
+-#define AT91_SSC_RXEN (1 << 0) /* Receive Enable */
+-#define AT91_SSC_RXDIS (1 << 1) /* Receive Disable */
+-#define AT91_SSC_TXEN (1 << 8) /* Transmit Enable */
+-#define AT91_SSC_TXDIS (1 << 9) /* Transmit Disable */
+-#define AT91_SSC_SWRST (1 << 15) /* Software Reset */
+-
+-#define AT91_SSC_CMR 0x04 /* Clock Mode Register */
+-#define AT91_SSC_CMR_DIV (0xfff << 0) /* Clock Divider */
+-
+-#define AT91_SSC_RCMR 0x10 /* Receive Clock Mode Register */
+-#define AT91_SSC_CKS (3 << 0) /* Clock Selection */
+-#define AT91_SSC_CKS_DIV (0 << 0)
+-#define AT91_SSC_CKS_CLOCK (1 << 0)
+-#define AT91_SSC_CKS_PIN (2 << 0)
+-#define AT91_SSC_CKO (7 << 2) /* Clock Output Mode Selection */
+-#define AT91_SSC_CKO_NONE (0 << 2)
+-#define AT91_SSC_CKO_CONTINUOUS (1 << 2)
+-#define AT91_SSC_CKI (1 << 5) /* Clock Inversion */
+-#define AT91_SSC_CKI_FALLING (0 << 5)
+-#define AT91_SSC_CK_RISING (1 << 5)
+-#define AT91_SSC_CKG (1 << 6) /* Receive Clock Gating Selection [AT91SAM9261 only] */
+-#define AT91_SSC_CKG_NONE (0 << 6)
+-#define AT91_SSC_CKG_RFLOW (1 << 6)
+-#define AT91_SSC_CKG_RFHIGH (2 << 6)
+-#define AT91_SSC_START (0xf << 8) /* Start Selection */
+-#define AT91_SSC_START_CONTINUOUS (0 << 8)
+-#define AT91_SSC_START_TX_RX (1 << 8)
+-#define AT91_SSC_START_LOW_RF (2 << 8)
+-#define AT91_SSC_START_HIGH_RF (3 << 8)
+-#define AT91_SSC_START_FALLING_RF (4 << 8)
+-#define AT91_SSC_START_RISING_RF (5 << 8)
+-#define AT91_SSC_START_LEVEL_RF (6 << 8)
+-#define AT91_SSC_START_EDGE_RF (7 << 8)
+-#define AT91_SSC_STOP (1 << 12) /* Receive Stop Selection [AT91SAM9261 only] */
+-#define AT91_SSC_STTDLY (0xff << 16) /* Start Delay */
+-#define AT91_SSC_PERIOD (0xff << 24) /* Period Divider Selection */
+-
+-#define AT91_SSC_RFMR 0x14 /* Receive Frame Mode Register */
+-#define AT91_SSC_DATALEN (0x1f << 0) /* Data Length */
+-#define AT91_SSC_LOOP (1 << 5) /* Loop Mode */
+-#define AT91_SSC_MSBF (1 << 7) /* Most Significant Bit First */
+-#define AT91_SSC_DATNB (0xf << 8) /* Data Number per Frame */
+-#define AT91_SSC_FSLEN (0xf << 16) /* Frame Sync Length */
+-#define AT91_SSC_FSOS (7 << 20) /* Frame Sync Output Selection */
+-#define AT91_SSC_FSOS_NONE (0 << 20)
+-#define AT91_SSC_FSOS_NEGATIVE (1 << 20)
+-#define AT91_SSC_FSOS_POSITIVE (2 << 20)
+-#define AT91_SSC_FSOS_LOW (3 << 20)
+-#define AT91_SSC_FSOS_HIGH (4 << 20)
+-#define AT91_SSC_FSOS_TOGGLE (5 << 20)
+-#define AT91_SSC_FSEDGE (1 << 24) /* Frame Sync Edge Detection */
+-#define AT91_SSC_FSEDGE_POSITIVE (0 << 24)
+-#define AT91_SSC_FSEDGE_NEGATIVE (1 << 24)
+-
+-#define AT91_SSC_TCMR 0x18 /* Transmit Clock Mode Register */
+-#define AT91_SSC_TFMR 0x1c /* Transmit Fram Mode Register */
+-#define AT91_SSC_DATDEF (1 << 5) /* Data Default Value */
+-#define AT91_SSC_FSDEN (1 << 23) /* Frame Sync Data Enable */
+-
+-#define AT91_SSC_RHR 0x20 /* Receive Holding Register */
+-#define AT91_SSC_THR 0x24 /* Transmit Holding Register */
+-#define AT91_SSC_RSHR 0x30 /* Receive Sync Holding Register */
+-#define AT91_SSC_TSHR 0x34 /* Transmit Sync Holding Register */
+-
+-#define AT91_SSC_RC0R 0x38 /* Receive Compare 0 Register [AT91SAM9261 only] */
+-#define AT91_SSC_RC1R 0x3c /* Receive Compare 1 Register [AT91SAM9261 only] */
+-
+-#define AT91_SSC_SR 0x40 /* Status Register */
+-#define AT91_SSC_TXRDY (1 << 0) /* Transmit Ready */
+-#define AT91_SSC_TXEMPTY (1 << 1) /* Transmit Empty */
+-#define AT91_SSC_ENDTX (1 << 2) /* End of Transmission */
+-#define AT91_SSC_TXBUFE (1 << 3) /* Transmit Buffer Empty */
+-#define AT91_SSC_RXRDY (1 << 4) /* Receive Ready */
+-#define AT91_SSC_OVRUN (1 << 5) /* Receive Overrun */
+-#define AT91_SSC_ENDRX (1 << 6) /* End of Reception */
+-#define AT91_SSC_RXBUFF (1 << 7) /* Receive Buffer Full */
+-#define AT91_SSC_CP0 (1 << 8) /* Compare 0 [AT91SAM9261 only] */
+-#define AT91_SSC_CP1 (1 << 9) /* Compare 1 [AT91SAM9261 only] */
+-#define AT91_SSC_TXSYN (1 << 10) /* Transmit Sync */
+-#define AT91_SSC_RXSYN (1 << 11) /* Receive Sync */
+-#define AT91_SSC_TXENA (1 << 16) /* Transmit Enable */
+-#define AT91_SSC_RXENA (1 << 17) /* Receive Enable */
+-
+-#define AT91_SSC_IER 0x44 /* Interrupt Enable Register */
+-#define AT91_SSC_IDR 0x48 /* Interrupt Disable Register */
+-#define AT91_SSC_IMR 0x4c /* Interrupt Mask Register */
+-
+-#endif
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0042-ARM-at91-fix-at91_aic_write-macro.patch b/patches.at91/0042-ARM-at91-fix-at91_aic_write-macro.patch
new file mode 100644
index 00000000000000..c5cb945c019f7f
--- /dev/null
+++ b/patches.at91/0042-ARM-at91-fix-at91_aic_write-macro.patch
@@ -0,0 +1,29 @@
+From f7a7be1650e7160181c9ab1c4aeb5dd8b67ac939 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Thu, 31 May 2012 17:26:05 +0200
+Subject: ARM: at91: fix at91_aic_write macro
+
+Fix at91_aic_write macro to avoid potential issues.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/include/mach/at91_aic.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm/mach-at91/include/mach/at91_aic.h b/arch/arm/mach-at91/include/mach/at91_aic.h
+index 3045781..c1413ed 100644
+--- a/arch/arm/mach-at91/include/mach/at91_aic.h
++++ b/arch/arm/mach-at91/include/mach/at91_aic.h
+@@ -23,7 +23,7 @@ extern void __iomem *at91_aic_base;
+ __raw_readl(at91_aic_base + field)
+
+ #define at91_aic_write(field, value) \
+- __raw_writel(value, at91_aic_base + field);
++ __raw_writel(value, at91_aic_base + field)
+ #else
+ .extern at91_aic_base
+ #endif
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0043-USB-ohci-at91-use-resource_size-for-memory-io-resour.patch b/patches.at91/0043-USB-ohci-at91-use-resource_size-for-memory-io-resour.patch
new file mode 100644
index 00000000000000..2f65c9fa765120
--- /dev/null
+++ b/patches.at91/0043-USB-ohci-at91-use-resource_size-for-memory-io-resour.patch
@@ -0,0 +1,27 @@
+From 6b36e56532a5b9d9f2311165a95f2a0d31c40464 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 9 May 2012 10:49:41 +0200
+Subject: USB: ohci-at91: use resource_size() for memory/io resource length
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/host/ohci-at91.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
+index 55d3d64..84901c3 100644
+--- a/drivers/usb/host/ohci-at91.c
++++ b/drivers/usb/host/ohci-at91.c
+@@ -129,7 +129,7 @@ static int __devinit usb_hcd_at91_probe(const struct hc_driver *driver,
+ if (!hcd)
+ return -ENOMEM;
+ hcd->rsrc_start = pdev->resource[0].start;
+- hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
++ hcd->rsrc_len = resource_size(&pdev->resource[0]);
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ pr_debug("request_mem_region failed\n");
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0044-USB-Kconfig-add-Atmel-usba-driver-entry.patch b/patches.at91/0044-USB-Kconfig-add-Atmel-usba-driver-entry.patch
new file mode 100644
index 00000000000000..782778b7ce0dc8
--- /dev/null
+++ b/patches.at91/0044-USB-Kconfig-add-Atmel-usba-driver-entry.patch
@@ -0,0 +1,29 @@
+From 4a0e29935e53da412664f85d25d46ba719ec2294 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 19 Jun 2012 13:14:10 +0200
+Subject: USB: Kconfig: add Atmel usba driver entry
+
+Allow the USBA entry to be selected for every AT91 SoC.
+Will allow to select driver for newer SoCs.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/usb/gadget/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
+index 2633f75..10fea8b 100644
+--- a/drivers/usb/gadget/Kconfig
++++ b/drivers/usb/gadget/Kconfig
+@@ -150,7 +150,7 @@ config USB_AT91
+ config USB_ATMEL_USBA
+ tristate "Atmel USBA"
+ select USB_GADGET_DUALSPEED
+- depends on AVR32 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
++ depends on AVR32 || ARCH_AT91
+ help
+ USBA is the integrated high-speed USB Device controller on
+ the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0045-ARM-at91-clock-fix-PLLA-overclock-warning.patch b/patches.at91/0045-ARM-at91-clock-fix-PLLA-overclock-warning.patch
new file mode 100644
index 00000000000000..50009b45b6faed
--- /dev/null
+++ b/patches.at91/0045-ARM-at91-clock-fix-PLLA-overclock-warning.patch
@@ -0,0 +1,47 @@
+From 0880824561e6e9769027d83be21e5ab3f8aa9d31 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 9 Jul 2012 21:06:25 +0200
+Subject: ARM: at91/clock: fix PLLA overclock warning
+
+Fix PLLA overclock warning in relation with datasheet numbers.
+Add new > 240 MHz and > 210 MHz SoC categories.
+
+Reported-by: Jiri Prchal <jiri.prchal@aksignal.cz>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/clock.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c
+index de2ec6b..188c829 100644
+--- a/arch/arm/mach-at91/clock.c
++++ b/arch/arm/mach-at91/clock.c
+@@ -63,6 +63,12 @@ EXPORT_SYMBOL_GPL(at91_pmc_base);
+
+ #define cpu_has_300M_plla() (cpu_is_at91sam9g10())
+
++#define cpu_has_240M_plla() (cpu_is_at91sam9261() \
++ || cpu_is_at91sam9263() \
++ || cpu_is_at91sam9rl())
++
++#define cpu_has_210M_plla() (cpu_is_at91sam9260())
++
+ #define cpu_has_pllb() (!(cpu_is_at91sam9rl() \
+ || cpu_is_at91sam9g45() \
+ || cpu_is_at91sam9x5() \
+@@ -706,6 +712,12 @@ static int __init at91_pmc_init(unsigned long main_clock)
+ } else if (cpu_has_800M_plla()) {
+ if (plla.rate_hz > 800000000)
+ pll_overclock = true;
++ } else if (cpu_has_240M_plla()) {
++ if (plla.rate_hz > 240000000)
++ pll_overclock = true;
++ } else if (cpu_has_210M_plla()) {
++ if (plla.rate_hz > 210000000)
++ pll_overclock = true;
+ } else {
+ if (plla.rate_hz > 209000000)
+ pll_overclock = true;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0046-ARM-at91-dts-remove-partial-parameter-in-at91sam9g25.patch b/patches.at91/0046-ARM-at91-dts-remove-partial-parameter-in-at91sam9g25.patch
new file mode 100644
index 00000000000000..721fb1e214f3d3
--- /dev/null
+++ b/patches.at91/0046-ARM-at91-dts-remove-partial-parameter-in-at91sam9g25.patch
@@ -0,0 +1,29 @@
+From 5870fd6e3a30ac854a4f38eba8976fbde68fa705 Mon Sep 17 00:00:00 2001
+From: Bo Shen <voice.shen@atmel.com>
+Date: Fri, 17 Aug 2012 16:23:56 +0800
+Subject: ARM: at91/dts: remove partial parameter in at91sam9g25ek.dts
+
+Remove the malformed "mem=" bootargs parameter in at91sam9g25ek.dts
+
+Signed-off-by: Bo Shen <voice.shen@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9g25ek.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts
+index 7829a4d..96514c1 100644
+--- a/arch/arm/boot/dts/at91sam9g25ek.dts
++++ b/arch/arm/boot/dts/at91sam9g25ek.dts
+@@ -15,7 +15,7 @@
+ compatible = "atmel,at91sam9g25ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
+
+ chosen {
+- bootargs = "128M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
++ bootargs = "console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
+ };
+
+ ahb {
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0047-ARM-at91-set-i2c_board_info.type-to-ds1339-directly.patch b/patches.at91/0047-ARM-at91-set-i2c_board_info.type-to-ds1339-directly.patch
new file mode 100644
index 00000000000000..503985d9b9f9a5
--- /dev/null
+++ b/patches.at91/0047-ARM-at91-set-i2c_board_info.type-to-ds1339-directly.patch
@@ -0,0 +1,33 @@
+From 632b3f90968b823b65b84cac6b348b13ad662a95 Mon Sep 17 00:00:00 2001
+From: Paul Bolle <pebolle@tiscali.nl>
+Date: Thu, 24 May 2012 16:30:29 +0200
+Subject: ARM: at91: set i2c_board_info.type to "ds1339" directly
+
+The single element of the cpu9krea_i2c_devices array (of type struct
+i2c_board_info) has its "type" member set twice. First to "rtc-ds1307"
+(through the I2C_BOARD_INFO macro) and then directly to "ds1339". Just
+set it (once and) directly to "ds1339" instead.
+
+Signed-off-by: Paul Bolle <pebolle@tiscali.nl>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/board-cpu9krea.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c
+index 69951ec..ece0d76 100644
+--- a/arch/arm/mach-at91/board-cpu9krea.c
++++ b/arch/arm/mach-at91/board-cpu9krea.c
+@@ -253,8 +253,7 @@ static struct gpio_led cpu9krea_leds[] = {
+
+ static struct i2c_board_info __initdata cpu9krea_i2c_devices[] = {
+ {
+- I2C_BOARD_INFO("rtc-ds1307", 0x68),
+- .type = "ds1339",
++ I2C_BOARD_INFO("ds1339", 0x68),
+ },
+ };
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0048-ARM-at91-defconfig-Remove-unaffected-config-option.patch b/patches.at91/0048-ARM-at91-defconfig-Remove-unaffected-config-option.patch
new file mode 100644
index 00000000000000..2a84b809661f54
--- /dev/null
+++ b/patches.at91/0048-ARM-at91-defconfig-Remove-unaffected-config-option.patch
@@ -0,0 +1,123 @@
+From 7b849b56ec5599dbe5454204511d904c0d1c2be4 Mon Sep 17 00:00:00 2001
+From: Richard Genoud <richard.genoud@gmail.com>
+Date: Fri, 22 Jun 2012 15:29:28 +0200
+Subject: ARM: at91/defconfig: Remove unaffected config option
+
+The commit bf4289cba02b8cf770ecd7959ca70839f0dd9d3c removed the use of
+CONFIG_MTD_NAND_ATMEL_ECC_NONE and CONFIG_MTD_NAND_ATMEL_ECC_HW but the
+Kconfig file was forgotten.
+
+This patch remove those inoperative options.
+
+Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/configs/afeb9260_defconfig | 1 -
+ arch/arm/configs/at91sam9263_defconfig | 1 -
+ arch/arm/configs/qil-a9260_defconfig | 1 -
+ arch/arm/configs/usb-a9260_defconfig | 1 -
+ drivers/mtd/nand/Kconfig | 40 ----------------------------------
+ 5 files changed, 44 deletions(-)
+
+diff --git a/arch/arm/configs/afeb9260_defconfig b/arch/arm/configs/afeb9260_defconfig
+index 2afdf67..c285a9d 100644
+--- a/arch/arm/configs/afeb9260_defconfig
++++ b/arch/arm/configs/afeb9260_defconfig
+@@ -39,7 +39,6 @@ CONFIG_MTD_BLOCK=y
+ CONFIG_MTD_DATAFLASH=y
+ CONFIG_MTD_NAND=y
+ CONFIG_MTD_NAND_ATMEL=y
+-CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
+ CONFIG_BLK_DEV_RAM=y
+ CONFIG_BLK_DEV_RAM_SIZE=8192
+ CONFIG_ATMEL_SSC=y
+diff --git a/arch/arm/configs/at91sam9263_defconfig b/arch/arm/configs/at91sam9263_defconfig
+index 1cf9626..585e7e0 100644
+--- a/arch/arm/configs/at91sam9263_defconfig
++++ b/arch/arm/configs/at91sam9263_defconfig
+@@ -61,7 +61,6 @@ CONFIG_MTD_DATAFLASH=y
+ CONFIG_MTD_BLOCK2MTD=y
+ CONFIG_MTD_NAND=y
+ CONFIG_MTD_NAND_ATMEL=y
+-CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
+ CONFIG_MTD_UBI=y
+ CONFIG_MTD_UBI_GLUEBI=y
+ CONFIG_BLK_DEV_LOOP=y
+diff --git a/arch/arm/configs/qil-a9260_defconfig b/arch/arm/configs/qil-a9260_defconfig
+index 9160f3b..2bb100b 100644
+--- a/arch/arm/configs/qil-a9260_defconfig
++++ b/arch/arm/configs/qil-a9260_defconfig
+@@ -50,7 +50,6 @@ CONFIG_MTD_BLOCK=y
+ CONFIG_MTD_DATAFLASH=y
+ CONFIG_MTD_NAND=y
+ CONFIG_MTD_NAND_ATMEL=y
+-CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
+ CONFIG_BLK_DEV_LOOP=y
+ # CONFIG_MISC_DEVICES is not set
+ CONFIG_SCSI=y
+diff --git a/arch/arm/configs/usb-a9260_defconfig b/arch/arm/configs/usb-a9260_defconfig
+index 2e39f38..a1501e1 100644
+--- a/arch/arm/configs/usb-a9260_defconfig
++++ b/arch/arm/configs/usb-a9260_defconfig
+@@ -49,7 +49,6 @@ CONFIG_MTD_BLOCK=y
+ CONFIG_MTD_DATAFLASH=y
+ CONFIG_MTD_NAND=y
+ CONFIG_MTD_NAND_ATMEL=y
+-CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
+ CONFIG_BLK_DEV_LOOP=y
+ # CONFIG_MISC_DEVICES is not set
+ CONFIG_SCSI=y
+diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
+index 7d17cec..0e43a3f 100644
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -366,46 +366,6 @@ config MTD_NAND_ATMEL
+ help
+ Enables support for NAND Flash / Smart Media Card interface
+ on Atmel AT91 and AVR32 processors.
+-choice
+- prompt "ECC management for NAND Flash / SmartMedia on AT91 / AVR32"
+- depends on MTD_NAND_ATMEL
+-
+-config MTD_NAND_ATMEL_ECC_HW
+- bool "Hardware ECC"
+- depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260 || AVR32
+- help
+- Use hardware ECC instead of software ECC when the chip
+- supports it.
+-
+- The hardware ECC controller is capable of single bit error
+- correction and 2-bit random detection per page.
+-
+- 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
+- Use software ECC.
+-
+- NB : hardware and software ECC schemes are incompatible.
+- If you switch from one to another, you'll have to erase your
+- mtd partition.
+-
+-config MTD_NAND_ATMEL_ECC_NONE
+- bool "No ECC (testing only, DANGEROUS)"
+- depends on DEBUG_KERNEL
+- help
+- No ECC will be used.
+- It's not a good idea and it should be reserved for testing
+- purpose only.
+-
+- If unsure, say N
+-
+-endchoice
+
+ config MTD_NAND_PXA3xx
+ tristate "Support for NAND flash devices on PXA3xx"
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0049-ARM-at91-fix-missing-interrupt-cells-on-gpio-control.patch b/patches.at91/0049-ARM-at91-fix-missing-interrupt-cells-on-gpio-control.patch
new file mode 100644
index 00000000000000..06db420f8ecdea
--- /dev/null
+++ b/patches.at91/0049-ARM-at91-fix-missing-interrupt-cells-on-gpio-control.patch
@@ -0,0 +1,207 @@
+From 567e6c4f49b1acf13d0e60ba9a6e1faa78f865a1 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Thu, 13 Sep 2012 12:40:26 +0200
+Subject: ARM: at91: fix missing #interrupt-cells on gpio-controller
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Tested-by: Bo Shen <voice.shen@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9260.dtsi | 3 +++
+ arch/arm/boot/dts/at91sam9263.dtsi | 5 +++++
+ arch/arm/boot/dts/at91sam9g45.dtsi | 5 +++++
+ arch/arm/boot/dts/at91sam9n12.dtsi | 4 ++++
+ arch/arm/boot/dts/at91sam9x5.dtsi | 4 ++++
+ 5 files changed, 21 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
+index f4605ff..eddc467 100644
+--- a/arch/arm/boot/dts/at91sam9260.dtsi
++++ b/arch/arm/boot/dts/at91sam9260.dtsi
+@@ -103,6 +103,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioB: gpio@fffff600 {
+@@ -112,6 +113,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioC: gpio@fffff800 {
+@@ -121,6 +123,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ dbgu: serial@fffff200 {
+diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
+index 0209913..d330de9 100644
+--- a/arch/arm/boot/dts/at91sam9263.dtsi
++++ b/arch/arm/boot/dts/at91sam9263.dtsi
+@@ -94,6 +94,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioB: gpio@fffff400 {
+@@ -103,6 +104,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioC: gpio@fffff600 {
+@@ -112,6 +114,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioD: gpio@fffff800 {
+@@ -121,6 +124,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioE: gpio@fffffa00 {
+@@ -130,6 +134,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ dbgu: serial@ffffee00 {
+diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
+index c804214..d1c497d 100644
+--- a/arch/arm/boot/dts/at91sam9g45.dtsi
++++ b/arch/arm/boot/dts/at91sam9g45.dtsi
+@@ -112,6 +112,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioB: gpio@fffff400 {
+@@ -121,6 +122,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioC: gpio@fffff600 {
+@@ -130,6 +132,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioD: gpio@fffff800 {
+@@ -139,6 +142,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioE: gpio@fffffa00 {
+@@ -148,6 +152,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ dbgu: serial@ffffee00 {
+diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
+index cb84de7..a69e89a 100644
+--- a/arch/arm/boot/dts/at91sam9n12.dtsi
++++ b/arch/arm/boot/dts/at91sam9n12.dtsi
+@@ -107,6 +107,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioB: gpio@fffff600 {
+@@ -116,6 +117,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioC: gpio@fffff800 {
+@@ -125,6 +127,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioD: gpio@fffffa00 {
+@@ -134,6 +137,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ dbgu: serial@fffff200 {
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index dd4ed74..80a50864 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -114,6 +114,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioB: gpio@fffff600 {
+@@ -123,6 +124,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioC: gpio@fffff800 {
+@@ -132,6 +134,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioD: gpio@fffffa00 {
+@@ -141,6 +144,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ dbgu: serial@fffff200 {
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0051-ARM-at91-missing-header-file-for-rtc-at91rm9200.c.patch b/patches.at91/0051-ARM-at91-missing-header-file-for-rtc-at91rm9200.c.patch
new file mode 100644
index 00000000000000..157177082280d2
--- /dev/null
+++ b/patches.at91/0051-ARM-at91-missing-header-file-for-rtc-at91rm9200.c.patch
@@ -0,0 +1,28 @@
+From d20929e0422398f34a241a11d9183fc7750c9f4e Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 19 Sep 2012 10:02:32 +0200
+Subject: ARM: at91: missing header file for rtc-at91rm9200.c
+
+Missing asm/io.h inclusion causing issue with __raw_readl and
+__raw_writel.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ drivers/rtc/rtc-at91rm9200.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
+index dc474bc..f02acb0 100644
+--- a/drivers/rtc/rtc-at91rm9200.c
++++ b/drivers/rtc/rtc-at91rm9200.c
+@@ -28,6 +28,7 @@
+ #include <linux/ioctl.h>
+ #include <linux/completion.h>
+
++#include <asm/io.h>
+ #include <asm/uaccess.h>
+
+ #include <mach/at91_rtc.h>
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0052-ASoC-atmel-ssc-include-linux-io.h-for-raw-io.patch b/patches.at91/0052-ASoC-atmel-ssc-include-linux-io.h-for-raw-io.patch
new file mode 100644
index 00000000000000..f5e8dcfeb5ac08
--- /dev/null
+++ b/patches.at91/0052-ASoC-atmel-ssc-include-linux-io.h-for-raw-io.patch
@@ -0,0 +1,37 @@
+From dc55ac7fd56dc3973d15f3a263b29ce222715771 Mon Sep 17 00:00:00 2001
+From: Joachim Eastwood <manabian@gmail.com>
+Date: Thu, 23 Aug 2012 18:14:54 +0200
+Subject: ASoC: atmel-ssc: include linux/io.h for raw io
+
+Include linux/io.h for raw io operations in atmel-scc header.
+
+This fixes the following build error:
+ CC [M] sound/soc/atmel/atmel_ssc_dai.o
+sound/soc/atmel/atmel_ssc_dai.c: In function 'atmel_ssc_interrupt':
+sound/soc/atmel/atmel_ssc_dai.c:171: error: implicit declaration of function '__raw_readl'
+sound/soc/atmel/atmel_ssc_dai.c: In function 'atmel_ssc_shutdown':
+sound/soc/atmel/atmel_ssc_dai.c:249: error: implicit declaration of function '__raw_writel'
+
+Signed-off-by: Joachim Eastwood <joachim.eastwood@jotron.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+---
+ include/linux/atmel-ssc.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/include/linux/atmel-ssc.h b/include/linux/atmel-ssc.h
+index 0602339..4eb3175 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 <linux/io.h>
+
+ struct ssc_device {
+ struct list_head list;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0053-ARM-at91-aic-can-use-fast-eoi-handler-type.patch b/patches.at91/0053-ARM-at91-aic-can-use-fast-eoi-handler-type.patch
new file mode 100644
index 00000000000000..6003ca8075efdc
--- /dev/null
+++ b/patches.at91/0053-ARM-at91-aic-can-use-fast-eoi-handler-type.patch
@@ -0,0 +1,158 @@
+From adc32a9ee5875fe4c0da12b676b38c696d95437c Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Fri, 25 May 2012 14:11:51 +0200
+Subject: ARM: at91: aic can use fast eoi handler type
+
+The Advanced Interrupt Controller allows us to use the fast EOI handler type.
+It lets us remove the Atmel specific workaround into arch/arm/kernel/irq.c
+used to indicate to the AIC the end of the interrupt treatment.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Will Deacon <will.deacon@arm.com>
+---
+ arch/arm/kernel/irq.c | 10 ----------
+ arch/arm/mach-at91/gpio.c | 9 +++++----
+ arch/arm/mach-at91/include/mach/irqs.h | 7 -------
+ arch/arm/mach-at91/irq.c | 15 ++++++++++++---
+ 4 files changed, 17 insertions(+), 24 deletions(-)
+
+diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
+index 8349d4e..16cedb4 100644
+--- a/arch/arm/kernel/irq.c
++++ b/arch/arm/kernel/irq.c
+@@ -40,13 +40,6 @@
+ #include <asm/mach/irq.h>
+ #include <asm/mach/time.h>
+
+-/*
+- * No architecture-specific irq_finish function defined in arm/arch/irqs.h.
+- */
+-#ifndef irq_finish
+-#define irq_finish(irq) do { } while (0)
+-#endif
+-
+ unsigned long irq_err_count;
+
+ int arch_show_interrupts(struct seq_file *p, int prec)
+@@ -85,9 +78,6 @@ void handle_IRQ(unsigned int irq, struct pt_regs *regs)
+ generic_handle_irq(irq);
+ }
+
+- /* AT91 specific workaround */
+- irq_finish(irq);
+-
+ irq_exit();
+ set_irq_regs(old_regs);
+ }
+diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
+index 325837a..be42cf0 100644
+--- a/arch/arm/mach-at91/gpio.c
++++ b/arch/arm/mach-at91/gpio.c
+@@ -26,6 +26,8 @@
+ #include <linux/of_irq.h>
+ #include <linux/of_gpio.h>
+
++#include <asm/mach/irq.h>
++
+ #include <mach/hardware.h>
+ #include <mach/at91_pio.h>
+
+@@ -585,15 +587,14 @@ static struct irq_chip gpio_irqchip = {
+
+ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+ {
++ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct irq_data *idata = irq_desc_get_irq_data(desc);
+- struct irq_chip *chip = irq_data_get_irq_chip(idata);
+ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(idata);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned long isr;
+ int n;
+
+- /* temporarily mask (level sensitive) parent IRQ */
+- chip->irq_ack(idata);
++ chained_irq_enter(chip, desc);
+ for (;;) {
+ /* Reading ISR acks pending (edge triggered) GPIO interrupts.
+ * When there none are pending, we're finished unless we need
+@@ -614,7 +615,7 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+ n = find_next_bit(&isr, BITS_PER_LONG, n + 1);
+ }
+ }
+- chip->irq_unmask(idata);
++ chained_irq_exit(chip, desc);
+ /* now it may re-trigger */
+ }
+
+diff --git a/arch/arm/mach-at91/include/mach/irqs.h b/arch/arm/mach-at91/include/mach/irqs.h
+index ac8b7df..2d510ee 100644
+--- a/arch/arm/mach-at91/include/mach/irqs.h
++++ b/arch/arm/mach-at91/include/mach/irqs.h
+@@ -28,13 +28,6 @@
+
+
+ /*
+- * Acknowledge interrupt with AIC after interrupt has been handled.
+- * (by kernel/irq.c)
+- */
+-#define irq_finish(irq) do { at91_aic_write(AT91_AIC_EOICR, 0); } while (0)
+-
+-
+-/*
+ * IRQ interrupt symbols are the AT91xxx_ID_* symbols
+ * for IRQs handled directly through the AIC, or else the AT91_PIN_*
+ * symbols in gpio.h for ones handled indirectly as GPIOs.
+diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
+index cfcfcbe..2d5d4c8 100644
+--- a/arch/arm/mach-at91/irq.c
++++ b/arch/arm/mach-at91/irq.c
+@@ -55,6 +55,15 @@ static void at91_aic_unmask_irq(struct irq_data *d)
+ at91_aic_write(AT91_AIC_IECR, 1 << d->hwirq);
+ }
+
++static void at91_aic_eoi(struct irq_data *d)
++{
++ /*
++ * Mark end-of-interrupt on AIC, the controller doesn't care about
++ * the value written. Moreover it's a write-only register.
++ */
++ at91_aic_write(AT91_AIC_EOICR, 0);
++}
++
+ unsigned int at91_extern_irq;
+
+ #define is_extern_irq(hwirq) ((1 << (hwirq)) & at91_extern_irq)
+@@ -128,11 +137,11 @@ void at91_irq_resume(void)
+
+ static struct irq_chip at91_aic_chip = {
+ .name = "AIC",
+- .irq_ack = at91_aic_mask_irq,
+ .irq_mask = at91_aic_mask_irq,
+ .irq_unmask = at91_aic_unmask_irq,
+ .irq_set_type = at91_aic_set_type,
+ .irq_set_wake = at91_aic_set_wake,
++ .irq_eoi = at91_aic_eoi,
+ };
+
+ static void __init at91_aic_hw_init(unsigned int spu_vector)
+@@ -171,7 +180,7 @@ static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
+ /* Active Low interrupt, without priority */
+ at91_aic_write(AT91_AIC_SMR(hw), AT91_AIC_SRCTYPE_LOW);
+
+- irq_set_chip_and_handler(virq, &at91_aic_chip, handle_level_irq);
++ irq_set_chip_and_handler(virq, &at91_aic_chip, handle_fasteoi_irq);
+ set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
+
+ return 0;
+@@ -238,7 +247,7 @@ void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
+ /* Active Low interrupt, with the specified priority */
+ at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
+
+- irq_set_chip_and_handler(i, &at91_aic_chip, handle_level_irq);
++ irq_set_chip_and_handler(i, &at91_aic_chip, handle_fasteoi_irq);
+ set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+ }
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0054-ARM-at91-aic-add-dt-support-for-external-irqs.patch b/patches.at91/0054-ARM-at91-aic-add-dt-support-for-external-irqs.patch
new file mode 100644
index 00000000000000..4850ef400ae862
--- /dev/null
+++ b/patches.at91/0054-ARM-at91-aic-add-dt-support-for-external-irqs.patch
@@ -0,0 +1,122 @@
+From 6591d7a4f331b00fa020ef27b367239854944459 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Mon, 9 Apr 2012 19:36:36 +0800
+Subject: ARM: at91: aic add dt support for external irqs
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ Documentation/devicetree/bindings/arm/atmel-aic.txt | 1 +
+ arch/arm/boot/dts/at91sam9260.dtsi | 1 +
+ arch/arm/boot/dts/at91sam9263.dtsi | 1 +
+ arch/arm/boot/dts/at91sam9g45.dtsi | 1 +
+ arch/arm/boot/dts/at91sam9x5.dtsi | 1 +
+ arch/arm/mach-at91/at91sam9x5.c | 2 --
+ arch/arm/mach-at91/irq.c | 12 ++++++++++++
+ 7 files changed, 17 insertions(+), 2 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/arm/atmel-aic.txt b/Documentation/devicetree/bindings/arm/atmel-aic.txt
+index aabca4f..1953b0c 100644
+--- a/Documentation/devicetree/bindings/arm/atmel-aic.txt
++++ b/Documentation/devicetree/bindings/arm/atmel-aic.txt
+@@ -15,6 +15,7 @@ Required properties:
+ Valid combinations are 1, 2, 3, 4, 8.
+ Default flag for internal sources should be set to 4 (active high).
+ - reg: Should contain AIC registers location and length
++- atmel,external-irqs: u32 array of external irqs.
+
+ Examples:
+ /*
+diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
+index eddc467..fb86de0 100644
+--- a/arch/arm/boot/dts/at91sam9260.dtsi
++++ b/arch/arm/boot/dts/at91sam9260.dtsi
+@@ -56,6 +56,7 @@
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
++ atmel,external-irqs = <29 30 31>;
+ };
+
+ ramc0: ramc@ffffea00 {
+diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
+index d330de9..78b2808 100644
+--- a/arch/arm/boot/dts/at91sam9263.dtsi
++++ b/arch/arm/boot/dts/at91sam9263.dtsi
+@@ -52,6 +52,7 @@
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
++ atmel,external-irqs = <30 31>;
+ };
+
+ pmc: pmc@fffffc00 {
+diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
+index d1c497d..779ffca 100644
+--- a/arch/arm/boot/dts/at91sam9g45.dtsi
++++ b/arch/arm/boot/dts/at91sam9g45.dtsi
+@@ -57,6 +57,7 @@
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
++ atmel,external-irqs = <31>;
+ };
+
+ ramc0: ramc@ffffe400 {
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 80a50864..170b6f8 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -55,6 +55,7 @@
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
++ atmel,external-irqs = <31>;
+ };
+
+ ramc0: ramc@ffffe800 {
+diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
+index 13c8cae..dce3ff3 100644
+--- a/arch/arm/mach-at91/at91sam9x5.c
++++ b/arch/arm/mach-at91/at91sam9x5.c
+@@ -306,8 +306,6 @@ static void __init at91sam9x5_map_io(void)
+
+ void __init at91sam9x5_initialize(void)
+ {
+- at91_extern_irq = (1 << AT91SAM9X5_ID_IRQ0);
+-
+ /* Register GPIO subsystem (using DT) */
+ at91_gpio_init(NULL, 0);
+ }
+diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
+index 2d5d4c8..df8605f 100644
+--- a/arch/arm/mach-at91/irq.c
++++ b/arch/arm/mach-at91/irq.c
+@@ -194,6 +194,10 @@ static struct irq_domain_ops at91_aic_irq_ops = {
+ int __init at91_aic_of_init(struct device_node *node,
+ struct device_node *parent)
+ {
++ struct property *prop;
++ const __be32 *p;
++ u32 val;
++
+ at91_aic_base = of_iomap(node, 0);
+ at91_aic_np = node;
+
+@@ -202,6 +206,14 @@ int __init at91_aic_of_init(struct device_node *node,
+ if (!at91_aic_domain)
+ panic("Unable to add AIC irq domain (DT)\n");
+
++ at91_extern_irq = 0;
++ of_property_for_each_u32(node, "atmel,external-irqs", prop, p, val) {
++ if (val > 31)
++ pr_warn("AIC: external irq %d > 31 skip it\n", val);
++ else
++ at91_extern_irq |= (1 << val);
++ }
++
+ irq_set_default_host(at91_aic_domain);
+
+ at91_aic_hw_init(NR_AIC_IRQS);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0055-ARM-at91-add-of-irq-priorities-support.patch b/patches.at91/0055-ARM-at91-add-of-irq-priorities-support.patch
new file mode 100644
index 00000000000000..ed2769e343edb5
--- /dev/null
+++ b/patches.at91/0055-ARM-at91-add-of-irq-priorities-support.patch
@@ -0,0 +1,883 @@
+From 2e9f08703ba386c61ee33e8a7018ef12c361b463 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 20 Jun 2012 16:13:30 +0200
+Subject: ARM: at91: add of irq priorities support
+
+Add a third cell to define irq priority.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Reviewed-by: Rob Herring <rob.herring@calxeda.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+
+Conflicts:
+ arch/arm/boot/dts/at91sam9260.dtsi
+ arch/arm/boot/dts/at91sam9g45.dtsi
+ arch/arm/boot/dts/at91sam9x5.dtsi
+---
+ .../devicetree/bindings/arm/atmel-aic.txt | 8 +++--
+ arch/arm/boot/dts/at91sam9260.dtsi | 34 ++++++++++----------
+ arch/arm/boot/dts/at91sam9263.dtsi | 30 +++++++++---------
+ arch/arm/boot/dts/at91sam9g45.dtsi | 36 +++++++++++-----------
+ arch/arm/boot/dts/at91sam9n12.dtsi | 30 +++++++++---------
+ arch/arm/boot/dts/at91sam9x5.dtsi | 36 +++++++++++-----------
+ arch/arm/mach-at91/include/mach/at91_aic.h | 3 ++
+ arch/arm/mach-at91/irq.c | 34 ++++++++++++++++++--
+ 8 files changed, 122 insertions(+), 89 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/arm/atmel-aic.txt b/Documentation/devicetree/bindings/arm/atmel-aic.txt
+index 1953b0c..19078bf 100644
+--- a/Documentation/devicetree/bindings/arm/atmel-aic.txt
++++ b/Documentation/devicetree/bindings/arm/atmel-aic.txt
+@@ -4,7 +4,7 @@ Required properties:
+ - compatible: Should be "atmel,<chip>-aic"
+ - interrupt-controller: Identifies the node as an interrupt controller.
+ - interrupt-parent: For single AIC system, it is an empty property.
+-- #interrupt-cells: The number of cells to define the interrupts. It sould be 2.
++- #interrupt-cells: The number of cells to define the interrupts. It sould be 3.
+ The first cell is the IRQ number (aka "Peripheral IDentifier" on datasheet).
+ The second cell is used to specify flags:
+ bits[3:0] trigger type and level flags:
+@@ -14,6 +14,8 @@ Required properties:
+ 8 = active low level-sensitive.
+ Valid combinations are 1, 2, 3, 4, 8.
+ Default flag for internal sources should be set to 4 (active high).
++ The third cell is used to specify the irq priority from 0 (lowest) to 7
++ (highest).
+ - reg: Should contain AIC registers location and length
+ - atmel,external-irqs: u32 array of external irqs.
+
+@@ -25,7 +27,7 @@ Examples:
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ interrupt-parent;
+- #interrupt-cells = <2>;
++ #interrupt-cells = <3>;
+ reg = <0xfffff000 0x200>;
+ };
+
+@@ -35,5 +37,5 @@ Examples:
+ dma: dma-controller@ffffec00 {
+ compatible = "atmel,at91sam9g45-dma";
+ reg = <0xffffec00 0x200>;
+- interrupts = <21 4>;
++ interrupts = <21 4 5>;
+ };
+diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
+index fb86de0..12df8ca 100644
+--- a/arch/arm/boot/dts/at91sam9260.dtsi
++++ b/arch/arm/boot/dts/at91sam9260.dtsi
+@@ -52,7 +52,7 @@
+ ranges;
+
+ aic: interrupt-controller@fffff000 {
+- #interrupt-cells = <2>;
++ #interrupt-cells = <3>;
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
+@@ -82,25 +82,25 @@
+ pit: timer@fffffd30 {
+ compatible = "atmel,at91sam9260-pit";
+ reg = <0xfffffd30 0xf>;
+- interrupts = <1 4>;
++ interrupts = <1 4 7>;
+ };
+
+ tcb0: timer@fffa0000 {
+ compatible = "atmel,at91rm9200-tcb";
+ reg = <0xfffa0000 0x100>;
+- interrupts = <17 4 18 4 19 4>;
++ interrupts = <17 4 0 18 4 0 19 4 0>;
+ };
+
+ tcb1: timer@fffdc000 {
+ compatible = "atmel,at91rm9200-tcb";
+ reg = <0xfffdc000 0x100>;
+- interrupts = <26 4 27 4 28 4>;
++ interrupts = <26 4 0 27 4 0 28 4 0>;
+ };
+
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x100>;
+- interrupts = <2 4>;
++ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -110,7 +110,7 @@
+ pioB: gpio@fffff600 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff600 0x100>;
+- interrupts = <3 4>;
++ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -120,7 +120,7 @@
+ pioC: gpio@fffff800 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff800 0x100>;
+- interrupts = <4 4>;
++ interrupts = <4 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -130,14 +130,14 @@
+ dbgu: serial@fffff200 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffff200 0x200>;
+- interrupts = <1 4>;
++ interrupts = <1 4 7>;
+ status = "disabled";
+ };
+
+ usart0: serial@fffb0000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffb0000 0x200>;
+- interrupts = <6 4>;
++ interrupts = <6 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -146,7 +146,7 @@
+ usart1: serial@fffb4000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffb4000 0x200>;
+- interrupts = <7 4>;
++ interrupts = <7 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -155,7 +155,7 @@
+ usart2: serial@fffb8000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffb8000 0x200>;
+- interrupts = <8 4>;
++ interrupts = <8 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -164,7 +164,7 @@
+ usart3: serial@fffd0000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffd0000 0x200>;
+- interrupts = <23 4>;
++ interrupts = <23 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -173,7 +173,7 @@
+ usart4: serial@fffd4000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffd4000 0x200>;
+- interrupts = <24 4>;
++ interrupts = <24 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -182,7 +182,7 @@
+ usart5: serial@fffd8000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffd8000 0x200>;
+- interrupts = <25 4>;
++ interrupts = <25 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -191,14 +191,14 @@
+ macb0: ethernet@fffc4000 {
+ compatible = "cdns,at32ap7000-macb", "cdns,macb";
+ reg = <0xfffc4000 0x100>;
+- interrupts = <21 4>;
++ interrupts = <21 4 3>;
+ status = "disabled";
+ };
+
+ usb1: gadget@fffa4000 {
+ compatible = "atmel,at91rm9200-udc";
+ reg = <0xfffa4000 0x4000>;
+- interrupts = <10 4>;
++ interrupts = <10 4 2>;
+ status = "disabled";
+ };
+ };
+@@ -222,7 +222,7 @@
+ usb0: ohci@00500000 {
+ compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+ reg = <0x00500000 0x100000>;
+- interrupts = <20 4>;
++ interrupts = <20 4 2>;
+ status = "disabled";
+ };
+ };
+diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
+index 78b2808..195019b 100644
+--- a/arch/arm/boot/dts/at91sam9263.dtsi
++++ b/arch/arm/boot/dts/at91sam9263.dtsi
+@@ -48,7 +48,7 @@
+ ranges;
+
+ aic: interrupt-controller@fffff000 {
+- #interrupt-cells = <2>;
++ #interrupt-cells = <3>;
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
+@@ -69,13 +69,13 @@
+ pit: timer@fffffd30 {
+ compatible = "atmel,at91sam9260-pit";
+ reg = <0xfffffd30 0xf>;
+- interrupts = <1 4>;
++ interrupts = <1 4 7>;
+ };
+
+ tcb0: timer@fff7c000 {
+ compatible = "atmel,at91rm9200-tcb";
+ reg = <0xfff7c000 0x100>;
+- interrupts = <19 4>;
++ interrupts = <19 4 0>;
+ };
+
+ rstc@fffffd00 {
+@@ -91,7 +91,7 @@
+ pioA: gpio@fffff200 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff200 0x100>;
+- interrupts = <2 4>;
++ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -101,7 +101,7 @@
+ pioB: gpio@fffff400 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x100>;
+- interrupts = <3 4>;
++ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -111,7 +111,7 @@
+ pioC: gpio@fffff600 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff600 0x100>;
+- interrupts = <4 4>;
++ interrupts = <4 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -121,7 +121,7 @@
+ pioD: gpio@fffff800 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff800 0x100>;
+- interrupts = <4 4>;
++ interrupts = <4 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -131,7 +131,7 @@
+ pioE: gpio@fffffa00 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffffa00 0x100>;
+- interrupts = <4 4>;
++ interrupts = <4 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -141,14 +141,14 @@
+ dbgu: serial@ffffee00 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xffffee00 0x200>;
+- interrupts = <1 4>;
++ interrupts = <1 4 7>;
+ status = "disabled";
+ };
+
+ usart0: serial@fff8c000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfff8c000 0x200>;
+- interrupts = <7 4>;
++ interrupts = <7 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -157,7 +157,7 @@
+ usart1: serial@fff90000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfff90000 0x200>;
+- interrupts = <8 4>;
++ interrupts = <8 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -166,7 +166,7 @@
+ usart2: serial@fff94000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfff94000 0x200>;
+- interrupts = <9 4>;
++ interrupts = <9 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -175,14 +175,14 @@
+ macb0: ethernet@fffbc000 {
+ compatible = "cdns,at32ap7000-macb", "cdns,macb";
+ reg = <0xfffbc000 0x100>;
+- interrupts = <21 4>;
++ interrupts = <21 4 3>;
+ status = "disabled";
+ };
+
+ usb1: gadget@fff78000 {
+ compatible = "atmel,at91rm9200-udc";
+ reg = <0xfff78000 0x4000>;
+- interrupts = <24 4>;
++ interrupts = <24 4 2>;
+ status = "disabled";
+ };
+ };
+@@ -206,7 +206,7 @@
+ usb0: ohci@00a00000 {
+ compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+ reg = <0x00a00000 0x100000>;
+- interrupts = <29 4>;
++ interrupts = <29 4 2>;
+ status = "disabled";
+ };
+ };
+diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
+index 779ffca..6a3ed54 100644
+--- a/arch/arm/boot/dts/at91sam9g45.dtsi
++++ b/arch/arm/boot/dts/at91sam9g45.dtsi
+@@ -53,7 +53,7 @@
+ ranges;
+
+ aic: interrupt-controller@fffff000 {
+- #interrupt-cells = <2>;
++ #interrupt-cells = <3>;
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
+@@ -79,7 +79,7 @@
+ pit: timer@fffffd30 {
+ compatible = "atmel,at91sam9260-pit";
+ reg = <0xfffffd30 0xf>;
+- interrupts = <1 4>;
++ interrupts = <1 4 7>;
+ };
+
+
+@@ -91,25 +91,25 @@
+ tcb0: timer@fff7c000 {
+ compatible = "atmel,at91rm9200-tcb";
+ reg = <0xfff7c000 0x100>;
+- interrupts = <18 4>;
++ interrupts = <18 4 0>;
+ };
+
+ tcb1: timer@fffd4000 {
+ compatible = "atmel,at91rm9200-tcb";
+ reg = <0xfffd4000 0x100>;
+- interrupts = <18 4>;
++ interrupts = <18 4 0>;
+ };
+
+ dma: dma-controller@ffffec00 {
+ compatible = "atmel,at91sam9g45-dma";
+ reg = <0xffffec00 0x200>;
+- interrupts = <21 4>;
++ interrupts = <21 4 0>;
+ };
+
+ pioA: gpio@fffff200 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff200 0x100>;
+- interrupts = <2 4>;
++ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -119,7 +119,7 @@
+ pioB: gpio@fffff400 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x100>;
+- interrupts = <3 4>;
++ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -129,7 +129,7 @@
+ pioC: gpio@fffff600 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff600 0x100>;
+- interrupts = <4 4>;
++ interrupts = <4 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -139,7 +139,7 @@
+ pioD: gpio@fffff800 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff800 0x100>;
+- interrupts = <5 4>;
++ interrupts = <5 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -149,7 +149,7 @@
+ pioE: gpio@fffffa00 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffffa00 0x100>;
+- interrupts = <5 4>;
++ interrupts = <5 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -159,14 +159,14 @@
+ dbgu: serial@ffffee00 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xffffee00 0x200>;
+- interrupts = <1 4>;
++ interrupts = <1 4 7>;
+ status = "disabled";
+ };
+
+ usart0: serial@fff8c000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfff8c000 0x200>;
+- interrupts = <7 4>;
++ interrupts = <7 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -175,7 +175,7 @@
+ usart1: serial@fff90000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfff90000 0x200>;
+- interrupts = <8 4>;
++ interrupts = <8 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -184,7 +184,7 @@
+ usart2: serial@fff94000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfff94000 0x200>;
+- interrupts = <9 4>;
++ interrupts = <9 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -193,7 +193,7 @@
+ usart3: serial@fff98000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfff98000 0x200>;
+- interrupts = <10 4>;
++ interrupts = <10 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -202,7 +202,7 @@
+ macb0: ethernet@fffbc000 {
+ compatible = "cdns,at32ap7000-macb", "cdns,macb";
+ reg = <0xfffbc000 0x100>;
+- interrupts = <25 4>;
++ interrupts = <25 4 3>;
+ status = "disabled";
+ };
+ };
+@@ -226,14 +226,14 @@
+ usb0: ohci@00700000 {
+ compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+ reg = <0x00700000 0x100000>;
+- interrupts = <22 4>;
++ interrupts = <22 4 2>;
+ status = "disabled";
+ };
+
+ usb1: ehci@00800000 {
+ compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
+ reg = <0x00800000 0x100000>;
+- interrupts = <22 4>;
++ interrupts = <22 4 2>;
+ status = "disabled";
+ };
+ };
+diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
+index a69e89a..ef9336a 100644
+--- a/arch/arm/boot/dts/at91sam9n12.dtsi
++++ b/arch/arm/boot/dts/at91sam9n12.dtsi
+@@ -50,7 +50,7 @@
+ ranges;
+
+ aic: interrupt-controller@fffff000 {
+- #interrupt-cells = <2>;
++ #interrupt-cells = <3>;
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
+@@ -74,7 +74,7 @@
+ pit: timer@fffffe30 {
+ compatible = "atmel,at91sam9260-pit";
+ reg = <0xfffffe30 0xf>;
+- interrupts = <1 4>;
++ interrupts = <1 4 7>;
+ };
+
+ shdwc@fffffe10 {
+@@ -85,25 +85,25 @@
+ tcb0: timer@f8008000 {
+ compatible = "atmel,at91sam9x5-tcb";
+ reg = <0xf8008000 0x100>;
+- interrupts = <17 4>;
++ interrupts = <17 4 0>;
+ };
+
+ tcb1: timer@f800c000 {
+ compatible = "atmel,at91sam9x5-tcb";
+ reg = <0xf800c000 0x100>;
+- interrupts = <17 4>;
++ interrupts = <17 4 0>;
+ };
+
+ dma: dma-controller@ffffec00 {
+ compatible = "atmel,at91sam9g45-dma";
+ reg = <0xffffec00 0x200>;
+- interrupts = <20 4>;
++ interrupts = <20 4 0>;
+ };
+
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x100>;
+- interrupts = <2 4>;
++ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -113,7 +113,7 @@
+ pioB: gpio@fffff600 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff600 0x100>;
+- interrupts = <2 4>;
++ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -123,7 +123,7 @@
+ pioC: gpio@fffff800 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff800 0x100>;
+- interrupts = <3 4>;
++ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -133,7 +133,7 @@
+ pioD: gpio@fffffa00 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffffa00 0x100>;
+- interrupts = <3 4>;
++ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -143,14 +143,14 @@
+ dbgu: serial@fffff200 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffff200 0x200>;
+- interrupts = <1 4>;
++ interrupts = <1 4 7>;
+ status = "disabled";
+ };
+
+ usart0: serial@f801c000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf801c000 0x4000>;
+- interrupts = <5 4>;
++ interrupts = <5 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -159,7 +159,7 @@
+ usart1: serial@f8020000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf8020000 0x4000>;
+- interrupts = <6 4>;
++ interrupts = <6 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -168,7 +168,7 @@
+ usart2: serial@f8024000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf8024000 0x4000>;
+- interrupts = <7 4>;
++ interrupts = <7 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -177,7 +177,7 @@
+ usart3: serial@f8028000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf8028000 0x4000>;
+- interrupts = <8 4>;
++ interrupts = <8 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -205,7 +205,7 @@
+ usb0: ohci@00500000 {
+ compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+ reg = <0x00500000 0x00100000>;
+- interrupts = <22 4>;
++ interrupts = <22 4 2>;
+ status = "disabled";
+ };
+ };
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 170b6f8..fc38d21 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -51,7 +51,7 @@
+ ranges;
+
+ aic: interrupt-controller@fffff000 {
+- #interrupt-cells = <2>;
++ #interrupt-cells = <3>;
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
+@@ -81,37 +81,37 @@
+ pit: timer@fffffe30 {
+ compatible = "atmel,at91sam9260-pit";
+ reg = <0xfffffe30 0xf>;
+- interrupts = <1 4>;
++ interrupts = <1 4 7>;
+ };
+
+ tcb0: timer@f8008000 {
+ compatible = "atmel,at91sam9x5-tcb";
+ reg = <0xf8008000 0x100>;
+- interrupts = <17 4>;
++ interrupts = <17 4 0>;
+ };
+
+ tcb1: timer@f800c000 {
+ compatible = "atmel,at91sam9x5-tcb";
+ reg = <0xf800c000 0x100>;
+- interrupts = <17 4>;
++ interrupts = <17 4 0>;
+ };
+
+ dma0: dma-controller@ffffec00 {
+ compatible = "atmel,at91sam9g45-dma";
+ reg = <0xffffec00 0x200>;
+- interrupts = <20 4>;
++ interrupts = <20 4 0>;
+ };
+
+ dma1: dma-controller@ffffee00 {
+ compatible = "atmel,at91sam9g45-dma";
+ reg = <0xffffee00 0x200>;
+- interrupts = <21 4>;
++ interrupts = <21 4 0>;
+ };
+
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x100>;
+- interrupts = <2 4>;
++ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -121,7 +121,7 @@
+ pioB: gpio@fffff600 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff600 0x100>;
+- interrupts = <2 4>;
++ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -131,7 +131,7 @@
+ pioC: gpio@fffff800 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff800 0x100>;
+- interrupts = <3 4>;
++ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -141,7 +141,7 @@
+ pioD: gpio@fffffa00 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffffa00 0x100>;
+- interrupts = <3 4>;
++ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -151,14 +151,14 @@
+ dbgu: serial@fffff200 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffff200 0x200>;
+- interrupts = <1 4>;
++ interrupts = <1 4 7>;
+ status = "disabled";
+ };
+
+ usart0: serial@f801c000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf801c000 0x200>;
+- interrupts = <5 4>;
++ interrupts = <5 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -167,7 +167,7 @@
+ usart1: serial@f8020000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf8020000 0x200>;
+- interrupts = <6 4>;
++ interrupts = <6 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -176,7 +176,7 @@
+ usart2: serial@f8024000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf8024000 0x200>;
+- interrupts = <7 4>;
++ interrupts = <7 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -185,14 +185,14 @@
+ macb0: ethernet@f802c000 {
+ compatible = "cdns,at32ap7000-macb", "cdns,macb";
+ reg = <0xf802c000 0x100>;
+- interrupts = <24 4>;
++ interrupts = <24 4 3>;
+ status = "disabled";
+ };
+
+ macb1: ethernet@f8030000 {
+ compatible = "cdns,at32ap7000-macb", "cdns,macb";
+ reg = <0xf8030000 0x100>;
+- interrupts = <27 4>;
++ interrupts = <27 4 3>;
+ status = "disabled";
+ };
+ };
+@@ -215,14 +215,14 @@
+ usb0: ohci@00600000 {
+ compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+ reg = <0x00600000 0x100000>;
+- interrupts = <22 4>;
++ interrupts = <22 4 2>;
+ status = "disabled";
+ };
+
+ usb1: ehci@00700000 {
+ compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
+ reg = <0x00700000 0x100000>;
+- interrupts = <22 4>;
++ interrupts = <22 4 2>;
+ status = "disabled";
+ };
+ };
+diff --git a/arch/arm/mach-at91/include/mach/at91_aic.h b/arch/arm/mach-at91/include/mach/at91_aic.h
+index c1413ed..3af7272 100644
+--- a/arch/arm/mach-at91/include/mach/at91_aic.h
++++ b/arch/arm/mach-at91/include/mach/at91_aic.h
+@@ -28,6 +28,9 @@ extern void __iomem *at91_aic_base;
+ .extern at91_aic_base
+ #endif
+
++#define AT91_AIC_IRQ_MIN_PRIORITY 0
++#define AT91_AIC_IRQ_MAX_PRIORITY 7
++
+ #define AT91_AIC_SMR(n) ((n) * 4) /* Source Mode Registers 0-31 */
+ #define AT91_AIC_PRIOR (7 << 0) /* Priority Level */
+ #define AT91_AIC_SRCTYPE (3 << 5) /* Interrupt Source Type */
+diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
+index df8605f..db8e141 100644
+--- a/arch/arm/mach-at91/irq.c
++++ b/arch/arm/mach-at91/irq.c
+@@ -30,6 +30,7 @@
+ #include <linux/of_irq.h>
+ #include <linux/irqdomain.h>
+ #include <linux/err.h>
++#include <linux/slab.h>
+
+ #include <mach/hardware.h>
+ #include <asm/irq.h>
+@@ -42,6 +43,7 @@
+ void __iomem *at91_aic_base;
+ static struct irq_domain *at91_aic_domain;
+ static struct device_node *at91_aic_np;
++static unsigned int *at91_aic_irq_priorities;
+
+ static void at91_aic_mask_irq(struct irq_data *d)
+ {
+@@ -177,8 +179,9 @@ static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
+ /* Put virq number in Source Vector Register */
+ at91_aic_write(AT91_AIC_SVR(hw), virq);
+
+- /* Active Low interrupt, without priority */
+- at91_aic_write(AT91_AIC_SMR(hw), AT91_AIC_SRCTYPE_LOW);
++ /* Active Low interrupt, with priority */
++ at91_aic_write(AT91_AIC_SMR(hw),
++ AT91_AIC_SRCTYPE_LOW | at91_aic_irq_priorities[hw]);
+
+ irq_set_chip_and_handler(virq, &at91_aic_chip, handle_fasteoi_irq);
+ set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
+@@ -186,9 +189,28 @@ static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
+ return 0;
+ }
+
++static int at91_aic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
++ const u32 *intspec, unsigned int intsize,
++ irq_hw_number_t *out_hwirq, unsigned int *out_type)
++{
++ if (WARN_ON(intsize < 3))
++ return -EINVAL;
++ if (WARN_ON(intspec[0] >= NR_AIC_IRQS))
++ return -EINVAL;
++ if (WARN_ON((intspec[2] < AT91_AIC_IRQ_MIN_PRIORITY)
++ || (intspec[2] > AT91_AIC_IRQ_MAX_PRIORITY)))
++ return -EINVAL;
++
++ *out_hwirq = intspec[0];
++ *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
++ at91_aic_irq_priorities[*out_hwirq] = intspec[2];
++
++ return 0;
++}
++
+ static struct irq_domain_ops at91_aic_irq_ops = {
+ .map = at91_aic_irq_map,
+- .xlate = irq_domain_xlate_twocell,
++ .xlate = at91_aic_irq_domain_xlate,
+ };
+
+ int __init at91_aic_of_init(struct device_node *node,
+@@ -198,6 +220,12 @@ int __init at91_aic_of_init(struct device_node *node,
+ const __be32 *p;
+ u32 val;
+
++ at91_aic_irq_priorities = kzalloc(NR_AIC_IRQS
++ * sizeof(*at91_aic_irq_priorities),
++ GFP_KERNEL);
++ if (!at91_aic_irq_priorities)
++ return -ENOMEM;
++
+ at91_aic_base = of_iomap(node, 0);
+ at91_aic_np = node;
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0056-ARM-at91-remove-static-irq-priorities-for-sam9x5.patch b/patches.at91/0056-ARM-at91-remove-static-irq-priorities-for-sam9x5.patch
new file mode 100644
index 00000000000000..395295b3151bb4
--- /dev/null
+++ b/patches.at91/0056-ARM-at91-remove-static-irq-priorities-for-sam9x5.patch
@@ -0,0 +1,69 @@
+From 253f40569228efcd947997772f9e913aef4e8dec Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Fri, 22 Jun 2012 11:41:34 +0200
+Subject: ARM: at91: remove static irq priorities for sam9x5
+
+Since irq priorites are managed in DT, static ones are no more required for
+sam9x5 which only has DT support.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/at91sam9x5.c | 38 --------------------------------------
+ 1 file changed, 38 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
+index dce3ff3..c949dc7 100644
+--- a/arch/arm/mach-at91/at91sam9x5.c
++++ b/arch/arm/mach-at91/at91sam9x5.c
+@@ -313,47 +313,9 @@ void __init at91sam9x5_initialize(void)
+ /* --------------------------------------------------------------------
+ * 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) */
+-};
+
+ struct at91_init_soc __initdata at91sam9x5_soc = {
+ .map_io = at91sam9x5_map_io,
+- .default_irq_priority = at91sam9x5_default_irq_priority,
+ .register_clocks = at91sam9x5_register_clocks,
+ .init = at91sam9x5_initialize,
+ };
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0057-ARM-at91-at91-based-machines-specify-their-own-irq-h.patch b/patches.at91/0057-ARM-at91-at91-based-machines-specify-their-own-irq-h.patch
new file mode 100644
index 00000000000000..a02a21ce88c4bd
--- /dev/null
+++ b/patches.at91/0057-ARM-at91-at91-based-machines-specify-their-own-irq-h.patch
@@ -0,0 +1,903 @@
+From 4d4e7847287b4ad784ac97768d4768bbbfabe8a1 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Mon, 11 Jun 2012 15:38:03 +0200
+Subject: ARM: at91: at91 based machines specify their own irq handler at run
+ time
+
+SOC_AT91SAM9 selects MULTI_IRQ_HANDLER in order to let machines specify their
+own IRQ handler at run time.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/Kconfig | 1 +
+ arch/arm/mach-at91/board-1arm.c | 2 ++
+ arch/arm/mach-at91/board-afeb-9260v1.c | 2 ++
+ arch/arm/mach-at91/board-cam60.c | 2 ++
+ arch/arm/mach-at91/board-carmeva.c | 2 ++
+ arch/arm/mach-at91/board-cpu9krea.c | 2 ++
+ arch/arm/mach-at91/board-cpuat91.c | 2 ++
+ arch/arm/mach-at91/board-csb337.c | 2 ++
+ arch/arm/mach-at91/board-csb637.c | 2 ++
+ arch/arm/mach-at91/board-dt.c | 2 ++
+ arch/arm/mach-at91/board-eb01.c | 2 ++
+ arch/arm/mach-at91/board-eb9200.c | 2 ++
+ arch/arm/mach-at91/board-ecbat91.c | 2 ++
+ arch/arm/mach-at91/board-eco920.c | 2 ++
+ arch/arm/mach-at91/board-flexibity.c | 2 ++
+ arch/arm/mach-at91/board-foxg20.c | 2 ++
+ arch/arm/mach-at91/board-gsia18s.c | 2 ++
+ arch/arm/mach-at91/board-kafa.c | 2 ++
+ arch/arm/mach-at91/board-kb9202.c | 2 ++
+ arch/arm/mach-at91/board-neocore926.c | 2 ++
+ arch/arm/mach-at91/board-pcontrol-g20.c | 2 ++
+ arch/arm/mach-at91/board-picotux200.c | 2 ++
+ arch/arm/mach-at91/board-qil-a9260.c | 2 ++
+ arch/arm/mach-at91/board-rm9200dk.c | 2 ++
+ arch/arm/mach-at91/board-rm9200ek.c | 2 ++
+ arch/arm/mach-at91/board-rsi-ews.c | 2 ++
+ arch/arm/mach-at91/board-sam9-l9260.c | 2 ++
+ arch/arm/mach-at91/board-sam9260ek.c | 2 ++
+ arch/arm/mach-at91/board-sam9261ek.c | 2 ++
+ arch/arm/mach-at91/board-sam9263ek.c | 2 ++
+ arch/arm/mach-at91/board-sam9g20ek.c | 3 +++
+ arch/arm/mach-at91/board-sam9m10g45ek.c | 2 ++
+ arch/arm/mach-at91/board-sam9rlek.c | 2 ++
+ arch/arm/mach-at91/board-snapper9260.c | 2 ++
+ arch/arm/mach-at91/board-stamp9g20.c | 3 +++
+ arch/arm/mach-at91/board-usb-a926x.c | 4 ++++
+ arch/arm/mach-at91/board-yl-9200.c | 2 ++
+ arch/arm/mach-at91/include/mach/at91_aic.h | 2 ++
+ arch/arm/mach-at91/include/mach/entry-macro.S | 27 ---------------------------
+ arch/arm/mach-at91/irq.c | 19 +++++++++++++++++++
+ 40 files changed, 98 insertions(+), 27 deletions(-)
+ delete mode 100644 arch/arm/mach-at91/include/mach/entry-macro.S
+
+diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
+index 19505c0..e401dea 100644
+--- a/arch/arm/mach-at91/Kconfig
++++ b/arch/arm/mach-at91/Kconfig
+@@ -29,6 +29,7 @@ comment "Atmel AT91 Processor"
+ config SOC_AT91SAM9
+ bool
+ select CPU_ARM926T
++ select MULTI_IRQ_HANDLER
+ select AT91_SAM9_TIME
+ select AT91_SAM9_SMC
+
+diff --git a/arch/arm/mach-at91/board-1arm.c b/arch/arm/mach-at91/board-1arm.c
+index 271f994..22d8856 100644
+--- a/arch/arm/mach-at91/board-1arm.c
++++ b/arch/arm/mach-at91/board-1arm.c
+@@ -36,6 +36,7 @@
+
+ #include <mach/board.h>
+ #include <mach/cpu.h>
++#include <mach/at91_aic.h>
+
+ #include "generic.h"
+
+@@ -91,6 +92,7 @@ MACHINE_START(ONEARM, "Ajeco 1ARM single board computer")
+ /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = onearm_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = onearm_board_init,
+diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c
+index b7d8aa7..de7be19 100644
+--- a/arch/arm/mach-at91/board-afeb-9260v1.c
++++ b/arch/arm/mach-at91/board-afeb-9260v1.c
+@@ -44,6 +44,7 @@
+ #include <asm/mach/irq.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+
+ #include "generic.h"
+
+@@ -212,6 +213,7 @@ MACHINE_START(AFEB9260, "Custom afeb9260 board")
+ /* Maintainer: Sergey Lapin <slapin@ossfans.org> */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = afeb9260_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = afeb9260_board_init,
+diff --git a/arch/arm/mach-at91/board-cam60.c b/arch/arm/mach-at91/board-cam60.c
+index 29d3ef0..477e708 100644
+--- a/arch/arm/mach-at91/board-cam60.c
++++ b/arch/arm/mach-at91/board-cam60.c
+@@ -39,6 +39,7 @@
+ #include <asm/mach/irq.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+
+ #include "sam9_smc.h"
+@@ -188,6 +189,7 @@ MACHINE_START(CAM60, "KwikByte CAM60")
+ /* Maintainer: KwikByte */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = cam60_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = cam60_board_init,
+diff --git a/arch/arm/mach-at91/board-carmeva.c b/arch/arm/mach-at91/board-carmeva.c
+index 44328a6..a5b002f 100644
+--- a/arch/arm/mach-at91/board-carmeva.c
++++ b/arch/arm/mach-at91/board-carmeva.c
+@@ -36,6 +36,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+
+ #include "generic.h"
+
+@@ -158,6 +159,7 @@ MACHINE_START(CARMEVA, "Carmeva")
+ /* Maintainer: Conitec Datasystems */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = carmeva_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = carmeva_board_init,
+diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c
+index ece0d76..7ddc219 100644
+--- a/arch/arm/mach-at91/board-cpu9krea.c
++++ b/arch/arm/mach-at91/board-cpu9krea.c
+@@ -41,6 +41,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91sam9260_matrix.h>
+ #include <mach/at91_matrix.h>
+@@ -375,6 +376,7 @@ MACHINE_START(CPUAT9G20, "Eukrea CPU9G20")
+ /* Maintainer: Eric Benard - EUKREA Electromatique */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = cpu9krea_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = cpu9krea_board_init,
+diff --git a/arch/arm/mach-at91/board-cpuat91.c b/arch/arm/mach-at91/board-cpuat91.c
+index 895cf2d..2e6d043 100644
+--- a/arch/arm/mach-at91/board-cpuat91.c
++++ b/arch/arm/mach-at91/board-cpuat91.c
+@@ -37,6 +37,7 @@
+ #include <asm/mach/irq.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91rm9200_mc.h>
+ #include <mach/at91_ramc.h>
+ #include <mach/cpu.h>
+@@ -178,6 +179,7 @@ MACHINE_START(CPUAT91, "Eukrea")
+ /* Maintainer: Eric Benard - EUKREA Electromatique */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = cpuat91_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = cpuat91_board_init,
+diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
+index cd81336..462bc31 100644
+--- a/arch/arm/mach-at91/board-csb337.c
++++ b/arch/arm/mach-at91/board-csb337.c
+@@ -39,6 +39,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+
+ #include "generic.h"
+
+@@ -252,6 +253,7 @@ MACHINE_START(CSB337, "Cogent CSB337")
+ /* Maintainer: Bill Gatliff */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = csb337_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = csb337_board_init,
+diff --git a/arch/arm/mach-at91/board-csb637.c b/arch/arm/mach-at91/board-csb637.c
+index 7c8b05a..872871a 100644
+--- a/arch/arm/mach-at91/board-csb637.c
++++ b/arch/arm/mach-at91/board-csb637.c
+@@ -36,6 +36,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+
+ #include "generic.h"
+
+@@ -133,6 +134,7 @@ MACHINE_START(CSB637, "Cogent CSB637")
+ /* Maintainer: Bill Gatliff */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = csb637_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = csb637_board_init,
+diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
+index a1fce05..e8f45c4 100644
+--- a/arch/arm/mach-at91/board-dt.c
++++ b/arch/arm/mach-at91/board-dt.c
+@@ -16,6 +16,7 @@
+ #include <linux/of_platform.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+
+ #include <asm/setup.h>
+ #include <asm/irq.h>
+@@ -53,6 +54,7 @@ DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM (Device Tree)")
+ /* Maintainer: Atmel */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = at91_dt_initialize,
+ .init_irq = at91_dt_init_irq,
+ .init_machine = at91_dt_device_init,
+diff --git a/arch/arm/mach-at91/board-eb01.c b/arch/arm/mach-at91/board-eb01.c
+index d2023f2..01f66e9 100644
+--- a/arch/arm/mach-at91/board-eb01.c
++++ b/arch/arm/mach-at91/board-eb01.c
+@@ -28,6 +28,7 @@
+ #include <asm/mach/arch.h>
+ #include <asm/mach/map.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include "generic.h"
+
+ static void __init at91eb01_init_irq(void)
+@@ -43,6 +44,7 @@ static void __init at91eb01_init_early(void)
+ MACHINE_START(AT91EB01, "Atmel AT91 EB01")
+ /* Maintainer: Greg Ungerer <gerg@snapgear.com> */
+ .timer = &at91x40_timer,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = at91eb01_init_early,
+ .init_irq = at91eb01_init_irq,
+ MACHINE_END
+diff --git a/arch/arm/mach-at91/board-eb9200.c b/arch/arm/mach-at91/board-eb9200.c
+index bd10172..d1e1f3f 100644
+--- a/arch/arm/mach-at91/board-eb9200.c
++++ b/arch/arm/mach-at91/board-eb9200.c
+@@ -36,6 +36,7 @@
+ #include <asm/mach/irq.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+
+ #include "generic.h"
+
+@@ -118,6 +119,7 @@ static void __init eb9200_board_init(void)
+ MACHINE_START(ATEB9200, "Embest ATEB9200")
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = eb9200_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = eb9200_board_init,
+diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c
+index 89cc372..9c24cb2 100644
+--- a/arch/arm/mach-at91/board-ecbat91.c
++++ b/arch/arm/mach-at91/board-ecbat91.c
+@@ -39,6 +39,7 @@
+
+ #include <mach/board.h>
+ #include <mach/cpu.h>
++#include <mach/at91_aic.h>
+
+ #include "generic.h"
+
+@@ -170,6 +171,7 @@ MACHINE_START(ECBAT91, "emQbit's ECB_AT91")
+ /* Maintainer: emQbit.com */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ecb_at91init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ecb_at91board_init,
+diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c
+index 558546c..82bdfde 100644
+--- a/arch/arm/mach-at91/board-eco920.c
++++ b/arch/arm/mach-at91/board-eco920.c
+@@ -25,6 +25,7 @@
+ #include <asm/mach/map.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91rm9200_mc.h>
+ #include <mach/at91_ramc.h>
+ #include <mach/cpu.h>
+@@ -132,6 +133,7 @@ MACHINE_START(ECO920, "eco920")
+ /* Maintainer: Sascha Hauer */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = eco920_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = eco920_board_init,
+diff --git a/arch/arm/mach-at91/board-flexibity.c b/arch/arm/mach-at91/board-flexibity.c
+index 47658f7..6cc83a8 100644
+--- a/arch/arm/mach-at91/board-flexibity.c
++++ b/arch/arm/mach-at91/board-flexibity.c
+@@ -34,6 +34,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+
+ #include "generic.h"
+
+@@ -160,6 +161,7 @@ MACHINE_START(FLEXIBITY, "Flexibity Connect")
+ /* Maintainer: Maxim Osipov */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = flexibity_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = flexibity_board_init,
+diff --git a/arch/arm/mach-at91/board-foxg20.c b/arch/arm/mach-at91/board-foxg20.c
+index 33411e6..69ab124 100644
+--- a/arch/arm/mach-at91/board-foxg20.c
++++ b/arch/arm/mach-at91/board-foxg20.c
+@@ -42,6 +42,7 @@
+ #include <asm/mach/irq.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+
+ #include "sam9_smc.h"
+@@ -262,6 +263,7 @@ MACHINE_START(ACMENETUSFOXG20, "Acme Systems srl FOX Board G20")
+ /* Maintainer: Sergio Tanzilli */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = foxg20_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = foxg20_board_init,
+diff --git a/arch/arm/mach-at91/board-gsia18s.c b/arch/arm/mach-at91/board-gsia18s.c
+index 3e0dfa6..a9d5e78 100644
+--- a/arch/arm/mach-at91/board-gsia18s.c
++++ b/arch/arm/mach-at91/board-gsia18s.c
+@@ -31,6 +31,7 @@
+ #include <asm/mach/arch.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/gsia18s.h>
+ #include <mach/stamp9g20.h>
+@@ -575,6 +576,7 @@ static void __init gsia18s_board_init(void)
+ MACHINE_START(GSIA18S, "GS_IA18_S")
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = gsia18s_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = gsia18s_board_init,
+diff --git a/arch/arm/mach-at91/board-kafa.c b/arch/arm/mach-at91/board-kafa.c
+index f260657..64c1dbf 100644
+--- a/arch/arm/mach-at91/board-kafa.c
++++ b/arch/arm/mach-at91/board-kafa.c
+@@ -35,6 +35,7 @@
+ #include <asm/mach/irq.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/cpu.h>
+
+ #include "generic.h"
+@@ -93,6 +94,7 @@ MACHINE_START(KAFA, "Sperry-Sun KAFA")
+ /* Maintainer: Sergei Sharonov */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = kafa_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = kafa_board_init,
+diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c
+index ba39db5..5d96cb8 100644
+--- a/arch/arm/mach-at91/board-kb9202.c
++++ b/arch/arm/mach-at91/board-kb9202.c
+@@ -37,6 +37,7 @@
+
+ #include <mach/board.h>
+ #include <mach/cpu.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91rm9200_mc.h>
+ #include <mach/at91_ramc.h>
+
+@@ -133,6 +134,7 @@ MACHINE_START(KB9200, "KB920x")
+ /* Maintainer: KwikByte, Inc. */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = kb9202_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = kb9202_board_init,
+diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
+index d2f4cc1..18103c5d 100644
+--- a/arch/arm/mach-at91/board-neocore926.c
++++ b/arch/arm/mach-at91/board-neocore926.c
+@@ -45,6 +45,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+
+ #include "sam9_smc.h"
+@@ -378,6 +379,7 @@ MACHINE_START(NEOCORE926, "ADENEO NEOCORE 926")
+ /* Maintainer: ADENEO */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = neocore926_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = neocore926_board_init,
+diff --git a/arch/arm/mach-at91/board-pcontrol-g20.c b/arch/arm/mach-at91/board-pcontrol-g20.c
+index 7fe6383..9ca3e32 100644
+--- a/arch/arm/mach-at91/board-pcontrol-g20.c
++++ b/arch/arm/mach-at91/board-pcontrol-g20.c
+@@ -30,6 +30,7 @@
+ #include <asm/mach/arch.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/stamp9g20.h>
+
+@@ -218,6 +219,7 @@ MACHINE_START(PCONTROL_G20, "PControl G20")
+ /* Maintainer: pgsellmann@portner-elektronik.at */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = pcontrol_g20_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = pcontrol_g20_board_init,
+diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c
+index b45c0a5..1270655 100644
+--- a/arch/arm/mach-at91/board-picotux200.c
++++ b/arch/arm/mach-at91/board-picotux200.c
+@@ -38,6 +38,7 @@
+ #include <asm/mach/irq.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91rm9200_mc.h>
+ #include <mach/at91_ramc.h>
+
+@@ -120,6 +121,7 @@ MACHINE_START(PICOTUX2XX, "picotux 200")
+ /* Maintainer: Kleinhenz Elektronik GmbH */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = picotux200_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = picotux200_board_init,
+diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c
+index 0c61bf0..bf351e2 100644
+--- a/arch/arm/mach-at91/board-qil-a9260.c
++++ b/arch/arm/mach-at91/board-qil-a9260.c
+@@ -41,6 +41,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+
+@@ -258,6 +259,7 @@ MACHINE_START(QIL_A9260, "CALAO QIL_A9260")
+ /* Maintainer: calao-systems */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c
+index afd7a47..cc2bf97 100644
+--- a/arch/arm/mach-at91/board-rm9200dk.c
++++ b/arch/arm/mach-at91/board-rm9200dk.c
+@@ -40,6 +40,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91rm9200_mc.h>
+ #include <mach/at91_ramc.h>
+
+@@ -223,6 +224,7 @@ MACHINE_START(AT91RM9200DK, "Atmel AT91RM9200-DK")
+ /* Maintainer: SAN People/Atmel */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = dk_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = dk_board_init,
+diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c
+index 2b15b8a..62e19e6 100644
+--- a/arch/arm/mach-at91/board-rm9200ek.c
++++ b/arch/arm/mach-at91/board-rm9200ek.c
+@@ -40,6 +40,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91rm9200_mc.h>
+ #include <mach/at91_ramc.h>
+
+@@ -190,6 +191,7 @@ MACHINE_START(AT91RM9200EK, "Atmel AT91RM9200-EK")
+ /* Maintainer: SAN People/Atmel */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+diff --git a/arch/arm/mach-at91/board-rsi-ews.c b/arch/arm/mach-at91/board-rsi-ews.c
+index 24ab9be..c3b43ae 100644
+--- a/arch/arm/mach-at91/board-rsi-ews.c
++++ b/arch/arm/mach-at91/board-rsi-ews.c
+@@ -26,6 +26,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+
+ #include <linux/gpio.h>
+
+@@ -225,6 +226,7 @@ MACHINE_START(RSI_EWS, "RSI EWS")
+ /* Maintainer: Josef Holzmayr <holzmayr@rsi-elektrotechnik.de> */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = rsi_ews_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = rsi_ews_board_init,
+diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c
+index cdd21f2..7bf6da7 100644
+--- a/arch/arm/mach-at91/board-sam9-l9260.c
++++ b/arch/arm/mach-at91/board-sam9-l9260.c
+@@ -38,6 +38,7 @@
+ #include <asm/mach/irq.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+
+ #include "sam9_smc.h"
+@@ -202,6 +203,7 @@ MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260")
+ /* Maintainer: Olimex */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
+index 7b3c391..889c1bf 100644
+--- a/arch/arm/mach-at91/board-sam9260ek.c
++++ b/arch/arm/mach-at91/board-sam9260ek.c
+@@ -42,6 +42,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+ #include <mach/system_rev.h>
+@@ -344,6 +345,7 @@ MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK")
+ /* Maintainer: Atmel */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
+index 2736453..2269be5 100644
+--- a/arch/arm/mach-at91/board-sam9261ek.c
++++ b/arch/arm/mach-at91/board-sam9261ek.c
+@@ -46,6 +46,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+ #include <mach/system_rev.h>
+@@ -615,6 +616,7 @@ MACHINE_START(AT91SAM9G10EK, "Atmel AT91SAM9G10-EK")
+ /* Maintainer: Atmel */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
+index 983cb98..82adf58 100644
+--- a/arch/arm/mach-at91/board-sam9263ek.c
++++ b/arch/arm/mach-at91/board-sam9263ek.c
+@@ -45,6 +45,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+ #include <mach/system_rev.h>
+@@ -443,6 +444,7 @@ MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK")
+ /* Maintainer: Atmel */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
+index 3d61553..da6d019 100644
+--- a/arch/arm/mach-at91/board-sam9g20ek.c
++++ b/arch/arm/mach-at91/board-sam9g20ek.c
+@@ -42,6 +42,7 @@
+ #include <asm/mach/irq.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/system_rev.h>
+
+@@ -399,6 +400,7 @@ MACHINE_START(AT91SAM9G20EK, "Atmel AT91SAM9G20-EK")
+ /* Maintainer: Atmel */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+@@ -408,6 +410,7 @@ MACHINE_START(AT91SAM9G20EK_2MMC, "Atmel AT91SAM9G20-EK 2 MMC Slot Mod")
+ /* Maintainer: Atmel */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
+index 9a87f0b..d1882d5 100644
+--- a/arch/arm/mach-at91/board-sam9m10g45ek.c
++++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
+@@ -41,6 +41,7 @@
+ #include <asm/mach/irq.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+ #include <mach/system_rev.h>
+@@ -491,6 +492,7 @@ MACHINE_START(AT91SAM9M10G45EK, "Atmel AT91SAM9M10G45-EK")
+ /* Maintainer: Atmel */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
+index be3239f..e7dc3ea 100644
+--- a/arch/arm/mach-at91/board-sam9rlek.c
++++ b/arch/arm/mach-at91/board-sam9rlek.c
+@@ -31,6 +31,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+
+@@ -319,6 +320,7 @@ MACHINE_START(AT91SAM9RLEK, "Atmel AT91SAM9RL-EK")
+ /* Maintainer: Atmel */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+diff --git a/arch/arm/mach-at91/board-snapper9260.c b/arch/arm/mach-at91/board-snapper9260.c
+index 9d446f1..a4e031a 100644
+--- a/arch/arm/mach-at91/board-snapper9260.c
++++ b/arch/arm/mach-at91/board-snapper9260.c
+@@ -33,6 +33,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+
+ #include "sam9_smc.h"
+@@ -178,6 +179,7 @@ static void __init snapper9260_board_init(void)
+ MACHINE_START(SNAPPER_9260, "Bluewater Systems Snapper 9260/9G20 module")
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = snapper9260_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = snapper9260_board_init,
+diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c
+index ee86f9d..29eae16 100644
+--- a/arch/arm/mach-at91/board-stamp9g20.c
++++ b/arch/arm/mach-at91/board-stamp9g20.c
+@@ -26,6 +26,7 @@
+ #include <asm/mach/arch.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+
+ #include "sam9_smc.h"
+@@ -287,6 +288,7 @@ MACHINE_START(PORTUXG20, "taskit PortuxG20")
+ /* Maintainer: taskit GmbH */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = stamp9g20_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = portuxg20_board_init,
+@@ -296,6 +298,7 @@ MACHINE_START(STAMP9G20, "taskit Stamp9G20")
+ /* Maintainer: taskit GmbH */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = stamp9g20_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = stamp9g20evb_board_init,
+diff --git a/arch/arm/mach-at91/board-usb-a926x.c b/arch/arm/mach-at91/board-usb-a926x.c
+index 95393fc..c1476b9 100644
+--- a/arch/arm/mach-at91/board-usb-a926x.c
++++ b/arch/arm/mach-at91/board-usb-a926x.c
+@@ -42,6 +42,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+
+@@ -358,6 +359,7 @@ MACHINE_START(USB_A9263, "CALAO USB_A9263")
+ /* Maintainer: calao-systems */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+@@ -367,6 +369,7 @@ MACHINE_START(USB_A9260, "CALAO USB_A9260")
+ /* Maintainer: calao-systems */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+@@ -376,6 +379,7 @@ MACHINE_START(USB_A9G20, "CALAO USB_A92G0")
+ /* Maintainer: Jean-Christophe PLAGNIOL-VILLARD */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c
+index d56665e..516d340 100644
+--- a/arch/arm/mach-at91/board-yl-9200.c
++++ b/arch/arm/mach-at91/board-yl-9200.c
+@@ -44,6 +44,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91rm9200_mc.h>
+ #include <mach/at91_ramc.h>
+ #include <mach/cpu.h>
+@@ -590,6 +591,7 @@ MACHINE_START(YL9200, "uCdragon YL-9200")
+ /* Maintainer: S.Birtles */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = yl9200_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = yl9200_board_init,
+diff --git a/arch/arm/mach-at91/include/mach/at91_aic.h b/arch/arm/mach-at91/include/mach/at91_aic.h
+index 3af7272..7867378 100644
+--- a/arch/arm/mach-at91/include/mach/at91_aic.h
++++ b/arch/arm/mach-at91/include/mach/at91_aic.h
+@@ -65,4 +65,6 @@ extern void __iomem *at91_aic_base;
+ #define AT91_AIC_FFDR 0x144 /* Fast Forcing Disable Register [SAM9 only] */
+ #define AT91_AIC_FFSR 0x148 /* Fast Forcing Status Register [SAM9 only] */
+
++void at91_aic_handle_irq(struct pt_regs *regs);
++
+ #endif
+diff --git a/arch/arm/mach-at91/include/mach/entry-macro.S b/arch/arm/mach-at91/include/mach/entry-macro.S
+deleted file mode 100644
+index 903bf20..0000000
+--- a/arch/arm/mach-at91/include/mach/entry-macro.S
++++ /dev/null
+@@ -1,27 +0,0 @@
+-/*
+- * arch/arm/mach-at91/include/mach/entry-macro.S
+- *
+- * Copyright (C) 2003-2005 SAN People
+- *
+- * Low-level IRQ helper macros for AT91RM9200 platforms
+- *
+- * This file is licensed under the terms of the GNU General Public
+- * License version 2. This program is licensed "as is" without any
+- * warranty of any kind, whether express or implied.
+- */
+-
+-#include <mach/hardware.h>
+-#include <mach/at91_aic.h>
+-
+- .macro get_irqnr_preamble, base, tmp
+- ldr \base, =at91_aic_base @ base virtual address of AIC peripheral
+- ldr \base, [\base]
+- .endm
+-
+- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
+- ldr \irqnr, [\base, #AT91_AIC_IVR] @ read IRQ vector register: de-asserts nIRQ to processor (and clears interrupt)
+- ldr \irqstat, [\base, #AT91_AIC_ISR] @ read interrupt source number
+- teq \irqstat, #0 @ ISR is 0 when no current interrupt, or spurious interrupt
+- streq \tmp, [\base, #AT91_AIC_EOICR] @ not going to be handled further, then ACK it now.
+- .endm
+-
+diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
+index db8e141..390d4df 100644
+--- a/arch/arm/mach-at91/irq.c
++++ b/arch/arm/mach-at91/irq.c
+@@ -36,6 +36,7 @@
+ #include <asm/irq.h>
+ #include <asm/setup.h>
+
++#include <asm/exception.h>
+ #include <asm/mach/arch.h>
+ #include <asm/mach/irq.h>
+ #include <asm/mach/map.h>
+@@ -45,6 +46,24 @@ static struct irq_domain *at91_aic_domain;
+ static struct device_node *at91_aic_np;
+ static unsigned int *at91_aic_irq_priorities;
+
++asmlinkage void __exception_irq_entry at91_aic_handle_irq(struct pt_regs *regs)
++{
++ u32 irqnr;
++ u32 irqstat;
++
++ irqnr = at91_aic_read(AT91_AIC_IVR);
++ irqstat = at91_aic_read(AT91_AIC_ISR);
++
++ /*
++ * ISR value is 0 when there is no current interrupt or when there is
++ * a spurious interrupt
++ */
++ if (!irqstat)
++ at91_aic_write(AT91_AIC_EOICR, 0);
++ else
++ handle_IRQ(irqnr, regs);
++}
++
+ static void at91_aic_mask_irq(struct irq_data *d)
+ {
+ /* Disable interrupt on AIC */
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0058-ARM-at91-sparse-irq-support.patch b/patches.at91/0058-ARM-at91-sparse-irq-support.patch
new file mode 100644
index 00000000000000..0947785f2886a0
--- /dev/null
+++ b/patches.at91/0058-ARM-at91-sparse-irq-support.patch
@@ -0,0 +1,1578 @@
+From 6fdddfc0d9b97a191bf49bb1b180822f156c515c Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Thu, 21 Jun 2012 14:47:27 +0200
+Subject: ARM: at91: sparse irq support
+
+Enable sparse irq support for multisoc image. It involves to add the
+NR_IRQS_LEGACY offset to static SoC irq number definitions since NR_IRQS_LEGACY
+irq descs are allocated before AIC requests irq descs allocation.
+Move NR_AIC_IRQS macro to a more appropiate place with the purpose to
+remove mach/irqs.h later.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+
+Conflicts:
+ arch/arm/mach-at91/at91sam9260_devices.c
+ arch/arm/mach-at91/at91sam9g45_devices.c
+---
+ arch/arm/mach-at91/Kconfig | 1 +
+ arch/arm/mach-at91/at91rm9200.c | 1 +
+ arch/arm/mach-at91/at91rm9200_devices.c | 84 +++++++++++------------
+ arch/arm/mach-at91/at91sam9260.c | 1 +
+ arch/arm/mach-at91/at91sam9260_devices.c | 88 ++++++++++++------------
+ arch/arm/mach-at91/at91sam9261.c | 1 +
+ arch/arm/mach-at91/at91sam9261_devices.c | 68 +++++++++----------
+ arch/arm/mach-at91/at91sam9263.c | 1 +
+ arch/arm/mach-at91/at91sam9263_devices.c | 80 +++++++++++-----------
+ arch/arm/mach-at91/at91sam926x_time.c | 2 +-
+ arch/arm/mach-at91/at91sam9g45.c | 1 +
+ arch/arm/mach-at91/at91sam9g45_devices.c | 104 ++++++++++++++---------------
+ arch/arm/mach-at91/at91sam9rl.c | 1 +
+ arch/arm/mach-at91/at91sam9rl_devices.c | 76 ++++++++++-----------
+ arch/arm/mach-at91/at91x40.c | 1 +
+ arch/arm/mach-at91/include/mach/at91_aic.h | 3 +
+ arch/arm/mach-at91/include/mach/irqs.h | 12 ----
+ arch/arm/mach-at91/irq.c | 6 +-
+ arch/arm/mach-at91/pm.c | 1 +
+ 19 files changed, 267 insertions(+), 265 deletions(-)
+
+diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
+index e401dea..7d0c40a 100644
+--- a/arch/arm/mach-at91/Kconfig
++++ b/arch/arm/mach-at91/Kconfig
+@@ -30,6 +30,7 @@ config SOC_AT91SAM9
+ bool
+ select CPU_ARM926T
+ select MULTI_IRQ_HANDLER
++ select SPARSE_IRQ
+ select AT91_SAM9_TIME
+ select AT91_SAM9_SMC
+
+diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
+index d50da1a..801c30b 100644
+--- a/arch/arm/mach-at91/at91rm9200.c
++++ b/arch/arm/mach-at91/at91rm9200.c
+@@ -17,6 +17,7 @@
+ #include <asm/mach/map.h>
+ #include <asm/system_misc.h>
+ #include <mach/at91rm9200.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91_pmc.h>
+ #include <mach/at91_st.h>
+ #include <mach/cpu.h>
+diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
+index 99affb5..04d69d3 100644
+--- a/arch/arm/mach-at91/at91rm9200_devices.c
++++ b/arch/arm/mach-at91/at91rm9200_devices.c
+@@ -41,8 +41,8 @@ static struct resource usbh_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_UHP,
+- .end = AT91RM9200_ID_UHP,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_UHP,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_UHP,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -94,8 +94,8 @@ static struct resource udc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_UDP,
+- .end = AT91RM9200_ID_UDP,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_UDP,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_UDP,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -145,8 +145,8 @@ static struct resource eth_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_EMAC,
+- .end = AT91RM9200_ID_EMAC,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_EMAC,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_EMAC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -305,8 +305,8 @@ static struct resource mmc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_MCI,
+- .end = AT91RM9200_ID_MCI,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_MCI,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_MCI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -488,8 +488,8 @@ static struct resource twi_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_TWI,
+- .end = AT91RM9200_ID_TWI,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_TWI,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_TWI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -532,8 +532,8 @@ static struct resource spi_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_SPI,
+- .end = AT91RM9200_ID_SPI,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_SPI,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_SPI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -598,18 +598,18 @@ static struct resource tcb0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_TC0,
+- .end = AT91RM9200_ID_TC0,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC0,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+- .start = AT91RM9200_ID_TC1,
+- .end = AT91RM9200_ID_TC1,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC1,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+- .start = AT91RM9200_ID_TC2,
+- .end = AT91RM9200_ID_TC2,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC2,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -628,18 +628,18 @@ static struct resource tcb1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_TC3,
+- .end = AT91RM9200_ID_TC3,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC3,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC3,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+- .start = AT91RM9200_ID_TC4,
+- .end = AT91RM9200_ID_TC4,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC4,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC4,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+- .start = AT91RM9200_ID_TC5,
+- .end = AT91RM9200_ID_TC5,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC5,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC5,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -673,8 +673,8 @@ static struct resource rtc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_SYS,
+- .end = AT91_ID_SYS,
++ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
++ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -729,8 +729,8 @@ static struct resource ssc0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_SSC0,
+- .end = AT91RM9200_ID_SSC0,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_SSC0,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_SSC0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -771,8 +771,8 @@ static struct resource ssc1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_SSC1,
+- .end = AT91RM9200_ID_SSC1,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_SSC1,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_SSC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -813,8 +813,8 @@ static struct resource ssc2_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_SSC2,
+- .end = AT91RM9200_ID_SSC2,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_SSC2,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_SSC2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -897,8 +897,8 @@ static struct resource dbgu_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_SYS,
+- .end = AT91_ID_SYS,
++ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
++ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -935,8 +935,8 @@ static struct resource uart0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_US0,
+- .end = AT91RM9200_ID_US0,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_US0,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_US0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -984,8 +984,8 @@ static struct resource uart1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_US1,
+- .end = AT91RM9200_ID_US1,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_US1,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_US1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1035,8 +1035,8 @@ static struct resource uart2_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_US2,
+- .end = AT91RM9200_ID_US2,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_US2,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_US2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1078,8 +1078,8 @@ static struct resource uart3_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_US3,
+- .end = AT91RM9200_ID_US3,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_US3,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_US3,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
+index a27bbec..c644131 100644
+--- a/arch/arm/mach-at91/at91sam9260.c
++++ b/arch/arm/mach-at91/at91sam9260.c
+@@ -20,6 +20,7 @@
+ #include <mach/cpu.h>
+ #include <mach/at91_dbgu.h>
+ #include <mach/at91sam9260.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91_pmc.h>
+ #include <mach/at91_rstc.h>
+
+diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
+index d556de1..43e60fb 100644
+--- a/arch/arm/mach-at91/at91sam9260_devices.c
++++ b/arch/arm/mach-at91/at91sam9260_devices.c
+@@ -42,8 +42,8 @@ static struct resource usbh_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_UHP,
+- .end = AT91SAM9260_ID_UHP,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_UHP,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_UHP,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -95,8 +95,8 @@ static struct resource udc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_UDP,
+- .end = AT91SAM9260_ID_UDP,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_UDP,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_UDP,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -146,8 +146,8 @@ static struct resource eth_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_EMAC,
+- .end = AT91SAM9260_ID_EMAC,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_EMAC,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_EMAC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -220,8 +220,8 @@ static struct resource mmc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_MCI,
+- .end = AT91SAM9260_ID_MCI,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -302,8 +302,8 @@ static struct resource mmc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_MCI,
+- .end = AT91SAM9260_ID_MCI,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -493,8 +493,8 @@ static struct resource twi_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_TWI,
+- .end = AT91SAM9260_ID_TWI,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TWI,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TWI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -537,8 +537,8 @@ static struct resource spi0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_SPI0,
+- .end = AT91SAM9260_ID_SPI0,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_SPI0,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_SPI0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -563,8 +563,8 @@ static struct resource spi1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_SPI1,
+- .end = AT91SAM9260_ID_SPI1,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_SPI1,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_SPI1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -649,18 +649,18 @@ static struct resource tcb0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_TC0,
+- .end = AT91SAM9260_ID_TC0,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC0,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+- .start = AT91SAM9260_ID_TC1,
+- .end = AT91SAM9260_ID_TC1,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC1,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+- .start = AT91SAM9260_ID_TC2,
+- .end = AT91SAM9260_ID_TC2,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC2,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -679,18 +679,18 @@ static struct resource tcb1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_TC3,
+- .end = AT91SAM9260_ID_TC3,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC3,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC3,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+- .start = AT91SAM9260_ID_TC4,
+- .end = AT91SAM9260_ID_TC4,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC4,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC4,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+- .start = AT91SAM9260_ID_TC5,
+- .end = AT91SAM9260_ID_TC5,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC5,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC5,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -804,8 +804,8 @@ static struct resource ssc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_SSC,
+- .end = AT91SAM9260_ID_SSC,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_SSC,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_SSC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -879,8 +879,8 @@ static struct resource dbgu_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_SYS,
+- .end = AT91_ID_SYS,
++ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
++ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -917,8 +917,8 @@ static struct resource uart0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_US0,
+- .end = AT91SAM9260_ID_US0,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US0,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -968,8 +968,8 @@ static struct resource uart1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_US1,
+- .end = AT91SAM9260_ID_US1,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US1,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1011,8 +1011,8 @@ static struct resource uart2_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_US2,
+- .end = AT91SAM9260_ID_US2,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US2,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1054,8 +1054,8 @@ static struct resource uart3_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_US3,
+- .end = AT91SAM9260_ID_US3,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US3,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US3,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1097,8 +1097,8 @@ static struct resource uart4_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_US4,
+- .end = AT91SAM9260_ID_US4,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US4,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US4,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1135,8 +1135,8 @@ static struct resource uart5_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_US5,
+- .end = AT91SAM9260_ID_US5,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US5,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US5,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
+index c77d503..f40762c 100644
+--- a/arch/arm/mach-at91/at91sam9261.c
++++ b/arch/arm/mach-at91/at91sam9261.c
+@@ -19,6 +19,7 @@
+ #include <asm/system_misc.h>
+ #include <mach/cpu.h>
+ #include <mach/at91sam9261.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91_pmc.h>
+ #include <mach/at91_rstc.h>
+
+diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
+index 9295e90..8df5c1b 100644
+--- a/arch/arm/mach-at91/at91sam9261_devices.c
++++ b/arch/arm/mach-at91/at91sam9261_devices.c
+@@ -45,8 +45,8 @@ static struct resource usbh_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_UHP,
+- .end = AT91SAM9261_ID_UHP,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_UHP,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_UHP,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -98,8 +98,8 @@ static struct resource udc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_UDP,
+- .end = AT91SAM9261_ID_UDP,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_UDP,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_UDP,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -148,8 +148,8 @@ static struct resource mmc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_MCI,
+- .end = AT91SAM9261_ID_MCI,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_MCI,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_MCI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -310,8 +310,8 @@ static struct resource twi_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_TWI,
+- .end = AT91SAM9261_ID_TWI,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_TWI,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_TWI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -354,8 +354,8 @@ static struct resource spi0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_SPI0,
+- .end = AT91SAM9261_ID_SPI0,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_SPI0,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_SPI0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -380,8 +380,8 @@ static struct resource spi1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_SPI1,
+- .end = AT91SAM9261_ID_SPI1,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_SPI1,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_SPI1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -468,8 +468,8 @@ static struct resource lcdc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_LCDC,
+- .end = AT91SAM9261_ID_LCDC,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_LCDC,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_LCDC,
+ .flags = IORESOURCE_IRQ,
+ },
+ #if defined(CONFIG_FB_INTSRAM)
+@@ -566,18 +566,18 @@ static struct resource tcb_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_TC0,
+- .end = AT91SAM9261_ID_TC0,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_TC0,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_TC0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+- .start = AT91SAM9261_ID_TC1,
+- .end = AT91SAM9261_ID_TC1,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_TC1,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_TC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+- .start = AT91SAM9261_ID_TC2,
+- .end = AT91SAM9261_ID_TC2,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_TC2,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_TC2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -689,8 +689,8 @@ static struct resource ssc0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_SSC0,
+- .end = AT91SAM9261_ID_SSC0,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC0,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -731,8 +731,8 @@ static struct resource ssc1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_SSC1,
+- .end = AT91SAM9261_ID_SSC1,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC1,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -773,8 +773,8 @@ static struct resource ssc2_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_SSC2,
+- .end = AT91SAM9261_ID_SSC2,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC2,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -857,8 +857,8 @@ static struct resource dbgu_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_SYS,
+- .end = AT91_ID_SYS,
++ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
++ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -895,8 +895,8 @@ static struct resource uart0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_US0,
+- .end = AT91SAM9261_ID_US0,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_US0,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_US0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -938,8 +938,8 @@ static struct resource uart1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_US1,
+- .end = AT91SAM9261_ID_US1,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_US1,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_US1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -981,8 +981,8 @@ static struct resource uart2_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_US2,
+- .end = AT91SAM9261_ID_US2,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_US2,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_US2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
+index ed91c7e..84b3810 100644
+--- a/arch/arm/mach-at91/at91sam9263.c
++++ b/arch/arm/mach-at91/at91sam9263.c
+@@ -18,6 +18,7 @@
+ #include <asm/mach/map.h>
+ #include <asm/system_misc.h>
+ #include <mach/at91sam9263.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91_pmc.h>
+ #include <mach/at91_rstc.h>
+
+diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
+index 175e000..eb6bbf8 100644
+--- a/arch/arm/mach-at91/at91sam9263_devices.c
++++ b/arch/arm/mach-at91/at91sam9263_devices.c
+@@ -44,8 +44,8 @@ static struct resource usbh_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_UHP,
+- .end = AT91SAM9263_ID_UHP,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_UHP,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_UHP,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -104,8 +104,8 @@ static struct resource udc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_UDP,
+- .end = AT91SAM9263_ID_UDP,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_UDP,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_UDP,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -155,8 +155,8 @@ static struct resource eth_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_EMAC,
+- .end = AT91SAM9263_ID_EMAC,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_EMAC,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_EMAC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -229,8 +229,8 @@ static struct resource mmc0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_MCI0,
+- .end = AT91SAM9263_ID_MCI0,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_MCI0,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_MCI0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -254,8 +254,8 @@ static struct resource mmc1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_MCI1,
+- .end = AT91SAM9263_ID_MCI1,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_MCI1,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_MCI1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -567,8 +567,8 @@ static struct resource twi_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_TWI,
+- .end = AT91SAM9263_ID_TWI,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_TWI,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_TWI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -611,8 +611,8 @@ static struct resource spi0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_SPI0,
+- .end = AT91SAM9263_ID_SPI0,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_SPI0,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_SPI0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -637,8 +637,8 @@ static struct resource spi1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_SPI1,
+- .end = AT91SAM9263_ID_SPI1,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_SPI1,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_SPI1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -725,8 +725,8 @@ static struct resource ac97_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_AC97C,
+- .end = AT91SAM9263_ID_AC97C,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_AC97C,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_AC97C,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -776,8 +776,8 @@ static struct resource can_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_CAN,
+- .end = AT91SAM9263_ID_CAN,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_CAN,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_CAN,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -816,8 +816,8 @@ static struct resource lcdc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_LCDC,
+- .end = AT91SAM9263_ID_LCDC,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_LCDC,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_LCDC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -883,8 +883,8 @@ struct resource isi_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_ISI,
+- .end = AT91SAM9263_ID_ISI,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_ISI,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_ISI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -940,8 +940,8 @@ static struct resource tcb_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_TCB,
+- .end = AT91SAM9263_ID_TCB,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_TCB,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_TCB,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1108,8 +1108,8 @@ static struct resource pwm_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_PWMC,
+- .end = AT91SAM9263_ID_PWMC,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_PWMC,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_PWMC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1161,8 +1161,8 @@ static struct resource ssc0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_SSC0,
+- .end = AT91SAM9263_ID_SSC0,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_SSC0,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_SSC0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1203,8 +1203,8 @@ static struct resource ssc1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_SSC1,
+- .end = AT91SAM9263_ID_SSC1,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_SSC1,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_SSC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1284,8 +1284,8 @@ static struct resource dbgu_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_SYS,
+- .end = AT91_ID_SYS,
++ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
++ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1322,8 +1322,8 @@ static struct resource uart0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_US0,
+- .end = AT91SAM9263_ID_US0,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_US0,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_US0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1365,8 +1365,8 @@ static struct resource uart1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_US1,
+- .end = AT91SAM9263_ID_US1,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_US1,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_US1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1408,8 +1408,8 @@ static struct resource uart2_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_US2,
+- .end = AT91SAM9263_ID_US2,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_US2,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_US2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+diff --git a/arch/arm/mach-at91/at91sam926x_time.c b/arch/arm/mach-at91/at91sam926x_time.c
+index a94758b..ffc0957 100644
+--- a/arch/arm/mach-at91/at91sam926x_time.c
++++ b/arch/arm/mach-at91/at91sam926x_time.c
+@@ -137,7 +137,7 @@ static struct irqaction at91sam926x_pit_irq = {
+ .name = "at91_tick",
+ .flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+ .handler = at91sam926x_pit_interrupt,
+- .irq = AT91_ID_SYS,
++ .irq = NR_IRQS_LEGACY + AT91_ID_SYS,
+ };
+
+ static void at91sam926x_pit_reset(void)
+diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
+index f205449..55d2959 100644
+--- a/arch/arm/mach-at91/at91sam9g45.c
++++ b/arch/arm/mach-at91/at91sam9g45.c
+@@ -18,6 +18,7 @@
+ #include <asm/mach/map.h>
+ #include <asm/system_misc.h>
+ #include <mach/at91sam9g45.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91_pmc.h>
+ #include <mach/cpu.h>
+
+diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
+index 35bd42d..7a3f0b3 100644
+--- a/arch/arm/mach-at91/at91sam9g45_devices.c
++++ b/arch/arm/mach-at91/at91sam9g45_devices.c
+@@ -50,8 +50,8 @@ static struct resource hdmac_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_DMA,
+- .end = AT91SAM9G45_ID_DMA,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_DMA,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_DMA,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -91,8 +91,8 @@ static struct resource usbh_ohci_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_UHPHS,
+- .end = AT91SAM9G45_ID_UHPHS,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_UHPHS,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_UHPHS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -153,8 +153,8 @@ static struct resource usbh_ehci_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_UHPHS,
+- .end = AT91SAM9G45_ID_UHPHS,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_UHPHS,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_UHPHS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -210,8 +210,8 @@ static struct resource usba_udc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+- .start = AT91SAM9G45_ID_UDPHS,
+- .end = AT91SAM9G45_ID_UDPHS,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_UDPHS,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_UDPHS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -293,8 +293,8 @@ static struct resource eth_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_EMAC,
+- .end = AT91SAM9G45_ID_EMAC,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_EMAC,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_EMAC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -367,8 +367,8 @@ static struct resource mmc0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_MCI0,
+- .end = AT91SAM9G45_ID_MCI0,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_MCI0,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_MCI0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -392,8 +392,8 @@ static struct resource mmc1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_MCI1,
+- .end = AT91SAM9G45_ID_MCI1,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_MCI1,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_MCI1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -643,8 +643,8 @@ static struct resource twi0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_TWI0,
+- .end = AT91SAM9G45_ID_TWI0,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_TWI0,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_TWI0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -663,8 +663,8 @@ static struct resource twi1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_TWI1,
+- .end = AT91SAM9G45_ID_TWI1,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_TWI1,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_TWI1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -718,8 +718,8 @@ static struct resource spi0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_SPI0,
+- .end = AT91SAM9G45_ID_SPI0,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_SPI0,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_SPI0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -744,8 +744,8 @@ static struct resource spi1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_SPI1,
+- .end = AT91SAM9G45_ID_SPI1,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_SPI1,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_SPI1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -832,8 +832,8 @@ static struct resource ac97_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_AC97C,
+- .end = AT91SAM9G45_ID_AC97C,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_AC97C,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_AC97C,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -885,8 +885,8 @@ struct resource isi_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_ISI,
+- .end = AT91SAM9G45_ID_ISI,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_ISI,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_ISI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -977,8 +977,8 @@ static struct resource lcdc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_LCDC,
+- .end = AT91SAM9G45_ID_LCDC,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_LCDC,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_LCDC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1052,8 +1052,8 @@ static struct resource tcb0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_TCB,
+- .end = AT91SAM9G45_ID_TCB,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_TCB,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_TCB,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1073,8 +1073,8 @@ static struct resource tcb1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_TCB,
+- .end = AT91SAM9G45_ID_TCB,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_TCB,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_TCB,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1108,8 +1108,8 @@ static struct resource rtc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_SYS,
+- .end = AT91_ID_SYS,
++ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
++ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1145,8 +1145,8 @@ static struct resource tsadcc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_TSC,
+- .end = AT91SAM9G45_ID_TSC,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_TSC,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_TSC,
+ .flags = IORESOURCE_IRQ,
+ }
+ };
+@@ -1300,8 +1300,8 @@ static struct resource pwm_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_PWMC,
+- .end = AT91SAM9G45_ID_PWMC,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_PWMC,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_PWMC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1353,8 +1353,8 @@ static struct resource ssc0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_SSC0,
+- .end = AT91SAM9G45_ID_SSC0,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_SSC0,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_SSC0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1395,8 +1395,8 @@ static struct resource ssc1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_SSC1,
+- .end = AT91SAM9G45_ID_SSC1,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_SSC1,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_SSC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1475,8 +1475,8 @@ static struct resource dbgu_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_SYS,
+- .end = AT91_ID_SYS,
++ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
++ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1513,8 +1513,8 @@ static struct resource uart0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_US0,
+- .end = AT91SAM9G45_ID_US0,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_US0,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_US0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1556,8 +1556,8 @@ static struct resource uart1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_US1,
+- .end = AT91SAM9G45_ID_US1,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_US1,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_US1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1599,8 +1599,8 @@ static struct resource uart2_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_US2,
+- .end = AT91SAM9G45_ID_US2,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_US2,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_US2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1642,8 +1642,8 @@ static struct resource uart3_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_US3,
+- .end = AT91SAM9G45_ID_US3,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_US3,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_US3,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
+index e420085..72ce50a 100644
+--- a/arch/arm/mach-at91/at91sam9rl.c
++++ b/arch/arm/mach-at91/at91sam9rl.c
+@@ -19,6 +19,7 @@
+ #include <mach/cpu.h>
+ #include <mach/at91_dbgu.h>
+ #include <mach/at91sam9rl.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91_pmc.h>
+ #include <mach/at91_rstc.h>
+
+diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
+index 9c0b148..f09fff9 100644
+--- a/arch/arm/mach-at91/at91sam9rl_devices.c
++++ b/arch/arm/mach-at91/at91sam9rl_devices.c
+@@ -41,8 +41,8 @@ static struct resource hdmac_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+- .start = AT91SAM9RL_ID_DMA,
+- .end = AT91SAM9RL_ID_DMA,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_DMA,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_DMA,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -84,8 +84,8 @@ static struct resource usba_udc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+- .start = AT91SAM9RL_ID_UDPHS,
+- .end = AT91SAM9RL_ID_UDPHS,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_UDPHS,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_UDPHS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -172,8 +172,8 @@ static struct resource mmc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_MCI,
+- .end = AT91SAM9RL_ID_MCI,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_MCI,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_MCI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -339,8 +339,8 @@ static struct resource twi_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_TWI0,
+- .end = AT91SAM9RL_ID_TWI0,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_TWI0,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_TWI0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -383,8 +383,8 @@ static struct resource spi_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_SPI,
+- .end = AT91SAM9RL_ID_SPI,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_SPI,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_SPI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -452,8 +452,8 @@ static struct resource ac97_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_AC97C,
+- .end = AT91SAM9RL_ID_AC97C,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_AC97C,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_AC97C,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -507,8 +507,8 @@ static struct resource lcdc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_LCDC,
+- .end = AT91SAM9RL_ID_LCDC,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_LCDC,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_LCDC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -574,18 +574,18 @@ static struct resource tcb_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_TC0,
+- .end = AT91SAM9RL_ID_TC0,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC0,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+- .start = AT91SAM9RL_ID_TC1,
+- .end = AT91SAM9RL_ID_TC1,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC1,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+- .start = AT91SAM9RL_ID_TC2,
+- .end = AT91SAM9RL_ID_TC2,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC2,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -621,8 +621,8 @@ static struct resource tsadcc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_TSC,
+- .end = AT91SAM9RL_ID_TSC,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_TSC,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_TSC,
+ .flags = IORESOURCE_IRQ,
+ }
+ };
+@@ -768,8 +768,8 @@ static struct resource pwm_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_PWMC,
+- .end = AT91SAM9RL_ID_PWMC,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_PWMC,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_PWMC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -821,8 +821,8 @@ static struct resource ssc0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_SSC0,
+- .end = AT91SAM9RL_ID_SSC0,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_SSC0,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_SSC0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -863,8 +863,8 @@ static struct resource ssc1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_SSC1,
+- .end = AT91SAM9RL_ID_SSC1,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_SSC1,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_SSC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -943,8 +943,8 @@ static struct resource dbgu_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_SYS,
+- .end = AT91_ID_SYS,
++ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
++ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -981,8 +981,8 @@ static struct resource uart0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_US0,
+- .end = AT91SAM9RL_ID_US0,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_US0,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_US0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1032,8 +1032,8 @@ static struct resource uart1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_US1,
+- .end = AT91SAM9RL_ID_US1,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_US1,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_US1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1075,8 +1075,8 @@ static struct resource uart2_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_US2,
+- .end = AT91SAM9RL_ID_US2,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_US2,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_US2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1118,8 +1118,8 @@ static struct resource uart3_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_US3,
+- .end = AT91SAM9RL_ID_US3,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_US3,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_US3,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+diff --git a/arch/arm/mach-at91/at91x40.c b/arch/arm/mach-at91/at91x40.c
+index d62fe09..4c0f5fd 100644
+--- a/arch/arm/mach-at91/at91x40.c
++++ b/arch/arm/mach-at91/at91x40.c
+@@ -17,6 +17,7 @@
+ #include <asm/system_misc.h>
+ #include <asm/mach/arch.h>
+ #include <mach/at91x40.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91_st.h>
+ #include <mach/timex.h>
+ #include "generic.h"
+diff --git a/arch/arm/mach-at91/include/mach/at91_aic.h b/arch/arm/mach-at91/include/mach/at91_aic.h
+index 7867378..fd42a85 100644
+--- a/arch/arm/mach-at91/include/mach/at91_aic.h
++++ b/arch/arm/mach-at91/include/mach/at91_aic.h
+@@ -28,6 +28,9 @@ extern void __iomem *at91_aic_base;
+ .extern at91_aic_base
+ #endif
+
++/* Number of irq lines managed by AIC */
++#define NR_AIC_IRQS 32
++
+ #define AT91_AIC_IRQ_MIN_PRIORITY 0
+ #define AT91_AIC_IRQ_MAX_PRIORITY 7
+
+diff --git a/arch/arm/mach-at91/include/mach/irqs.h b/arch/arm/mach-at91/include/mach/irqs.h
+index 2d510ee..cab60d5 100644
+--- a/arch/arm/mach-at91/include/mach/irqs.h
++++ b/arch/arm/mach-at91/include/mach/irqs.h
+@@ -22,18 +22,6 @@
+ #define __ASM_ARCH_IRQS_H
+
+ #include <linux/io.h>
+-#include <mach/at91_aic.h>
+-
+-#define NR_AIC_IRQS 32
+-
+-
+-/*
+- * IRQ interrupt symbols are the AT91xxx_ID_* symbols
+- * for IRQs handled directly through the AIC, or else the AT91_PIN_*
+- * symbols in gpio.h for ones handled indirectly as GPIOs.
+- * We make provision for 5 banks of GPIO.
+- */
+-#define NR_IRQS (NR_AIC_IRQS + (5 * 32))
+
+ /* FIQ is AIC source 0. */
+ #define FIQ_START AT91_ID_FIQ
+diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
+index 390d4df..75ca2f4 100644
+--- a/arch/arm/mach-at91/irq.c
++++ b/arch/arm/mach-at91/irq.c
+@@ -41,6 +41,8 @@
+ #include <asm/mach/irq.h>
+ #include <asm/mach/map.h>
+
++#include <mach/at91_aic.h>
++
+ void __iomem *at91_aic_base;
+ static struct irq_domain *at91_aic_domain;
+ static struct device_node *at91_aic_np;
+@@ -302,11 +304,11 @@ void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
+ */
+ for (i = 0; i < NR_AIC_IRQS; i++) {
+ /* Put hardware irq number in Source Vector Register: */
+- at91_aic_write(AT91_AIC_SVR(i), i);
++ at91_aic_write(AT91_AIC_SVR(i), NR_IRQS_LEGACY + i);
+ /* Active Low interrupt, with the specified priority */
+ at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
+
+- irq_set_chip_and_handler(i, &at91_aic_chip, handle_fasteoi_irq);
++ irq_set_chip_and_handler(NR_IRQS_LEGACY + i, &at91_aic_chip, handle_fasteoi_irq);
+ set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+ }
+
+diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
+index 1bfaad6..2c2d865 100644
+--- a/arch/arm/mach-at91/pm.c
++++ b/arch/arm/mach-at91/pm.c
+@@ -25,6 +25,7 @@
+ #include <asm/mach/time.h>
+ #include <asm/mach/irq.h>
+
++#include <mach/at91_aic.h>
+ #include <mach/at91_pmc.h>
+ #include <mach/cpu.h>
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0059-ARM-at91-remove-mach-irqs.h.patch b/patches.at91/0059-ARM-at91-remove-mach-irqs.h.patch
new file mode 100644
index 00000000000000..17aa40e9ef3034
--- /dev/null
+++ b/patches.at91/0059-ARM-at91-remove-mach-irqs.h.patch
@@ -0,0 +1,53 @@
+From 45fba6f03c7b2ec9fd1b0d37715c6e8b9ebb3a4d Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Thu, 14 Jun 2012 15:41:04 +0200
+Subject: ARM: at91: remove mach/irqs.h
+
+mach/irqs only defines FIQ_START which doesn't appear to be used anywhere
+so remove it.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/include/mach/irqs.h | 29 -----------------------------
+ 1 file changed, 29 deletions(-)
+ delete mode 100644 arch/arm/mach-at91/include/mach/irqs.h
+
+diff --git a/arch/arm/mach-at91/include/mach/irqs.h b/arch/arm/mach-at91/include/mach/irqs.h
+deleted file mode 100644
+index cab60d5..0000000
+--- a/arch/arm/mach-at91/include/mach/irqs.h
++++ /dev/null
+@@ -1,29 +0,0 @@
+-/*
+- * arch/arm/mach-at91/include/mach/irqs.h
+- *
+- * Copyright (C) 2004 SAN People
+- *
+- * 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 __ASM_ARCH_IRQS_H
+-#define __ASM_ARCH_IRQS_H
+-
+-#include <linux/io.h>
+-
+-/* FIQ is AIC source 0. */
+-#define FIQ_START AT91_ID_FIQ
+-
+-#endif
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0060-ARM-at91-add-AIC5-support.patch b/patches.at91/0060-ARM-at91-add-AIC5-support.patch
new file mode 100644
index 00000000000000..feaacd1db0f4ae
--- /dev/null
+++ b/patches.at91/0060-ARM-at91-add-AIC5-support.patch
@@ -0,0 +1,606 @@
+From 2ab4fd505a722e59d1a7b02d4b8fe5a89bc2f761 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 30 May 2012 10:01:09 +0200
+Subject: ARM: at91: add AIC5 support
+
+The number of lines of AIC5 has increased from 32 to 128. Due to this
+increase, a source select register has been introduced for the interrupt
+line selection. Moreover, register mapping has been changed. For that reasons,
+we need some dedicated callbacks for AIC5.
+Power management is also concerned by these changes. On suspend, we can't get
+the whole interrupt mask register as before, we have to read this register 128
+times. To reduce this overhead, a snapshot of the whole IMR is maintained.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/generic.h | 2 +
+ arch/arm/mach-at91/include/mach/at91_aic.h | 26 +++
+ arch/arm/mach-at91/irq.c | 343 ++++++++++++++++++++++++-----
+ 3 files changed, 314 insertions(+), 57 deletions(-)
+
+diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
+index 0a60bf8..f496506 100644
+--- a/arch/arm/mach-at91/generic.h
++++ b/arch/arm/mach-at91/generic.h
+@@ -29,6 +29,8 @@ extern void __init at91x40_init_interrupts(unsigned int priority[]);
+ extern void __init at91_aic_init(unsigned int priority[]);
+ extern int __init at91_aic_of_init(struct device_node *node,
+ struct device_node *parent);
++extern int __init at91_aic5_of_init(struct device_node *node,
++ struct device_node *parent);
+
+
+ /* Timer */
+diff --git a/arch/arm/mach-at91/include/mach/at91_aic.h b/arch/arm/mach-at91/include/mach/at91_aic.h
+index fd42a85..eaea661 100644
+--- a/arch/arm/mach-at91/include/mach/at91_aic.h
++++ b/arch/arm/mach-at91/include/mach/at91_aic.h
+@@ -30,11 +30,16 @@ extern void __iomem *at91_aic_base;
+
+ /* Number of irq lines managed by AIC */
+ #define NR_AIC_IRQS 32
++#define NR_AIC5_IRQS 128
++
++#define AT91_AIC5_SSR 0x0 /* Source Select Register [AIC5] */
++#define AT91_AIC5_INTSEL_MSK (0x7f << 0) /* Interrupt Line Selection Mask */
+
+ #define AT91_AIC_IRQ_MIN_PRIORITY 0
+ #define AT91_AIC_IRQ_MAX_PRIORITY 7
+
+ #define AT91_AIC_SMR(n) ((n) * 4) /* Source Mode Registers 0-31 */
++#define AT91_AIC5_SMR 0x4 /* Source Mode Register [AIC5] */
+ #define AT91_AIC_PRIOR (7 << 0) /* Priority Level */
+ #define AT91_AIC_SRCTYPE (3 << 5) /* Interrupt Source Type */
+ #define AT91_AIC_SRCTYPE_LOW (0 << 5)
+@@ -43,31 +48,52 @@ extern void __iomem *at91_aic_base;
+ #define AT91_AIC_SRCTYPE_RISING (3 << 5)
+
+ #define AT91_AIC_SVR(n) (0x80 + ((n) * 4)) /* Source Vector Registers 0-31 */
++#define AT91_AIC5_SVR 0x8 /* Source Vector Register [AIC5] */
+ #define AT91_AIC_IVR 0x100 /* Interrupt Vector Register */
++#define AT91_AIC5_IVR 0x10 /* Interrupt Vector Register [AIC5] */
+ #define AT91_AIC_FVR 0x104 /* Fast Interrupt Vector Register */
++#define AT91_AIC5_FVR 0x14 /* Fast Interrupt Vector Register [AIC5] */
+ #define AT91_AIC_ISR 0x108 /* Interrupt Status Register */
++#define AT91_AIC5_ISR 0x18 /* Interrupt Status Register [AIC5] */
+ #define AT91_AIC_IRQID (0x1f << 0) /* Current Interrupt Identifier */
+
+ #define AT91_AIC_IPR 0x10c /* Interrupt Pending Register */
++#define AT91_AIC5_IPR0 0x20 /* Interrupt Pending Register 0 [AIC5] */
++#define AT91_AIC5_IPR1 0x24 /* Interrupt Pending Register 1 [AIC5] */
++#define AT91_AIC5_IPR2 0x28 /* Interrupt Pending Register 2 [AIC5] */
++#define AT91_AIC5_IPR3 0x2c /* Interrupt Pending Register 3 [AIC5] */
+ #define AT91_AIC_IMR 0x110 /* Interrupt Mask Register */
++#define AT91_AIC5_IMR 0x30 /* Interrupt Mask Register [AIC5] */
+ #define AT91_AIC_CISR 0x114 /* Core Interrupt Status Register */
++#define AT91_AIC5_CISR 0x34 /* Core Interrupt Status Register [AIC5] */
+ #define AT91_AIC_NFIQ (1 << 0) /* nFIQ Status */
+ #define AT91_AIC_NIRQ (1 << 1) /* nIRQ Status */
+
+ #define AT91_AIC_IECR 0x120 /* Interrupt Enable Command Register */
++#define AT91_AIC5_IECR 0x40 /* Interrupt Enable Command Register [AIC5] */
+ #define AT91_AIC_IDCR 0x124 /* Interrupt Disable Command Register */
++#define AT91_AIC5_IDCR 0x44 /* Interrupt Disable Command Register [AIC5] */
+ #define AT91_AIC_ICCR 0x128 /* Interrupt Clear Command Register */
++#define AT91_AIC5_ICCR 0x48 /* Interrupt Clear Command Register [AIC5] */
+ #define AT91_AIC_ISCR 0x12c /* Interrupt Set Command Register */
++#define AT91_AIC5_ISCR 0x4c /* Interrupt Set Command Register [AIC5] */
+ #define AT91_AIC_EOICR 0x130 /* End of Interrupt Command Register */
++#define AT91_AIC5_EOICR 0x38 /* End of Interrupt Command Register [AIC5] */
+ #define AT91_AIC_SPU 0x134 /* Spurious Interrupt Vector Register */
++#define AT91_AIC5_SPU 0x3c /* Spurious Interrupt Vector Register [AIC5] */
+ #define AT91_AIC_DCR 0x138 /* Debug Control Register */
++#define AT91_AIC5_DCR 0x6c /* Debug Control Register [AIC5] */
+ #define AT91_AIC_DCR_PROT (1 << 0) /* Protection Mode */
+ #define AT91_AIC_DCR_GMSK (1 << 1) /* General Mask */
+
+ #define AT91_AIC_FFER 0x140 /* Fast Forcing Enable Register [SAM9 only] */
++#define AT91_AIC5_FFER 0x50 /* Fast Forcing Enable Register [AIC5] */
+ #define AT91_AIC_FFDR 0x144 /* Fast Forcing Disable Register [SAM9 only] */
++#define AT91_AIC5_FFDR 0x54 /* Fast Forcing Disable Register [AIC5] */
+ #define AT91_AIC_FFSR 0x148 /* Fast Forcing Status Register [SAM9 only] */
++#define AT91_AIC5_FFSR 0x58 /* Fast Forcing Status Register [AIC5] */
+
+ void at91_aic_handle_irq(struct pt_regs *regs);
++void at91_aic5_handle_irq(struct pt_regs *regs);
+
+ #endif
+diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
+index 75ca2f4..c5eaaa0 100644
+--- a/arch/arm/mach-at91/irq.c
++++ b/arch/arm/mach-at91/irq.c
+@@ -23,6 +23,7 @@
+ #include <linux/init.h>
+ #include <linux/module.h>
+ #include <linux/mm.h>
++#include <linux/bitmap.h>
+ #include <linux/types.h>
+ #include <linux/irq.h>
+ #include <linux/of.h>
+@@ -46,9 +47,116 @@
+ void __iomem *at91_aic_base;
+ static struct irq_domain *at91_aic_domain;
+ static struct device_node *at91_aic_np;
++static unsigned int n_irqs = NR_AIC_IRQS;
++static unsigned long at91_aic_caps = 0;
+ static unsigned int *at91_aic_irq_priorities;
+
+-asmlinkage void __exception_irq_entry at91_aic_handle_irq(struct pt_regs *regs)
++/* AIC5 introduces a Source Select Register */
++#define AT91_AIC_CAP_AIC5 (1 << 0)
++#define has_aic5() (at91_aic_caps & AT91_AIC_CAP_AIC5)
++
++#ifdef CONFIG_PM
++
++static unsigned long *wakeups;
++static unsigned long *backups;
++
++#define set_backup(bit) set_bit(bit, backups)
++#define clear_backup(bit) clear_bit(bit, backups)
++
++static int at91_aic_pm_init(void)
++{
++ backups = kzalloc(BITS_TO_LONGS(n_irqs) * sizeof(*backups), GFP_KERNEL);
++ if (!backups)
++ return -ENOMEM;
++
++ wakeups = kzalloc(BITS_TO_LONGS(n_irqs) * sizeof(*backups), GFP_KERNEL);
++ if (!wakeups) {
++ kfree(backups);
++ return -ENOMEM;
++ }
++
++ return 0;
++}
++
++static int at91_aic_set_wake(struct irq_data *d, unsigned value)
++{
++ if (unlikely(d->hwirq >= n_irqs))
++ return -EINVAL;
++
++ if (value)
++ set_bit(d->hwirq, wakeups);
++ else
++ clear_bit(d->hwirq, wakeups);
++
++ return 0;
++}
++
++void at91_irq_suspend(void)
++{
++ int i = 0, bit;
++
++ if (has_aic5()) {
++ /* disable enabled irqs */
++ while ((bit = find_next_bit(backups, n_irqs, i)) < n_irqs) {
++ at91_aic_write(AT91_AIC5_SSR,
++ bit & AT91_AIC5_INTSEL_MSK);
++ at91_aic_write(AT91_AIC5_IDCR, 1);
++ i = bit;
++ }
++ /* enable wakeup irqs */
++ i = 0;
++ while ((bit = find_next_bit(wakeups, n_irqs, i)) < n_irqs) {
++ at91_aic_write(AT91_AIC5_SSR,
++ bit & AT91_AIC5_INTSEL_MSK);
++ at91_aic_write(AT91_AIC5_IECR, 1);
++ i = bit;
++ }
++ } else {
++ at91_aic_write(AT91_AIC_IDCR, *backups);
++ at91_aic_write(AT91_AIC_IECR, *wakeups);
++ }
++}
++
++void at91_irq_resume(void)
++{
++ int i = 0, bit;
++
++ if (has_aic5()) {
++ /* disable wakeup irqs */
++ while ((bit = find_next_bit(wakeups, n_irqs, i)) < n_irqs) {
++ at91_aic_write(AT91_AIC5_SSR,
++ bit & AT91_AIC5_INTSEL_MSK);
++ at91_aic_write(AT91_AIC5_IDCR, 1);
++ i = bit;
++ }
++ /* enable irqs disabled for suspend */
++ i = 0;
++ while ((bit = find_next_bit(backups, n_irqs, i)) < n_irqs) {
++ at91_aic_write(AT91_AIC5_SSR,
++ bit & AT91_AIC5_INTSEL_MSK);
++ at91_aic_write(AT91_AIC5_IECR, 1);
++ i = bit;
++ }
++ } else {
++ at91_aic_write(AT91_AIC_IDCR, *wakeups);
++ at91_aic_write(AT91_AIC_IECR, *backups);
++ }
++}
++
++#else
++static inline int at91_aic_pm_init(void)
++{
++ return 0;
++}
++
++#define set_backup(bit)
++#define clear_backup(bit)
++#define at91_aic_set_wake NULL
++
++#endif /* CONFIG_PM */
++
++asmlinkage void __exception_irq_entry
++at91_aic_handle_irq(struct pt_regs *regs)
+ {
+ u32 irqnr;
+ u32 irqstat;
+@@ -66,16 +174,53 @@ asmlinkage void __exception_irq_entry at91_aic_handle_irq(struct pt_regs *regs)
+ handle_IRQ(irqnr, regs);
+ }
+
++asmlinkage void __exception_irq_entry
++at91_aic5_handle_irq(struct pt_regs *regs)
++{
++ u32 irqnr;
++ u32 irqstat;
++
++ irqnr = at91_aic_read(AT91_AIC5_IVR);
++ irqstat = at91_aic_read(AT91_AIC5_ISR);
++
++ if (!irqstat)
++ at91_aic_write(AT91_AIC5_EOICR, 0);
++ else
++ handle_IRQ(irqnr, regs);
++}
++
+ static void at91_aic_mask_irq(struct irq_data *d)
+ {
+ /* Disable interrupt on AIC */
+ at91_aic_write(AT91_AIC_IDCR, 1 << d->hwirq);
++ /* Update ISR cache */
++ clear_backup(d->hwirq);
++}
++
++static void __maybe_unused at91_aic5_mask_irq(struct irq_data *d)
++{
++ /* Disable interrupt on AIC5 */
++ at91_aic_write(AT91_AIC5_SSR, d->hwirq & AT91_AIC5_INTSEL_MSK);
++ at91_aic_write(AT91_AIC5_IDCR, 1);
++ /* Update ISR cache */
++ clear_backup(d->hwirq);
+ }
+
+ static void at91_aic_unmask_irq(struct irq_data *d)
+ {
+ /* Enable interrupt on AIC */
+ at91_aic_write(AT91_AIC_IECR, 1 << d->hwirq);
++ /* Update ISR cache */
++ set_backup(d->hwirq);
++}
++
++static void __maybe_unused at91_aic5_unmask_irq(struct irq_data *d)
++{
++ /* Enable interrupt on AIC5 */
++ at91_aic_write(AT91_AIC5_SSR, d->hwirq & AT91_AIC5_INTSEL_MSK);
++ at91_aic_write(AT91_AIC5_IECR, 1);
++ /* Update ISR cache */
++ set_backup(d->hwirq);
+ }
+
+ static void at91_aic_eoi(struct irq_data *d)
+@@ -87,13 +232,18 @@ static void at91_aic_eoi(struct irq_data *d)
+ at91_aic_write(AT91_AIC_EOICR, 0);
+ }
+
+-unsigned int at91_extern_irq;
++static void __maybe_unused at91_aic5_eoi(struct irq_data *d)
++{
++ at91_aic_write(AT91_AIC5_EOICR, 0);
++}
+
+-#define is_extern_irq(hwirq) ((1 << (hwirq)) & at91_extern_irq)
++unsigned long *at91_extern_irq;
+
+-static int at91_aic_set_type(struct irq_data *d, unsigned type)
++#define is_extern_irq(hwirq) test_bit(hwirq, at91_extern_irq)
++
++static int at91_aic_compute_srctype(struct irq_data *d, unsigned type)
+ {
+- unsigned int smr, srctype;
++ int srctype;
+
+ switch (type) {
+ case IRQ_TYPE_LEVEL_HIGH:
+@@ -106,58 +256,44 @@ static int at91_aic_set_type(struct irq_data *d, unsigned type)
+ if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */
+ srctype = AT91_AIC_SRCTYPE_LOW;
+ else
+- return -EINVAL;
++ srctype = -EINVAL;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */
+ srctype = AT91_AIC_SRCTYPE_FALLING;
+ else
+- return -EINVAL;
++ srctype = -EINVAL;
+ break;
+ default:
+- return -EINVAL;
++ srctype = -EINVAL;
+ }
+
+- smr = at91_aic_read(AT91_AIC_SMR(d->hwirq)) & ~AT91_AIC_SRCTYPE;
+- at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype);
+- return 0;
++ return srctype;
+ }
+
+-#ifdef CONFIG_PM
+-
+-static u32 wakeups;
+-static u32 backups;
+-
+-static int at91_aic_set_wake(struct irq_data *d, unsigned value)
++static int at91_aic_set_type(struct irq_data *d, unsigned type)
+ {
+- if (unlikely(d->hwirq >= NR_AIC_IRQS))
+- return -EINVAL;
+-
+- if (value)
+- wakeups |= (1 << d->hwirq);
+- else
+- wakeups &= ~(1 << d->hwirq);
++ unsigned int smr;
++ int srctype;
++
++ srctype = at91_aic_compute_srctype(d, type);
++ if (srctype < 0)
++ return srctype;
++
++ if (has_aic5()) {
++ at91_aic_write(AT91_AIC5_SSR,
++ d->hwirq & AT91_AIC5_INTSEL_MSK);
++ smr = at91_aic_read(AT91_AIC5_SMR) & ~AT91_AIC_SRCTYPE;
++ at91_aic_write(AT91_AIC5_SMR, smr | srctype);
++ } else {
++ smr = at91_aic_read(AT91_AIC_SMR(d->hwirq))
++ & ~AT91_AIC_SRCTYPE;
++ at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype);
++ }
+
+ return 0;
+ }
+
+-void at91_irq_suspend(void)
+-{
+- backups = at91_aic_read(AT91_AIC_IMR);
+- at91_aic_write(AT91_AIC_IDCR, backups);
+- at91_aic_write(AT91_AIC_IECR, wakeups);
+-}
+-
+-void at91_irq_resume(void)
+-{
+- at91_aic_write(AT91_AIC_IDCR, wakeups);
+- at91_aic_write(AT91_AIC_IECR, backups);
+-}
+-
+-#else
+-#define at91_aic_set_wake NULL
+-#endif
+-
+ static struct irq_chip at91_aic_chip = {
+ .name = "AIC",
+ .irq_mask = at91_aic_mask_irq,
+@@ -193,6 +329,35 @@ static void __init at91_aic_hw_init(unsigned int spu_vector)
+ at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF);
+ }
+
++static void __init __maybe_unused at91_aic5_hw_init(unsigned int spu_vector)
++{
++ int i;
++
++ /*
++ * Perform 8 End Of Interrupt Command to make sure AIC
++ * will not Lock out nIRQ
++ */
++ for (i = 0; i < 8; i++)
++ at91_aic_write(AT91_AIC5_EOICR, 0);
++
++ /*
++ * Spurious Interrupt ID in Spurious Vector Register.
++ * When there is no current interrupt, the IRQ Vector Register
++ * reads the value stored in AIC_SPU
++ */
++ at91_aic_write(AT91_AIC5_SPU, spu_vector);
++
++ /* No debugging in AIC: Debug (Protect) Control Register */
++ at91_aic_write(AT91_AIC5_DCR, 0);
++
++ /* Disable and clear all interrupts initially */
++ for (i = 0; i < n_irqs; i++) {
++ at91_aic_write(AT91_AIC5_SSR, i & AT91_AIC5_INTSEL_MSK);
++ at91_aic_write(AT91_AIC5_IDCR, 1);
++ at91_aic_write(AT91_AIC5_ICCR, 1);
++ }
++}
++
+ #if defined(CONFIG_OF)
+ static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+@@ -210,13 +375,31 @@ static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
+ return 0;
+ }
+
++static int at91_aic5_irq_map(struct irq_domain *h, unsigned int virq,
++ irq_hw_number_t hw)
++{
++ at91_aic_write(AT91_AIC5_SSR, hw & AT91_AIC5_INTSEL_MSK);
++
++ /* Put virq number in Source Vector Register */
++ at91_aic_write(AT91_AIC5_SVR, virq);
++
++ /* Active Low interrupt, with priority */
++ at91_aic_write(AT91_AIC5_SMR,
++ AT91_AIC_SRCTYPE_LOW | at91_aic_irq_priorities[hw]);
++
++ irq_set_chip_and_handler(virq, &at91_aic_chip, handle_fasteoi_irq);
++ set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
++
++ return 0;
++}
++
+ static int at91_aic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
+ const u32 *intspec, unsigned int intsize,
+ irq_hw_number_t *out_hwirq, unsigned int *out_type)
+ {
+ if (WARN_ON(intsize < 3))
+ return -EINVAL;
+- if (WARN_ON(intspec[0] >= NR_AIC_IRQS))
++ if (WARN_ON(intspec[0] >= n_irqs))
+ return -EINVAL;
+ if (WARN_ON((intspec[2] < AT91_AIC_IRQ_MIN_PRIORITY)
+ || (intspec[2] > AT91_AIC_IRQ_MAX_PRIORITY)))
+@@ -234,14 +417,24 @@ static struct irq_domain_ops at91_aic_irq_ops = {
+ .xlate = at91_aic_irq_domain_xlate,
+ };
+
+-int __init at91_aic_of_init(struct device_node *node,
+- struct device_node *parent)
++int __init at91_aic_of_common_init(struct device_node *node,
++ struct device_node *parent)
+ {
+ struct property *prop;
+ const __be32 *p;
+ u32 val;
+
+- at91_aic_irq_priorities = kzalloc(NR_AIC_IRQS
++ at91_extern_irq = kzalloc(BITS_TO_LONGS(n_irqs)
++ * sizeof(*at91_extern_irq), GFP_KERNEL);
++ if (!at91_extern_irq)
++ return -ENOMEM;
++
++ if (at91_aic_pm_init()) {
++ kfree(at91_extern_irq);
++ return -ENOMEM;
++ }
++
++ at91_aic_irq_priorities = kzalloc(n_irqs
+ * sizeof(*at91_aic_irq_priorities),
+ GFP_KERNEL);
+ if (!at91_aic_irq_priorities)
+@@ -250,22 +443,56 @@ int __init at91_aic_of_init(struct device_node *node,
+ at91_aic_base = of_iomap(node, 0);
+ at91_aic_np = node;
+
+- at91_aic_domain = irq_domain_add_linear(at91_aic_np, NR_AIC_IRQS,
++ at91_aic_domain = irq_domain_add_linear(at91_aic_np, n_irqs,
+ &at91_aic_irq_ops, NULL);
+ if (!at91_aic_domain)
+ panic("Unable to add AIC irq domain (DT)\n");
+
+- at91_extern_irq = 0;
+ of_property_for_each_u32(node, "atmel,external-irqs", prop, p, val) {
+- if (val > 31)
+- pr_warn("AIC: external irq %d > 31 skip it\n", val);
++ if (val >= n_irqs)
++ pr_warn("AIC: external irq %d >= %d skip it\n",
++ val, n_irqs);
+ else
+- at91_extern_irq |= (1 << val);
++ set_bit(val, at91_extern_irq);
+ }
+
+ irq_set_default_host(at91_aic_domain);
+
+- at91_aic_hw_init(NR_AIC_IRQS);
++ return 0;
++}
++
++int __init at91_aic_of_init(struct device_node *node,
++ struct device_node *parent)
++{
++ int err;
++
++ err = at91_aic_of_common_init(node, parent);
++ if (err)
++ return err;
++
++ at91_aic_hw_init(n_irqs);
++
++ return 0;
++}
++
++int __init at91_aic5_of_init(struct device_node *node,
++ struct device_node *parent)
++{
++ int err;
++
++ at91_aic_caps |= AT91_AIC_CAP_AIC5;
++ n_irqs = NR_AIC5_IRQS;
++ at91_aic_chip.irq_ack = at91_aic5_mask_irq;
++ at91_aic_chip.irq_mask = at91_aic5_mask_irq;
++ at91_aic_chip.irq_unmask = at91_aic5_unmask_irq;
++ at91_aic_chip.irq_eoi = at91_aic5_eoi;
++ at91_aic_irq_ops.map = at91_aic5_irq_map;
++
++ err = at91_aic_of_common_init(node, parent);
++ if (err)
++ return err;
++
++ at91_aic5_hw_init(n_irqs);
+
+ return 0;
+ }
+@@ -274,22 +501,25 @@ int __init at91_aic_of_init(struct device_node *node,
+ /*
+ * Initialize the AIC interrupt controller.
+ */
+-void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
++void __init at91_aic_init(unsigned int *priority)
+ {
+ unsigned int i;
+ int irq_base;
+
++ if (at91_aic_pm_init())
++ panic("Unable to allocate bit maps\n");
++
+ at91_aic_base = ioremap(AT91_AIC, 512);
+ if (!at91_aic_base)
+ panic("Unable to ioremap AIC registers\n");
+
+ /* Add irq domain for AIC */
+- irq_base = irq_alloc_descs(-1, 0, NR_AIC_IRQS, 0);
++ irq_base = irq_alloc_descs(-1, 0, n_irqs, 0);
+ if (irq_base < 0) {
+ WARN(1, "Cannot allocate irq_descs, assuming pre-allocated\n");
+ irq_base = 0;
+ }
+- at91_aic_domain = irq_domain_add_legacy(at91_aic_np, NR_AIC_IRQS,
++ at91_aic_domain = irq_domain_add_legacy(at91_aic_np, n_irqs,
+ irq_base, 0,
+ &irq_domain_simple_ops, NULL);
+
+@@ -302,15 +532,14 @@ void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
+ * The IVR is used by macro get_irqnr_and_base to read and verify.
+ * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
+ */
+- for (i = 0; i < NR_AIC_IRQS; i++) {
++ for (i = 0; i < n_irqs; i++) {
+ /* Put hardware irq number in Source Vector Register: */
+ at91_aic_write(AT91_AIC_SVR(i), NR_IRQS_LEGACY + i);
+ /* Active Low interrupt, with the specified priority */
+ at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
+-
+ irq_set_chip_and_handler(NR_IRQS_LEGACY + i, &at91_aic_chip, handle_fasteoi_irq);
+ set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+ }
+
+- at91_aic_hw_init(NR_AIC_IRQS);
++ at91_aic_hw_init(n_irqs);
+ }
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0061-dt-add-property-iteration-helpers.patch b/patches.at91/0061-dt-add-property-iteration-helpers.patch
new file mode 100644
index 00000000000000..40f12e568a1529
--- /dev/null
+++ b/patches.at91/0061-dt-add-property-iteration-helpers.patch
@@ -0,0 +1,129 @@
+From b0a2eb064f2171838c4562f34eb1e492ce0361d5 Mon Sep 17 00:00:00 2001
+From: Stephen Warren <swarren@nvidia.com>
+Date: Wed, 4 Apr 2012 09:27:46 -0600
+Subject: dt: add property iteration helpers
+
+This patch adds macros of_property_for_each_u32() and
+of_property_for_each_string(), which iterate over an array of values
+within a device-tree property. Usage is for example:
+
+struct property *prop;
+const __be32 *p;
+u32 u;
+of_property_for_each_u32(np, "propname", prop, p, u)
+ printk("U32 value: %x\n", u);
+
+struct property *prop;
+const char *s;
+of_property_for_each_string(np, "propname", prop, s)
+ printk("String value: %s\n", s);
+
+Based on work by Rob Herring <robherring2@gmail.com>
+
+Cc: Grant Likely <grant.likely@secretlab.ca>
+Signed-off-by: Stephen Warren <swarren@nvidia.com>
+Acked-by: Rob Herring <rob.herring@calxeda.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/of/base.c | 41 +++++++++++++++++++++++++++++++++++++++++
+ include/linux/of.h | 35 +++++++++++++++++++++++++++++++++++
+ 2 files changed, 76 insertions(+)
+
+--- a/drivers/of/base.c
++++ b/drivers/of/base.c
+@@ -1260,3 +1260,44 @@ int of_alias_get_id(struct device_node *
+ return id;
+ }
+ EXPORT_SYMBOL_GPL(of_alias_get_id);
++
++const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
++ u32 *pu)
++{
++ const void *curv = cur;
++
++ if (!prop)
++ return NULL;
++
++ if (!cur) {
++ curv = prop->value;
++ goto out_val;
++ }
++
++ curv += sizeof(*cur);
++ if (curv >= prop->value + prop->length)
++ return NULL;
++
++out_val:
++ *pu = be32_to_cpup(curv);
++ return curv;
++}
++EXPORT_SYMBOL_GPL(of_prop_next_u32);
++
++const char *of_prop_next_string(struct property *prop, const char *cur)
++{
++ const void *curv = cur;
++
++ if (!prop)
++ return NULL;
++
++ if (!cur)
++ return prop->value;
++
++ curv += strlen(cur) + 1;
++ if (curv >= prop->value + prop->length)
++ return NULL;
++
++ return curv;
++}
++EXPORT_SYMBOL_GPL(of_prop_next_string);
+--- a/include/linux/of.h
++++ b/include/linux/of.h
+@@ -260,6 +260,37 @@ extern void of_detach_node(struct device
+ #endif
+
+ #define of_match_ptr(_ptr) (_ptr)
++
++/*
++ * struct property *prop;
++ * const __be32 *p;
++ * u32 u;
++ *
++ * of_property_for_each_u32(np, "propname", prop, p, u)
++ * printk("U32 value: %x\n", u);
++ */
++const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
++ u32 *pu);
++#define of_property_for_each_u32(np, propname, prop, p, u) \
++ for (prop = of_find_property(np, propname, NULL), \
++ p = of_prop_next_u32(prop, NULL, &u); \
++ p; \
++ p = of_prop_next_u32(prop, p, &u))
++
++/*
++ * struct property *prop;
++ * const char *s;
++ *
++ * of_property_for_each_string(np, "propname", prop, s)
++ * printk("String value: %s\n", s);
++ */
++const char *of_prop_next_string(struct property *prop, const char *cur);
++#define of_property_for_each_string(np, propname, prop, s) \
++ for (prop = of_find_property(np, propname, NULL), \
++ s = of_prop_next_string(prop, NULL); \
++ s; \
++ s = of_prop_next_string(prop, s))
++
+ #else /* CONFIG_OF */
+
+ static inline const char* of_node_full_name(struct device_node *np)
+@@ -355,6 +386,10 @@ static inline int of_machine_is_compatib
+
+ #define of_match_ptr(_ptr) NULL
+ #define of_match_node(_matches, _node) NULL
++#define of_property_for_each_u32(np, propname, prop, p, u) \
++ while (0)
++#define of_property_for_each_string(np, propname, prop, s) \
++ while (0)
+ #endif /* CONFIG_OF */
+
+ #ifndef of_node_to_nid
diff --git a/patches.at91/0062-ARM-at91-fix-new-build-errors.patch b/patches.at91/0062-ARM-at91-fix-new-build-errors.patch
new file mode 100644
index 00000000000000..b26870b9f081b0
--- /dev/null
+++ b/patches.at91/0062-ARM-at91-fix-new-build-errors.patch
@@ -0,0 +1,95 @@
+From a00b0ccc24fe0904fa187dd320709da1b6f44c90 Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Wed, 4 Jul 2012 07:45:16 +0000
+Subject: ARM: at91: fix new build errors
+
+MULTI_IRQ_HANDLER and SPARSE_IRQ are now required everywhere because
+mach/irqs.h and mach/entry-macros.S are gone but the symbols are
+only selected for AT91SAM9, not for the NOMMU parts.
+
+A few files now need to include linux/io.h directly, which used to
+be included through other headers that have changed.
+
+The new at91_aic_irq_priorities variable is only used with CONFIG_OF
+enabled and should not be visible otherwise.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/Kconfig | 4 ++++
+ arch/arm/mach-at91/at91x40.c | 1 +
+ arch/arm/mach-at91/irq.c | 3 ++-
+ drivers/rtc/rtc-at91rm9200.c | 1 +
+ 4 files changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
+index 7d0c40a..c8050b1 100644
+--- a/arch/arm/mach-at91/Kconfig
++++ b/arch/arm/mach-at91/Kconfig
+@@ -37,6 +37,8 @@ config SOC_AT91SAM9
+ config SOC_AT91RM9200
+ bool "AT91RM9200"
+ select CPU_ARM920T
++ select MULTI_IRQ_HANDLER
++ select SPARSE_IRQ
+ select GENERIC_CLOCKEVENTS
+ select HAVE_AT91_DBGU0
+
+@@ -142,6 +144,8 @@ config ARCH_AT91SAM9G45
+ config ARCH_AT91X40
+ bool "AT91x40"
+ depends on !MMU
++ select MULTI_IRQ_HANDLER
++ select SPARSE_IRQ
+ select ARCH_USES_GETTIMEOFFSET
+
+ endchoice
+diff --git a/arch/arm/mach-at91/at91x40.c b/arch/arm/mach-at91/at91x40.c
+index 4c0f5fd..46090e6 100644
+--- a/arch/arm/mach-at91/at91x40.c
++++ b/arch/arm/mach-at91/at91x40.c
+@@ -13,6 +13,7 @@
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/irq.h>
++#include <linux/io.h>
+ #include <asm/proc-fns.h>
+ #include <asm/system_misc.h>
+ #include <asm/mach/arch.h>
+diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
+index c5eaaa0..1e02c0e 100644
+--- a/arch/arm/mach-at91/irq.c
++++ b/arch/arm/mach-at91/irq.c
+@@ -49,7 +49,6 @@ static struct irq_domain *at91_aic_domain;
+ static struct device_node *at91_aic_np;
+ static unsigned int n_irqs = NR_AIC_IRQS;
+ static unsigned long at91_aic_caps = 0;
+-static unsigned int *at91_aic_irq_priorities;
+
+ /* AIC5 introduces a Source Select Register */
+ #define AT91_AIC_CAP_AIC5 (1 << 0)
+@@ -359,6 +358,8 @@ static void __init __maybe_unused at91_aic5_hw_init(unsigned int spu_vector)
+ }
+
+ #if defined(CONFIG_OF)
++static unsigned int *at91_aic_irq_priorities;
++
+ static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+ {
+diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
+index f02acb0..a4c78c0 100644
+--- a/drivers/rtc/rtc-at91rm9200.c
++++ b/drivers/rtc/rtc-at91rm9200.c
+@@ -27,6 +27,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/ioctl.h>
+ #include <linux/completion.h>
++#include <linux/io.h>
+
+ #include <asm/io.h>
+ #include <asm/uaccess.h>
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0063-dmaengine-at_hdmac-remove-some-at_dma_slave-comments.patch b/patches.at91/0063-dmaengine-at_hdmac-remove-some-at_dma_slave-comments.patch
new file mode 100644
index 00000000000000..64a2b3ea490bfa
--- /dev/null
+++ b/patches.at91/0063-dmaengine-at_hdmac-remove-some-at_dma_slave-comments.patch
@@ -0,0 +1,32 @@
+From 0144b540ede14f0e1c1f3d084e4d48552a347b6a Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 10 May 2012 12:17:39 +0200
+Subject: dmaengine: at_hdmac: remove some at_dma_slave comments
+
+These comments were covering removed struct at_dma_slave fields.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
+---
+ arch/arm/mach-at91/include/mach/at_hdmac.h | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/arch/arm/mach-at91/include/mach/at_hdmac.h b/arch/arm/mach-at91/include/mach/at_hdmac.h
+index fff48d1..810a13e 100644
+--- a/arch/arm/mach-at91/include/mach/at_hdmac.h
++++ b/arch/arm/mach-at91/include/mach/at_hdmac.h
+@@ -26,11 +26,6 @@ struct at_dma_platform_data {
+ /**
+ * struct at_dma_slave - Controller-specific information about a slave
+ * @dma_dev: required DMA master device
+- * @tx_reg: physical address of data register used for
+- * memory-to-peripheral transfers
+- * @rx_reg: physical address of data register used for
+- * peripheral-to-memory transfers
+- * @reg_width: peripheral register width
+ * @cfg: Platform-specific initializer for the CFG register
+ * @ctrla: Platform-specific initializer for the CTRLA register
+ */
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0064-dmaengine-at_hdmac-remove-ATC_DEFAULT_CTRLA-constant.patch b/patches.at91/0064-dmaengine-at_hdmac-remove-ATC_DEFAULT_CTRLA-constant.patch
new file mode 100644
index 00000000000000..ff3c21c85f24bb
--- /dev/null
+++ b/patches.at91/0064-dmaengine-at_hdmac-remove-ATC_DEFAULT_CTRLA-constant.patch
@@ -0,0 +1,66 @@
+From 6a24ecd4c954856980e2c5be94c85d97bf6a47d6 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 10 May 2012 12:17:40 +0200
+Subject: dmaengine: at_hdmac: remove ATC_DEFAULT_CTRLA constant
+
+Not needed constant that was set to 0.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
+---
+ drivers/dma/at_hdmac.c | 12 +++++-------
+ 1 file changed, 5 insertions(+), 7 deletions(-)
+
+--- a/drivers/dma/at_hdmac.c
++++ b/drivers/dma/at_hdmac.c
+@@ -39,7 +39,6 @@
+ */
+
+ #define ATC_DEFAULT_CFG (ATC_FIFOCFG_HALFFIFO)
+-#define ATC_DEFAULT_CTRLA (0)
+ #define ATC_DEFAULT_CTRLB (ATC_SIF(AT_DMA_MEM_IF) \
+ |ATC_DIF(AT_DMA_MEM_IF))
+
+@@ -574,7 +573,6 @@ atc_prep_dma_memcpy(struct dma_chan *cha
+ return NULL;
+ }
+
+- ctrla = ATC_DEFAULT_CTRLA;
+ ctrlb = ATC_DEFAULT_CTRLB | ATC_IEN
+ | ATC_SRC_ADDR_MODE_INCR
+ | ATC_DST_ADDR_MODE_INCR
+@@ -585,13 +583,13 @@ atc_prep_dma_memcpy(struct dma_chan *cha
+ * of the most common optimization.
+ */
+ if (!((src | dest | len) & 3)) {
+- ctrla |= ATC_SRC_WIDTH_WORD | ATC_DST_WIDTH_WORD;
++ ctrla = ATC_SRC_WIDTH_WORD | ATC_DST_WIDTH_WORD;
+ src_width = dst_width = 2;
+ } else if (!((src | dest | len) & 1)) {
+- ctrla |= ATC_SRC_WIDTH_HALFWORD | ATC_DST_WIDTH_HALFWORD;
++ ctrla = ATC_SRC_WIDTH_HALFWORD | ATC_DST_WIDTH_HALFWORD;
+ src_width = dst_width = 1;
+ } else {
+- ctrla |= ATC_SRC_WIDTH_BYTE | ATC_DST_WIDTH_BYTE;
++ ctrla = ATC_SRC_WIDTH_BYTE | ATC_DST_WIDTH_BYTE;
+ src_width = dst_width = 0;
+ }
+
+@@ -668,7 +666,7 @@ atc_prep_slave_sg(struct dma_chan *chan,
+ return NULL;
+ }
+
+- ctrla = ATC_DEFAULT_CTRLA | atslave->ctrla;
++ ctrla = atslave->ctrla;
+ ctrlb = ATC_IEN;
+
+ switch (direction) {
+@@ -812,7 +810,7 @@ atc_dma_cyclic_fill_desc(struct dma_chan
+ u32 ctrla;
+
+ /* prepare common CRTLA value */
+- ctrla = ATC_DEFAULT_CTRLA | atslave->ctrla
++ ctrla = atslave->ctrla
+ | ATC_DST_WIDTH(reg_width)
+ | ATC_SRC_WIDTH(reg_width)
+ | period_len >> reg_width;
diff --git a/patches.at91/0065-dmaengine-at_hdmac-take-maxburst-from-slave-configur.patch b/patches.at91/0065-dmaengine-at_hdmac-take-maxburst-from-slave-configur.patch
new file mode 100644
index 00000000000000..2dc96e7fde2fb6
--- /dev/null
+++ b/patches.at91/0065-dmaengine-at_hdmac-take-maxburst-from-slave-configur.patch
@@ -0,0 +1,129 @@
+From a692d1243e4c2513c96f00b9be1ab36fb65d2992 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 10 May 2012 12:17:41 +0200
+Subject: dmaengine: at_hdmac: take maxburst from slave configuration
+
+The maxburst/chunk size was taken from the private slave DMA data structure.
+Use the common API provided by DMA_SLAVE_CONFIG to setup src/dst maxburst
+values.
+The ctrla field is not needed anymore in the slave private structure nor the
+header constants that were located in an architecture specific directory.
+The at91sam9g45_devices.c file that was using this platform data is also
+modified to remove this now useless data.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
+---
+ arch/arm/mach-at91/at91sam9g45_devices.c | 1 -
+ arch/arm/mach-at91/include/mach/at_hdmac.h | 21 ---------------------
+ drivers/dma/at_hdmac.c | 7 ++++---
+ drivers/dma/at_hdmac_regs.h | 21 ++++++++++++++++++++-
+ 4 files changed, 24 insertions(+), 26 deletions(-)
+
+--- a/arch/arm/mach-at91/at91sam9g45_devices.c
++++ b/arch/arm/mach-at91/at91sam9g45_devices.c
+@@ -433,7 +433,6 @@ void __init at91_add_device_mci(short mm
+ atslave->dma_dev = &at_hdmac_device.dev;
+ 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);
+--- a/arch/arm/mach-at91/include/mach/at_hdmac.h
++++ b/arch/arm/mach-at91/include/mach/at_hdmac.h
+@@ -27,12 +27,10 @@ struct at_dma_platform_data {
+ * struct at_dma_slave - Controller-specific information about a slave
+ * @dma_dev: required DMA master device
+ * @cfg: Platform-specific initializer for the CFG register
+- * @ctrla: Platform-specific initializer for the CTRLA register
+ */
+ struct at_dma_slave {
+ struct device *dma_dev;
+ u32 cfg;
+- u32 ctrla;
+ };
+
+
+@@ -59,24 +57,5 @@ struct at_dma_slave {
+ #define ATC_FIFOCFG_HALFFIFO (0x1 << 28)
+ #define ATC_FIFOCFG_ENOUGHSPACE (0x2 << 28)
+
+-/* Platform-configurable bits in CTRLA */
+-#define ATC_SCSIZE_MASK (0x7 << 16) /* Source Chunk Transfer Size */
+-#define ATC_SCSIZE_1 (0x0 << 16)
+-#define ATC_SCSIZE_4 (0x1 << 16)
+-#define ATC_SCSIZE_8 (0x2 << 16)
+-#define ATC_SCSIZE_16 (0x3 << 16)
+-#define ATC_SCSIZE_32 (0x4 << 16)
+-#define ATC_SCSIZE_64 (0x5 << 16)
+-#define ATC_SCSIZE_128 (0x6 << 16)
+-#define ATC_SCSIZE_256 (0x7 << 16)
+-#define ATC_DCSIZE_MASK (0x7 << 20) /* Destination Chunk Transfer Size */
+-#define ATC_DCSIZE_1 (0x0 << 20)
+-#define ATC_DCSIZE_4 (0x1 << 20)
+-#define ATC_DCSIZE_8 (0x2 << 20)
+-#define ATC_DCSIZE_16 (0x3 << 20)
+-#define ATC_DCSIZE_32 (0x4 << 20)
+-#define ATC_DCSIZE_64 (0x5 << 20)
+-#define ATC_DCSIZE_128 (0x6 << 20)
+-#define ATC_DCSIZE_256 (0x7 << 20)
+
+ #endif /* AT_HDMAC_H */
+--- a/drivers/dma/at_hdmac.c
++++ b/drivers/dma/at_hdmac.c
+@@ -666,7 +666,8 @@ atc_prep_slave_sg(struct dma_chan *chan,
+ return NULL;
+ }
+
+- ctrla = atslave->ctrla;
++ ctrla = ATC_SCSIZE(sconfig->src_maxburst)
++ | ATC_DCSIZE(sconfig->dst_maxburst);
+ ctrlb = ATC_IEN;
+
+ switch (direction) {
+@@ -805,12 +806,12 @@ atc_dma_cyclic_fill_desc(struct dma_chan
+ enum dma_transfer_direction direction)
+ {
+ struct at_dma_chan *atchan = to_at_dma_chan(chan);
+- struct at_dma_slave *atslave = chan->private;
+ struct dma_slave_config *sconfig = &atchan->dma_sconfig;
+ u32 ctrla;
+
+ /* prepare common CRTLA value */
+- ctrla = atslave->ctrla
++ ctrla = ATC_SCSIZE(sconfig->src_maxburst)
++ | ATC_DCSIZE(sconfig->dst_maxburst)
+ | ATC_DST_WIDTH(reg_width)
+ | ATC_SRC_WIDTH(reg_width)
+ | period_len >> reg_width;
+--- a/drivers/dma/at_hdmac_regs.h
++++ b/drivers/dma/at_hdmac_regs.h
+@@ -87,7 +87,26 @@
+ /* Bitfields in CTRLA */
+ #define ATC_BTSIZE_MAX 0xFFFFUL /* Maximum Buffer Transfer Size */
+ #define ATC_BTSIZE(x) (ATC_BTSIZE_MAX & (x)) /* Buffer Transfer Size */
+-/* Chunck Tranfer size definitions are in at_hdmac.h */
++#define ATC_SCSIZE_MASK (0x7 << 16) /* Source Chunk Transfer Size */
++#define ATC_SCSIZE(x) (ATC_SCSIZE_MASK & ((x) << 16))
++#define ATC_SCSIZE_1 (0x0 << 16)
++#define ATC_SCSIZE_4 (0x1 << 16)
++#define ATC_SCSIZE_8 (0x2 << 16)
++#define ATC_SCSIZE_16 (0x3 << 16)
++#define ATC_SCSIZE_32 (0x4 << 16)
++#define ATC_SCSIZE_64 (0x5 << 16)
++#define ATC_SCSIZE_128 (0x6 << 16)
++#define ATC_SCSIZE_256 (0x7 << 16)
++#define ATC_DCSIZE_MASK (0x7 << 20) /* Destination Chunk Transfer Size */
++#define ATC_DCSIZE(x) (ATC_DCSIZE_MASK & ((x) << 20))
++#define ATC_DCSIZE_1 (0x0 << 20)
++#define ATC_DCSIZE_4 (0x1 << 20)
++#define ATC_DCSIZE_8 (0x2 << 20)
++#define ATC_DCSIZE_16 (0x3 << 20)
++#define ATC_DCSIZE_32 (0x4 << 20)
++#define ATC_DCSIZE_64 (0x5 << 20)
++#define ATC_DCSIZE_128 (0x6 << 20)
++#define ATC_DCSIZE_256 (0x7 << 20)
+ #define ATC_SRC_WIDTH_MASK (0x3 << 24) /* Source Single Transfer Size */
+ #define ATC_SRC_WIDTH(x) ((x) << 24)
+ #define ATC_SRC_WIDTH_BYTE (0x0 << 24)
diff --git a/patches.at91/0066-dmaengine-at_hdmac-trivial-fix-comment-in-header.patch b/patches.at91/0066-dmaengine-at_hdmac-trivial-fix-comment-in-header.patch
new file mode 100644
index 00000000000000..60572dc4f2a8d5
--- /dev/null
+++ b/patches.at91/0066-dmaengine-at_hdmac-trivial-fix-comment-in-header.patch
@@ -0,0 +1,36 @@
+From e7d260949873bedcc9fe6cd9f60eb1d99359d119 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 12 Jun 2012 10:34:52 +0200
+Subject: dmaengine: at_hdmac: trivial: fix comment in header
+
+Not all Atmel SoCs were pointed out in header comment which was bringing
+confusion. Remove the truncated list of supported devices, replace by the
+only one that is not supported.
+
+Reported-by: Elen Song <elen.song@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/dma/at_hdmac.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
+index 7292aa8..bb16013 100644
+--- a/drivers/dma/at_hdmac.c
++++ b/drivers/dma/at_hdmac.c
+@@ -9,10 +9,9 @@
+ * (at your option) any later version.
+ *
+ *
+- * This supports the Atmel AHB DMA Controller,
+- *
+- * The driver has currently been tested with the Atmel AT91SAM9RL
+- * and AT91SAM9G45 series.
++ * This supports the Atmel AHB DMA Controller found in several Atmel SoCs.
++ * The only Atmel DMA Controller that is not covered by this driver is the one
++ * found on AT91SAM9263.
+ */
+
+ #include <linux/clk.h>
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0069-AT91-Remove-fixed-mapping-for-AT91RM9200-ethernet.patch b/patches.at91/0069-AT91-Remove-fixed-mapping-for-AT91RM9200-ethernet.patch
new file mode 100644
index 00000000000000..d2942666314b6f
--- /dev/null
+++ b/patches.at91/0069-AT91-Remove-fixed-mapping-for-AT91RM9200-ethernet.patch
@@ -0,0 +1,1121 @@
+From 272e7886507edd10614cdb998e2374afd122149e Mon Sep 17 00:00:00 2001
+From: Andrew Victor <avictor.za@gmail.com>
+Date: Thu, 26 Apr 2012 00:30:42 +0000
+Subject: AT91: Remove fixed mapping for AT91RM9200 ethernet
+
+The AT91RM9200 Ethernet controller still has a fixed IO mapping.
+So:
+* Remove the fixed IO mapping and AT91_VA_BASE_EMAC definition.
+* Pass the physical base-address via platform-resources to the driver.
+* Convert at91_ether.c driver to perform an ioremap().
+* Ethernet PHY detection needs to be performed during the driver
+initialization process, it can no longer be done first.
+
+Signed-off-by: Andrew Victor <linux@maxim.org.za>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ arch/arm/mach-at91/at91rm9200.c | 10 -
+ arch/arm/mach-at91/at91rm9200_devices.c | 4 +-
+ arch/arm/mach-at91/include/mach/hardware.h | 1 -
+ drivers/net/ethernet/cadence/at91_ether.c | 527 ++++++++++++++++-------------
+ drivers/net/ethernet/cadence/at91_ether.h | 1 +
+ 5 files changed, 287 insertions(+), 256 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
+index 801c30b..6f50c67 100644
+--- a/arch/arm/mach-at91/at91rm9200.c
++++ b/arch/arm/mach-at91/at91rm9200.c
+@@ -27,15 +27,6 @@
+ #include "clock.h"
+ #include "sam9_smc.h"
+
+-static struct map_desc at91rm9200_io_desc[] __initdata = {
+- {
+- .virtual = AT91_VA_BASE_EMAC,
+- .pfn = __phys_to_pfn(AT91RM9200_BASE_EMAC),
+- .length = SZ_16K,
+- .type = MT_DEVICE,
+- },
+-};
+-
+ /* --------------------------------------------------------------------
+ * Clocks
+ * -------------------------------------------------------------------- */
+@@ -304,7 +295,6 @@ static void __init at91rm9200_map_io(void)
+ {
+ /* Map peripherals */
+ at91_init_sram(0, AT91RM9200_SRAM_BASE, AT91RM9200_SRAM_SIZE);
+- iotable_init(at91rm9200_io_desc, ARRAY_SIZE(at91rm9200_io_desc));
+ }
+
+ static void __init at91rm9200_ioremap_registers(void)
+diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
+index 04d69d3..01fb732 100644
+--- a/arch/arm/mach-at91/at91rm9200_devices.c
++++ b/arch/arm/mach-at91/at91rm9200_devices.c
+@@ -140,8 +140,8 @@ static struct macb_platform_data eth_data;
+
+ static struct resource eth_resources[] = {
+ [0] = {
+- .start = AT91_VA_BASE_EMAC,
+- .end = AT91_VA_BASE_EMAC + SZ_16K - 1,
++ .start = AT91RM9200_BASE_EMAC,
++ .end = AT91RM9200_BASE_EMAC + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h
+index 24b46bd..09242b6 100644
+--- a/arch/arm/mach-at91/include/mach/hardware.h
++++ b/arch/arm/mach-at91/include/mach/hardware.h
+@@ -85,7 +85,6 @@
+ * Virtual to Physical Address mapping for IO devices.
+ */
+ #define AT91_VA_BASE_SYS AT91_IO_P2V(AT91_BASE_SYS)
+-#define AT91_VA_BASE_EMAC AT91_IO_P2V(AT91RM9200_BASE_EMAC)
+
+ /* Internal SRAM is mapped below the IO devices */
+ #define AT91_SRAM_MAX SZ_1M
+diff --git a/drivers/net/ethernet/cadence/at91_ether.c b/drivers/net/ethernet/cadence/at91_ether.c
+index 9061170..62761e1 100644
+--- a/drivers/net/ethernet/cadence/at91_ether.c
++++ b/drivers/net/ethernet/cadence/at91_ether.c
+@@ -30,6 +30,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/clk.h>
+ #include <linux/gfp.h>
++#include <linux/phy.h>
+
+ #include <asm/io.h>
+ #include <asm/uaccess.h>
+@@ -51,21 +52,17 @@
+ /*
+ * Read from a EMAC register.
+ */
+-static inline unsigned long at91_emac_read(unsigned int reg)
++static inline unsigned long at91_emac_read(struct at91_private *lp, unsigned int reg)
+ {
+- void __iomem *emac_base = (void __iomem *)AT91_VA_BASE_EMAC;
+-
+- return __raw_readl(emac_base + reg);
++ return __raw_readl(lp->emac_base + reg);
+ }
+
+ /*
+ * Write to a EMAC register.
+ */
+-static inline void at91_emac_write(unsigned int reg, unsigned long value)
++static inline void at91_emac_write(struct at91_private *lp, unsigned int reg, unsigned long value)
+ {
+- void __iomem *emac_base = (void __iomem *)AT91_VA_BASE_EMAC;
+-
+- __raw_writel(value, emac_base + reg);
++ __raw_writel(value, lp->emac_base + reg);
+ }
+
+ /* ........................... PHY INTERFACE ........................... */
+@@ -75,32 +72,33 @@ static inline void at91_emac_write(unsigned int reg, unsigned long value)
+ * When not called from an interrupt-handler, access to the PHY must be
+ * protected by a spinlock.
+ */
+-static void enable_mdi(void)
++static void enable_mdi(struct at91_private *lp)
+ {
+ unsigned long ctl;
+
+- ctl = at91_emac_read(AT91_EMAC_CTL);
+- at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_MPE); /* enable management port */
++ ctl = at91_emac_read(lp, AT91_EMAC_CTL);
++ at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_MPE); /* enable management port */
+ }
+
+ /*
+ * Disable the MDIO bit in the MAC control register
+ */
+-static void disable_mdi(void)
++static void disable_mdi(struct at91_private *lp)
+ {
+ unsigned long ctl;
+
+- ctl = at91_emac_read(AT91_EMAC_CTL);
+- at91_emac_write(AT91_EMAC_CTL, ctl & ~AT91_EMAC_MPE); /* disable management port */
++ ctl = at91_emac_read(lp, AT91_EMAC_CTL);
++ at91_emac_write(lp, AT91_EMAC_CTL, ctl & ~AT91_EMAC_MPE); /* disable management port */
+ }
+
+ /*
+ * Wait until the PHY operation is complete.
+ */
+-static inline void at91_phy_wait(void) {
++static inline void at91_phy_wait(struct at91_private *lp)
++{
+ unsigned long timeout = jiffies + 2;
+
+- while (!(at91_emac_read(AT91_EMAC_SR) & AT91_EMAC_SR_IDLE)) {
++ while (!(at91_emac_read(lp, AT91_EMAC_SR) & AT91_EMAC_SR_IDLE)) {
+ if (time_after(jiffies, timeout)) {
+ printk("at91_ether: MIO timeout\n");
+ break;
+@@ -113,28 +111,28 @@ static inline void at91_phy_wait(void) {
+ * Write value to the a PHY register
+ * Note: MDI interface is assumed to already have been enabled.
+ */
+-static void write_phy(unsigned char phy_addr, unsigned char address, unsigned int value)
++static void write_phy(struct at91_private *lp, unsigned char phy_addr, unsigned char address, unsigned int value)
+ {
+- at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_W
++ at91_emac_write(lp, AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_W
+ | ((phy_addr & 0x1f) << 23) | (address << 18) | (value & AT91_EMAC_DATA));
+
+ /* Wait until IDLE bit in Network Status register is cleared */
+- at91_phy_wait();
++ at91_phy_wait(lp);
+ }
+
+ /*
+ * Read value stored in a PHY register.
+ * Note: MDI interface is assumed to already have been enabled.
+ */
+-static void read_phy(unsigned char phy_addr, unsigned char address, unsigned int *value)
++static void read_phy(struct at91_private *lp, unsigned char phy_addr, unsigned char address, unsigned int *value)
+ {
+- at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_R
++ at91_emac_write(lp, AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_R
+ | ((phy_addr & 0x1f) << 23) | (address << 18));
+
+ /* Wait until IDLE bit in Network Status register is cleared */
+- at91_phy_wait();
++ at91_phy_wait(lp);
+
+- *value = at91_emac_read(AT91_EMAC_MAN) & AT91_EMAC_DATA;
++ *value = at91_emac_read(lp, AT91_EMAC_MAN) & AT91_EMAC_DATA;
+ }
+
+ /* ........................... PHY MANAGEMENT .......................... */
+@@ -158,13 +156,13 @@ static void update_linkspeed(struct net_device *dev, int silent)
+ }
+
+ /* Link up, or auto-negotiation still in progress */
+- read_phy(lp->phy_address, MII_BMSR, &bmsr);
+- read_phy(lp->phy_address, MII_BMCR, &bmcr);
++ read_phy(lp, lp->phy_address, MII_BMSR, &bmsr);
++ read_phy(lp, lp->phy_address, MII_BMCR, &bmcr);
+ if (bmcr & BMCR_ANENABLE) { /* AutoNegotiation is enabled */
+ if (!(bmsr & BMSR_ANEGCOMPLETE))
+ return; /* Do nothing - another interrupt generated when negotiation complete */
+
+- read_phy(lp->phy_address, MII_LPA, &lpa);
++ read_phy(lp, lp->phy_address, MII_LPA, &lpa);
+ if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF)) speed = SPEED_100;
+ else speed = SPEED_10;
+ if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL)) duplex = DUPLEX_FULL;
+@@ -175,7 +173,7 @@ static void update_linkspeed(struct net_device *dev, int silent)
+ }
+
+ /* Update the MAC */
+- mac_cfg = at91_emac_read(AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD);
++ mac_cfg = at91_emac_read(lp, AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD);
+ if (speed == SPEED_100) {
+ if (duplex == DUPLEX_FULL) /* 100 Full Duplex */
+ mac_cfg |= AT91_EMAC_SPD | AT91_EMAC_FD;
+@@ -186,7 +184,7 @@ static void update_linkspeed(struct net_device *dev, int silent)
+ mac_cfg |= AT91_EMAC_FD;
+ else {} /* 10 Half Duplex */
+ }
+- at91_emac_write(AT91_EMAC_CFG, mac_cfg);
++ at91_emac_write(lp, AT91_EMAC_CFG, mac_cfg);
+
+ if (!silent)
+ printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
+@@ -207,34 +205,34 @@ static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id)
+ * level-triggering. We therefore have to check if the PHY actually has
+ * an IRQ pending.
+ */
+- enable_mdi();
++ enable_mdi(lp);
+ if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {
+- read_phy(lp->phy_address, MII_DSINTR_REG, &phy); /* ack interrupt in Davicom PHY */
++ read_phy(lp, lp->phy_address, MII_DSINTR_REG, &phy); /* ack interrupt in Davicom PHY */
+ if (!(phy & (1 << 0)))
+ goto done;
+ }
+ else if (lp->phy_type == MII_LXT971A_ID) {
+- read_phy(lp->phy_address, MII_ISINTS_REG, &phy); /* ack interrupt in Intel PHY */
++ read_phy(lp, lp->phy_address, MII_ISINTS_REG, &phy); /* ack interrupt in Intel PHY */
+ if (!(phy & (1 << 2)))
+ goto done;
+ }
+ else if (lp->phy_type == MII_BCM5221_ID) {
+- read_phy(lp->phy_address, MII_BCMINTR_REG, &phy); /* ack interrupt in Broadcom PHY */
++ read_phy(lp, lp->phy_address, MII_BCMINTR_REG, &phy); /* ack interrupt in Broadcom PHY */
+ if (!(phy & (1 << 0)))
+ goto done;
+ }
+ else if (lp->phy_type == MII_KS8721_ID) {
+- read_phy(lp->phy_address, MII_TPISTATUS, &phy); /* ack interrupt in Micrel PHY */
++ read_phy(lp, lp->phy_address, MII_TPISTATUS, &phy); /* ack interrupt in Micrel PHY */
+ if (!(phy & ((1 << 2) | 1)))
+ goto done;
+ }
+- else if (lp->phy_type == MII_T78Q21x3_ID) { /* ack interrupt in Teridian PHY */
+- read_phy(lp->phy_address, MII_T78Q21INT_REG, &phy);
++ else if (lp->phy_type == MII_T78Q21x3_ID) { /* ack interrupt in Teridian PHY */
++ read_phy(lp, lp->phy_address, MII_T78Q21INT_REG, &phy);
+ if (!(phy & ((1 << 2) | 1)))
+ goto done;
+ }
+ else if (lp->phy_type == MII_DP83848_ID) {
+- read_phy(lp->phy_address, MII_DPPHYSTS_REG, &phy); /* ack interrupt in DP83848 PHY */
++ read_phy(lp, lp->phy_address, MII_DPPHYSTS_REG, &phy); /* ack interrupt in DP83848 PHY */
+ if (!(phy & (1 << 7)))
+ goto done;
+ }
+@@ -242,7 +240,7 @@ static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id)
+ update_linkspeed(dev, 0);
+
+ done:
+- disable_mdi();
++ disable_mdi(lp);
+
+ return IRQ_HANDLED;
+ }
+@@ -273,41 +271,41 @@ static void enable_phyirq(struct net_device *dev)
+ }
+
+ spin_lock_irq(&lp->lock);
+- enable_mdi();
++ enable_mdi(lp);
+
+ if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { /* for Davicom PHY */
+- read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr);
++ read_phy(lp, lp->phy_address, MII_DSINTR_REG, &dsintr);
+ dsintr = dsintr & ~0xf00; /* clear bits 8..11 */
+- write_phy(lp->phy_address, MII_DSINTR_REG, dsintr);
++ write_phy(lp, lp->phy_address, MII_DSINTR_REG, dsintr);
+ }
+ else if (lp->phy_type == MII_LXT971A_ID) { /* for Intel PHY */
+- read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr);
++ read_phy(lp, lp->phy_address, MII_ISINTE_REG, &dsintr);
+ dsintr = dsintr | 0xf2; /* set bits 1, 4..7 */
+- write_phy(lp->phy_address, MII_ISINTE_REG, dsintr);
++ write_phy(lp, lp->phy_address, MII_ISINTE_REG, dsintr);
+ }
+ else if (lp->phy_type == MII_BCM5221_ID) { /* for Broadcom PHY */
+ dsintr = (1 << 15) | ( 1 << 14);
+- write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr);
++ write_phy(lp, lp->phy_address, MII_BCMINTR_REG, dsintr);
+ }
+ else if (lp->phy_type == MII_KS8721_ID) { /* for Micrel PHY */
+ dsintr = (1 << 10) | ( 1 << 8);
+- write_phy(lp->phy_address, MII_TPISTATUS, dsintr);
++ write_phy(lp, lp->phy_address, MII_TPISTATUS, dsintr);
+ }
+ else if (lp->phy_type == MII_T78Q21x3_ID) { /* for Teridian PHY */
+- read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr);
++ read_phy(lp, lp->phy_address, MII_T78Q21INT_REG, &dsintr);
+ dsintr = dsintr | 0x500; /* set bits 8, 10 */
+- write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr);
++ write_phy(lp, lp->phy_address, MII_T78Q21INT_REG, dsintr);
+ }
+ else if (lp->phy_type == MII_DP83848_ID) { /* National Semiconductor DP83848 PHY */
+- read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr);
++ read_phy(lp, lp->phy_address, MII_DPMISR_REG, &dsintr);
+ dsintr = dsintr | 0x3c; /* set bits 2..5 */
+- write_phy(lp->phy_address, MII_DPMISR_REG, dsintr);
+- read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr);
++ write_phy(lp, lp->phy_address, MII_DPMISR_REG, dsintr);
++ read_phy(lp, lp->phy_address, MII_DPMICR_REG, &dsintr);
+ dsintr = dsintr | 0x3; /* set bits 0,1 */
+- write_phy(lp->phy_address, MII_DPMICR_REG, dsintr);
++ write_phy(lp, lp->phy_address, MII_DPMICR_REG, dsintr);
+ }
+
+- disable_mdi();
++ disable_mdi(lp);
+ spin_unlock_irq(&lp->lock);
+ }
+
+@@ -326,43 +324,43 @@ static void disable_phyirq(struct net_device *dev)
+ }
+
+ spin_lock_irq(&lp->lock);
+- enable_mdi();
++ enable_mdi(lp);
+
+ if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { /* for Davicom PHY */
+- read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr);
++ read_phy(lp, lp->phy_address, MII_DSINTR_REG, &dsintr);
+ dsintr = dsintr | 0xf00; /* set bits 8..11 */
+- write_phy(lp->phy_address, MII_DSINTR_REG, dsintr);
++ write_phy(lp, lp->phy_address, MII_DSINTR_REG, dsintr);
+ }
+ else if (lp->phy_type == MII_LXT971A_ID) { /* for Intel PHY */
+- read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr);
++ read_phy(lp, lp->phy_address, MII_ISINTE_REG, &dsintr);
+ dsintr = dsintr & ~0xf2; /* clear bits 1, 4..7 */
+- write_phy(lp->phy_address, MII_ISINTE_REG, dsintr);
++ write_phy(lp, lp->phy_address, MII_ISINTE_REG, dsintr);
+ }
+ else if (lp->phy_type == MII_BCM5221_ID) { /* for Broadcom PHY */
+- read_phy(lp->phy_address, MII_BCMINTR_REG, &dsintr);
++ read_phy(lp, lp->phy_address, MII_BCMINTR_REG, &dsintr);
+ dsintr = ~(1 << 14);
+- write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr);
++ write_phy(lp, lp->phy_address, MII_BCMINTR_REG, dsintr);
+ }
+ else if (lp->phy_type == MII_KS8721_ID) { /* for Micrel PHY */
+- read_phy(lp->phy_address, MII_TPISTATUS, &dsintr);
++ read_phy(lp, lp->phy_address, MII_TPISTATUS, &dsintr);
+ dsintr = ~((1 << 10) | (1 << 8));
+- write_phy(lp->phy_address, MII_TPISTATUS, dsintr);
++ write_phy(lp, lp->phy_address, MII_TPISTATUS, dsintr);
+ }
+ else if (lp->phy_type == MII_T78Q21x3_ID) { /* for Teridian PHY */
+- read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr);
++ read_phy(lp, lp->phy_address, MII_T78Q21INT_REG, &dsintr);
+ dsintr = dsintr & ~0x500; /* clear bits 8, 10 */
+- write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr);
++ write_phy(lp, lp->phy_address, MII_T78Q21INT_REG, dsintr);
+ }
+ else if (lp->phy_type == MII_DP83848_ID) { /* National Semiconductor DP83848 PHY */
+- read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr);
++ read_phy(lp, lp->phy_address, MII_DPMICR_REG, &dsintr);
+ dsintr = dsintr & ~0x3; /* clear bits 0, 1 */
+- write_phy(lp->phy_address, MII_DPMICR_REG, dsintr);
+- read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr);
++ write_phy(lp, lp->phy_address, MII_DPMICR_REG, dsintr);
++ read_phy(lp, lp->phy_address, MII_DPMISR_REG, &dsintr);
+ dsintr = dsintr & ~0x3c; /* clear bits 2..5 */
+- write_phy(lp->phy_address, MII_DPMISR_REG, dsintr);
++ write_phy(lp, lp->phy_address, MII_DPMISR_REG, dsintr);
+ }
+
+- disable_mdi();
++ disable_mdi(lp);
+ spin_unlock_irq(&lp->lock);
+
+ irq_number = lp->board_data.phy_irq_pin;
+@@ -379,17 +377,17 @@ static void reset_phy(struct net_device *dev)
+ unsigned int bmcr;
+
+ spin_lock_irq(&lp->lock);
+- enable_mdi();
++ enable_mdi(lp);
+
+ /* Perform PHY reset */
+- write_phy(lp->phy_address, MII_BMCR, BMCR_RESET);
++ write_phy(lp, lp->phy_address, MII_BMCR, BMCR_RESET);
+
+ /* Wait until PHY reset is complete */
+ do {
+- read_phy(lp->phy_address, MII_BMCR, &bmcr);
++ read_phy(lp, lp->phy_address, MII_BMCR, &bmcr);
+ } while (!(bmcr & BMCR_RESET));
+
+- disable_mdi();
++ disable_mdi(lp);
+ spin_unlock_irq(&lp->lock);
+ }
+ #endif
+@@ -399,13 +397,37 @@ static void at91ether_check_link(unsigned long dev_id)
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct at91_private *lp = netdev_priv(dev);
+
+- enable_mdi();
++ enable_mdi(lp);
+ update_linkspeed(dev, 1);
+- disable_mdi();
++ disable_mdi(lp);
+
+ mod_timer(&lp->check_timer, jiffies + LINK_POLL_INTERVAL);
+ }
+
++/*
++ * Perform any PHY-specific initialization.
++ */
++static void __init initialize_phy(struct at91_private *lp)
++{
++ unsigned int val;
++
++ spin_lock_irq(&lp->lock);
++ enable_mdi(lp);
++
++ if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {
++ read_phy(lp, lp->phy_address, MII_DSCR_REG, &val);
++ if ((val & (1 << 10)) == 0) /* DSCR bit 10 is 0 -- fiber mode */
++ lp->phy_media = PORT_FIBRE;
++ } else if (machine_is_csb337()) {
++ /* mix link activity status into LED2 link state */
++ write_phy(lp, lp->phy_address, MII_LEDCTRL_REG, 0x0d22);
++ } else if (machine_is_ecbat91())
++ write_phy(lp, lp->phy_address, MII_LEDCTRL_REG, 0x156A);
++
++ disable_mdi(lp);
++ spin_unlock_irq(&lp->lock);
++}
++
+ /* ......................... ADDRESS MANAGEMENT ........................ */
+
+ /*
+@@ -454,17 +476,19 @@ static short __init unpack_mac_address(struct net_device *dev, unsigned int hi,
+ */
+ static void __init get_mac_address(struct net_device *dev)
+ {
++ struct at91_private *lp = netdev_priv(dev);
++
+ /* Check Specific-Address 1 */
+- if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA1H), at91_emac_read(AT91_EMAC_SA1L)))
++ if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA1H), at91_emac_read(lp, AT91_EMAC_SA1L)))
+ return;
+ /* Check Specific-Address 2 */
+- if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA2H), at91_emac_read(AT91_EMAC_SA2L)))
++ if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA2H), at91_emac_read(lp, AT91_EMAC_SA2L)))
+ return;
+ /* Check Specific-Address 3 */
+- if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA3H), at91_emac_read(AT91_EMAC_SA3L)))
++ if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA3H), at91_emac_read(lp, AT91_EMAC_SA3L)))
+ return;
+ /* Check Specific-Address 4 */
+- if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA4H), at91_emac_read(AT91_EMAC_SA4L)))
++ if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA4H), at91_emac_read(lp, AT91_EMAC_SA4L)))
+ return;
+
+ printk(KERN_ERR "at91_ether: Your bootloader did not configure a MAC address.\n");
+@@ -475,11 +499,13 @@ static void __init get_mac_address(struct net_device *dev)
+ */
+ static void update_mac_address(struct net_device *dev)
+ {
+- at91_emac_write(AT91_EMAC_SA1L, (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | (dev->dev_addr[1] << 8) | (dev->dev_addr[0]));
+- at91_emac_write(AT91_EMAC_SA1H, (dev->dev_addr[5] << 8) | (dev->dev_addr[4]));
++ struct at91_private *lp = netdev_priv(dev);
+
+- at91_emac_write(AT91_EMAC_SA2L, 0);
+- at91_emac_write(AT91_EMAC_SA2H, 0);
++ at91_emac_write(lp, AT91_EMAC_SA1L, (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | (dev->dev_addr[1] << 8) | (dev->dev_addr[0]));
++ at91_emac_write(lp, AT91_EMAC_SA1H, (dev->dev_addr[5] << 8) | (dev->dev_addr[4]));
++
++ at91_emac_write(lp, AT91_EMAC_SA2L, 0);
++ at91_emac_write(lp, AT91_EMAC_SA2H, 0);
+ }
+
+ /*
+@@ -559,6 +585,7 @@ static int hash_get_index(__u8 *addr)
+ */
+ static void at91ether_sethashtable(struct net_device *dev)
+ {
++ struct at91_private *lp = netdev_priv(dev);
+ struct netdev_hw_addr *ha;
+ unsigned long mc_filter[2];
+ unsigned int bitnr;
+@@ -570,8 +597,8 @@ static void at91ether_sethashtable(struct net_device *dev)
+ mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
+ }
+
+- at91_emac_write(AT91_EMAC_HSL, mc_filter[0]);
+- at91_emac_write(AT91_EMAC_HSH, mc_filter[1]);
++ at91_emac_write(lp, AT91_EMAC_HSL, mc_filter[0]);
++ at91_emac_write(lp, AT91_EMAC_HSH, mc_filter[1]);
+ }
+
+ /*
+@@ -579,9 +606,10 @@ static void at91ether_sethashtable(struct net_device *dev)
+ */
+ static void at91ether_set_multicast_list(struct net_device *dev)
+ {
++ struct at91_private *lp = netdev_priv(dev);
+ unsigned long cfg;
+
+- cfg = at91_emac_read(AT91_EMAC_CFG);
++ cfg = at91_emac_read(lp, AT91_EMAC_CFG);
+
+ if (dev->flags & IFF_PROMISC) /* Enable promiscuous mode */
+ cfg |= AT91_EMAC_CAF;
+@@ -589,34 +617,37 @@ static void at91ether_set_multicast_list(struct net_device *dev)
+ cfg &= ~AT91_EMAC_CAF;
+
+ if (dev->flags & IFF_ALLMULTI) { /* Enable all multicast mode */
+- at91_emac_write(AT91_EMAC_HSH, -1);
+- at91_emac_write(AT91_EMAC_HSL, -1);
++ at91_emac_write(lp, AT91_EMAC_HSH, -1);
++ at91_emac_write(lp, AT91_EMAC_HSL, -1);
+ cfg |= AT91_EMAC_MTI;
+ } else if (!netdev_mc_empty(dev)) { /* Enable specific multicasts */
+ at91ether_sethashtable(dev);
+ cfg |= AT91_EMAC_MTI;
+ } else if (dev->flags & (~IFF_ALLMULTI)) { /* Disable all multicast mode */
+- at91_emac_write(AT91_EMAC_HSH, 0);
+- at91_emac_write(AT91_EMAC_HSL, 0);
++ at91_emac_write(lp, AT91_EMAC_HSH, 0);
++ at91_emac_write(lp, AT91_EMAC_HSL, 0);
+ cfg &= ~AT91_EMAC_MTI;
+ }
+
+- at91_emac_write(AT91_EMAC_CFG, cfg);
++ at91_emac_write(lp, AT91_EMAC_CFG, cfg);
+ }
+
+ /* ......................... ETHTOOL SUPPORT ........................... */
+
+ static int mdio_read(struct net_device *dev, int phy_id, int location)
+ {
++ struct at91_private *lp = netdev_priv(dev);
+ unsigned int value;
+
+- read_phy(phy_id, location, &value);
++ read_phy(lp, phy_id, location, &value);
+ return value;
+ }
+
+ static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
+ {
+- write_phy(phy_id, location, value);
++ struct at91_private *lp = netdev_priv(dev);
++
++ write_phy(lp, phy_id, location, value);
+ }
+
+ static int at91ether_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+@@ -625,11 +656,11 @@ static int at91ether_get_settings(struct net_device *dev, struct ethtool_cmd *cm
+ int ret;
+
+ spin_lock_irq(&lp->lock);
+- enable_mdi();
++ enable_mdi(lp);
+
+ ret = mii_ethtool_gset(&lp->mii, cmd);
+
+- disable_mdi();
++ disable_mdi(lp);
+ spin_unlock_irq(&lp->lock);
+
+ if (lp->phy_media == PORT_FIBRE) { /* override media type since mii.c doesn't know */
+@@ -646,11 +677,11 @@ static int at91ether_set_settings(struct net_device *dev, struct ethtool_cmd *cm
+ int ret;
+
+ spin_lock_irq(&lp->lock);
+- enable_mdi();
++ enable_mdi(lp);
+
+ ret = mii_ethtool_sset(&lp->mii, cmd);
+
+- disable_mdi();
++ disable_mdi(lp);
+ spin_unlock_irq(&lp->lock);
+
+ return ret;
+@@ -662,11 +693,11 @@ static int at91ether_nwayreset(struct net_device *dev)
+ int ret;
+
+ spin_lock_irq(&lp->lock);
+- enable_mdi();
++ enable_mdi(lp);
+
+ ret = mii_nway_restart(&lp->mii);
+
+- disable_mdi();
++ disable_mdi(lp);
+ spin_unlock_irq(&lp->lock);
+
+ return ret;
+@@ -696,9 +727,9 @@ static int at91ether_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+ return -EINVAL;
+
+ spin_lock_irq(&lp->lock);
+- enable_mdi();
++ enable_mdi(lp);
+ res = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL);
+- disable_mdi();
++ disable_mdi(lp);
+ spin_unlock_irq(&lp->lock);
+
+ return res;
+@@ -731,11 +762,11 @@ static void at91ether_start(struct net_device *dev)
+ lp->rxBuffIndex = 0;
+
+ /* Program address of descriptor list in Rx Buffer Queue register */
+- at91_emac_write(AT91_EMAC_RBQP, (unsigned long) dlist_phys);
++ at91_emac_write(lp, AT91_EMAC_RBQP, (unsigned long) dlist_phys);
+
+ /* Enable Receive and Transmit */
+- ctl = at91_emac_read(AT91_EMAC_CTL);
+- at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_RE | AT91_EMAC_TE);
++ ctl = at91_emac_read(lp, AT91_EMAC_CTL);
++ at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_RE | AT91_EMAC_TE);
+ }
+
+ /*
+@@ -752,8 +783,8 @@ static int at91ether_open(struct net_device *dev)
+ clk_enable(lp->ether_clk); /* Re-enable Peripheral clock */
+
+ /* Clear internal statistics */
+- ctl = at91_emac_read(AT91_EMAC_CTL);
+- at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_CSR);
++ ctl = at91_emac_read(lp, AT91_EMAC_CTL);
++ at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_CSR);
+
+ /* Update the MAC address (incase user has changed it) */
+ update_mac_address(dev);
+@@ -762,15 +793,15 @@ static int at91ether_open(struct net_device *dev)
+ enable_phyirq(dev);
+
+ /* Enable MAC interrupts */
+- at91_emac_write(AT91_EMAC_IER, AT91_EMAC_RCOM | AT91_EMAC_RBNA
++ at91_emac_write(lp, AT91_EMAC_IER, AT91_EMAC_RCOM | AT91_EMAC_RBNA
+ | AT91_EMAC_TUND | AT91_EMAC_RTRY | AT91_EMAC_TCOM
+ | AT91_EMAC_ROVR | AT91_EMAC_ABT);
+
+ /* Determine current link speed */
+ spin_lock_irq(&lp->lock);
+- enable_mdi();
++ enable_mdi(lp);
+ update_linkspeed(dev, 0);
+- disable_mdi();
++ disable_mdi(lp);
+ spin_unlock_irq(&lp->lock);
+
+ at91ether_start(dev);
+@@ -787,14 +818,14 @@ static int at91ether_close(struct net_device *dev)
+ unsigned long ctl;
+
+ /* Disable Receiver and Transmitter */
+- ctl = at91_emac_read(AT91_EMAC_CTL);
+- at91_emac_write(AT91_EMAC_CTL, ctl & ~(AT91_EMAC_TE | AT91_EMAC_RE));
++ ctl = at91_emac_read(lp, AT91_EMAC_CTL);
++ at91_emac_write(lp, AT91_EMAC_CTL, ctl & ~(AT91_EMAC_TE | AT91_EMAC_RE));
+
+ /* Disable PHY interrupt */
+ disable_phyirq(dev);
+
+ /* Disable MAC interrupts */
+- at91_emac_write(AT91_EMAC_IDR, AT91_EMAC_RCOM | AT91_EMAC_RBNA
++ at91_emac_write(lp, AT91_EMAC_IDR, AT91_EMAC_RCOM | AT91_EMAC_RBNA
+ | AT91_EMAC_TUND | AT91_EMAC_RTRY | AT91_EMAC_TCOM
+ | AT91_EMAC_ROVR | AT91_EMAC_ABT);
+
+@@ -812,7 +843,7 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct at91_private *lp = netdev_priv(dev);
+
+- if (at91_emac_read(AT91_EMAC_TSR) & AT91_EMAC_TSR_BNQ) {
++ if (at91_emac_read(lp, AT91_EMAC_TSR) & AT91_EMAC_TSR_BNQ) {
+ netif_stop_queue(dev);
+
+ /* Store packet information (to free when Tx completed) */
+@@ -822,9 +853,9 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ dev->stats.tx_bytes += skb->len;
+
+ /* Set address of the data in the Transmit Address register */
+- at91_emac_write(AT91_EMAC_TAR, lp->skb_physaddr);
++ at91_emac_write(lp, AT91_EMAC_TAR, lp->skb_physaddr);
+ /* Set length of the packet in the Transmit Control register */
+- at91_emac_write(AT91_EMAC_TCR, skb->len);
++ at91_emac_write(lp, AT91_EMAC_TCR, skb->len);
+
+ } else {
+ printk(KERN_ERR "at91_ether.c: at91ether_start_xmit() called, but device is busy!\n");
+@@ -841,31 +872,32 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ */
+ static struct net_device_stats *at91ether_stats(struct net_device *dev)
+ {
++ struct at91_private *lp = netdev_priv(dev);
+ int ale, lenerr, seqe, lcol, ecol;
+
+ if (netif_running(dev)) {
+- dev->stats.rx_packets += at91_emac_read(AT91_EMAC_OK); /* Good frames received */
+- ale = at91_emac_read(AT91_EMAC_ALE);
++ dev->stats.rx_packets += at91_emac_read(lp, AT91_EMAC_OK); /* Good frames received */
++ ale = at91_emac_read(lp, AT91_EMAC_ALE);
+ dev->stats.rx_frame_errors += ale; /* Alignment errors */
+- lenerr = at91_emac_read(AT91_EMAC_ELR) + at91_emac_read(AT91_EMAC_USF);
++ lenerr = at91_emac_read(lp, AT91_EMAC_ELR) + at91_emac_read(lp, AT91_EMAC_USF);
+ dev->stats.rx_length_errors += lenerr; /* Excessive Length or Undersize Frame error */
+- seqe = at91_emac_read(AT91_EMAC_SEQE);
++ seqe = at91_emac_read(lp, AT91_EMAC_SEQE);
+ dev->stats.rx_crc_errors += seqe; /* CRC error */
+- dev->stats.rx_fifo_errors += at91_emac_read(AT91_EMAC_DRFC); /* Receive buffer not available */
++ dev->stats.rx_fifo_errors += at91_emac_read(lp, AT91_EMAC_DRFC);/* Receive buffer not available */
+ dev->stats.rx_errors += (ale + lenerr + seqe
+- + at91_emac_read(AT91_EMAC_CDE) + at91_emac_read(AT91_EMAC_RJB));
++ + at91_emac_read(lp, AT91_EMAC_CDE) + at91_emac_read(lp, AT91_EMAC_RJB));
+
+- dev->stats.tx_packets += at91_emac_read(AT91_EMAC_FRA); /* Frames successfully transmitted */
+- dev->stats.tx_fifo_errors += at91_emac_read(AT91_EMAC_TUE); /* Transmit FIFO underruns */
+- dev->stats.tx_carrier_errors += at91_emac_read(AT91_EMAC_CSE); /* Carrier Sense errors */
+- dev->stats.tx_heartbeat_errors += at91_emac_read(AT91_EMAC_SQEE);/* Heartbeat error */
++ dev->stats.tx_packets += at91_emac_read(lp, AT91_EMAC_FRA); /* Frames successfully transmitted */
++ dev->stats.tx_fifo_errors += at91_emac_read(lp, AT91_EMAC_TUE); /* Transmit FIFO underruns */
++ dev->stats.tx_carrier_errors += at91_emac_read(lp, AT91_EMAC_CSE); /* Carrier Sense errors */
++ dev->stats.tx_heartbeat_errors += at91_emac_read(lp, AT91_EMAC_SQEE);/* Heartbeat error */
+
+- lcol = at91_emac_read(AT91_EMAC_LCOL);
+- ecol = at91_emac_read(AT91_EMAC_ECOL);
++ lcol = at91_emac_read(lp, AT91_EMAC_LCOL);
++ ecol = at91_emac_read(lp, AT91_EMAC_ECOL);
+ dev->stats.tx_window_errors += lcol; /* Late collisions */
+ dev->stats.tx_aborted_errors += ecol; /* 16 collisions */
+
+- dev->stats.collisions += (at91_emac_read(AT91_EMAC_SCOL) + at91_emac_read(AT91_EMAC_MCOL) + lcol + ecol);
++ dev->stats.collisions += (at91_emac_read(lp, AT91_EMAC_SCOL) + at91_emac_read(lp, AT91_EMAC_MCOL) + lcol + ecol);
+ }
+ return &dev->stats;
+ }
+@@ -922,7 +954,7 @@ static irqreturn_t at91ether_interrupt(int irq, void *dev_id)
+
+ /* MAC Interrupt Status register indicates what interrupts are pending.
+ It is automatically cleared once read. */
+- intstatus = at91_emac_read(AT91_EMAC_ISR);
++ intstatus = at91_emac_read(lp, AT91_EMAC_ISR);
+
+ if (intstatus & AT91_EMAC_RCOM) /* Receive complete */
+ at91ether_rx(dev);
+@@ -942,9 +974,9 @@ static irqreturn_t at91ether_interrupt(int irq, void *dev_id)
+
+ /* Work-around for Errata #11 */
+ if (intstatus & AT91_EMAC_RBNA) {
+- ctl = at91_emac_read(AT91_EMAC_CTL);
+- at91_emac_write(AT91_EMAC_CTL, ctl & ~AT91_EMAC_RE);
+- at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_RE);
++ ctl = at91_emac_read(lp, AT91_EMAC_CTL);
++ at91_emac_write(lp, AT91_EMAC_CTL, ctl & ~AT91_EMAC_RE);
++ at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_RE);
+ }
+
+ if (intstatus & AT91_EMAC_ROVR)
+@@ -980,189 +1012,199 @@ static const struct net_device_ops at91ether_netdev_ops = {
+ };
+
+ /*
+- * Initialize the ethernet interface
++ * Detect the PHY type, and its address.
+ */
+-static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_address,
+- struct platform_device *pdev, struct clk *ether_clk)
++static int __init at91ether_phy_detect(struct at91_private *lp)
++{
++ unsigned int phyid1, phyid2;
++ unsigned long phy_id;
++ unsigned short phy_address = 0;
++
++ while (phy_address < PHY_MAX_ADDR) {
++ /* Read the PHY ID registers */
++ enable_mdi(lp);
++ read_phy(lp, phy_address, MII_PHYSID1, &phyid1);
++ read_phy(lp, phy_address, MII_PHYSID2, &phyid2);
++ disable_mdi(lp);
++
++ phy_id = (phyid1 << 16) | (phyid2 & 0xfff0);
++ switch (phy_id) {
++ case MII_DM9161_ID: /* Davicom 9161: PHY_ID1 = 0x181, PHY_ID2 = B881 */
++ case MII_DM9161A_ID: /* Davicom 9161A: PHY_ID1 = 0x181, PHY_ID2 = B8A0 */
++ case MII_LXT971A_ID: /* Intel LXT971A: PHY_ID1 = 0x13, PHY_ID2 = 78E0 */
++ case MII_RTL8201_ID: /* Realtek RTL8201: PHY_ID1 = 0, PHY_ID2 = 0x8201 */
++ case MII_BCM5221_ID: /* Broadcom BCM5221: PHY_ID1 = 0x40, PHY_ID2 = 0x61e0 */
++ case MII_DP83847_ID: /* National Semiconductor DP83847: */
++ case MII_DP83848_ID: /* National Semiconductor DP83848: */
++ case MII_AC101L_ID: /* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */
++ case MII_KS8721_ID: /* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
++ case MII_T78Q21x3_ID: /* Teridian 78Q21x3: PHY_ID1 = 0x0E, PHY_ID2 = 7237 */
++ case MII_LAN83C185_ID: /* SMSC LAN83C185: PHY_ID1 = 0x0007, PHY_ID2 = 0xC0A1 */
++ /* store detected values */
++ lp->phy_type = phy_id; /* Type of PHY connected */
++ lp->phy_address = phy_address; /* MDI address of PHY */
++ return 1;
++ }
++
++ phy_address++;
++ }
++
++ return 0; /* not detected */
++}
++
++
++/*
++ * Detect MAC & PHY and perform ethernet interface initialization
++ */
++static int __init at91ether_probe(struct platform_device *pdev)
+ {
+ struct macb_platform_data *board_data = pdev->dev.platform_data;
++ struct resource *regs;
+ struct net_device *dev;
+ struct at91_private *lp;
+- unsigned int val;
+ int res;
+
++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!regs)
++ return -ENOENT;
++
+ dev = alloc_etherdev(sizeof(struct at91_private));
+ if (!dev)
+ return -ENOMEM;
+
+- dev->base_addr = AT91_VA_BASE_EMAC;
+- dev->irq = AT91RM9200_ID_EMAC;
++ lp = netdev_priv(dev);
++ lp->board_data = *board_data;
++ spin_lock_init(&lp->lock);
++
++ dev->base_addr = regs->start; /* physical base address */
++ lp->emac_base = ioremap(regs->start, regs->end - regs->start + 1);
++ if (!lp->emac_base) {
++ res = -ENOMEM;
++ goto err_free_dev;
++ }
++
++ /* Clock */
++ lp->ether_clk = clk_get(&pdev->dev, "ether_clk");
++ if (IS_ERR(lp->ether_clk)) {
++ res = -ENODEV;
++ goto err_ioumap;
++ }
++ clk_enable(lp->ether_clk);
+
+ /* Install the interrupt handler */
++ dev->irq = platform_get_irq(pdev, 0);
+ if (request_irq(dev->irq, at91ether_interrupt, 0, dev->name, dev)) {
+- free_netdev(dev);
+- return -EBUSY;
++ res = -EBUSY;
++ goto err_disable_clock;
+ }
+
+ /* Allocate memory for DMA Receive descriptors */
+- lp = netdev_priv(dev);
+ lp->dlist = (struct recv_desc_bufs *) dma_alloc_coherent(NULL, sizeof(struct recv_desc_bufs), (dma_addr_t *) &lp->dlist_phys, GFP_KERNEL);
+ if (lp->dlist == NULL) {
+- free_irq(dev->irq, dev);
+- free_netdev(dev);
+- return -ENOMEM;
++ res = -ENOMEM;
++ goto err_free_irq;
+ }
+- lp->board_data = *board_data;
+- lp->ether_clk = ether_clk;
+- platform_set_drvdata(pdev, dev);
+-
+- spin_lock_init(&lp->lock);
+
+ ether_setup(dev);
+ dev->netdev_ops = &at91ether_netdev_ops;
+ dev->ethtool_ops = &at91ether_ethtool_ops;
+-
++ platform_set_drvdata(pdev, dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ get_mac_address(dev); /* Get ethernet address and store it in dev->dev_addr */
+ update_mac_address(dev); /* Program ethernet address into MAC */
+
+- at91_emac_write(AT91_EMAC_CTL, 0);
++ at91_emac_write(lp, AT91_EMAC_CTL, 0);
+
+- if (lp->board_data.is_rmii)
+- at91_emac_write(AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG | AT91_EMAC_RMII);
++ if (board_data->is_rmii)
++ at91_emac_write(lp, AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG | AT91_EMAC_RMII);
+ else
+- at91_emac_write(AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG);
++ at91_emac_write(lp, AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG);
+
+- /* Perform PHY-specific initialization */
+- spin_lock_irq(&lp->lock);
+- enable_mdi();
+- if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {
+- read_phy(phy_address, MII_DSCR_REG, &val);
+- if ((val & (1 << 10)) == 0) /* DSCR bit 10 is 0 -- fiber mode */
+- lp->phy_media = PORT_FIBRE;
+- } else if (machine_is_csb337()) {
+- /* mix link activity status into LED2 link state */
+- write_phy(phy_address, MII_LEDCTRL_REG, 0x0d22);
+- } else if (machine_is_ecbat91())
+- write_phy(phy_address, MII_LEDCTRL_REG, 0x156A);
++ /* Detect PHY */
++ if (!at91ether_phy_detect(lp)) {
++ printk(KERN_ERR "at91_ether: Could not detect ethernet PHY\n");
++ res = -ENODEV;
++ goto err_free_dmamem;
++ }
+
+- disable_mdi();
+- spin_unlock_irq(&lp->lock);
++ initialize_phy(lp);
+
+ lp->mii.dev = dev; /* Support for ethtool */
+ lp->mii.mdio_read = mdio_read;
+ lp->mii.mdio_write = mdio_write;
+- lp->mii.phy_id = phy_address;
++ lp->mii.phy_id = lp->phy_address;
+ lp->mii.phy_id_mask = 0x1f;
+ lp->mii.reg_num_mask = 0x1f;
+
+- lp->phy_type = phy_type; /* Type of PHY connected */
+- lp->phy_address = phy_address; /* MDI address of PHY */
+-
+ /* Register the network interface */
+ res = register_netdev(dev);
+- if (res) {
+- free_irq(dev->irq, dev);
+- free_netdev(dev);
+- dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys);
+- return res;
+- }
++ if (res)
++ goto err_free_dmamem;
+
+ /* Determine current link speed */
+ spin_lock_irq(&lp->lock);
+- enable_mdi();
++ enable_mdi(lp);
+ update_linkspeed(dev, 0);
+- disable_mdi();
++ disable_mdi(lp);
+ spin_unlock_irq(&lp->lock);
+ netif_carrier_off(dev); /* will be enabled in open() */
+
+ /* If board has no PHY IRQ, use a timer to poll the PHY */
+- if (!gpio_is_valid(lp->board_data.phy_irq_pin)) {
++ if (gpio_is_valid(lp->board_data.phy_irq_pin)) {
++ gpio_request(board_data->phy_irq_pin, "ethernet_phy");
++ } else {
++ /* If board has no PHY IRQ, use a timer to poll the PHY */
+ init_timer(&lp->check_timer);
+ lp->check_timer.data = (unsigned long)dev;
+ lp->check_timer.function = at91ether_check_link;
+- } else if (lp->board_data.phy_irq_pin >= 32)
+- gpio_request(lp->board_data.phy_irq_pin, "ethernet_phy");
++ }
+
+ /* Display ethernet banner */
+ printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%pM)\n",
+ dev->name, (uint) dev->base_addr, dev->irq,
+- at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-",
+- at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex",
++ at91_emac_read(lp, AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-",
++ at91_emac_read(lp, AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex",
+ dev->dev_addr);
+- if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID))
++ if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID))
+ printk(KERN_INFO "%s: Davicom 9161 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)");
+- else if (phy_type == MII_LXT971A_ID)
++ else if (lp->phy_type == MII_LXT971A_ID)
+ printk(KERN_INFO "%s: Intel LXT971A PHY\n", dev->name);
+- else if (phy_type == MII_RTL8201_ID)
++ else if (lp->phy_type == MII_RTL8201_ID)
+ printk(KERN_INFO "%s: Realtek RTL8201(B)L PHY\n", dev->name);
+- else if (phy_type == MII_BCM5221_ID)
++ else if (lp->phy_type == MII_BCM5221_ID)
+ printk(KERN_INFO "%s: Broadcom BCM5221 PHY\n", dev->name);
+- else if (phy_type == MII_DP83847_ID)
++ else if (lp->phy_type == MII_DP83847_ID)
+ printk(KERN_INFO "%s: National Semiconductor DP83847 PHY\n", dev->name);
+- else if (phy_type == MII_DP83848_ID)
++ else if (lp->phy_type == MII_DP83848_ID)
+ printk(KERN_INFO "%s: National Semiconductor DP83848 PHY\n", dev->name);
+- else if (phy_type == MII_AC101L_ID)
++ else if (lp->phy_type == MII_AC101L_ID)
+ printk(KERN_INFO "%s: Altima AC101L PHY\n", dev->name);
+- else if (phy_type == MII_KS8721_ID)
++ else if (lp->phy_type == MII_KS8721_ID)
+ printk(KERN_INFO "%s: Micrel KS8721 PHY\n", dev->name);
+- else if (phy_type == MII_T78Q21x3_ID)
++ else if (lp->phy_type == MII_T78Q21x3_ID)
+ printk(KERN_INFO "%s: Teridian 78Q21x3 PHY\n", dev->name);
+- else if (phy_type == MII_LAN83C185_ID)
++ else if (lp->phy_type == MII_LAN83C185_ID)
+ printk(KERN_INFO "%s: SMSC LAN83C185 PHY\n", dev->name);
+
+- return 0;
+-}
+-
+-/*
+- * Detect MAC and PHY and perform initialization
+- */
+-static int __init at91ether_probe(struct platform_device *pdev)
+-{
+- unsigned int phyid1, phyid2;
+- int detected = -1;
+- unsigned long phy_id;
+- unsigned short phy_address = 0;
+- struct clk *ether_clk;
+-
+- ether_clk = clk_get(&pdev->dev, "ether_clk");
+- if (IS_ERR(ether_clk)) {
+- printk(KERN_ERR "at91_ether: no clock defined\n");
+- return -ENODEV;
+- }
+- clk_enable(ether_clk); /* Enable Peripheral clock */
+-
+- while ((detected != 0) && (phy_address < 32)) {
+- /* Read the PHY ID registers */
+- enable_mdi();
+- read_phy(phy_address, MII_PHYSID1, &phyid1);
+- read_phy(phy_address, MII_PHYSID2, &phyid2);
+- disable_mdi();
+-
+- phy_id = (phyid1 << 16) | (phyid2 & 0xfff0);
+- switch (phy_id) {
+- case MII_DM9161_ID: /* Davicom 9161: PHY_ID1 = 0x181, PHY_ID2 = B881 */
+- case MII_DM9161A_ID: /* Davicom 9161A: PHY_ID1 = 0x181, PHY_ID2 = B8A0 */
+- case MII_LXT971A_ID: /* Intel LXT971A: PHY_ID1 = 0x13, PHY_ID2 = 78E0 */
+- case MII_RTL8201_ID: /* Realtek RTL8201: PHY_ID1 = 0, PHY_ID2 = 0x8201 */
+- case MII_BCM5221_ID: /* Broadcom BCM5221: PHY_ID1 = 0x40, PHY_ID2 = 0x61e0 */
+- case MII_DP83847_ID: /* National Semiconductor DP83847: */
+- case MII_DP83848_ID: /* National Semiconductor DP83848: */
+- case MII_AC101L_ID: /* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */
+- case MII_KS8721_ID: /* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
+- case MII_T78Q21x3_ID: /* Teridian 78Q21x3: PHY_ID1 = 0x0E, PHY_ID2 = 7237 */
+- case MII_LAN83C185_ID: /* SMSC LAN83C185: PHY_ID1 = 0x0007, PHY_ID2 = 0xC0A1 */
+- detected = at91ether_setup(phy_id, phy_address, pdev, ether_clk);
+- break;
+- }
++ clk_disable(lp->ether_clk); /* Disable Peripheral clock */
+
+- phy_address++;
+- }
++ return 0;
+
+- clk_disable(ether_clk); /* Disable Peripheral clock */
+
+- return detected;
++err_free_dmamem:
++ platform_set_drvdata(pdev, NULL);
++ dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys);
++err_free_irq:
++ free_irq(dev->irq, dev);
++err_disable_clock:
++ clk_disable(lp->ether_clk);
++ clk_put(lp->ether_clk);
++err_ioumap:
++ iounmap(lp->emac_base);
++err_free_dev:
++ free_netdev(dev);
++ return res;
+ }
+
+ static int __devexit at91ether_remove(struct platform_device *pdev)
+@@ -1170,8 +1212,7 @@ static int __devexit at91ether_remove(struct platform_device *pdev)
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct at91_private *lp = netdev_priv(dev);
+
+- if (gpio_is_valid(lp->board_data.phy_irq_pin) &&
+- lp->board_data.phy_irq_pin >= 32)
++ if (gpio_is_valid(lp->board_data.phy_irq_pin))
+ gpio_free(lp->board_data.phy_irq_pin);
+
+ unregister_netdev(dev);
+diff --git a/drivers/net/ethernet/cadence/at91_ether.h b/drivers/net/ethernet/cadence/at91_ether.h
+index 3725fbb0..0ef6328 100644
+--- a/drivers/net/ethernet/cadence/at91_ether.h
++++ b/drivers/net/ethernet/cadence/at91_ether.h
+@@ -88,6 +88,7 @@ struct at91_private
+ struct macb_platform_data board_data; /* board-specific
+ * configuration (shared with
+ * macb for common data */
++ void __iomem *emac_base; /* base register address */
+ struct clk *ether_clk; /* clock */
+
+ /* PHY */
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0070-net-at91_ether-use-gpio_to_irq-for-phy-IRQ-line.patch b/patches.at91/0070-net-at91_ether-use-gpio_to_irq-for-phy-IRQ-line.patch
new file mode 100644
index 00000000000000..07c79ae379694e
--- /dev/null
+++ b/patches.at91/0070-net-at91_ether-use-gpio_to_irq-for-phy-IRQ-line.patch
@@ -0,0 +1,62 @@
+From 4c7f53afde86fed3bbc8cb4583b46e0b154ca01f Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 26 Apr 2012 00:30:43 +0000
+Subject: net/at91_ether: use gpio_to_irq for phy IRQ line
+
+Use the gpio_to_irq() function to retrieve the phy IRQ line
+from the GPIO pin specification.
+This fix is needed now that we have moved to irqdomains on AT91.
+
+Reported-by: Jamie Iles <jamie@jamieiles.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Cc: Andrew Victor <avictor.za@gmail.com>
+Cc: David S. Miller <davem@davemloft.net>
+Cc: netdev@vger.kernel.org
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/cadence/at91_ether.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/at91_ether.c b/drivers/net/ethernet/cadence/at91_ether.c
+index 62761e1..7788419 100644
+--- a/drivers/net/ethernet/cadence/at91_ether.c
++++ b/drivers/net/ethernet/cadence/at91_ether.c
+@@ -263,7 +263,7 @@ static void enable_phyirq(struct net_device *dev)
+ return;
+ }
+
+- irq_number = lp->board_data.phy_irq_pin;
++ irq_number = gpio_to_irq(lp->board_data.phy_irq_pin);
+ status = request_irq(irq_number, at91ether_phy_interrupt, 0, dev->name, dev);
+ if (status) {
+ printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status);
+@@ -363,7 +363,7 @@ static void disable_phyirq(struct net_device *dev)
+ disable_mdi(lp);
+ spin_unlock_irq(&lp->lock);
+
+- irq_number = lp->board_data.phy_irq_pin;
++ irq_number = gpio_to_irq(lp->board_data.phy_irq_pin);
+ free_irq(irq_number, dev); /* Free interrupt handler */
+ }
+
+@@ -1234,7 +1234,7 @@ static int at91ether_suspend(struct platform_device *pdev, pm_message_t mesg)
+
+ if (netif_running(net_dev)) {
+ if (gpio_is_valid(lp->board_data.phy_irq_pin)) {
+- int phy_irq = lp->board_data.phy_irq_pin;
++ int phy_irq = gpio_to_irq(lp->board_data.phy_irq_pin);
+ disable_irq(phy_irq);
+ }
+
+@@ -1258,7 +1258,7 @@ static int at91ether_resume(struct platform_device *pdev)
+ netif_start_queue(net_dev);
+
+ if (gpio_is_valid(lp->board_data.phy_irq_pin)) {
+- int phy_irq = lp->board_data.phy_irq_pin;
++ int phy_irq = gpio_to_irq(lp->board_data.phy_irq_pin);
+ enable_irq(phy_irq);
+ }
+ }
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0071-net-macb-manage-carrier-state-with-call-to-netif_car.patch b/patches.at91/0071-net-macb-manage-carrier-state-with-call-to-netif_car.patch
new file mode 100644
index 00000000000000..de3a73a9d785bf
--- /dev/null
+++ b/patches.at91/0071-net-macb-manage-carrier-state-with-call-to-netif_car.patch
@@ -0,0 +1,67 @@
+From 7753ed0e33522a318f41773a78c2900a038c23be Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 3 Jul 2012 23:14:13 +0000
+Subject: net/macb: manage carrier state with call to netif_carrier_{on|off}()
+
+OFF carrier state is setup in probe() open() and suspend() functions.
+The carrier ON state is managed in macb_handle_link_change().
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/cadence/macb.c | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index c4834c2..6100b85 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -179,13 +179,16 @@ static void macb_handle_link_change(struct net_device *dev)
+ spin_unlock_irqrestore(&bp->lock, flags);
+
+ if (status_change) {
+- if (phydev->link)
++ if (phydev->link) {
++ netif_carrier_on(dev);
+ netdev_info(dev, "link up (%d/%s)\n",
+ phydev->speed,
+ phydev->duplex == DUPLEX_FULL ?
+ "Full" : "Half");
+- else
++ } else {
++ netif_carrier_off(dev);
+ netdev_info(dev, "link down\n");
++ }
+ }
+ }
+
+@@ -1033,6 +1036,9 @@ static int macb_open(struct net_device *dev)
+
+ netdev_dbg(bp->dev, "open\n");
+
++ /* carrier starts down */
++ netif_carrier_off(dev);
++
+ /* if the phy is not yet register, retry later*/
+ if (!bp->phy_dev)
+ return -EAGAIN;
+@@ -1405,6 +1411,8 @@ static int __init macb_probe(struct platform_device *pdev)
+
+ platform_set_drvdata(pdev, dev);
+
++ netif_carrier_off(dev);
++
+ netdev_info(dev, "Cadence %s at 0x%08lx irq %d (%pM)\n",
+ macb_is_gem(bp) ? "GEM" : "MACB", dev->base_addr,
+ dev->irq, dev->dev_addr);
+@@ -1468,6 +1476,7 @@ static int macb_suspend(struct platform_device *pdev, pm_message_t state)
+ struct net_device *netdev = platform_get_drvdata(pdev);
+ struct macb *bp = netdev_priv(netdev);
+
++ netif_carrier_off(netdev);
+ netif_device_detach(netdev);
+
+ clk_disable(bp->hclk);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0072-ALSA-atmel-ac97c-correct-the-unexpected-behavior-whe.patch b/patches.at91/0072-ALSA-atmel-ac97c-correct-the-unexpected-behavior-whe.patch
new file mode 100644
index 00000000000000..d8a89a2cc95341
--- /dev/null
+++ b/patches.at91/0072-ALSA-atmel-ac97c-correct-the-unexpected-behavior-whe.patch
@@ -0,0 +1,35 @@
+From dbbe3702cb9bf1aa4e07dc6fe2cce479f75ab39e Mon Sep 17 00:00:00 2001
+From: Bo Shen <voice.shen@atmel.com>
+Date: Fri, 11 May 2012 17:39:28 +0800
+Subject: ALSA: atmel/ac97c: correct the unexpected behavior when using
+ uninitial value for reset pin
+
+When pdata->reset_pin is passed with a negative value (means gpio
+is invalid), then chip->reset_pin will not be assigned to a vaule,
+it will use default value 0. This will cause unexpected behavior.
+
+So, add this patch to correct.
+
+Signed-off-by: Bo Shen <voice.shen@atmel.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+---
+ sound/atmel/ac97c.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
+index 115313e..f5ded64 100644
+--- a/sound/atmel/ac97c.c
++++ b/sound/atmel/ac97c.c
+@@ -991,6 +991,8 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
+ gpio_direction_output(pdata->reset_pin, 1);
+ chip->reset_pin = pdata->reset_pin;
+ }
++ } else {
++ chip->reset_pin = -EINVAL;
+ }
+
+ snd_card_set_dev(card, &pdev->dev);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0073-MTD-at91-extract-hw-ecc-initialization-to-one-functi.patch b/patches.at91/0073-MTD-at91-extract-hw-ecc-initialization-to-one-functi.patch
new file mode 100644
index 00000000000000..436c88279c1fde
--- /dev/null
+++ b/patches.at91/0073-MTD-at91-extract-hw-ecc-initialization-to-one-functi.patch
@@ -0,0 +1,188 @@
+From 37a9c14614a63c3e5fed9d6cb18638d765a65f80 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Thu, 31 May 2012 18:09:20 +0800
+Subject: 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>
+---
+ drivers/mtd/nand/atmel_nand.c | 127 ++++++++++++++++++++++--------------------
+ 1 file changed, 66 insertions(+), 61 deletions(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index 2165576..4ea0a04 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -523,6 +523,66 @@ static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
+ }
+ #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;
++ nand_chip->ecc.strength = 1;
++
++ return 0;
++}
++
+ /*
+ * Probe for the NAND device.
+ */
+@@ -531,7 +591,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;
+ struct mtd_part_parser_data ppdata = {};
+ int res;
+@@ -583,29 +642,6 @@ 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;
+-
+- regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+- if (!regs && nand_chip->ecc.mode == NAND_ECC_HW) {
+- 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;
+- }
+-
+- if (nand_chip->ecc.mode == NAND_ECC_HW) {
+- host->ecc = ioremap(regs->start, resource_size(regs));
+- if (host->ecc == NULL) {
+- printk(KERN_ERR "atmel_nand: ioremap failed\n");
+- res = -EIO;
+- goto err_ecc_ioremap;
+- }
+- 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.strength = 1;
+- }
+-
+ nand_chip->chip_delay = 20; /* 20us command delay time */
+
+ if (host->board.bus_width_16) /* 16-bit bus width */
+@@ -657,40 +693,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 */
+@@ -707,15 +712,15 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ return res;
+
+ 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.8.0.197.g5a90748
+
diff --git a/patches.at91/0074-MTD-at91-add-dt-parameters-for-Atmel-PMECC.patch b/patches.at91/0074-MTD-at91-add-dt-parameters-for-Atmel-PMECC.patch
new file mode 100644
index 00000000000000..b1711f6c37c108
--- /dev/null
+++ b/patches.at91/0074-MTD-at91-add-dt-parameters-for-Atmel-PMECC.patch
@@ -0,0 +1,157 @@
+From 7f3d2c9c00b937d2932b337fe259dd4f56c048b7 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Tue, 26 Jun 2012 17:42:22 +0800
+Subject: MTD: at91: add dt parameters for Atmel PMECC
+
+Add DT support for PMECC parameters.
+
+Signed-off-by: Hong Xu <hong.xu@atmel.com>
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ .../devicetree/bindings/mtd/atmel-nand.txt | 40 ++++++++++++++++-
+ drivers/mtd/nand/atmel_nand.c | 52 +++++++++++++++++++++-
+ 2 files changed, 90 insertions(+), 2 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
+index a200695..d555421 100644
+--- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt
++++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
+@@ -3,7 +3,9 @@ Atmel NAND flash
+ Required properties:
+ - compatible : "atmel,at91rm9200-nand".
+ - reg : should specify localbus address and size used for the chip,
+- and if availlable the ECC.
++ and hardware ECC controller if available.
++ If the hardware ECC is PMECC, it should contain address and size for
++ PMECC, PMECC Error Location controller and ROM which has lookup tables.
+ - atmel,nand-addr-offset : offset for the address latch.
+ - atmel,nand-cmd-offset : offset for the command latch.
+ - #address-cells, #size-cells : Must be present if the device has sub-nodes
+@@ -16,6 +18,15 @@ Optional properties:
+ - nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default.
+ Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
+ "soft_bch".
++- atmel,has-pmecc : boolean to enable Programmable Multibit ECC hardware.
++ Only supported by at91sam9x5 or later sam9 product.
++- atmel,pmecc-cap : error correct capability for Programmable Multibit ECC
++ Controller. Supported values are: 2, 4, 8, 12, 24.
++- atmel,pmecc-sector-size : sector size for ECC computation. Supported values
++ are: 512, 1024.
++- atmel,pmecc-lookup-table-offset : includes two offsets of lookup table in ROM
++ for different sector size. First one is for sector size 512, the next is for
++ sector size 1024.
+ - nand-bus-width : 8 or 16 bus width if not present 8
+ - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
+
+@@ -39,3 +50,30 @@ nand0: nand@40000000,0 {
+ ...
+ };
+ };
++
++/* for PMECC supported chips */
++nand0: nand@40000000 {
++ compatible = "atmel,at91rm9200-nand";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ reg = < 0x40000000 0x10000000 /* bus addr & size */
++ 0xffffe000 0x00000600 /* PMECC addr & size */
++ 0xffffe600 0x00000200 /* PMECC ERRLOC addr & size */
++ 0x00100000 0x00100000 /* ROM addr & size */
++ >;
++ atmel,nand-addr-offset = <21>; /* ale */
++ atmel,nand-cmd-offset = <22>; /* cle */
++ nand-on-flash-bbt;
++ nand-ecc-mode = "hw";
++ atmel,has-pmecc; /* enable PMECC */
++ atmel,pmecc-cap = <2>;
++ atmel,pmecc-sector-size = <512>;
++ atmel,pmecc-lookup-table-offset = <0x8000 0x10000>;
++ gpios = <&pioD 5 0 /* rdy */
++ &pioD 4 0 /* nce */
++ 0 /* cd */
++ >;
++ partition@0 {
++ ...
++ };
++};
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index 4ea0a04..712a705 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -93,6 +93,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)
+@@ -477,7 +482,8 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
+ static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
+ struct device_node *np)
+ {
+- u32 val;
++ u32 val, table_offset;
++ u32 offset[2];
+ int ecc_mode;
+ struct atmel_nand_data *board = &host->board;
+ enum of_gpio_flags flags;
+@@ -513,6 +519,50 @@ static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
+ board->enable_pin = of_get_gpio(np, 1);
+ board->det_pin = of_get_gpio(np, 2);
+
++ host->has_pmecc = of_property_read_bool(np, "atmel,has-pmecc");
++
++ if (!(board->ecc_mode == NAND_ECC_HW) || !host->has_pmecc)
++ return 0; /* Not using PMECC */
++
++ /* use PMECC, get correction capability, sector size and lookup
++ * table offset.
++ */
++ if (of_property_read_u32(np, "atmel,pmecc-cap", &val) != 0) {
++ dev_err(host->dev, "Cannot decide PMECC Capability\n");
++ return -EINVAL;
++ } else if ((val != 2) && (val != 4) && (val != 8) && (val != 12) &&
++ (val != 24)) {
++ dev_err(host->dev,
++ "Unsupported PMECC correction capability: %d; should be 2, 4, 8, 12 or 24\n",
++ val);
++ return -EINVAL;
++ }
++ host->pmecc_corr_cap = (u8)val;
++
++ if (of_property_read_u32(np, "atmel,pmecc-sector-size", &val) != 0) {
++ dev_err(host->dev, "Cannot decide PMECC Sector Size\n");
++ return -EINVAL;
++ } else if ((val != 512) && (val != 1024)) {
++ dev_err(host->dev,
++ "Unsupported PMECC sector size: %d; should be 512 or 1024 bytes\n",
++ val);
++ return -EINVAL;
++ }
++ host->pmecc_sector_size = (u16)val;
++
++ if (of_property_read_u32_array(np, "atmel,pmecc-lookup-table-offset",
++ offset, 2) != 0) {
++ dev_err(host->dev, "Cannot get PMECC lookup table offset\n");
++ return -EINVAL;
++ }
++ table_offset = host->pmecc_sector_size == 512 ? offset[0] : offset[1];
++
++ if (!table_offset) {
++ dev_err(host->dev, "Invalid PMECC lookup table offset\n");
++ return -EINVAL;
++ }
++ host->pmecc_lookup_table_offset = table_offset;
++
+ return 0;
+ }
+ #else
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0075-MTD-at91-atmel_nand-Update-driver-to-support-Program.patch b/patches.at91/0075-MTD-at91-atmel_nand-Update-driver-to-support-Program.patch
new file mode 100644
index 00000000000000..df8ea11c4f2dcb
--- /dev/null
+++ b/patches.at91/0075-MTD-at91-atmel_nand-Update-driver-to-support-Program.patch
@@ -0,0 +1,959 @@
+From 6dc4ff786c62fa34390607264d4d3ec54e22d5b7 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Fri, 29 Jun 2012 15:29:21 +0800
+Subject: MTD: at91: atmel_nand: Update driver to support Programmable Multibit
+ ECC controller
+
+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>
+---
+ drivers/mtd/nand/atmel_nand.c | 747 +++++++++++++++++++++++++++++++++++++-
+ drivers/mtd/nand/atmel_nand_ecc.h | 114 +++++-
+ 2 files changed, 859 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index 712a705..42b64fb 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 Programmable Multibit ECC support for various AT91 SoC
++ * (C) 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
+@@ -98,8 +100,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();
+@@ -293,6 +318,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
+@@ -743,7 +1465,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;
+ }
+@@ -762,8 +1488,16 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ return res;
+
+ 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:
+@@ -789,8 +1523,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.8.0.197.g5a90748
+
diff --git a/patches.at91/0076-MTD-nand-add-return-value-for-write_page-write_page_.patch b/patches.at91/0076-MTD-nand-add-return-value-for-write_page-write_page_.patch
new file mode 100644
index 00000000000000..af5354607adb12
--- /dev/null
+++ b/patches.at91/0076-MTD-nand-add-return-value-for-write_page-write_page_.patch
@@ -0,0 +1,153 @@
+From c00279166e428d885fd658d0be8d2419acc87d18 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Mon, 25 Jun 2012 15:15:54 +0800
+Subject: MTD: nand: add return value for write_page()/write_page_raw()
+ functions in structure of nand_ecc_ctrl.
+
+There is an implemention of hardware ECC write page function which may return an
+error indication.
+For instance, using Atmel HW PMECC to write one page into a nand flash, the hardware
+engine will compute the BCH ecc code for this page. so we need read a the
+status register to theck whether the ecc code is generated.
+But we cannot assume the status register always can be ready, for example,
+incorrect hardware configuration or hardware issue, in such case we need
+write_page() to return a error code.
+
+Since the definition of 'write_page' function in struct nand_ecc_ctrl is 'void'.
+So this patch will:
+ 1. add return 'int' value for 'write_page' function.
+ 2. to be consitent, add return 'int' value for 'write_page_raw' fuctions too.
+ 3. add code to test the return value, and if negative, indicate an
+ error happend when write page with ECC.
+ 4. fix the compile warning in all impacted nand flash driver.
+
+Note: I couldn't compile-test all of these easily, as some had ARCH dependencies.
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ drivers/mtd/nand/nand_base.c | 27 +++++++++++++++++++--------
+ include/linux/mtd/nand.h | 4 ++--
+ 2 files changed, 21 insertions(+), 10 deletions(-)
+
+--- a/drivers/mtd/nand/nand_base.c
++++ b/drivers/mtd/nand/nand_base.c
+@@ -1922,11 +1922,13 @@ out:
+ *
+ * Not for syndrome calculating ECC controllers, which use a special oob layout.
+ */
+-static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
++static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf)
+ {
+ chip->write_buf(mtd, buf, mtd->writesize);
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++ return 0;
+ }
+
+ /**
+@@ -1937,7 +1939,7 @@ static void nand_write_page_raw(struct m
+ *
+ * We need a special oob layout and handling even when ECC isn't checked.
+ */
+-static void nand_write_page_raw_syndrome(struct mtd_info *mtd,
++static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
+ struct nand_chip *chip,
+ const uint8_t *buf)
+ {
+@@ -1967,6 +1969,8 @@ static void nand_write_page_raw_syndrome
+ size = mtd->oobsize - (oob - chip->oob_poi);
+ if (size)
+ chip->write_buf(mtd, oob, size);
++
++ return 0;
+ }
+ /**
+ * nand_write_page_swecc - [REPLACEABLE] software ECC based page write function
+@@ -1974,7 +1978,7 @@ static void nand_write_page_raw_syndrome
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ */
+-static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
++static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf)
+ {
+ int i, eccsize = chip->ecc.size;
+@@ -1991,7 +1995,7 @@ static void nand_write_page_swecc(struct
+ for (i = 0; i < chip->ecc.total; i++)
+ chip->oob_poi[eccpos[i]] = ecc_calc[i];
+
+- chip->ecc.write_page_raw(mtd, chip, buf);
++ return chip->ecc.write_page_raw(mtd, chip, buf);
+ }
+
+ /**
+@@ -2000,7 +2004,7 @@ static void nand_write_page_swecc(struct
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ */
+-static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
++static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf)
+ {
+ int i, eccsize = chip->ecc.size;
+@@ -2020,6 +2024,8 @@ static void nand_write_page_hwecc(struct
+ chip->oob_poi[eccpos[i]] = ecc_calc[i];
+
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++ return 0;
+ }
+
+ /**
+@@ -2031,7 +2037,7 @@ static void nand_write_page_hwecc(struct
+ * The hw generator calculates the error syndrome automatically. Therefore we
+ * need a special oob layout and handling.
+ */
+-static void nand_write_page_syndrome(struct mtd_info *mtd,
++static int nand_write_page_syndrome(struct mtd_info *mtd,
+ struct nand_chip *chip, const uint8_t *buf)
+ {
+ int i, eccsize = chip->ecc.size;
+@@ -2064,6 +2070,8 @@ static void nand_write_page_syndrome(str
+ i = mtd->oobsize - (oob - chip->oob_poi);
+ if (i)
+ chip->write_buf(mtd, oob, i);
++
++ return 0;
+ }
+
+ /**
+@@ -2083,9 +2091,12 @@ static int nand_write_page(struct mtd_in
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+
+ if (unlikely(raw))
+- chip->ecc.write_page_raw(mtd, chip, buf);
++ status = chip->ecc.write_page_raw(mtd, chip, buf);
+ else
+- chip->ecc.write_page(mtd, chip, buf);
++ status = chip->ecc.write_page(mtd, chip, buf);
++
++ if (status < 0)
++ return status;
+
+ /*
+ * Cached progamming disabled for now. Not sure if it's worth the
+--- a/include/linux/mtd/nand.h
++++ b/include/linux/mtd/nand.h
+@@ -361,13 +361,13 @@ struct nand_ecc_ctrl {
+ uint8_t *calc_ecc);
+ int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf, int page);
+- void (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
++ int (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf);
+ int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf, int page);
+ int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
+ uint32_t offs, uint32_t len, uint8_t *buf);
+- void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
++ int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf);
+ int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
+ int page);
diff --git a/patches.at91/0077-MTD-atmel_nand-revet-the-oob_required-parameter-in-e.patch b/patches.at91/0077-MTD-atmel_nand-revet-the-oob_required-parameter-in-e.patch
new file mode 100644
index 00000000000000..bdccc954ab88b0
--- /dev/null
+++ b/patches.at91/0077-MTD-atmel_nand-revet-the-oob_required-parameter-in-e.patch
@@ -0,0 +1,38 @@
+From 7d92178b306bf2b8020da2a5c53077885e6239f9 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Fri, 21 Sep 2012 15:49:29 +0200
+Subject: MTD: atmel_nand: revet the oob_required parameter in
+ ecc.read/write_page
+
+Only for v3.4 compatibility. Do not propagate upstream
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/mtd/nand/atmel_nand.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index 42b64fb..ec0745e 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -759,7 +759,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;
+@@ -797,7 +797,7 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
+ }
+
+ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
+- struct nand_chip *chip, const uint8_t *buf, int oob_required)
++ struct nand_chip *chip, const uint8_t *buf)
+ {
+ struct atmel_nand_host *host = chip->priv;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0078-MTD-atmel_nand-add-9x5-to-list-of-SoC-with-DMA.patch b/patches.at91/0078-MTD-atmel_nand-add-9x5-to-list-of-SoC-with-DMA.patch
new file mode 100644
index 00000000000000..052f8ee81486ce
--- /dev/null
+++ b/patches.at91/0078-MTD-atmel_nand-add-9x5-to-list-of-SoC-with-DMA.patch
@@ -0,0 +1,28 @@
+From ddee6570ee156ed3d758fbfb0931054d77da29c5 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 24 Sep 2012 14:57:08 +0200
+Subject: MTD: atmel_nand: add 9x5 to list of SoC with DMA
+
+Temporary: may have to be replaced by a device-tree property.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/mtd/nand/atmel_nand.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index ec0745e..a5c184e 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -127,7 +127,7 @@ 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.8.0.197.g5a90748
+
diff --git a/patches.at91/0079-MTD-atmel_nand-POI-fall-back-is-not-an-issue-change-.patch b/patches.at91/0079-MTD-atmel_nand-POI-fall-back-is-not-an-issue-change-.patch
new file mode 100644
index 00000000000000..cbecb401cca41d
--- /dev/null
+++ b/patches.at91/0079-MTD-atmel_nand-POI-fall-back-is-not-an-issue-change-.patch
@@ -0,0 +1,26 @@
+From 3efc10bd73879d566ad573e6ce4419fb79d9eda0 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 24 Sep 2012 15:07:06 +0200
+Subject: MTD: atmel_nand: POI fall back is not an issue: change log
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/mtd/nand/atmel_nand.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index a5c184e..17ef011 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -281,7 +281,7 @@ err_dma:
+ dma_unmap_single(dma_dev->dev, phys_addr, len, dir);
+ err_buf:
+ if (err != 0)
+- dev_warn(host->dev, "Fall back to CPU I/O\n");
++ dev_dbg(host->dev, "Fall back to CPU I/O\n");
+ return err;
+ }
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0080-MTD-atmel_nand-add-9n12-to-list-of-SoC-with-DMA.patch b/patches.at91/0080-MTD-atmel_nand-add-9n12-to-list-of-SoC-with-DMA.patch
new file mode 100644
index 00000000000000..0b9ce93686f38f
--- /dev/null
+++ b/patches.at91/0080-MTD-atmel_nand-add-9n12-to-list-of-SoC-with-DMA.patch
@@ -0,0 +1,29 @@
+From 6d16ae9b0f776651f60af120bb799d77504a2703 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 8 Oct 2012 16:55:29 +0200
+Subject: MTD: atmel_nand: add 9n12 to list of SoC with DMA
+
+Temporary: may have to be replaced by a device-tree property.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@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 17ef011..b1158b4 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -127,7 +127,8 @@ static struct nand_ecclayout atmel_pmecc_oobinfo;
+
+ static int cpu_has_dma(void)
+ {
+- return cpu_is_at91sam9rl() || cpu_is_at91sam9g45() || cpu_is_at91sam9x5();
++ return cpu_is_at91sam9rl() || cpu_is_at91sam9g45()
++ || cpu_is_at91sam9x5() || cpu_is_at91sam9n12();
+ }
+
+ /*
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0081-input-atmel_tsadcc-add-support-for-ARCH_AT91SAM9X5.patch b/patches.at91/0081-input-atmel_tsadcc-add-support-for-ARCH_AT91SAM9X5.patch
new file mode 100644
index 00000000000000..e0fbdeb181a8df
--- /dev/null
+++ b/patches.at91/0081-input-atmel_tsadcc-add-support-for-ARCH_AT91SAM9X5.patch
@@ -0,0 +1,392 @@
+From 205e3ae2e153f8cd611e980d02c5ca629e726f06 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Wed, 17 Nov 2010 12:28:13 +0100
+Subject: input: atmel_tsadcc: add support for ARCH_AT91SAM9X5
+
+XXX: split header creation in a new patch (or don't do it)
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ drivers/input/touchscreen/atmel_tsadcc.c | 150 ++++++++++++----------------
+ drivers/input/touchscreen/atmel_tsadcc.h | 162 +++++++++++++++++++++++++++++++
+ 2 files changed, 222 insertions(+), 90 deletions(-)
+ create mode 100644 drivers/input/touchscreen/atmel_tsadcc.h
+
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
+index 201b2d2..a0e8d52 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.8.0.197.g5a90748
+
diff --git a/patches.at91/0082-input-atmel_tsadcc-add-touch-screen-pressure-measure.patch b/patches.at91/0082-input-atmel_tsadcc-add-touch-screen-pressure-measure.patch
new file mode 100644
index 00000000000000..c9e59344022416
--- /dev/null
+++ b/patches.at91/0082-input-atmel_tsadcc-add-touch-screen-pressure-measure.patch
@@ -0,0 +1,104 @@
+From f924876dcc5572639dbb81e2e148cc84066f9571 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Wed, 17 Nov 2010 13:12:11 +0100
+Subject: input: atmel_tsadcc: add touch screen pressure measurement
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ 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 a0e8d52..b6a1630 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.8.0.197.g5a90748
+
diff --git a/patches.at91/0083-input-atmel_tsadcc-enable-touchscreen-averaging-and-.patch b/patches.at91/0083-input-atmel_tsadcc-enable-touchscreen-averaging-and-.patch
new file mode 100644
index 00000000000000..f368baf433b557
--- /dev/null
+++ b/patches.at91/0083-input-atmel_tsadcc-enable-touchscreen-averaging-and-.patch
@@ -0,0 +1,77 @@
+From c331326e3dcab10a8930f9f685bec700ec0d604a Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Tue, 5 Apr 2011 17:30:03 +0200
+Subject: input: atmel_tsadcc: enable touchscreen averaging and add fast wake
+ up
+
+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>
+---
+ 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 b6a1630..48faecb 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.8.0.197.g5a90748
+
diff --git a/patches.at91/0084-input-atmel_tsadcc-add-ACR-register-and-change-trigg.patch b/patches.at91/0084-input-atmel_tsadcc-add-ACR-register-and-change-trigg.patch
new file mode 100644
index 00000000000000..82ce0dbcb7ee06
--- /dev/null
+++ b/patches.at91/0084-input-atmel_tsadcc-add-ACR-register-and-change-trigg.patch
@@ -0,0 +1,92 @@
+From bb2bbaa1312891063aed730f0fd3eeddf77f95cb Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Fri, 6 May 2011 17:54:45 +0200
+Subject: input: atmel_tsadcc: add ACR register and change trigger period value
+
+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>
+---
+ drivers/input/touchscreen/atmel_tsadcc.c | 30 +++++++++++++++++++++++++++++-
+ drivers/input/touchscreen/atmel_tsadcc.h | 3 +++
+ 2 files changed, 32 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
+index 48faecb..20154ba 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.8.0.197.g5a90748
+
diff --git a/patches.at91/0085-AT91-input-atmel_tsadcc-rework-irq-infrastructure-an.patch b/patches.at91/0085-AT91-input-atmel_tsadcc-rework-irq-infrastructure-an.patch
new file mode 100644
index 00000000000000..a42080f6c46216
--- /dev/null
+++ b/patches.at91/0085-AT91-input-atmel_tsadcc-rework-irq-infrastructure-an.patch
@@ -0,0 +1,168 @@
+From dd05003395a5ae175e64b5ae8d78f6867d5d7398 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 16 Jun 2011 19:24:04 +0200
+Subject: AT91/input: atmel_tsadcc: rework irq infrastructure and parameters
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/input/touchscreen/atmel_tsadcc.c | 70 ++++++++++++++++++--------------
+ 1 file changed, 40 insertions(+), 30 deletions(-)
+
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
+index 20154ba..397d17a 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.8.0.197.g5a90748
+
diff --git a/patches.at91/0086-input-at91-add-tsadcc_data-for-9x5.patch b/patches.at91/0086-input-at91-add-tsadcc_data-for-9x5.patch
new file mode 100644
index 00000000000000..3b361bce87d490
--- /dev/null
+++ b/patches.at91/0086-input-at91-add-tsadcc_data-for-9x5.patch
@@ -0,0 +1,27 @@
+From 6fa3817bddf46d9e1fc43a6a217826ec84ededa4 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Thu, 7 Jun 2012 14:19:11 +0800
+Subject: input: at91: add tsadcc_data for 9x5
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ arch/arm/mach-at91/include/mach/board.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
+index 369afc2..726e5f3 100644
+--- a/arch/arm/mach-at91/include/mach/board.h
++++ b/arch/arm/mach-at91/include/mach/board.h
+@@ -175,7 +175,9 @@ extern void __init at91_add_device_isi(struct isi_platform_data *data,
+ /* 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);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0087-input-at91-add-dt-support-for-atmel-touch-screen-adc.patch b/patches.at91/0087-input-at91-add-dt-support-for-atmel-touch-screen-adc.patch
new file mode 100644
index 00000000000000..1a432fc8060284
--- /dev/null
+++ b/patches.at91/0087-input-at91-add-dt-support-for-atmel-touch-screen-adc.patch
@@ -0,0 +1,157 @@
+From 9dec1a67c24abf90346706d2fb3172c14d0fbcdf Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Wed, 13 Jun 2012 17:28:40 +0800
+Subject: input: at91: add dt support for atmel touch screen adc controller.
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ drivers/input/touchscreen/atmel_tsadcc.c | 86 ++++++++++++++++++++++++++++++--
+ 1 file changed, 82 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
+index 397d17a..021f87e 100644
+--- a/drivers/input/touchscreen/atmel_tsadcc.c
++++ b/drivers/input/touchscreen/atmel_tsadcc.c
+@@ -40,6 +40,8 @@ struct atmel_tsadcc {
+ unsigned int prev_absx;
+ unsigned int prev_absy;
+ unsigned int prev_absz;
++
++ struct at91_tsadcc_data board;
+ };
+
+ static void __iomem *tsc_base;
+@@ -62,7 +64,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;
++ struct at91_tsadcc_data *pdata = &ts_dev->board;
+
+ unsigned int status;
+ unsigned int reg;
+@@ -172,6 +174,63 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ return IRQ_HANDLED;
+ }
+
++#if defined(CONFIG_OF)
++static int __devinit atmel_of_init_tsadcc(struct device_node *np,
++ struct at91_tsadcc_data *pdata,
++ struct platform_device *pdev)
++{
++ u32 val;
++
++ if (of_property_read_u32(np, "atmel,tsadcc_clock", &val) == 0)
++ pdata->adc_clock = val;
++
++ if (of_property_read_u32(np, "atmel,filtering_average", &val) == 0) {
++ if (val > 0x03) {
++ dev_err(&pdev->dev, "invalid touch average setting, 0x%02x\n",
++ val);
++ return -EINVAL;
++ }
++ pdata->filtering_average = (u8)val;
++ }
++
++ if (of_property_read_u32(np, "atmel,pendet_debounce", &val) == 0) {
++ if (val > 0x0f) {
++ dev_err(&pdev->dev, "invalid pen detect debounce, 0x%02x\n",
++ val);
++ return -EINVAL;
++ }
++ pdata->pendet_debounce = (u8)val;
++ }
++
++ if (of_property_read_u32(np, "atmel,pendet_sensitivity", &val) == 0) {
++ if (val > 0x03) {
++ dev_err(&pdev->dev, "invalid pen detective sensitivity setting, 0x%02x\n",
++ val);
++ return -EINVAL;
++ }
++ pdata->pendet_sensitivity = (u8)val;
++ }
++
++ if (of_property_read_u32(np, "atmel,ts_sample_hold_time", &val) == 0) {
++ if (val > 0x0f) {
++ dev_err(&pdev->dev, "invalid ts sample hold time, 0x%02x\n",
++ val);
++ return -EINVAL;
++ }
++ pdata->ts_sample_hold_time = (u8)val;
++ }
++
++ return 0;
++}
++#else
++static int __devinit atmel_of_init_tsadcc(struct device_node *np,
++ struct at91_tsadcc_data *pdata,
++ struct platform_device *pdev)
++{
++ return -EINVAL;
++}
++#endif
++
+ /*
+ * The functions for inserting/removing us as a module.
+ */
+@@ -181,7 +240,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+ struct atmel_tsadcc *ts_dev;
+ struct input_dev *input_dev;
+ struct resource *res;
+- struct at91_tsadcc_data *pdata = pdev->dev.platform_data;
++ struct at91_tsadcc_data *pdata;
+ int err = 0;
+ unsigned int prsc;
+ unsigned int reg;
+@@ -199,6 +258,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+ return -ENOMEM;
+ }
+ platform_set_drvdata(pdev, ts_dev);
++ pdata = &ts_dev->board;
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+@@ -264,8 +324,16 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+ prsc = clk_get_rate(ts_dev->clk);
+ dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc);
+
+- if (!pdata)
+- goto err_fail;
++ if (pdev->dev.of_node) {
++ err = atmel_of_init_tsadcc(pdev->dev.of_node, pdata, pdev);
++ if (err)
++ goto err_fail;
++ } else {
++ if (!pdev->dev.platform_data)
++ goto err_fail;
++ else
++ memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata));
++ }
+
+ if (!pdata->adc_clock)
+ pdata->adc_clock = ADC_DEFAULT_CLOCK;
+@@ -374,11 +442,21 @@ static int __devexit atmel_tsadcc_remove(struct platform_device *pdev)
+ return 0;
+ }
+
++#if defined(CONFIG_OF)
++static const struct of_device_id atmel_tsaddcc_dt_ids[] = {
++ { .compatible = "atmel,at91sam9x5-tsadcc"},
++ { /* sentinel */ }
++}
++
++MODULE_DEVICE_TABLE(of, atmel_tsaddcc_dt_ids);
++#endif
++
+ static struct platform_driver atmel_tsadcc_driver = {
+ .probe = atmel_tsadcc_probe,
+ .remove = __devexit_p(atmel_tsadcc_remove),
+ .driver = {
+ .name = "atmel_tsadcc",
++ .of_match_table = of_match_ptr(atmel_tsaddcc_dt_ids),
+ },
+ };
+ module_platform_driver(atmel_tsadcc_driver);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0088-net-macb-Add-support-for-Gigabit-Ethernet-mode.patch b/patches.at91/0088-net-macb-Add-support-for-Gigabit-Ethernet-mode.patch
new file mode 100644
index 00000000000000..df89e312b3d33e
--- /dev/null
+++ b/patches.at91/0088-net-macb-Add-support-for-Gigabit-Ethernet-mode.patch
@@ -0,0 +1,85 @@
+From 5c2ed1407b5a897a7bd9c9ba0bb6dbc550c71d64 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 6 Sep 2012 14:55:37 +0200
+Subject: net/macb: Add support for Gigabit Ethernet mode
+
+Add Gigabit Ethernet mode to GEM cadence IP and enable RGMII connection.
+
+Signed-off-by: Patrice Vilchez <patrice.vilchez@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 15 ++++++++++++---
+ drivers/net/ethernet/cadence/macb.h | 4 ++++
+ 2 files changed, 16 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index 6100b85..e9b909a 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -152,13 +152,17 @@ static void macb_handle_link_change(struct net_device *dev)
+
+ reg = macb_readl(bp, NCFGR);
+ reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
++ if (macb_is_gem(bp))
++ reg &= ~GEM_BIT(GBE);
+
+ if (phydev->duplex)
+ reg |= MACB_BIT(FD);
+ if (phydev->speed == SPEED_100)
+ reg |= MACB_BIT(SPD);
++ if (phydev->speed == SPEED_1000)
++ reg |= GEM_BIT(GBE);
+
+- macb_writel(bp, NCFGR, reg);
++ macb_or_gem_writel(bp, NCFGR, reg);
+
+ bp->speed = phydev->speed;
+ bp->duplex = phydev->duplex;
+@@ -216,7 +220,10 @@ static int macb_mii_probe(struct net_device *dev)
+ }
+
+ /* mask with MAC supported features */
+- phydev->supported &= PHY_BASIC_FEATURES;
++ if (macb_is_gem(bp))
++ phydev->supported &= PHY_GBIT_FEATURES;
++ else
++ phydev->supported &= PHY_BASIC_FEATURES;
+
+ phydev->advertising = phydev->supported;
+
+@@ -1383,7 +1390,9 @@ static int __init macb_probe(struct platform_device *pdev)
+ bp->phy_interface = err;
+ }
+
+- if (bp->phy_interface == PHY_INTERFACE_MODE_RMII)
++ if (bp->phy_interface == PHY_INTERFACE_MODE_RGMII)
++ macb_or_gem_writel(bp, USRIO, GEM_BIT(RGMII));
++ else if (bp->phy_interface == PHY_INTERFACE_MODE_RMII)
+ #if defined(CONFIG_ARCH_AT91)
+ macb_or_gem_writel(bp, USRIO, (MACB_BIT(RMII) |
+ MACB_BIT(CLKEN)));
+diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
+index 335e288..f69ceef 100644
+--- a/drivers/net/ethernet/cadence/macb.h
++++ b/drivers/net/ethernet/cadence/macb.h
+@@ -145,6 +145,8 @@
+ #define MACB_IRXFCS_SIZE 1
+
+ /* GEM specific NCFGR bitfields. */
++#define GEM_GBE_OFFSET 10
++#define GEM_GBE_SIZE 1
+ #define GEM_CLK_OFFSET 18
+ #define GEM_CLK_SIZE 3
+ #define GEM_DBW_OFFSET 21
+@@ -246,6 +248,8 @@
+ /* Bitfields in USRIO (AT91) */
+ #define MACB_RMII_OFFSET 0
+ #define MACB_RMII_SIZE 1
++#define GEM_RGMII_OFFSET 0 /* GEM gigabit mode */
++#define GEM_RGMII_SIZE 1
+ #define MACB_CLKEN_OFFSET 1
+ #define MACB_CLKEN_SIZE 1
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0089-net-macb-memory-barriers-cleanup.patch b/patches.at91/0089-net-macb-memory-barriers-cleanup.patch
new file mode 100644
index 00000000000000..7950edb7c417f5
--- /dev/null
+++ b/patches.at91/0089-net-macb-memory-barriers-cleanup.patch
@@ -0,0 +1,96 @@
+From fe758f5a6775fb6b71fdf086c07e5247cafd53f3 Mon Sep 17 00:00:00 2001
+From: Havard Skinnemoen <havard@skinnemoen.net>
+Date: Fri, 28 May 2010 17:13:33 +0200
+Subject: net/macb: memory barriers cleanup
+
+Remove a couple of unneeded barriers and document the remaining ones.
+
+Signed-off-by: Havard Skinnemoen <havard@skinnemoen.net>
+[nicolas.ferre@atmel.com: split patch in topics]
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 18 ++++++++++++++----
+ 1 file changed, 14 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index e9b909a..a4dcd11 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -372,7 +372,9 @@ static void macb_tx(struct macb *bp)
+
+ BUG_ON(skb == NULL);
+
++ /* Make hw descriptor updates visible to CPU */
+ rmb();
++
+ bufstat = bp->tx_ring[tail].ctrl;
+
+ if (!(bufstat & MACB_BIT(TX_USED)))
+@@ -415,7 +417,10 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ if (frag == last_frag)
+ break;
+ }
++
++ /* Make descriptor updates visible to hardware */
+ wmb();
++
+ return 1;
+ }
+
+@@ -436,12 +441,14 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ frag_len);
+ offset += RX_BUFFER_SIZE;
+ bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED);
+- wmb();
+
+ if (frag == last_frag)
+ break;
+ }
+
++ /* Make descriptor updates visible to hardware */
++ wmb();
++
+ skb->protocol = eth_type_trans(skb, bp->dev);
+
+ bp->stats.rx_packets++;
+@@ -461,6 +468,8 @@ static void discard_partial_frame(struct macb *bp, unsigned int begin,
+
+ for (frag = begin; frag != end; frag = NEXT_RX(frag))
+ bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED);
++
++ /* Make descriptor updates visible to hardware */
+ wmb();
+
+ /*
+@@ -479,7 +488,9 @@ static int macb_rx(struct macb *bp, int budget)
+ for (; budget > 0; tail = NEXT_RX(tail)) {
+ u32 addr, ctrl;
+
++ /* Make hw descriptor updates visible to CPU */
+ rmb();
++
+ addr = bp->rx_ring[tail].addr;
+ ctrl = bp->rx_ring[tail].ctrl;
+
+@@ -674,6 +685,8 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
+
+ bp->tx_ring[entry].addr = mapping;
+ bp->tx_ring[entry].ctrl = ctrl;
++
++ /* Make newly initialized descriptor visible to hardware */
+ wmb();
+
+ entry = NEXT_TX(entry);
+@@ -782,9 +795,6 @@ static void macb_init_rings(struct macb *bp)
+
+ static void macb_reset_hw(struct macb *bp)
+ {
+- /* Make sure we have the write buffer for ourselves */
+- wmb();
+-
+ /*
+ * Disable RX and TX (XXX: Should we halt the transmission
+ * more gracefully?)
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0090-net-macb-change-debugging-messages.patch b/patches.at91/0090-net-macb-change-debugging-messages.patch
new file mode 100644
index 00000000000000..014d00ddc601be
--- /dev/null
+++ b/patches.at91/0090-net-macb-change-debugging-messages.patch
@@ -0,0 +1,112 @@
+From 7dd52f7f7728c264880ed982dcc5cebeb2ee76c0 Mon Sep 17 00:00:00 2001
+From: Havard Skinnemoen <havard@skinnemoen.net>
+Date: Fri, 28 May 2010 17:45:43 +0200
+Subject: net/macb: change debugging messages
+
+Convert some noisy netdev_dbg() statements to netdev_vdbg(). Defining
+DEBUG will no longer fill up the logs; VERBOSE_DEBUG still does.
+Add one more verbose debug for ISR status.
+
+Signed-off-by: Havard Skinnemoen <havard@skinnemoen.net>
+[nicolas.ferre@atmel.com: split patch in topics, add ISR status]
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 22 ++++++++++++----------
+ 1 file changed, 12 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index a4dcd11..ce1f558 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -313,7 +313,7 @@ static void macb_tx(struct macb *bp)
+ status = macb_readl(bp, TSR);
+ macb_writel(bp, TSR, status);
+
+- netdev_dbg(bp->dev, "macb_tx status = %02lx\n", (unsigned long)status);
++ netdev_vdbg(bp->dev, "macb_tx status = %02lx\n", (unsigned long)status);
+
+ if (status & (MACB_BIT(UND) | MACB_BIT(TSR_RLE))) {
+ int i;
+@@ -380,7 +380,7 @@ static void macb_tx(struct macb *bp)
+ if (!(bufstat & MACB_BIT(TX_USED)))
+ break;
+
+- netdev_dbg(bp->dev, "skb %u (data %p) TX complete\n",
++ netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n",
+ tail, skb->data);
+ dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len,
+ DMA_TO_DEVICE);
+@@ -406,7 +406,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+
+ len = MACB_BFEXT(RX_FRMLEN, bp->rx_ring[last_frag].ctrl);
+
+- netdev_dbg(bp->dev, "macb_rx_frame frags %u - %u (len %u)\n",
++ netdev_vdbg(bp->dev, "macb_rx_frame frags %u - %u (len %u)\n",
+ first_frag, last_frag, len);
+
+ skb = netdev_alloc_skb(bp->dev, len + RX_OFFSET);
+@@ -453,7 +453,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+
+ bp->stats.rx_packets++;
+ bp->stats.rx_bytes += len;
+- netdev_dbg(bp->dev, "received skb of length %u, csum: %08x\n",
++ netdev_vdbg(bp->dev, "received skb of length %u, csum: %08x\n",
+ skb->len, skb->csum);
+ netif_receive_skb(skb);
+
+@@ -535,7 +535,7 @@ static int macb_poll(struct napi_struct *napi, int budget)
+
+ work_done = 0;
+
+- netdev_dbg(bp->dev, "poll: status = %08lx, budget = %d\n",
++ netdev_vdbg(bp->dev, "poll: status = %08lx, budget = %d\n",
+ (unsigned long)status, budget);
+
+ work_done = macb_rx(bp, budget);
+@@ -574,6 +574,8 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
+ break;
+ }
+
++ netdev_vdbg(bp->dev, "isr = 0x%08lx\n", (unsigned long)status);
++
+ if (status & MACB_RX_INT_FLAGS) {
+ /*
+ * There's no point taking any more interrupts
+@@ -585,7 +587,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
+ macb_writel(bp, IDR, MACB_RX_INT_FLAGS);
+
+ if (napi_schedule_prep(&bp->napi)) {
+- netdev_dbg(bp->dev, "scheduling RX softirq\n");
++ netdev_vdbg(bp->dev, "scheduling RX softirq\n");
+ __napi_schedule(&bp->napi);
+ }
+ }
+@@ -647,8 +649,8 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ u32 ctrl;
+ unsigned long flags;
+
+-#ifdef DEBUG
+- netdev_dbg(bp->dev,
++#if defined(DEBUG) && defined(VERBOSE_DEBUG)
++ netdev_vdbg(bp->dev,
+ "start_xmit: len %u head %p data %p tail %p end %p\n",
+ skb->len, skb->head, skb->data,
+ skb_tail_pointer(skb), skb_end_pointer(skb));
+@@ -670,12 +672,12 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ }
+
+ entry = bp->tx_head;
+- netdev_dbg(bp->dev, "Allocated ring entry %u\n", entry);
++ netdev_vdbg(bp->dev, "Allocated ring entry %u\n", entry);
+ mapping = dma_map_single(&bp->pdev->dev, skb->data,
+ len, DMA_TO_DEVICE);
+ bp->tx_skb[entry].skb = skb;
+ bp->tx_skb[entry].mapping = mapping;
+- netdev_dbg(bp->dev, "Mapped skb data %p to DMA addr %08lx\n",
++ netdev_vdbg(bp->dev, "Mapped skb data %p to DMA addr %08lx\n",
+ skb->data, (unsigned long)mapping);
+
+ ctrl = MACB_BF(TX_FRMLEN, len);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0091-net-macb-remove-macb_get_drvinfo.patch b/patches.at91/0091-net-macb-remove-macb_get_drvinfo.patch
new file mode 100644
index 00000000000000..c9e7cdb252c15b
--- /dev/null
+++ b/patches.at91/0091-net-macb-remove-macb_get_drvinfo.patch
@@ -0,0 +1,41 @@
+From 93c3f8300d6da2e5a670ac681548509d4aa3b020 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 6 Sep 2012 15:23:47 +0200
+Subject: net/macb: remove macb_get_drvinfo()
+
+This function has little meaning so remove it altogether and
+let ethtool core fill in the fields automatically.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 11 -----------
+ 1 file changed, 11 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index ce1f558..dc34ff1 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -1223,20 +1223,9 @@ static int macb_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+ return phy_ethtool_sset(phydev, cmd);
+ }
+
+-static void macb_get_drvinfo(struct net_device *dev,
+- struct ethtool_drvinfo *info)
+-{
+- struct macb *bp = netdev_priv(dev);
+-
+- strcpy(info->driver, bp->pdev->dev.driver->name);
+- strcpy(info->version, "$Revision: 1.14 $");
+- strcpy(info->bus_info, dev_name(&bp->pdev->dev));
+-}
+-
+ static const struct ethtool_ops macb_ethtool_ops = {
+ .get_settings = macb_get_settings,
+ .set_settings = macb_set_settings,
+- .get_drvinfo = macb_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ };
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0092-net-macb-tx-status-is-more-than-8-bits-now.patch b/patches.at91/0092-net-macb-tx-status-is-more-than-8-bits-now.patch
new file mode 100644
index 00000000000000..9c0d4ce58f495b
--- /dev/null
+++ b/patches.at91/0092-net-macb-tx-status-is-more-than-8-bits-now.patch
@@ -0,0 +1,28 @@
+From 69eb5ddf7b65fe255a87b7613360c17fc8db2bbc Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 3 Sep 2012 17:52:09 +0200
+Subject: net/macb: tx status is more than 8 bits now
+
+On some revision of GEM, TSR status register has more information.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index dc34ff1..4e05a29 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -313,7 +313,7 @@ static void macb_tx(struct macb *bp)
+ status = macb_readl(bp, TSR);
+ macb_writel(bp, TSR, status);
+
+- netdev_vdbg(bp->dev, "macb_tx status = %02lx\n", (unsigned long)status);
++ netdev_vdbg(bp->dev, "macb_tx status = 0x%03lx\n", (unsigned long)status);
+
+ if (status & (MACB_BIT(UND) | MACB_BIT(TSR_RLE))) {
+ int i;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0093-net-macb-clean-up-ring-buffer-logic.patch b/patches.at91/0093-net-macb-clean-up-ring-buffer-logic.patch
new file mode 100644
index 00000000000000..4e781ee0d84477
--- /dev/null
+++ b/patches.at91/0093-net-macb-clean-up-ring-buffer-logic.patch
@@ -0,0 +1,409 @@
+From 5c7c8fe88a651f0e3313e644a952d40f83ce8dee Mon Sep 17 00:00:00 2001
+From: Havard Skinnemoen <havard@skinnemoen.net>
+Date: Mon, 21 Jun 2010 18:56:29 +0200
+Subject: net/macb: clean up ring buffer logic
+
+Instead of masking head and tail every time we increment them, just let them
+wrap through UINT_MAX and mask them when subscripting. Add simple accessor
+functions to do the subscripting properly to minimize the chances of messing
+this up.
+
+This makes the code slightly smaller, and hopefully faster as well. Also,
+doing the ring buffer management this way will simplify things a lot when
+making the ring sizes configurable in the future.
+
+Signed-off-by: Havard Skinnemoen <havard@skinnemoen.net>
+[nicolas.ferre@atmel.com: split patch in topics, adapt to newer kernel]
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 168 +++++++++++++++++++++++-------------
+ drivers/net/ethernet/cadence/macb.h | 22 +++--
+ 2 files changed, 122 insertions(+), 68 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index 4e05a29..2554354 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -31,24 +31,13 @@
+
+ #define RX_BUFFER_SIZE 128
+ #define RX_RING_SIZE 512
+-#define RX_RING_BYTES (sizeof(struct dma_desc) * RX_RING_SIZE)
++#define RX_RING_BYTES (sizeof(struct macb_dma_desc) * RX_RING_SIZE)
+
+ /* Make the IP header word-aligned (the ethernet header is 14 bytes) */
+ #define RX_OFFSET 2
+
+ #define TX_RING_SIZE 128
+-#define DEF_TX_RING_PENDING (TX_RING_SIZE - 1)
+-#define TX_RING_BYTES (sizeof(struct dma_desc) * TX_RING_SIZE)
+-
+-#define TX_RING_GAP(bp) \
+- (TX_RING_SIZE - (bp)->tx_pending)
+-#define TX_BUFFS_AVAIL(bp) \
+- (((bp)->tx_tail <= (bp)->tx_head) ? \
+- (bp)->tx_tail + (bp)->tx_pending - (bp)->tx_head : \
+- (bp)->tx_tail - (bp)->tx_head - TX_RING_GAP(bp))
+-#define NEXT_TX(n) (((n) + 1) & (TX_RING_SIZE - 1))
+-
+-#define NEXT_RX(n) (((n) + 1) & (RX_RING_SIZE - 1))
++#define TX_RING_BYTES (sizeof(struct macb_dma_desc) * TX_RING_SIZE)
+
+ /* minimum number of free TX descriptors before waking up TX process */
+ #define MACB_TX_WAKEUP_THRESH (TX_RING_SIZE / 4)
+@@ -56,6 +45,51 @@
+ #define MACB_RX_INT_FLAGS (MACB_BIT(RCOMP) | MACB_BIT(RXUBR) \
+ | MACB_BIT(ISR_ROVR))
+
++/* Ring buffer accessors */
++static unsigned int macb_tx_ring_wrap(unsigned int index)
++{
++ return index & (TX_RING_SIZE - 1);
++}
++
++static unsigned int macb_tx_ring_avail(struct macb *bp)
++{
++ return TX_RING_SIZE - (bp->tx_head - bp->tx_tail);
++}
++
++static struct macb_dma_desc *macb_tx_desc(struct macb *bp, unsigned int index)
++{
++ return &bp->tx_ring[macb_tx_ring_wrap(index)];
++}
++
++static struct macb_tx_skb *macb_tx_skb(struct macb *bp, unsigned int index)
++{
++ return &bp->tx_skb[macb_tx_ring_wrap(index)];
++}
++
++static dma_addr_t macb_tx_dma(struct macb *bp, unsigned int index)
++{
++ dma_addr_t offset;
++
++ offset = macb_tx_ring_wrap(index) * sizeof(struct macb_dma_desc);
++
++ return bp->tx_ring_dma + offset;
++}
++
++static unsigned int macb_rx_ring_wrap(unsigned int index)
++{
++ return index & (RX_RING_SIZE - 1);
++}
++
++static struct macb_dma_desc *macb_rx_desc(struct macb *bp, unsigned int index)
++{
++ return &bp->rx_ring[macb_rx_ring_wrap(index)];
++}
++
++static void *macb_rx_buffer(struct macb *bp, unsigned int index)
++{
++ return bp->rx_buffers + RX_BUFFER_SIZE * macb_rx_ring_wrap(index);
++}
++
+ static void __macb_set_hwaddr(struct macb *bp)
+ {
+ u32 bottom;
+@@ -335,17 +369,18 @@ static void macb_tx(struct macb *bp)
+ bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP);
+
+ /* free transmit buffer in upper layer*/
+- for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) {
+- struct ring_info *rp = &bp->tx_skb[tail];
+- struct sk_buff *skb = rp->skb;
+-
+- BUG_ON(skb == NULL);
++ for (tail = bp->tx_tail; tail != head; tail++) {
++ struct macb_tx_skb *tx_skb;
++ struct sk_buff *skb;
+
+ rmb();
+
+- dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len,
+- DMA_TO_DEVICE);
+- rp->skb = NULL;
++ tx_skb = macb_tx_skb(bp, tail);
++ skb = tx_skb->skb;
++
++ dma_unmap_single(&bp->pdev->dev, tx_skb->mapping,
++ skb->len, DMA_TO_DEVICE);
++ tx_skb->skb = NULL;
+ dev_kfree_skb_irq(skb);
+ }
+
+@@ -365,34 +400,38 @@ static void macb_tx(struct macb *bp)
+ return;
+
+ head = bp->tx_head;
+- for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) {
+- struct ring_info *rp = &bp->tx_skb[tail];
+- struct sk_buff *skb = rp->skb;
+- u32 bufstat;
++ for (tail = bp->tx_tail; tail != head; tail++) {
++ struct macb_tx_skb *tx_skb;
++ struct sk_buff *skb;
++ struct macb_dma_desc *desc;
++ u32 ctrl;
+
+- BUG_ON(skb == NULL);
++ desc = macb_tx_desc(bp, tail);
+
+ /* Make hw descriptor updates visible to CPU */
+ rmb();
+
+- bufstat = bp->tx_ring[tail].ctrl;
++ ctrl = desc->ctrl;
+
+- if (!(bufstat & MACB_BIT(TX_USED)))
++ if (!(ctrl & MACB_BIT(TX_USED)))
+ break;
+
++ tx_skb = macb_tx_skb(bp, tail);
++ skb = tx_skb->skb;
++
+ netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n",
+- tail, skb->data);
+- dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len,
++ macb_tx_ring_wrap(tail), skb->data);
++ dma_unmap_single(&bp->pdev->dev, tx_skb->mapping, skb->len,
+ DMA_TO_DEVICE);
+ bp->stats.tx_packets++;
+ bp->stats.tx_bytes += skb->len;
+- rp->skb = NULL;
++ tx_skb->skb = NULL;
+ dev_kfree_skb_irq(skb);
+ }
+
+ bp->tx_tail = tail;
+- if (netif_queue_stopped(bp->dev) &&
+- TX_BUFFS_AVAIL(bp) > MACB_TX_WAKEUP_THRESH)
++ if (netif_queue_stopped(bp->dev)
++ && macb_tx_ring_avail(bp) > MACB_TX_WAKEUP_THRESH)
+ netif_wake_queue(bp->dev);
+ }
+
+@@ -403,17 +442,21 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ unsigned int frag;
+ unsigned int offset = 0;
+ struct sk_buff *skb;
++ struct macb_dma_desc *desc;
+
+- len = MACB_BFEXT(RX_FRMLEN, bp->rx_ring[last_frag].ctrl);
++ desc = macb_rx_desc(bp, last_frag);
++ len = MACB_BFEXT(RX_FRMLEN, desc->ctrl);
+
+ netdev_vdbg(bp->dev, "macb_rx_frame frags %u - %u (len %u)\n",
+- first_frag, last_frag, len);
++ macb_rx_ring_wrap(first_frag),
++ macb_rx_ring_wrap(last_frag), len);
+
+ skb = netdev_alloc_skb(bp->dev, len + RX_OFFSET);
+ if (!skb) {
+ bp->stats.rx_dropped++;
+- for (frag = first_frag; ; frag = NEXT_RX(frag)) {
+- bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED);
++ for (frag = first_frag; ; frag++) {
++ desc = macb_rx_desc(bp, frag);
++ desc->addr &= ~MACB_BIT(RX_USED);
+ if (frag == last_frag)
+ break;
+ }
+@@ -428,7 +471,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ skb_checksum_none_assert(skb);
+ skb_put(skb, len);
+
+- for (frag = first_frag; ; frag = NEXT_RX(frag)) {
++ for (frag = first_frag; ; frag++) {
+ unsigned int frag_len = RX_BUFFER_SIZE;
+
+ if (offset + frag_len > len) {
+@@ -436,11 +479,10 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ frag_len = len - offset;
+ }
+ skb_copy_to_linear_data_offset(skb, offset,
+- (bp->rx_buffers +
+- (RX_BUFFER_SIZE * frag)),
+- frag_len);
++ macb_rx_buffer(bp, frag), frag_len);
+ offset += RX_BUFFER_SIZE;
+- bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED);
++ desc = macb_rx_desc(bp, frag);
++ desc->addr &= ~MACB_BIT(RX_USED);
+
+ if (frag == last_frag)
+ break;
+@@ -466,8 +508,10 @@ static void discard_partial_frame(struct macb *bp, unsigned int begin,
+ {
+ unsigned int frag;
+
+- for (frag = begin; frag != end; frag = NEXT_RX(frag))
+- bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED);
++ for (frag = begin; frag != end; frag++) {
++ struct macb_dma_desc *desc = macb_rx_desc(bp, frag);
++ desc->addr &= ~MACB_BIT(RX_USED);
++ }
+
+ /* Make descriptor updates visible to hardware */
+ wmb();
+@@ -482,17 +526,18 @@ static void discard_partial_frame(struct macb *bp, unsigned int begin,
+ static int macb_rx(struct macb *bp, int budget)
+ {
+ int received = 0;
+- unsigned int tail = bp->rx_tail;
++ unsigned int tail;
+ int first_frag = -1;
+
+- for (; budget > 0; tail = NEXT_RX(tail)) {
++ for (tail = bp->rx_tail; budget > 0; tail++) {
++ struct macb_dma_desc *desc = macb_rx_desc(bp, tail);
+ u32 addr, ctrl;
+
+ /* Make hw descriptor updates visible to CPU */
+ rmb();
+
+- addr = bp->rx_ring[tail].addr;
+- ctrl = bp->rx_ring[tail].ctrl;
++ addr = desc->addr;
++ ctrl = desc->ctrl;
+
+ if (!(addr & MACB_BIT(RX_USED)))
+ break;
+@@ -646,6 +691,8 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ struct macb *bp = netdev_priv(dev);
+ dma_addr_t mapping;
+ unsigned int len, entry;
++ struct macb_dma_desc *desc;
++ struct macb_tx_skb *tx_skb;
+ u32 ctrl;
+ unsigned long flags;
+
+@@ -662,7 +709,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ spin_lock_irqsave(&bp->lock, flags);
+
+ /* This is a hard error, log it. */
+- if (TX_BUFFS_AVAIL(bp) < 1) {
++ if (macb_tx_ring_avail(bp) < 1) {
+ netif_stop_queue(dev);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ netdev_err(bp->dev, "BUG! Tx Ring full when queue awake!\n");
+@@ -671,12 +718,15 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ return NETDEV_TX_BUSY;
+ }
+
+- entry = bp->tx_head;
++ entry = macb_tx_ring_wrap(bp->tx_head);
++ bp->tx_head++;
+ netdev_vdbg(bp->dev, "Allocated ring entry %u\n", entry);
+ mapping = dma_map_single(&bp->pdev->dev, skb->data,
+ len, DMA_TO_DEVICE);
+- bp->tx_skb[entry].skb = skb;
+- bp->tx_skb[entry].mapping = mapping;
++
++ tx_skb = &bp->tx_skb[entry];
++ tx_skb->skb = skb;
++ tx_skb->mapping = mapping;
+ netdev_vdbg(bp->dev, "Mapped skb data %p to DMA addr %08lx\n",
+ skb->data, (unsigned long)mapping);
+
+@@ -685,20 +735,18 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ if (entry == (TX_RING_SIZE - 1))
+ ctrl |= MACB_BIT(TX_WRAP);
+
+- bp->tx_ring[entry].addr = mapping;
+- bp->tx_ring[entry].ctrl = ctrl;
++ desc = &bp->tx_ring[entry];
++ desc->addr = mapping;
++ desc->ctrl = ctrl;
+
+ /* Make newly initialized descriptor visible to hardware */
+ wmb();
+
+- entry = NEXT_TX(entry);
+- bp->tx_head = entry;
+-
+ skb_tx_timestamp(skb);
+
+ macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
+
+- if (TX_BUFFS_AVAIL(bp) < 1)
++ if (macb_tx_ring_avail(bp) < 1)
+ netif_stop_queue(dev);
+
+ spin_unlock_irqrestore(&bp->lock, flags);
+@@ -734,7 +782,7 @@ static int macb_alloc_consistent(struct macb *bp)
+ {
+ int size;
+
+- size = TX_RING_SIZE * sizeof(struct ring_info);
++ size = TX_RING_SIZE * sizeof(struct macb_tx_skb);
+ bp->tx_skb = kmalloc(size, GFP_KERNEL);
+ if (!bp->tx_skb)
+ goto out_err;
+@@ -1407,8 +1455,6 @@ static int __init macb_probe(struct platform_device *pdev)
+ macb_or_gem_writel(bp, USRIO, MACB_BIT(MII));
+ #endif
+
+- bp->tx_pending = DEF_TX_RING_PENDING;
+-
+ err = register_netdev(dev);
+ if (err) {
+ dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
+diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
+index f69ceef..8a4ee2f 100644
+--- a/drivers/net/ethernet/cadence/macb.h
++++ b/drivers/net/ethernet/cadence/macb.h
+@@ -356,7 +356,12 @@
+ __v; \
+ })
+
+-struct dma_desc {
++/**
++ * struct macb_dma_desc - Hardware DMA descriptor
++ * @addr: DMA address of data buffer
++ * @ctrl: Control and status bits
++ */
++struct macb_dma_desc {
+ u32 addr;
+ u32 ctrl;
+ };
+@@ -421,7 +426,12 @@ struct dma_desc {
+ #define MACB_TX_USED_OFFSET 31
+ #define MACB_TX_USED_SIZE 1
+
+-struct ring_info {
++/**
++ * struct macb_tx_skb - data about an skb which is being transmitted
++ * @skb: skb currently being transmitted
++ * @mapping: DMA address of the skb's data buffer
++ */
++struct macb_tx_skb {
+ struct sk_buff *skb;
+ dma_addr_t mapping;
+ };
+@@ -506,12 +516,12 @@ struct macb {
+ void __iomem *regs;
+
+ unsigned int rx_tail;
+- struct dma_desc *rx_ring;
++ struct macb_dma_desc *rx_ring;
+ void *rx_buffers;
+
+ unsigned int tx_head, tx_tail;
+- struct dma_desc *tx_ring;
+- struct ring_info *tx_skb;
++ struct macb_dma_desc *tx_ring;
++ struct macb_tx_skb *tx_skb;
+
+ spinlock_t lock;
+ struct platform_device *pdev;
+@@ -529,8 +539,6 @@ struct macb {
+ dma_addr_t tx_ring_dma;
+ dma_addr_t rx_buffers_dma;
+
+- unsigned int rx_pending, tx_pending;
+-
+ struct mii_bus *mii_bus;
+ struct phy_device *phy_dev;
+ unsigned int link;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0094-net-macb-ethtool-interface-add-register-dump-feature.patch b/patches.at91/0094-net-macb-ethtool-interface-add-register-dump-feature.patch
new file mode 100644
index 00000000000000..0b4bc9cbb76af4
--- /dev/null
+++ b/patches.at91/0094-net-macb-ethtool-interface-add-register-dump-feature.patch
@@ -0,0 +1,88 @@
+From 07007d3c709662f4cc5e186cb8dd0596e8b0d769 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 3 Sep 2012 17:56:18 +0200
+Subject: net/macb: ethtool interface: add register dump feature
+
+Add macb_get_regs() ethtool function and its helper function:
+macb_get_regs_len().
+The version field is deduced from the IP revision which gives the
+"MACB or GEM" information. An additional version field is reserved.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Reviewed-by: Ben Hutchings <bhutchings@solarflare.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 40 +++++++++++++++++++++++++++++++++++++
+ drivers/net/ethernet/cadence/macb.h | 3 +++
+ 2 files changed, 43 insertions(+)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index 2554354..6486a56 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -1271,9 +1271,49 @@ static int macb_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+ return phy_ethtool_sset(phydev, cmd);
+ }
+
++static int macb_get_regs_len(struct net_device *netdev)
++{
++ return MACB_GREGS_NBR * sizeof(u32);
++}
++
++static void macb_get_regs(struct net_device *dev, struct ethtool_regs *regs,
++ void *p)
++{
++ struct macb *bp = netdev_priv(dev);
++ unsigned int tail, head;
++ u32 *regs_buff = p;
++
++ regs->version = (macb_readl(bp, MID) & ((1 << MACB_REV_SIZE) - 1))
++ | MACB_GREGS_VERSION;
++
++ tail = macb_tx_ring_wrap(bp->tx_tail);
++ head = macb_tx_ring_wrap(bp->tx_head);
++
++ regs_buff[0] = macb_readl(bp, NCR);
++ regs_buff[1] = macb_or_gem_readl(bp, NCFGR);
++ regs_buff[2] = macb_readl(bp, NSR);
++ regs_buff[3] = macb_readl(bp, TSR);
++ regs_buff[4] = macb_readl(bp, RBQP);
++ regs_buff[5] = macb_readl(bp, TBQP);
++ regs_buff[6] = macb_readl(bp, RSR);
++ regs_buff[7] = macb_readl(bp, IMR);
++
++ regs_buff[8] = tail;
++ regs_buff[9] = head;
++ regs_buff[10] = macb_tx_dma(bp, tail);
++ regs_buff[11] = macb_tx_dma(bp, head);
++
++ if (macb_is_gem(bp)) {
++ regs_buff[12] = gem_readl(bp, USRIO);
++ regs_buff[13] = gem_readl(bp, DMACFG);
++ }
++}
++
+ static const struct ethtool_ops macb_ethtool_ops = {
+ .get_settings = macb_get_settings,
+ .set_settings = macb_set_settings,
++ .get_regs_len = macb_get_regs_len,
++ .get_regs = macb_get_regs,
+ .get_link = ethtool_op_get_link,
+ };
+
+diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
+index 8a4ee2f..5be5900 100644
+--- a/drivers/net/ethernet/cadence/macb.h
++++ b/drivers/net/ethernet/cadence/macb.h
+@@ -10,6 +10,9 @@
+ #ifndef _MACB_H
+ #define _MACB_H
+
++#define MACB_GREGS_NBR 16
++#define MACB_GREGS_VERSION 1
++
+ /* MACB register offsets */
+ #define MACB_NCR 0x0000
+ #define MACB_NCFGR 0x0004
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0095-net-macb-better-manage-tx-errors.patch b/patches.at91/0095-net-macb-better-manage-tx-errors.patch
new file mode 100644
index 00000000000000..1be968b607b33c
--- /dev/null
+++ b/patches.at91/0095-net-macb-better-manage-tx-errors.patch
@@ -0,0 +1,257 @@
+From 950c22b78992b706fd8f446efbabb695e2fa2ac1 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 22 Jun 2010 18:38:26 +0200
+Subject: net/macb: better manage tx errors
+
+Handle all TX errors, not only underruns. TX error management is
+deferred to a dedicated workqueue.
+Reinitialize the TX ring after treating all remaining frames, and
+restart the controller when everything has been cleaned up properly.
+Napi is not stopped during this task as the driver only handles
+napi for RX for now.
+With this sequence, we do not need a special check during the xmit
+method as the packets will be caught by TX disable during workqueue
+execution.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 166 ++++++++++++++++++++++++------------
+ drivers/net/ethernet/cadence/macb.h | 1 +
+ 2 files changed, 113 insertions(+), 54 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index 6486a56..cd24ce6 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -44,6 +44,16 @@
+
+ #define MACB_RX_INT_FLAGS (MACB_BIT(RCOMP) | MACB_BIT(RXUBR) \
+ | MACB_BIT(ISR_ROVR))
++#define MACB_TX_ERR_FLAGS (MACB_BIT(ISR_TUND) \
++ | MACB_BIT(ISR_RLE) \
++ | MACB_BIT(TXERR))
++#define MACB_TX_INT_FLAGS (MACB_TX_ERR_FLAGS | MACB_BIT(TCOMP))
++
++/*
++ * Graceful stop timeouts in us. We should allow up to
++ * 1 frame time (10 Mbits/s, full-duplex, ignoring collisions)
++ */
++#define MACB_HALT_TIMEOUT 1230
+
+ /* Ring buffer accessors */
+ static unsigned int macb_tx_ring_wrap(unsigned int index)
+@@ -338,66 +348,113 @@ static void macb_update_stats(struct macb *bp)
+ *p += __raw_readl(reg);
+ }
+
+-static void macb_tx(struct macb *bp)
++static int macb_halt_tx(struct macb *bp)
+ {
+- unsigned int tail;
+- unsigned int head;
+- u32 status;
++ unsigned long halt_time, timeout;
++ u32 status;
+
+- status = macb_readl(bp, TSR);
+- macb_writel(bp, TSR, status);
++ macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(THALT));
+
+- netdev_vdbg(bp->dev, "macb_tx status = 0x%03lx\n", (unsigned long)status);
++ timeout = jiffies + usecs_to_jiffies(MACB_HALT_TIMEOUT);
++ do {
++ halt_time = jiffies;
++ status = macb_readl(bp, TSR);
++ if (!(status & MACB_BIT(TGO)))
++ return 0;
+
+- if (status & (MACB_BIT(UND) | MACB_BIT(TSR_RLE))) {
+- int i;
+- netdev_err(bp->dev, "TX %s, resetting buffers\n",
+- status & MACB_BIT(UND) ?
+- "underrun" : "retry limit exceeded");
++ usleep_range(10, 250);
++ } while (time_before(halt_time, timeout));
+
+- /* Transfer ongoing, disable transmitter, to avoid confusion */
+- if (status & MACB_BIT(TGO))
+- macb_writel(bp, NCR, macb_readl(bp, NCR) & ~MACB_BIT(TE));
++ return -ETIMEDOUT;
++}
+
+- head = bp->tx_head;
++static void macb_tx_error_task(struct work_struct *work)
++{
++ struct macb *bp = container_of(work, struct macb, tx_error_task);
++ struct macb_tx_skb *tx_skb;
++ struct sk_buff *skb;
++ unsigned int tail;
+
+- /*Mark all the buffer as used to avoid sending a lost buffer*/
+- for (i = 0; i < TX_RING_SIZE; i++)
+- bp->tx_ring[i].ctrl = MACB_BIT(TX_USED);
++ netdev_vdbg(bp->dev, "macb_tx_error_task: t = %u, h = %u\n",
++ bp->tx_tail, bp->tx_head);
+
+- /* Add wrap bit */
+- bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP);
++ /* Make sure nobody is trying to queue up new packets */
++ netif_stop_queue(bp->dev);
+
+- /* free transmit buffer in upper layer*/
+- for (tail = bp->tx_tail; tail != head; tail++) {
+- struct macb_tx_skb *tx_skb;
+- struct sk_buff *skb;
++ /*
++ * Stop transmission now
++ * (in case we have just queued new packets)
++ */
++ if (macb_halt_tx(bp))
++ /* Just complain for now, reinitializing TX path can be good */
++ netdev_err(bp->dev, "BUG: halt tx timed out\n");
+
+- rmb();
++ /* No need for the lock here as nobody will interrupt us anymore */
+
+- tx_skb = macb_tx_skb(bp, tail);
+- skb = tx_skb->skb;
++ /*
++ * Treat frames in TX queue including the ones that caused the error.
++ * Free transmit buffers in upper layer.
++ */
++ for (tail = bp->tx_tail; tail != bp->tx_head; tail++) {
++ struct macb_dma_desc *desc;
++ u32 ctrl;
+
+- dma_unmap_single(&bp->pdev->dev, tx_skb->mapping,
+- skb->len, DMA_TO_DEVICE);
+- tx_skb->skb = NULL;
+- dev_kfree_skb_irq(skb);
+- }
++ desc = macb_tx_desc(bp, tail);
++ ctrl = desc->ctrl;
++ tx_skb = macb_tx_skb(bp, tail);
++ skb = tx_skb->skb;
+
+- bp->tx_head = bp->tx_tail = 0;
++ if (ctrl & MACB_BIT(TX_USED)) {
++ netdev_vdbg(bp->dev, "txerr skb %u (data %p) TX complete\n",
++ macb_tx_ring_wrap(tail), skb->data);
++ bp->stats.tx_packets++;
++ bp->stats.tx_bytes += skb->len;
++ } else {
++ /*
++ * "Buffers exhausted mid-frame" errors may only happen
++ * if the driver is buggy, so complain loudly about those.
++ * Statistics are updated by hardware.
++ */
++ if (ctrl & MACB_BIT(TX_BUF_EXHAUSTED))
++ netdev_err(bp->dev,
++ "BUG: TX buffers exhausted mid-frame\n");
+
+- /* Enable the transmitter again */
+- if (status & MACB_BIT(TGO))
+- macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TE));
++ desc->ctrl = ctrl | MACB_BIT(TX_USED);
++ }
++
++ dma_unmap_single(&bp->pdev->dev, tx_skb->mapping, skb->len,
++ DMA_TO_DEVICE);
++ tx_skb->skb = NULL;
++ dev_kfree_skb(skb);
+ }
+
+- if (!(status & MACB_BIT(COMP)))
+- /*
+- * This may happen when a buffer becomes complete
+- * between reading the ISR and scanning the
+- * descriptors. Nothing to worry about.
+- */
+- return;
++ /* Make descriptor updates visible to hardware */
++ wmb();
++
++ /* Reinitialize the TX desc queue */
++ macb_writel(bp, TBQP, bp->tx_ring_dma);
++ /* Make TX ring reflect state of hardware */
++ bp->tx_head = bp->tx_tail = 0;
++
++ /* Now we are ready to start transmission again */
++ netif_wake_queue(bp->dev);
++
++ /* Housework before enabling TX IRQ */
++ macb_writel(bp, TSR, macb_readl(bp, TSR));
++ macb_writel(bp, IER, MACB_TX_INT_FLAGS);
++}
++
++static void macb_tx_interrupt(struct macb *bp)
++{
++ unsigned int tail;
++ unsigned int head;
++ u32 status;
++
++ status = macb_readl(bp, TSR);
++ macb_writel(bp, TSR, status);
++
++ netdev_vdbg(bp->dev, "macb_tx_interrupt status = 0x%03lx\n",
++ (unsigned long)status);
+
+ head = bp->tx_head;
+ for (tail = bp->tx_tail; tail != head; tail++) {
+@@ -637,9 +694,14 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
+ }
+ }
+
+- if (status & (MACB_BIT(TCOMP) | MACB_BIT(ISR_TUND) |
+- MACB_BIT(ISR_RLE)))
+- macb_tx(bp);
++ if (unlikely(status & (MACB_TX_ERR_FLAGS))) {
++ macb_writel(bp, IDR, MACB_TX_INT_FLAGS);
++ schedule_work(&bp->tx_error_task);
++ break;
++ }
++
++ if (status & MACB_BIT(TCOMP))
++ macb_tx_interrupt(bp);
+
+ /*
+ * Link change detection isn't possible with RMII, so we'll
+@@ -969,13 +1031,8 @@ static void macb_init_hw(struct macb *bp)
+ macb_writel(bp, NCR, MACB_BIT(RE) | MACB_BIT(TE) | MACB_BIT(MPE));
+
+ /* Enable interrupts */
+- macb_writel(bp, IER, (MACB_BIT(RCOMP)
+- | MACB_BIT(RXUBR)
+- | MACB_BIT(ISR_TUND)
+- | MACB_BIT(ISR_RLE)
+- | MACB_BIT(TXERR)
+- | MACB_BIT(TCOMP)
+- | MACB_BIT(ISR_ROVR)
++ macb_writel(bp, IER, (MACB_RX_INT_FLAGS
++ | MACB_TX_INT_FLAGS
+ | MACB_BIT(HRESP)));
+
+ }
+@@ -1423,6 +1480,7 @@ static int __init macb_probe(struct platform_device *pdev)
+ bp->dev = dev;
+
+ spin_lock_init(&bp->lock);
++ INIT_WORK(&bp->tx_error_task, macb_tx_error_task);
+
+ bp->pclk = clk_get(&pdev->dev, "pclk");
+ if (IS_ERR(bp->pclk)) {
+diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
+index 5be5900..bfab8ef 100644
+--- a/drivers/net/ethernet/cadence/macb.h
++++ b/drivers/net/ethernet/cadence/macb.h
+@@ -532,6 +532,7 @@ struct macb {
+ struct clk *hclk;
+ struct net_device *dev;
+ struct napi_struct napi;
++ struct work_struct tx_error_task;
+ struct net_device_stats stats;
+ union {
+ struct macb_stats macb;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0096-net-macb-Offset-first-RX-buffer-by-two-bytes.patch b/patches.at91/0096-net-macb-Offset-first-RX-buffer-by-two-bytes.patch
new file mode 100644
index 00000000000000..8037759a4005e6
--- /dev/null
+++ b/patches.at91/0096-net-macb-Offset-first-RX-buffer-by-two-bytes.patch
@@ -0,0 +1,94 @@
+From ebff9d35a64e87d3a6c6d05421b7be4ceedbb589 Mon Sep 17 00:00:00 2001
+From: Havard Skinnemoen <havard@skinnemoen.net>
+Date: Tue, 24 Mar 2009 10:45:18 +0100
+Subject: net/macb: Offset first RX buffer by two bytes
+
+Make the ethernet frame payload word-aligned, possibly making the
+memcpy into the skb a bit faster. This will be even more important
+after we eliminate the copy altogether.
+
+Also eliminate the redundant RX_OFFSET constant -- it has the same
+definition and purpose as NET_IP_ALIGN.
+
+Signed-off-by: Havard Skinnemoen <havard@skinnemoen.net>
+[nicolas.ferre@atmel.com: adapt to newer kernel]
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 23 ++++++++++++++++-------
+ 1 file changed, 16 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index cd24ce6..88a1d20 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -33,9 +33,6 @@
+ #define RX_RING_SIZE 512
+ #define RX_RING_BYTES (sizeof(struct macb_dma_desc) * RX_RING_SIZE)
+
+-/* Make the IP header word-aligned (the ethernet header is 14 bytes) */
+-#define RX_OFFSET 2
+-
+ #define TX_RING_SIZE 128
+ #define TX_RING_BYTES (sizeof(struct macb_dma_desc) * TX_RING_SIZE)
+
+@@ -497,7 +494,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ {
+ unsigned int len;
+ unsigned int frag;
+- unsigned int offset = 0;
++ unsigned int offset;
+ struct sk_buff *skb;
+ struct macb_dma_desc *desc;
+
+@@ -508,7 +505,16 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ macb_rx_ring_wrap(first_frag),
+ macb_rx_ring_wrap(last_frag), len);
+
+- skb = netdev_alloc_skb(bp->dev, len + RX_OFFSET);
++ /*
++ * The ethernet header starts NET_IP_ALIGN bytes into the
++ * first buffer. Since the header is 14 bytes, this makes the
++ * payload word-aligned.
++ *
++ * Instead of calling skb_reserve(NET_IP_ALIGN), we just copy
++ * the two padding bytes into the skb so that we avoid hitting
++ * the slowpath in memcpy(), and pull them off afterwards.
++ */
++ skb = netdev_alloc_skb(bp->dev, len + NET_IP_ALIGN);
+ if (!skb) {
+ bp->stats.rx_dropped++;
+ for (frag = first_frag; ; frag++) {
+@@ -524,7 +530,8 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ return 1;
+ }
+
+- skb_reserve(skb, RX_OFFSET);
++ offset = 0;
++ len += NET_IP_ALIGN;
+ skb_checksum_none_assert(skb);
+ skb_put(skb, len);
+
+@@ -548,10 +555,11 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ /* Make descriptor updates visible to hardware */
+ wmb();
+
++ __skb_pull(skb, NET_IP_ALIGN);
+ skb->protocol = eth_type_trans(skb, bp->dev);
+
+ bp->stats.rx_packets++;
+- bp->stats.rx_bytes += len;
++ bp->stats.rx_bytes += skb->len;
+ netdev_vdbg(bp->dev, "received skb of length %u, csum: %08x\n",
+ skb->len, skb->csum);
+ netif_receive_skb(skb);
+@@ -1011,6 +1019,7 @@ static void macb_init_hw(struct macb *bp)
+ __macb_set_hwaddr(bp);
+
+ config = macb_mdc_clk_div(bp);
++ config |= MACB_BF(RBOF, NET_IP_ALIGN); /* Make eth data aligned */
+ config |= MACB_BIT(PAE); /* PAuse Enable */
+ config |= MACB_BIT(DRFCS); /* Discard Rx FCS */
+ config |= MACB_BIT(BIG); /* Receive oversized frames */
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0097-net-macb-GEM-DMA-configuration-register-update.patch b/patches.at91/0097-net-macb-GEM-DMA-configuration-register-update.patch
new file mode 100644
index 00000000000000..2cfd5c29859c8d
--- /dev/null
+++ b/patches.at91/0097-net-macb-GEM-DMA-configuration-register-update.patch
@@ -0,0 +1,71 @@
+From 5d30336b8a420e0a8b24572d3fbc7458477e2a2e Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 19 Sep 2012 15:14:34 +0200
+Subject: net/macb: GEM DMA configuration register update
+
+Add information to the DMA Configuration Register to
+maximize system performance:
+- rx/tx packet buffer full memory size
+- allow possibility to use INCR16 if supported
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 10 ++++++++--
+ drivers/net/ethernet/cadence/macb.h | 11 +++++++++++
+ 2 files changed, 19 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index 88a1d20..56bab3c 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -997,8 +997,12 @@ static u32 macb_dbw(struct macb *bp)
+ }
+
+ /*
+- * Configure the receive DMA engine to use the correct receive buffer size.
+- * This is a configurable parameter for GEM.
++ * Configure the receive DMA engine
++ * - use the correct receive buffer size
++ * - set the possibility to use INCR16 bursts
++ * (if not supported by FIFO, it will fallback to default)
++ * - set both rx/tx packet buffers to full memory size
++ * These are configurable parameters for GEM.
+ */
+ static void macb_configure_dma(struct macb *bp)
+ {
+@@ -1007,6 +1011,8 @@ static void macb_configure_dma(struct macb *bp)
+ if (macb_is_gem(bp)) {
+ dmacfg = gem_readl(bp, DMACFG) & ~GEM_BF(RXBS, -1L);
+ dmacfg |= GEM_BF(RXBS, RX_BUFFER_SIZE / 64);
++ dmacfg |= GEM_BF(FBLDO, 16);
++ dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L);
+ gem_writel(bp, DMACFG, dmacfg);
+ }
+ }
+diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
+index bfab8ef..256559d 100644
+--- a/drivers/net/ethernet/cadence/macb.h
++++ b/drivers/net/ethernet/cadence/macb.h
+@@ -161,8 +161,19 @@
+ #define GEM_DBW128 2
+
+ /* Bitfields in DMACFG. */
++#define GEM_FBLDO_OFFSET 0
++#define GEM_FBLDO_SIZE 5
++#define GEM_RXBMS_OFFSET 8
++#define GEM_RXBMS_SIZE 2
++#define GEM_TXPBMS_OFFSET 10
++#define GEM_TXPBMS_SIZE 1
++#define GEM_TXCOEN_OFFSET 11
++#define GEM_TXCOEN_SIZE 1
+ #define GEM_RXBS_OFFSET 16
+ #define GEM_RXBS_SIZE 8
++#define GEM_DDRP_OFFSET 24
++#define GEM_DDRP_SIZE 1
++
+
+ /* Bitfields in NSR */
+ #define MACB_NSR_LINK_OFFSET 0
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0098-net-macb-Use-non-coherent-memory-for-rx-buffers.patch b/patches.at91/0098-net-macb-Use-non-coherent-memory-for-rx-buffers.patch
new file mode 100644
index 00000000000000..19fb2b0a74abfa
--- /dev/null
+++ b/patches.at91/0098-net-macb-Use-non-coherent-memory-for-rx-buffers.patch
@@ -0,0 +1,378 @@
+From d753b91290e2caf097dcb0d216710fcce4208327 Mon Sep 17 00:00:00 2001
+From: Havard Skinnemoen <havard@skinnemoen.net>
+Date: Tue, 24 Mar 2009 10:45:19 +0100
+Subject: net/macb: Use non-coherent memory for rx buffers
+
+Allocate regular pages to use as backing for the RX ring and use the
+DMA API to sync the caches. This should give a bit better performance
+since it allows the CPU to do burst transfers from memory. It is also
+a necessary step on the way to reduce the amount of copying done by
+the driver.
+
+Signed-off-by: Havard Skinnemoen <havard@skinnemoen.net>
+[nicolas.ferre@atmel.com: adapt to newer kernel]
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 206 +++++++++++++++++++++++-------------
+ drivers/net/ethernet/cadence/macb.h | 20 +++-
+ 2 files changed, 148 insertions(+), 78 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index 56bab3c..e3168bf 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -10,6 +10,7 @@
+
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+ #include <linux/clk.h>
++#include <linux/highmem.h>
+ #include <linux/module.h>
+ #include <linux/moduleparam.h>
+ #include <linux/kernel.h>
+@@ -32,6 +33,8 @@
+ #define RX_BUFFER_SIZE 128
+ #define RX_RING_SIZE 512
+ #define RX_RING_BYTES (sizeof(struct macb_dma_desc) * RX_RING_SIZE)
++#define RX_BUFFERS_PER_PAGE (PAGE_SIZE / RX_BUFFER_SIZE)
++#define RX_RING_PAGES (RX_RING_SIZE / RX_BUFFERS_PER_PAGE)
+
+ #define TX_RING_SIZE 128
+ #define TX_RING_BYTES (sizeof(struct macb_dma_desc) * TX_RING_SIZE)
+@@ -92,9 +95,16 @@ static struct macb_dma_desc *macb_rx_desc(struct macb *bp, unsigned int index)
+ return &bp->rx_ring[macb_rx_ring_wrap(index)];
+ }
+
+-static void *macb_rx_buffer(struct macb *bp, unsigned int index)
++static struct macb_rx_page *macb_rx_page(struct macb *bp, unsigned int index)
+ {
+- return bp->rx_buffers + RX_BUFFER_SIZE * macb_rx_ring_wrap(index);
++ unsigned int entry = macb_rx_ring_wrap(index);
++
++ return &bp->rx_page[entry / RX_BUFFERS_PER_PAGE];
++}
++
++static unsigned int macb_rx_page_offset(struct macb *bp, unsigned int index)
++{
++ return (index % RX_BUFFERS_PER_PAGE) * RX_BUFFER_SIZE;
+ }
+
+ static void __macb_set_hwaddr(struct macb *bp)
+@@ -492,11 +502,15 @@ static void macb_tx_interrupt(struct macb *bp)
+ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ unsigned int last_frag)
+ {
+- unsigned int len;
+- unsigned int frag;
+- unsigned int offset;
+- struct sk_buff *skb;
+- struct macb_dma_desc *desc;
++ unsigned int len;
++ unsigned int frag;
++ unsigned int skb_offset;
++ unsigned int pg_offset;
++ struct macb_rx_page *rx_page;
++ dma_addr_t phys;
++ void *buf;
++ struct sk_buff *skb;
++ struct macb_dma_desc *desc;
+
+ desc = macb_rx_desc(bp, last_frag);
+ len = MACB_BFEXT(RX_FRMLEN, desc->ctrl);
+@@ -530,7 +544,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ return 1;
+ }
+
+- offset = 0;
++ skb_offset = 0;
+ len += NET_IP_ALIGN;
+ skb_checksum_none_assert(skb);
+ skb_put(skb, len);
+@@ -538,13 +552,28 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ for (frag = first_frag; ; frag++) {
+ unsigned int frag_len = RX_BUFFER_SIZE;
+
+- if (offset + frag_len > len) {
++ if (skb_offset + frag_len > len) {
+ BUG_ON(frag != last_frag);
+- frag_len = len - offset;
++ frag_len = len - skb_offset;
+ }
+- skb_copy_to_linear_data_offset(skb, offset,
+- macb_rx_buffer(bp, frag), frag_len);
+- offset += RX_BUFFER_SIZE;
++
++ rx_page = macb_rx_page(bp, frag);
++ pg_offset = macb_rx_page_offset(bp, frag);
++ phys = rx_page->phys;
++
++ dma_sync_single_range_for_cpu(&bp->pdev->dev, phys,
++ pg_offset, frag_len, DMA_FROM_DEVICE);
++
++ buf = kmap_atomic(rx_page->page);
++ skb_copy_to_linear_data_offset(skb, skb_offset,
++ buf + pg_offset, frag_len);
++ kunmap_atomic(buf);
++
++ skb_offset += frag_len;
++
++ dma_sync_single_range_for_device(&bp->pdev->dev, phys,
++ pg_offset, frag_len, DMA_FROM_DEVICE);
++
+ desc = macb_rx_desc(bp, frag);
+ desc->addr &= ~MACB_BIT(RX_USED);
+
+@@ -824,86 +853,90 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ return NETDEV_TX_OK;
+ }
+
+-static void macb_free_consistent(struct macb *bp)
++static void macb_free_rings(struct macb *bp)
+ {
+- if (bp->tx_skb) {
+- kfree(bp->tx_skb);
+- bp->tx_skb = NULL;
+- }
+- if (bp->rx_ring) {
+- dma_free_coherent(&bp->pdev->dev, RX_RING_BYTES,
+- bp->rx_ring, bp->rx_ring_dma);
+- bp->rx_ring = NULL;
+- }
+- if (bp->tx_ring) {
+- dma_free_coherent(&bp->pdev->dev, TX_RING_BYTES,
+- bp->tx_ring, bp->tx_ring_dma);
+- bp->tx_ring = NULL;
+- }
+- if (bp->rx_buffers) {
+- dma_free_coherent(&bp->pdev->dev,
+- RX_RING_SIZE * RX_BUFFER_SIZE,
+- bp->rx_buffers, bp->rx_buffers_dma);
+- bp->rx_buffers = NULL;
++ int i;
++
++ for (i = 0; i < RX_RING_PAGES; i++) {
++ struct macb_rx_page *rx_page = &bp->rx_page[i];
++
++ if (!rx_page->page)
++ continue;
++
++ dma_unmap_page(&bp->pdev->dev, rx_page->phys,
++ PAGE_SIZE, DMA_FROM_DEVICE);
++ put_page(rx_page->page);
++ rx_page->page = NULL;
+ }
++
++ kfree(bp->tx_skb);
++ kfree(bp->rx_page);
++ dma_free_coherent(&bp->pdev->dev, TX_RING_BYTES, bp->tx_ring,
++ bp->tx_ring_dma);
++ dma_free_coherent(&bp->pdev->dev, RX_RING_BYTES, bp->rx_ring,
++ bp->rx_ring_dma);
+ }
+
+-static int macb_alloc_consistent(struct macb *bp)
++static int macb_init_rings(struct macb *bp)
+ {
+- int size;
++ struct page *page;
++ dma_addr_t phys;
++ unsigned int page_idx;
++ unsigned int ring_idx;
++ unsigned int i;
+
+- size = TX_RING_SIZE * sizeof(struct macb_tx_skb);
+- bp->tx_skb = kmalloc(size, GFP_KERNEL);
+- if (!bp->tx_skb)
+- goto out_err;
+-
+- size = RX_RING_BYTES;
+- bp->rx_ring = dma_alloc_coherent(&bp->pdev->dev, size,
++ bp->rx_ring = dma_alloc_coherent(&bp->pdev->dev, RX_RING_BYTES,
+ &bp->rx_ring_dma, GFP_KERNEL);
+ if (!bp->rx_ring)
+- goto out_err;
++ goto err_alloc_rx_ring;
++
+ netdev_dbg(bp->dev,
+ "Allocated RX ring of %d bytes at %08lx (mapped %p)\n",
+- size, (unsigned long)bp->rx_ring_dma, bp->rx_ring);
++ RX_RING_BYTES, (unsigned long)bp->rx_ring_dma, bp->rx_ring);
+
+- size = TX_RING_BYTES;
+- bp->tx_ring = dma_alloc_coherent(&bp->pdev->dev, size,
++ bp->tx_ring = dma_alloc_coherent(&bp->pdev->dev, TX_RING_BYTES,
+ &bp->tx_ring_dma, GFP_KERNEL);
+ if (!bp->tx_ring)
+- goto out_err;
+- netdev_dbg(bp->dev,
+- "Allocated TX ring of %d bytes at %08lx (mapped %p)\n",
+- size, (unsigned long)bp->tx_ring_dma, bp->tx_ring);
+-
+- size = RX_RING_SIZE * RX_BUFFER_SIZE;
+- bp->rx_buffers = dma_alloc_coherent(&bp->pdev->dev, size,
+- &bp->rx_buffers_dma, GFP_KERNEL);
+- if (!bp->rx_buffers)
+- goto out_err;
++ goto err_alloc_tx_ring;
++
+ netdev_dbg(bp->dev,
+- "Allocated RX buffers of %d bytes at %08lx (mapped %p)\n",
+- size, (unsigned long)bp->rx_buffers_dma, bp->rx_buffers);
++ "Allocated TX ring of %d bytes at 0x%08lx (mapped %p)\n",
++ TX_RING_BYTES, (unsigned long)bp->tx_ring_dma, bp->tx_ring);
+
+- return 0;
++ bp->rx_page = kcalloc(RX_RING_PAGES, sizeof(struct macb_rx_page),
++ GFP_KERNEL);
++ if (!bp->rx_page)
++ goto err_alloc_rx_page;
+
+-out_err:
+- macb_free_consistent(bp);
+- return -ENOMEM;
+-}
++ bp->tx_skb = kcalloc(TX_RING_SIZE, sizeof(struct macb_tx_skb),
++ GFP_KERNEL);
++ if (!bp->tx_skb)
++ goto err_alloc_tx_skb;
+
+-static void macb_init_rings(struct macb *bp)
+-{
+- int i;
+- dma_addr_t addr;
++ for (page_idx = 0, ring_idx = 0; page_idx < RX_RING_PAGES; page_idx++) {
++ page = alloc_page(GFP_KERNEL);
++ if (!page)
++ goto err_alloc_page;
++
++ phys = dma_map_page(&bp->pdev->dev, page, 0, PAGE_SIZE,
++ DMA_FROM_DEVICE);
++ if (dma_mapping_error(&bp->pdev->dev, phys))
++ goto err_map_page;
++
++ bp->rx_page[page_idx].page = page;
++ bp->rx_page[page_idx].phys = phys;
+
+- addr = bp->rx_buffers_dma;
+- for (i = 0; i < RX_RING_SIZE; i++) {
+- bp->rx_ring[i].addr = addr;
+- bp->rx_ring[i].ctrl = 0;
+- addr += RX_BUFFER_SIZE;
++ for (i = 0; i < RX_BUFFERS_PER_PAGE; i++, ring_idx++) {
++ bp->rx_ring[ring_idx].addr = phys;
++ bp->rx_ring[ring_idx].ctrl = 0;
++ phys += RX_BUFFER_SIZE;
++ }
+ }
+ bp->rx_ring[RX_RING_SIZE - 1].addr |= MACB_BIT(RX_WRAP);
+
++ netdev_dbg(bp->dev, "Allocated %u RX buffers (%lu pages)\n",
++ RX_RING_SIZE, RX_RING_PAGES);
++
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ bp->tx_ring[i].addr = 0;
+ bp->tx_ring[i].ctrl = MACB_BIT(TX_USED);
+@@ -911,6 +944,28 @@ static void macb_init_rings(struct macb *bp)
+ bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP);
+
+ bp->rx_tail = bp->tx_head = bp->tx_tail = 0;
++
++ return 0;
++
++err_map_page:
++ __free_page(page);
++err_alloc_page:
++ while (page_idx--) {
++ dma_unmap_page(&bp->pdev->dev, bp->rx_page[page_idx].phys,
++ PAGE_SIZE, DMA_FROM_DEVICE);
++ __free_page(bp->rx_page[page_idx].page);
++ }
++ kfree(bp->tx_skb);
++err_alloc_tx_skb:
++ kfree(bp->rx_page);
++err_alloc_rx_page:
++ dma_free_coherent(&bp->pdev->dev, TX_RING_BYTES, bp->tx_ring,
++ bp->tx_ring_dma);
++err_alloc_tx_ring:
++ dma_free_coherent(&bp->pdev->dev, RX_RING_BYTES, bp->rx_ring,
++ bp->rx_ring_dma);
++err_alloc_rx_ring:
++ return -ENOMEM;
+ }
+
+ static void macb_reset_hw(struct macb *bp)
+@@ -1185,16 +1240,15 @@ static int macb_open(struct net_device *dev)
+ if (!is_valid_ether_addr(dev->dev_addr))
+ return -EADDRNOTAVAIL;
+
+- err = macb_alloc_consistent(bp);
++ err = macb_init_rings(bp);
+ if (err) {
+- netdev_err(dev, "Unable to allocate DMA memory (error %d)\n",
++ netdev_err(dev, "Unable to allocate DMA rings (error %d)\n",
+ err);
+ return err;
+ }
+
+ napi_enable(&bp->napi);
+
+- macb_init_rings(bp);
+ macb_init_hw(bp);
+
+ /* schedule a link state check */
+@@ -1221,7 +1275,7 @@ static int macb_close(struct net_device *dev)
+ netif_carrier_off(dev);
+ spin_unlock_irqrestore(&bp->lock, flags);
+
+- macb_free_consistent(bp);
++ macb_free_rings(bp);
+
+ return 0;
+ }
+diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
+index 256559d..01aecea 100644
+--- a/drivers/net/ethernet/cadence/macb.h
++++ b/drivers/net/ethernet/cadence/macb.h
+@@ -441,6 +441,23 @@ struct macb_dma_desc {
+ #define MACB_TX_USED_SIZE 1
+
+ /**
++ * struct macb_rx_page - data associated with a page used as RX buffers
++ * @page: Physical page used as storage for the buffers
++ * @phys: DMA address of the page
++ *
++ * Each page is used to provide %MACB_RX_BUFFERS_PER_PAGE RX buffers.
++ * The page gets an initial reference when it is inserted into the
++ * ring, and an additional reference each time it is passed up the
++ * stack as a fragment. When all the buffers have been used, we drop
++ * the initial reference and allocate a new page. Any additional
++ * references are dropped when the higher layers free the skb.
++ */
++struct macb_rx_page {
++ struct page *page;
++ dma_addr_t phys;
++};
++
++/**
+ * struct macb_tx_skb - data about an skb which is being transmitted
+ * @skb: skb currently being transmitted
+ * @mapping: DMA address of the skb's data buffer
+@@ -531,7 +548,7 @@ struct macb {
+
+ unsigned int rx_tail;
+ struct macb_dma_desc *rx_ring;
+- void *rx_buffers;
++ struct macb_rx_page *rx_page;
+
+ unsigned int tx_head, tx_tail;
+ struct macb_dma_desc *tx_ring;
+@@ -552,7 +569,6 @@ struct macb {
+
+ dma_addr_t rx_ring_dma;
+ dma_addr_t tx_ring_dma;
+- dma_addr_t rx_buffers_dma;
+
+ struct mii_bus *mii_bus;
+ struct phy_device *phy_dev;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0099-phy-micrel-Use-proper-phy-in-gmac.patch b/patches.at91/0099-phy-micrel-Use-proper-phy-in-gmac.patch
new file mode 100644
index 00000000000000..2c1d4bb38c472d
--- /dev/null
+++ b/patches.at91/0099-phy-micrel-Use-proper-phy-in-gmac.patch
@@ -0,0 +1,49 @@
+From 0a488fbfdd0525849b8a67cc8158523643aaba7e Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 26 Jun 2012 11:07:32 +0200
+Subject: phy/micrel: Use proper phy in gmac
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/phy/micrel.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
+index 590f902..cc7f75b 100644
+--- a/drivers/net/phy/micrel.c
++++ b/drivers/net/phy/micrel.c
+@@ -191,6 +191,7 @@ static int __init ksphy_init(void)
+ {
+ int ret;
+
++#if 0
+ ret = phy_driver_register(&ks8001_driver);
+ if (ret)
+ goto err1;
+@@ -208,9 +209,15 @@ static int __init ksphy_init(void)
+ ret = phy_driver_register(&ks8051_driver);
+ if (ret)
+ goto err5;
++#endif
++
++ ret = phy_driver_register(&ksz9021_driver);
++ if (ret)
++ goto err1;
+
+ return 0;
+
++#if 0
+ err5:
+ phy_driver_unregister(&ks8041_driver);
+ err4:
+@@ -219,6 +226,7 @@ err3:
+ phy_driver_unregister(&ksz9021_driver);
+ err2:
+ phy_driver_unregister(&ks8001_driver);
++#endif
+ err1:
+ return ret;
+ }
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0100-phy-micrel-we-need-to-register-ks8051-phy-for-emac.patch b/patches.at91/0100-phy-micrel-we-need-to-register-ks8051-phy-for-emac.patch
new file mode 100644
index 00000000000000..32d46d482232f8
--- /dev/null
+++ b/patches.at91/0100-phy-micrel-we-need-to-register-ks8051-phy-for-emac.patch
@@ -0,0 +1,39 @@
+From db4349884ad9dd53c6a3e866aefd00a78532907f Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Tue, 10 Jul 2012 12:03:54 +0200
+Subject: phy/micrel: we need to register ks8051 phy for emac
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ drivers/net/phy/micrel.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
+index cc7f75b..2d80e01 100644
+--- a/drivers/net/phy/micrel.c
++++ b/drivers/net/phy/micrel.c
+@@ -206,10 +206,10 @@ static int __init ksphy_init(void)
+ ret = phy_driver_register(&ks8041_driver);
+ if (ret)
+ goto err4;
++#endif
+ ret = phy_driver_register(&ks8051_driver);
+ if (ret)
+- goto err5;
+-#endif
++ goto err2;
+
+ ret = phy_driver_register(&ksz9021_driver);
+ if (ret)
+@@ -227,6 +227,8 @@ err3:
+ err2:
+ phy_driver_unregister(&ks8001_driver);
+ #endif
++err2:
++ phy_driver_unregister(&ks8051_driver);
+ err1:
+ return ret;
+ }
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0101-usb-gadget-at91_udc-move-the-dereference-below-the-N.patch b/patches.at91/0101-usb-gadget-at91_udc-move-the-dereference-below-the-N.patch
new file mode 100644
index 00000000000000..b28e71bae4041a
--- /dev/null
+++ b/patches.at91/0101-usb-gadget-at91_udc-move-the-dereference-below-the-N.patch
@@ -0,0 +1,40 @@
+From ae50ff05ab833b25bb7d581dd0beaeec1ab830da Mon Sep 17 00:00:00 2001
+From: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
+Date: Fri, 7 Sep 2012 14:54:25 +0800
+Subject: usb: gadget: at91_udc: move the dereference below the NULL test
+
+The dereference should be moved below the NULL test.
+
+spatch with a semantic match is used to found this.
+(http://coccinelle.lip6.fr/)
+
+Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
+Signed-off-by: Felipe Balbi <balbi@ti.com>
+---
+ drivers/usb/gadget/at91_udc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
+index 9d7bcd9..d6249f0 100644
+--- a/drivers/usb/gadget/at91_udc.c
++++ b/drivers/usb/gadget/at91_udc.c
+@@ -469,7 +469,7 @@ static int at91_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+ {
+ struct at91_ep *ep = container_of(_ep, struct at91_ep, ep);
+- struct at91_udc *udc = ep->udc;
++ struct at91_udc *udc;
+ u16 maxpacket;
+ u32 tmp;
+ unsigned long flags;
+@@ -484,6 +484,7 @@ static int at91_ep_enable(struct usb_ep *_ep,
+ return -EINVAL;
+ }
+
++ udc = ep->udc;
+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
+ DBG("bogus device state\n");
+ return -ESHUTDOWN;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0103-USB-ohci-at91-fix-PIO-handling-in-relation-with-numb.patch b/patches.at91/0103-USB-ohci-at91-fix-PIO-handling-in-relation-with-numb.patch
new file mode 100644
index 00000000000000..4f7467a03a8c14
--- /dev/null
+++ b/patches.at91/0103-USB-ohci-at91-fix-PIO-handling-in-relation-with-numb.patch
@@ -0,0 +1,41 @@
+From 42e76043636c925fe4de3223092e587d12a1be2a Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 29 Aug 2012 11:49:18 +0200
+Subject: USB: ohci-at91: fix PIO handling in relation with number of ports
+
+If the number of ports present on the SoC/board is not the maximum
+and that the platform data is not filled with all data, there is
+an easy way to mess the PIO setup for this interface.
+This quick fix addresses mis-configuration in USB host platform data
+that is common in at91 boards since commit 0ee6d1e (USB: ohci-at91:
+change maximum number of ports) that did not modified the associatd
+board files.
+
+Reported-by: Klaus Falkner <klaus.falkner@solectrix.de>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Cc: Stable <stable@vger.kernel.org> [3.4+]
+Acked-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/host/ohci-at91.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/usb/host/ohci-at91.c
++++ b/drivers/usb/host/ohci-at91.c
+@@ -647,6 +647,16 @@ static int __devexit ohci_hcd_at91_drv_r
+
+ if (pdata) {
+ at91_for_each_port(i) {
++ /*
++ * do not configure PIO if not in relation with
++ * real USB port on board
++ */
++ if (i >= pdata->ports) {
++ pdata->vbus_pin[i] = -EINVAL;
++ pdata->overcurrent_pin[i] = -EINVAL;
++ break;
++ }
++
+ if (!gpio_is_valid(pdata->vbus_pin[i]))
+ continue;
+ ohci_at91_usb_set_power(pdata, i, 0);
diff --git a/patches.at91/0104-usb-gadget-at91_udc-Propagate-devicetree-to-gadget-d.patch b/patches.at91/0104-usb-gadget-at91_udc-Propagate-devicetree-to-gadget-d.patch
new file mode 100644
index 00000000000000..014d66dc902dc5
--- /dev/null
+++ b/patches.at91/0104-usb-gadget-at91_udc-Propagate-devicetree-to-gadget-d.patch
@@ -0,0 +1,28 @@
+From 3be7e4694db4d894b3bbb2252d033a58a8805cf0 Mon Sep 17 00:00:00 2001
+From: Alexandre Pereira da Silva <aletes.xgr@gmail.com>
+Date: Tue, 26 Jun 2012 11:27:12 -0300
+Subject: usb: gadget: at91_udc: Propagate devicetree to gadget drivers
+
+Fill dev.of_node of gadget drivers, so they can use devicetree
+
+Signed-off-by: Alexandre Pereira da Silva <aletes.xgr@gmail.com>
+Signed-off-by: Felipe Balbi <balbi@ti.com>
+---
+ drivers/usb/gadget/at91_udc.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
+index ffb46bc..ddeaadb 100644
+--- a/drivers/usb/gadget/at91_udc.c
++++ b/drivers/usb/gadget/at91_udc.c
+@@ -1650,6 +1650,7 @@ static int at91_start(struct usb_gadget_driver *driver,
+
+ udc->driver = driver;
+ udc->gadget.dev.driver = &driver->driver;
++ udc->gadget.dev.of_node = udc->pdev->dev.of_node;
+ dev_set_drvdata(&udc->gadget.dev, &driver->driver);
+ udc->enabled = 1;
+ udc->selfpowered = 1;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0105-USB-ohci-at91.c-remove-err-usage.patch b/patches.at91/0105-USB-ohci-at91.c-remove-err-usage.patch
new file mode 100644
index 00000000000000..c90aef45d3d88b
--- /dev/null
+++ b/patches.at91/0105-USB-ohci-at91.c-remove-err-usage.patch
@@ -0,0 +1,34 @@
+From 3b08384658865b98f31a74f07550ac0a562887e8 Mon Sep 17 00:00:00 2001
+From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Date: Fri, 27 Apr 2012 11:24:39 -0700
+Subject: USB: ohci-at91.c: remove err() usage
+
+err() was a very old USB-specific macro that I thought had
+gone away. This patch removes it from being used in the
+driver and uses dev_err() instead.
+
+CC: Alan Stern <stern@rowland.harvard.edu>
+CC: Grant Likely <grant.likely@secretlab.ca>
+CC: Rob Herring <rob.herring@calxeda.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/host/ohci-at91.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
+index 5dfea46..aaa8d2b 100644
+--- a/drivers/usb/host/ohci-at91.c
++++ b/drivers/usb/host/ohci-at91.c
+@@ -243,7 +243,8 @@ ohci_at91_start (struct usb_hcd *hcd)
+ int ret;
+
+ if ((ret = ohci_run(ohci)) < 0) {
+- err("can't start %s", hcd->self.bus_name);
++ dev_err(hcd->self.controller, "can't start %s\n",
++ hcd->self.bus_name);
+ ohci_stop(hcd);
+ return ret;
+ }
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0107-media-video-atmel-isi-add-dumb-set_parm.patch b/patches.at91/0107-media-video-atmel-isi-add-dumb-set_parm.patch
new file mode 100644
index 00000000000000..d61092555b688a
--- /dev/null
+++ b/patches.at91/0107-media-video-atmel-isi-add-dumb-set_parm.patch
@@ -0,0 +1,42 @@
+From 705b4b4645cf6f31bc1e267e193388a82b7f2df3 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Fri, 10 Jun 2011 17:21:28 +0200
+Subject: media/video: atmel-isi: add dumb set_parm()
+
+Add dumb set_parm() & get_parm() function to struct soc_camera_host_ops.
+Needed for ffmpeg to be able to capture frames from ISI driver.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/media/video/atmel-isi.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c
+index ec3f6a0..7a44df4 100644
+--- a/drivers/media/video/atmel-isi.c
++++ b/drivers/media/video/atmel-isi.c
+@@ -893,6 +893,12 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd)
+ 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,
+@@ -904,6 +910,8 @@ 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,
++ .get_parm = isi_camera_set_parm,
+ };
+
+ /* -----------------------------------------------------------------------*/
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0108-video-atmel_lcdfb-add-support-for-AT91SAM9x5.patch b/patches.at91/0108-video-atmel_lcdfb-add-support-for-AT91SAM9x5.patch
new file mode 100644
index 00000000000000..4e4c77bc85b99b
--- /dev/null
+++ b/patches.at91/0108-video-atmel_lcdfb-add-support-for-AT91SAM9x5.patch
@@ -0,0 +1,1810 @@
+From 5c29a55f144400febf2dfcdc327253b813113c07 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Mon, 1 Nov 2010 16:38:41 +0800
+Subject: 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.39-rcish]
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+Conflicts:
+
+ drivers/video/atmel_lcdfb.c
+---
+ arch/arm/mach-at91/include/mach/atmel_hlcdfb.h | 865 +++++++++++++++++++++++++
+ drivers/video/atmel_lcdfb.c | 668 ++++++++++++++-----
+ include/video/atmel_lcdc.h | 15 +
+ 3 files changed, 1389 insertions(+), 159 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..a57b79b
+--- /dev/null
++++ b/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h
+@@ -0,0 +1,865 @@
++/*
++ * 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)
++#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 << 11)
++#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 << 11)
++#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 << 11)
++#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 << 11)
++#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 d99505b..c35f5c7 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
+@@ -25,6 +25,7 @@
+ #include <asm/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))
+@@ -76,6 +77,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 */
+@@ -84,6 +88,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
+@@ -94,17 +99,28 @@ 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);
+- if (contrast_ctr & ATMEL_LCDC_POL_POSITIVE)
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
+- brightness ? contrast_ctr : 0);
+- else
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
++ 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);
++ if (contrast_ctr & ATMEL_LCDC_POL_POSITIVE)
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
++ brightness ? contrast_ctr : 0);
++ else
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
++ }
+
+ bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
+
+@@ -115,7 +131,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 = {
+@@ -171,14 +190,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);
+ }
+@@ -220,32 +242,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,
+@@ -254,14 +322,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 * info->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, info);
+ }
+@@ -272,12 +357,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.
+ */
+@@ -300,6 +391,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;
+ }
+
+@@ -393,18 +497,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);
+@@ -419,9 +538,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;
+@@ -436,6 +599,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 */
+@@ -472,6 +636,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
+@@ -489,11 +899,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();
+
+@@ -518,98 +924,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);
+
+@@ -772,14 +1088,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;
+ }
+
+@@ -920,6 +1254,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;
+@@ -1030,7 +1366,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);
+@@ -1075,7 +1411,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);
+@@ -1100,10 +1436,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_CTR);
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
+ if (sinfo->atmel_lcdfb_power_control)
+ sinfo->atmel_lcdfb_power_control(0);
+
+@@ -1122,11 +1465,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.8.0.197.g5a90748
+
diff --git a/patches.at91/0109-video-atmel_lcdfb-The-output-bpp-should-not-change-a.patch b/patches.at91/0109-video-atmel_lcdfb-The-output-bpp-should-not-change-a.patch
new file mode 100644
index 00000000000000..b7357c71772d21
--- /dev/null
+++ b/patches.at91/0109-video-atmel_lcdfb-The-output-bpp-should-not-change-a.patch
@@ -0,0 +1,66 @@
+From 08626997ca3446eab14d17f0c422c4835d6da2d7 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Wed, 9 Mar 2011 11:21:51 +0800
+Subject: 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 file changed, 3 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index c35f5c7..ae0e8e9 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -666,7 +666,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;
+
+@@ -675,27 +677,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.8.0.197.g5a90748
+
diff --git a/patches.at91/0110-video-atmelfb-initially-split-atmelfb-into-a-driver-.patch b/patches.at91/0110-video-atmelfb-initially-split-atmelfb-into-a-driver-.patch
new file mode 100644
index 00000000000000..51c6f1091d3355
--- /dev/null
+++ b/patches.at91/0110-video-atmelfb-initially-split-atmelfb-into-a-driver-.patch
@@ -0,0 +1,2643 @@
+From 5613e37ca48a7ff009aa3d86325e44d68803fed4 Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Thu, 19 May 2011 09:42:55 +0200
+Subject: 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>
+
+Conflicts:
+
+ drivers/video/atmel_lcdfb.c
+---
+ drivers/video/Makefile | 2 +-
+ drivers/video/atmel_lcdfb.c | 1427 +-------------------------------------
+ drivers/video/atmel_lcdfb_core.c | 1077 ++++++++++++++++++++++++++++
+ include/video/atmel_lcdc.h | 17 +-
+ 4 files changed, 1104 insertions(+), 1419 deletions(-)
+ create mode 100644 drivers/video/atmel_lcdfb_core.c
+
+diff --git a/drivers/video/Makefile b/drivers/video/Makefile
+index 9356add..37c5625 100644
+--- a/drivers/video/Makefile
++++ b/drivers/video/Makefile
+@@ -95,7 +95,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 ae0e8e9..4e1454c 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -10,1401 +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 <linux/module.h>
+-
+-#include <mach/board.h>
+-#include <mach/cpu.h>
+-#include <asm/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,
+- struct fb_info *info)
+-{
+-
+-}
+-#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,
+- struct fb_info *info)
+-{
+- u32 dma2dcfg;
+- u32 pixeloff;
+-
+- pixeloff = (var->xoffset * info->var.bits_per_pixel) & 0x1f;
+-
+- dma2dcfg = (info->var.xres_virtual - info->var.xres)
+- * info->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);
+- if (contrast_ctr & ATMEL_LCDC_POL_POSITIVE)
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
+- brightness ? contrast_ctr : 0);
+- else
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
+- }
+-
+- 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 * info->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, info);
+-}
+-
+-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;
+- } else {
+- /* BGR:565 mode */
+- var->red.offset = 0;
+- var->blue.offset = 11;
+- }
+- var->green.offset = 5;
+- var->green.length = 6;
+- 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);
+-
+- 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) {
+- if (cpu_is_at91sam9261() || cpu_is_at91sam9263()
+- || cpu_is_at91sam9rl()) {
+- /* old style I+BGR:555 */
+- 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
+- */
+- } else {
+- /* new style BGR:565 / RGB:565 */
+- if (sinfo->lcd_wiring_mode ==
+- ATMEL_LCDC_WIRING_RGB) {
+- val = ((blue >> 11) & 0x001f);
+- val |= ((red >> 0) & 0xf800);
+- } else {
+- val = ((red >> 11) & 0x001f);
+- val |= ((blue >> 0) & 0xf800);
+- }
+-
+- val |= ((green >> 5) & 0x07e0);
+- }
+-
+- 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 {
+- 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 = resource_size(map);
+- 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 = resource_size(regs);
+-
+- 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;
+-}
+-
+-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
+
+@@ -1417,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);
+@@ -1447,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;
+ }
+@@ -1467,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,
+@@ -1482,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.8.0.197.g5a90748
+
diff --git a/patches.at91/0111-video-atmelfb-refactor-core-setup.patch b/patches.at91/0111-video-atmelfb-refactor-core-setup.patch
new file mode 100644
index 00000000000000..c45df550414cc8
--- /dev/null
+++ b/patches.at91/0111-video-atmelfb-refactor-core-setup.patch
@@ -0,0 +1,403 @@
+From 4a211d9df5fc6bfabb2a85f1bbf9610bee0eef32 Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Thu, 19 May 2011 14:29:36 +0200
+Subject: 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.8.0.197.g5a90748
+
diff --git a/patches.at91/0112-video-atmelfb-refactor-start-stop.patch b/patches.at91/0112-video-atmelfb-refactor-start-stop.patch
new file mode 100644
index 00000000000000..7fe9e81a7e6ff2
--- /dev/null
+++ b/patches.at91/0112-video-atmelfb-refactor-start-stop.patch
@@ -0,0 +1,196 @@
+From 93000ba8524c38cd973ad541bf8675a204cad07a Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Thu, 19 May 2011 15:12:30 +0200
+Subject: 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.8.0.197.g5a90748
+
diff --git a/patches.at91/0113-video-atmelfb-refactor-isr.patch b/patches.at91/0113-video-atmelfb-refactor-isr.patch
new file mode 100644
index 00000000000000..8601fec22aa699
--- /dev/null
+++ b/patches.at91/0113-video-atmelfb-refactor-isr.patch
@@ -0,0 +1,154 @@
+From 8043f427b2e8eb8f92e1193836809b0454c424e4 Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Thu, 19 May 2011 15:37:12 +0200
+Subject: 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.8.0.197.g5a90748
+
diff --git a/patches.at91/0114-video-atmelfb-refactor-backlight-routines.patch b/patches.at91/0114-video-atmelfb-refactor-backlight-routines.patch
new file mode 100644
index 00000000000000..95fb0aa4a6457d
--- /dev/null
+++ b/patches.at91/0114-video-atmelfb-refactor-backlight-routines.patch
@@ -0,0 +1,256 @@
+From bf33aaec05fd4dc512ce1cc11de5562c8b5bfefc Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Thu, 19 May 2011 16:40:13 +0200
+Subject: 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.8.0.197.g5a90748
+
diff --git a/patches.at91/0115-video-atmelfb-refactor-dma_update.patch b/patches.at91/0115-video-atmelfb-refactor-dma_update.patch
new file mode 100644
index 00000000000000..e4f46be359de0a
--- /dev/null
+++ b/patches.at91/0115-video-atmelfb-refactor-dma_update.patch
@@ -0,0 +1,211 @@
+From 8faef3934fa0d515e72eea2197f1d00d636deb23 Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Fri, 20 May 2011 14:31:29 +0200
+Subject: 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.8.0.197.g5a90748
+
diff --git a/patches.at91/0116-video-atmelfb-refactor-LUT.patch b/patches.at91/0116-video-atmelfb-refactor-LUT.patch
new file mode 100644
index 00000000000000..e8c12dea2ab83d
--- /dev/null
+++ b/patches.at91/0116-video-atmelfb-refactor-LUT.patch
@@ -0,0 +1,80 @@
+From 8c0682446f887908ea3d93ed7e7dee05fb5fd911 Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Fri, 20 May 2011 14:51:45 +0200
+Subject: 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.8.0.197.g5a90748
+
diff --git a/patches.at91/0117-video-atmelfb-refactor-limit_screeninfo.patch b/patches.at91/0117-video-atmelfb-refactor-limit_screeninfo.patch
new file mode 100644
index 00000000000000..ed6800e75428da
--- /dev/null
+++ b/patches.at91/0117-video-atmelfb-refactor-limit_screeninfo.patch
@@ -0,0 +1,92 @@
+From 00420e8e99b5d5ce4a1a461c01b2eb6750b734d7 Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Fri, 20 May 2011 15:04:10 +0200
+Subject: 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.8.0.197.g5a90748
+
diff --git a/patches.at91/0118-arm-at91-refactor-lcdc-includes.patch b/patches.at91/0118-arm-at91-refactor-lcdc-includes.patch
new file mode 100644
index 00000000000000..031e89fff7c0a3
--- /dev/null
+++ b/patches.at91/0118-arm-at91-refactor-lcdc-includes.patch
@@ -0,0 +1,804 @@
+From daafaa8acad56047c2805a29610eea22ee50b705 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 22 Oct 2012 15:45:30 +0200
+Subject: 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>
+
+Conflicts:
+ arch/arm/mach-at91/board-neocore926.c
+ arch/arm/mach-at91/board-sam9261ek.c
+ arch/arm/mach-at91/board-sam9263ek.c
+ arch/arm/mach-at91/board-sam9m10g45ek.c
+ arch/arm/mach-at91/board-sam9rlek.c
+---
+ arch/arm/mach-at91/at91sam9261_devices.c | 4 +-
+ arch/arm/mach-at91/at91sam9263_devices.c | 4 +-
+ arch/arm/mach-at91/at91sam9g45_devices.c | 4 +-
+ arch/arm/mach-at91/at91sam9rl_devices.c | 4 +-
+ arch/arm/mach-at91/board-neocore926.c | 4 +-
+ arch/arm/mach-at91/board-sam9261ek.c | 4 +-
+ arch/arm/mach-at91/board-sam9263ek.c | 4 +-
+ arch/arm/mach-at91/board-sam9m10g45ek.c | 4 +-
+ arch/arm/mach-at91/board-sam9rlek.c | 4 +-
+ .../include/mach/{atmel_hlcdfb.h => atmel_hlcdc.h} | 157 +--------------------
+ arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h | 156 ++++++++++++++++++++
+ .../arm/mach-at91/include/mach}/atmel_lcdc.h | 77 +---------
+ drivers/video/atmel_lcdfb.c | 3 +-
+ drivers/video/atmel_lcdfb_core.c | 2 +-
+ include/video/atmel_lcdfb.h | 100 +++++++++++++
+ 15 files changed, 294 insertions(+), 237 deletions(-)
+ rename arch/arm/mach-at91/include/mach/{atmel_hlcdfb.h => atmel_hlcdc.h} (82%)
+ create mode 100644 arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h
+ rename {include/video => arch/arm/mach-at91/include/mach}/atmel_lcdc.h (73%)
+ create mode 100644 include/video/atmel_lcdfb.h
+
+diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
+index 8df5c1b..1eecff8 100644
+--- a/arch/arm/mach-at91/at91sam9261_devices.c
++++ b/arch/arm/mach-at91/at91sam9261_devices.c
+@@ -19,9 +19,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/at91_matrix.h>
+diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
+index eb6bbf8..f0318e9 100644
+--- a/arch/arm/mach-at91/at91sam9263_devices.c
++++ b/arch/arm/mach-at91/at91sam9263_devices.c
+@@ -18,9 +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/at91sam9263.h>
+ #include <mach/at91sam9263_matrix.h>
+ #include <mach/at91_matrix.h>
+diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
+index 7ab7e06..73eb743 100644
+--- a/arch/arm/mach-at91/at91sam9g45_devices.c
++++ b/arch/arm/mach-at91/at91sam9g45_devices.c
+@@ -20,9 +20,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/at91_matrix.h>
+diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
+index f09fff9..0d1b76f 100644
+--- a/arch/arm/mach-at91/at91sam9rl_devices.c
++++ b/arch/arm/mach-at91/at91sam9rl_devices.c
+@@ -15,9 +15,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/at91_matrix.h>
+diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
+index 18103c5d..5d3b4d6 100644
+--- a/arch/arm/mach-at91/board-neocore926.c
++++ b/arch/arm/mach-at91/board-neocore926.c
+@@ -32,7 +32,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,8 @@
+ #include <mach/hardware.h>
+ #include <mach/board.h>
+ #include <mach/at91_aic.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 2269be5..2e1c9c5 100644
+--- a/arch/arm/mach-at91/board-sam9261ek.c
++++ b/arch/arm/mach-at91/board-sam9261ek.c
+@@ -34,7 +34,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>
+@@ -47,6 +47,8 @@
+ #include <mach/hardware.h>
+ #include <mach/board.h>
+ #include <mach/at91_aic.h>
++#include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+ #include <mach/system_rev.h>
+diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
+index 82adf58..7c34908 100644
+--- a/arch/arm/mach-at91/board-sam9263ek.c
++++ b/arch/arm/mach-at91/board-sam9263ek.c
+@@ -33,7 +33,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>
+@@ -46,6 +46,8 @@
+ #include <mach/hardware.h>
+ #include <mach/board.h>
+ #include <mach/at91_aic.h>
++#include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+ #include <mach/system_rev.h>
+diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
+index d1882d5..78210f6 100644
+--- a/arch/arm/mach-at91/board-sam9m10g45ek.c
++++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
+@@ -28,7 +28,7 @@
+ #include <linux/delay.h>
+
+ #include <mach/hardware.h>
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+ #include <media/soc_camera.h>
+ #include <media/atmel-isi.h>
+
+@@ -42,6 +42,8 @@
+
+ #include <mach/board.h>
+ #include <mach/at91_aic.h>
++#include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+ #include <mach/system_rev.h>
+diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
+index e7dc3ea..81d82be 100644
+--- a/arch/arm/mach-at91/board-sam9rlek.c
++++ b/arch/arm/mach-at91/board-sam9rlek.c
+@@ -19,7 +19,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>
+@@ -32,6 +32,8 @@
+ #include <mach/hardware.h>
+ #include <mach/board.h>
+ #include <mach/at91_aic.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/include/mach/atmel_hlcdfb.h b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
+similarity index 82%
+rename from arch/arm/mach-at91/include/mach/atmel_hlcdfb.h
+rename to arch/arm/mach-at91/include/mach/atmel_hlcdc.h
+index a57b79b..9ed7e6e 100644
+--- a/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h
++++ b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
+@@ -19,8 +19,8 @@
+ * 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__
++#ifndef __MACH_ATMEL_HLCD_H__
++#define __MACH_ATMEL_HLCD_H__
+
+ /* Lcdc hardware registers */
+ #define ATMEL_LCDC_LCDCFG0 0x0000
+@@ -145,7 +145,7 @@
+ #define LCDC_LCDISR_FIFOERR (0x1 << 4)
+ #define LCDC_LCDISR_BASE (0x1 << 8)
+ #define LCDC_LCDISR_OVR1 (0x1 << 9)
+-#define LCDC_LCDISR_HEO (0x1 << 11)
++#define LCDC_LCDISR_HEO (0x1 << 10)
+ #define LCDC_LCDISR_HCR (0x1 << 12)
+
+ #define ATMEL_LCDC_BASECHER 0x0040
+@@ -252,153 +252,6 @@
+ #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)
+@@ -859,7 +712,7 @@
+ #define LCDC_HCRCLUT_ACLUT (0xff << LCDC_HCRCLUT_ACLUT_OFFSET)
+
+ /* Base layer CLUT */
+-#define ATMEL_LCDC_LUT(n) (0x0400 + ((n)*4))
++#define ATMEL_HLCDC_LUT 0x0400
+
+
+-#endif /* __ATMEL_HLCDC4_H__ */
++#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/include/video/atmel_lcdc.h b/arch/arm/mach-at91/include/mach/atmel_lcdc.h
+similarity index 73%
+rename from include/video/atmel_lcdc.h
+rename to arch/arm/mach-at91/include/mach/atmel_lcdc.h
+index 6031b5a..248fed3 100644
+--- a/include/video/atmel_lcdc.h
++++ b/arch/arm/mach-at91/include/mach/atmel_lcdc.h
+@@ -19,79 +19,8 @@
+ * 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))
++#ifndef __MACH_ATMEL_LCDC_H__
++#define __MACH_ATMEL_LCDC_H__
+
+ #define ATMEL_LCDC_DMABADDR1 0x00
+ #define ATMEL_LCDC_DMABADDR2 0x04
+@@ -245,4 +174,4 @@ struct atmel_lcdfb_info {
+
+ #define ATMEL_LCDC_LUT 0x0c00
+
+-#endif /* __ATMEL_LCDC_H__ */
++#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_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.8.0.197.g5a90748
+
diff --git a/patches.at91/0119-video-atmel_hlcdfb-add-new-driver.patch b/patches.at91/0119-video-atmel_hlcdfb-add-new-driver.patch
new file mode 100644
index 00000000000000..72eb3a079a7243
--- /dev/null
+++ b/patches.at91/0119-video-atmel_hlcdfb-add-new-driver.patch
@@ -0,0 +1,606 @@
+From ea87fdee7c94f994ebcb9b731a68c11ee065780b Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Mon, 23 May 2011 15:36:52 +0200
+Subject: 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(+)
+ create mode 100644 drivers/video/atmel_hlcdfb.c
+
+diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
+index a290be5..ceccaa3 100644
+--- a/drivers/video/Kconfig
++++ b/drivers/video/Kconfig
+@@ -1028,6 +1028,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 37c5625..36320ea 100644
+--- a/drivers/video/Makefile
++++ b/drivers/video/Makefile
+@@ -96,6 +96,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.8.0.197.g5a90748
+
diff --git a/patches.at91/0120-WIP-add-clut-resource.patch b/patches.at91/0120-WIP-add-clut-resource.patch
new file mode 100644
index 00000000000000..0cee03c10be08d
--- /dev/null
+++ b/patches.at91/0120-WIP-add-clut-resource.patch
@@ -0,0 +1,167 @@
+From 952cff7d64d122e94ca17a2281fc170a8c73ec95 Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Mon, 30 May 2011 17:04:35 +0200
+Subject: 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.8.0.197.g5a90748
+
diff --git a/patches.at91/0121-video-atmel_lcdfb-add-error-msg-when-out-of-memory.patch b/patches.at91/0121-video-atmel_lcdfb-add-error-msg-when-out-of-memory.patch
new file mode 100644
index 00000000000000..e2a279bc687d6e
--- /dev/null
+++ b/patches.at91/0121-video-atmel_lcdfb-add-error-msg-when-out-of-memory.patch
@@ -0,0 +1,33 @@
+From 3df2f96a9b65c88f3caaba3ea667e3feffb14b0c Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Tue, 7 Jun 2011 12:58:36 +0200
+Subject: 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 file changed, 3 insertions(+), 1 deletion(-)
+
+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.8.0.197.g5a90748
+
diff --git a/patches.at91/0122-video-atmel_lcdfb-HLCD-modifications.patch b/patches.at91/0122-video-atmel_lcdfb-HLCD-modifications.patch
new file mode 100644
index 00000000000000..f8311916d7d182
--- /dev/null
+++ b/patches.at91/0122-video-atmel_lcdfb-HLCD-modifications.patch
@@ -0,0 +1,238 @@
+From 21ab2ac12ae088515007d81868b9d3eb8446baad Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Fri, 17 Feb 2012 13:12:21 +0100
+Subject: video: atmel_lcdfb: HLCD modifications
+
+HAS TO BE REWORKED: break compatibility with previous LCD IP due to register
+map changes
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ arch/arm/mach-at91/include/mach/atmel_hlcdc.h | 43 +++++++++++++++++++++++++++
+ drivers/video/atmel_hlcdfb.c | 5 ++--
+ drivers/video/atmel_lcdfb.c | 1 +
+ drivers/video/atmel_lcdfb_core.c | 1 +
+ drivers/video/backlight/Kconfig | 4 +--
+ 5 files changed, 50 insertions(+), 4 deletions(-)
+
+diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdc.h b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
+index 9ed7e6e..738a853 100644
+--- a/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
++++ b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
+@@ -29,8 +29,10 @@
+ #define LCDC_LCDCFG0_CLKPWMSEL (0x1 << 3)
+ #define LCDC_LCDCFG0_CGDISBASE (0x1 << 8)
+ #define LCDC_LCDCFG0_CGDISOVR1 (0x1 << 9)
++#define LCDC_LCDCFG0_CGDISOVR2 (0x1 << 10)
+ #define LCDC_LCDCFG0_CGDISHEO (0x1 << 11)
+ #define LCDC_LCDCFG0_CGDISHCR (0x1 << 12)
++#define LCDC_LCDCFG0_CGDISPP (0x1 << 13)
+ #define LCDC_LCDCFG0_CLKDIV_OFFSET 16
+ #define LCDC_LCDCFG0_CLKDIV (0xff << LCDC_LCDCFG0_CLKDIV_OFFSET)
+
+@@ -49,8 +51,10 @@
+ #define ATMEL_LCDC_LCDCFG3 0x000C
+ #define LCDC_LCDCFG3_HFPW_OFFSET 0
+ #define LCDC_LCDCFG3_HFPW (0xff << LCDC_LCDCFG3_HFPW_OFFSET)
++#define LCDC2_LCDCFG3_HFPW (0x1ff << LCDC_LCDCFG3_HFPW_OFFSET)
+ #define LCDC_LCDCFG3_HBPW_OFFSET 16
+ #define LCDC_LCDCFG3_HBPW (0xff << LCDC_LCDCFG3_HBPW_OFFSET)
++#define LCDC2_LCDCFG3_HBPW (0x1ff << LCDC_LCDCFG3_HBPW_OFFSET)
+
+ #define ATMEL_LCDC_LCDCFG4 0x0010
+ #define LCDC_LCDCFG4_PPL_OFFSET 0
+@@ -73,6 +77,7 @@
+ #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_PP (0x1 << 10)
+ #define LCDC_LCDCFG5_VSPSU (0x1 << 12)
+ #define LCDC_LCDCFG5_VSPHO (0x1 << 13)
+ #define LCDC_LCDCFG5_GUARDTIME_OFFSET 16
+@@ -115,8 +120,10 @@
+ #define LCDC_LCDIER_FIFOERRIE (0x1 << 4)
+ #define LCDC_LCDIER_BASEIE (0x1 << 8)
+ #define LCDC_LCDIER_OVR1IE (0x1 << 9)
++#define LCDC_LCDIER_OVR2IE (0x1 << 10)
+ #define LCDC_LCDIER_HEOIE (0x1 << 11)
+ #define LCDC_LCDIER_HCRIE (0x1 << 12)
++#define LCDC_LCDIER_PPIE (0x1 << 13)
+
+ #define ATMEL_LCDC_LCDIDR 0x0030
+ #define LCDC_LCDIDR_SOFID (0x1 << 0)
+@@ -125,8 +132,10 @@
+ #define LCDC_LCDIDR_FIFOERRID (0x1 << 4)
+ #define LCDC_LCDIDR_BASEID (0x1 << 8)
+ #define LCDC_LCDIDR_OVR1ID (0x1 << 9)
++#define LCDC_LCDIDR_OVR2ID (0x1 << 10)
+ #define LCDC_LCDIDR_HEOID (0x1 << 11)
+ #define LCDC_LCDIDR_HCRID (0x1 << 12)
++#define LCDC_LCDIDR_PPID (0x1 << 13)
+
+ #define ATMEL_LCDC_LCDIMR 0x0034
+ #define LCDC_LCDIMR_SOFIM (0x1 << 0)
+@@ -135,8 +144,10 @@
+ #define LCDC_LCDIMR_FIFOERRIM (0x1 << 4)
+ #define LCDC_LCDIMR_BASEIM (0x1 << 8)
+ #define LCDC_LCDIMR_OVR1IM (0x1 << 9)
++#define LCDC_LCDIMR_OVR2IM (0x1 << 10)
+ #define LCDC_LCDIMR_HEOIM (0x1 << 11)
+ #define LCDC_LCDIMR_HCRIM (0x1 << 12)
++#define LCDC_LCDIMR_PPIM (0x1 << 13)
+
+ #define ATMEL_LCDC_LCDISR 0x0038
+ #define LCDC_LCDISR_SOF (0x1 << 0)
+@@ -145,8 +156,11 @@
+ #define LCDC_LCDISR_FIFOERR (0x1 << 4)
+ #define LCDC_LCDISR_BASE (0x1 << 8)
+ #define LCDC_LCDISR_OVR1 (0x1 << 9)
++#define LCDC_LCDISR_OVR2 (0x1 << 10)
+ #define LCDC_LCDISR_HEO (0x1 << 10)
++#define LCDC2_LCDISR_HEO (0x1 << 11)
+ #define LCDC_LCDISR_HCR (0x1 << 12)
++#define LCDC_LCDISR_PP (0x1 << 13)
+
+ #define ATMEL_LCDC_BASECHER 0x0040
+ #define LCDC_BASECHER_CHEN (0x1 << 0)
+@@ -205,6 +219,7 @@
+ #define ATMEL_LCDC_BASENEXT 0x0068
+
+ #define ATMEL_LCDC_BASECFG0 0x006C
++#define LCDC_BASECFG0_SIF (0x1 << 0)
+ #define LCDC_BASECFG0_BLEN_OFFSET 4
+ #define LCDC_BASECFG0_BLEN (0x3 << LCDC_BASECFG0_BLEN_OFFSET)
+ #define LCDC_BASECFG0_BLEN_AHB_SINGLE (0x0 << 4)
+@@ -251,8 +266,22 @@
+ #define ATMEL_LCDC_BASECFG4 0x007C
+ #define LCDC_BASECFG4_DMA (0x1 << 8)
+ #define LCDC_BASECFG4_REP (0x1 << 9)
++#define LCDC_BASECFG4_DISCEN (0x1 << 11)
++
++#define ATMEL_LCDC_BASECFG5 0x0080
++#define LCDC_BASECFG5_DISCXPOS_OFFSET 0
++#define LCDC_BASECFG5_DISCXPOS (0x7ff << LCDC_BASECFG5_DISCXPOS_OFFSET)
++#define LCDC_BASECFG5_DISCYPOS_OFFSET 16
++#define LCDC_BASECFG5_DISCYPOS (0x7ff << LCDC_BASECFG5_DISCYPOS_OFFSET)
++
++#define ATMEL_LCDC_BASECFG6 0x0084
++#define LCDC_BASECFG6_DISCXSIZE_OFFSET 0
++#define LCDC_BASECFG6_DISCXSIZE (0x7ff << LCDC_BASECFG6_DISCXSIZE_OFFSET)
++#define LCDC_BASECFG6_DISCYSIZE_OFFSET 16
++#define LCDC_BASECFG6_DISCYSIZE (0x7ff << LCDC_BASECFG6_DISCYSIZE_OFFSET)
+
+ #define ATMEL_LCDC_HEOCHER 0x0280
++#define ATMEL_LCDC2_HEOCHER 0x0340
+ #define LCDC_HEOCHER_CHEN (0x1 << 0)
+ #define LCDC_HEOCHER_UPDATEEN (0x1 << 1)
+ #define LCDC_HEOCHER_A2QEN (0x1 << 2)
+@@ -674,6 +703,7 @@
+ #define LCDC_HCRCFG9_GA_Msk (0xff << LCDC_HCRCFG9_GA_OFFSET)
+
+ #define ATMEL_LCDC_BASECLUT 0x400
++#define ATMEL_LCDC2_BASECLUT 0x600
+ #define LCDC_BASECLUT_BCLUT_OFFSET 0
+ #define LCDC_BASECLUT_BCLUT (0xff << LCDC_BASECLUT_BCLUT_OFFSET)
+ #define LCDC_BASECLUT_GCLUT_OFFSET 8
+@@ -682,6 +712,7 @@
+ #define LCDC_BASECLUT_RCLUT (0xff << LCDC_BASECLUT_RCLUT_OFFSET)
+
+ #define ATMEL_LCDC_OVR1CLUT 0x800
++#define ATMEL_LCDC2_OVR1CLUT 0xa00
+ #define LCDC_OVR1CLUT_BCLUT_OFFSET 0
+ #define LCDC_OVR1CLUT_BCLUT (0xff << LCDC_OVR1CLUT_BCLUT_OFFSET)
+ #define LCDC_OVR1CLUT_GCLUT_OFFSET 8
+@@ -691,7 +722,18 @@
+ #define LCDC_OVR1CLUT_ACLUT_OFFSET 24
+ #define LCDC_OVR1CLUT_ACLUT (0xff << LCDC_OVR1CLUT_ACLUT_OFFSET)
+
++#define ATMEL_LCDC_OVR2CLUT 0xe00
++#define LCDC_OVR2CLUT_BCLUT_OFFSET 0
++#define LCDC_OVR2CLUT_BCLUT (0xff << LCDC_OVR2CLUT_BCLUT_OFFSET)
++#define LCDC_OVR2CLUT_GCLUT_OFFSET 8
++#define LCDC_OVR2CLUT_GCLUT (0xff << LCDC_OVR2CLUT_GCLUT_OFFSET)
++#define LCDC_OVR2CLUT_RCLUT_OFFSET 16
++#define LCDC_OVR2CLUT_RCLUT (0xff << LCDC_OVR2CLUT_RCLUT_OFFSET)
++#define LCDC_OVR2CLUT_ACLUT_OFFSET 24
++#define LCDC_OVR2CLUT_ACLUT (0xff << LCDC_OVR2CLUT_ACLUT_OFFSET)
++
+ #define ATMEL_LCDC_HEOCLUT 0x1000
++#define ATMEL_LCDC2_HEOCLUT 0x1200
+ #define LCDC_HEOCLUT_BCLUT_OFFSET 0
+ #define LCDC_HEOCLUT_BCLUT (0xff << LCDC_HEOCLUT_BCLUT_OFFSET)
+ #define LCDC_HEOCLUT_GCLUT_OFFSET 8
+@@ -702,6 +744,7 @@
+ #define LCDC_HEOCLUT_ACLUT (0xff << LCDC_HEOCLUT_ACLUT_OFFSET)
+
+ #define ATMEL_LCDC_HCRCLUT 0x1400
++#define ATMEL_LCDC2_HCRCLUT 0x1600
+ #define LCDC_HCRCLUT_BCLUT_OFFSET 0
+ #define LCDC_HCRCLUT_BCLUT (0xff << LCDC_HCRCLUT_BCLUT_OFFSET)
+ #define LCDC_HCRCLUT_GCLUT_OFFSET 8
+diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c
+index 346bb80..c4c4559 100644
+--- a/drivers/video/atmel_hlcdfb.c
++++ b/drivers/video/atmel_hlcdfb.c
+@@ -9,6 +9,7 @@
+ */
+
+ #include <linux/kernel.h>
++#include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/interrupt.h>
+ #include <linux/backlight.h>
+@@ -363,11 +364,11 @@ static void atmelfb_limit_screeninfo(struct fb_var_screeninfo *var)
+ 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);
++ (LCDC2_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);
++ (LCDC2_LCDCFG3_HFPW >> LCDC_LCDCFG3_HFPW_OFFSET) + 1);
+
+ }
+
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 402cb24..86e3e32 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -9,6 +9,7 @@
+ */
+
+ #include <linux/kernel.h>
++#include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/interrupt.h>
+ #include <linux/backlight.h>
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index ff84234..133d4ad 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -9,6 +9,7 @@
+ */
+
+ #include <linux/kernel.h>
++#include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/interrupt.h>
+diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
+index af16884..18d066b 100644
+--- a/drivers/video/backlight/Kconfig
++++ b/drivers/video/backlight/Kconfig
+@@ -144,8 +144,8 @@ 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
++ depends on FB_ATMEL || FB_ATMEL_HLCD
++ default y
+ help
+ This provides a backlight control internal to the Atmel LCDC
+ driver. If the LCD "contrast control" on your board is wired
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0123-atmel_lcdfb-change-pixel-clock-ratio-calculation.patch b/patches.at91/0123-atmel_lcdfb-change-pixel-clock-ratio-calculation.patch
new file mode 100644
index 00000000000000..aad35a8cab5ed2
--- /dev/null
+++ b/patches.at91/0123-atmel_lcdfb-change-pixel-clock-ratio-calculation.patch
@@ -0,0 +1,31 @@
+From 61d28fa28e8249fea4d28589346eb68b022ccbfe Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Fri, 24 Jun 2011 13:03:29 +0200
+Subject: 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 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c
+index c4c4559..a629dda 100644
+--- a/drivers/video/atmel_hlcdfb.c
++++ b/drivers/video/atmel_hlcdfb.c
+@@ -247,7 +247,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.8.0.197.g5a90748
+
diff --git a/patches.at91/0124-media-at91sam9x5-video-new-driver-for-the-high-end-o.patch b/patches.at91/0124-media-at91sam9x5-video-new-driver-for-the-high-end-o.patch
new file mode 100644
index 00000000000000..0ec35eef617c46
--- /dev/null
+++ b/patches.at91/0124-media-at91sam9x5-video-new-driver-for-the-high-end-o.patch
@@ -0,0 +1,1498 @@
+From 05f008850856d65b80cc67cba9eb329e44c63cf1 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: 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 | 1441 ++++++++++++++++++++++++++++++++
+ 3 files changed, 1450 insertions(+)
+ create mode 100644 drivers/media/video/at91sam9x5-video.c
+
+diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
+index ce1e7ba..70a6a55 100644
+--- a/drivers/media/video/Kconfig
++++ b/drivers/media/video/Kconfig
+@@ -1163,6 +1163,14 @@ source "drivers/media/video/s5p-tv/Kconfig"
+ endif # V4L_PLATFORM_DRIVERS
+ endif # VIDEO_CAPTURE_DRIVERS
+
++config VIDEO_AT91SAM9X5
++ tristate "Support for AT91SAM9X5 Video"
++ depends on ARCH_AT91
++ depends on VIDEO_V4L2
++ select VIDEOBUF2_DMA_CONTIG
++ help
++ support for the "High End Overlay" found in Atmel's AT91SAM9X5 SoCs.
++
+ menuconfig V4L_MEM2MEM_DRIVERS
+ bool "Memory-to-memory multimedia devices"
+ depends on VIDEO_V4L2
+diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
+index a6282a3..2b41c18 100644
+--- a/drivers/media/video/Makefile
++++ b/drivers/media/video/Makefile
+@@ -121,6 +121,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..26ce376
+--- /dev/null
++++ b/drivers/media/video/at91sam9x5-video.c
+@@ -0,0 +1,1441 @@
++/*
++ * 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_dma_addr(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_dma_addr(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_dma_addr(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_dma_addr(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,
++ const struct v4l2_format *fmt,
++ unsigned int *num_buffers, unsigned int *num_planes,
++ unsigned int 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");
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0125-video-atmel_lcdfb-protect-bl_power-with-CONFIG_BACKL.patch b/patches.at91/0125-video-atmel_lcdfb-protect-bl_power-with-CONFIG_BACKL.patch
new file mode 100644
index 00000000000000..6051fc3303766b
--- /dev/null
+++ b/patches.at91/0125-video-atmel_lcdfb-protect-bl_power-with-CONFIG_BACKL.patch
@@ -0,0 +1,112 @@
+From 565de7199ff8177b8034e2d799d820243ae76a0f Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 9 Oct 2012 18:23:51 +0200
+Subject: video: atmel_lcdfb*: protect bl_power with
+ CONFIG_BACKLIGHT_ATMEL_LCDC
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/video/atmel_hlcdfb.c | 24 +++++++++++++++++++-----
+ drivers/video/atmel_lcdfb.c | 24 +++++++++++++++++++-----
+ 2 files changed, 38 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c
+index a629dda..db6ec3e 100644
+--- a/drivers/video/atmel_hlcdfb.c
++++ b/drivers/video/atmel_hlcdfb.c
+@@ -94,6 +94,7 @@ static void atmel_hlcdfb_update_dma_ovl(struct fb_info *info,
+ lcdc_writel(sinfo, ATMEL_LCDC_OVRCHER1, LCDC_OVRCHER1_CHEN | LCDC_OVRCHER1_UPDATEEN);
+ }
+
++#if defined(CONFIG_BACKLIGHT_ATMEL_LCDC)
+ /* some bl->props field just changed */
+ static int atmel_bl_update_status(struct backlight_device *bl)
+ {
+@@ -133,17 +134,30 @@ static int atmel_bl_get_brightness(struct backlight_device *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));
+ }
++#else
++static int atmel_bl_update_status(struct backlight_device *bl)
++{
++ return 0;
++}
++
++static int atmel_bl_get_brightness(struct backlight_device *bl)
++{
++ return ATMEL_LCDC_CVAL_DEFAULT;
++}
++
++static void atmel_hlcdfb_init_contrast(struct atmel_lcdfb_info *sinfo) {}
++#endif
++
++static const struct backlight_ops atmel_hlcdc_bl_ops = {
++ .update_status = atmel_bl_update_status,
++ .get_brightness = atmel_bl_get_brightness,
++};
+
+ void atmel_hlcdfb_start(struct atmel_lcdfb_info *sinfo)
+ {
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 86e3e32..651c88f 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -86,6 +86,7 @@ static void atmel_lcdfb_update_dma(struct fb_info *info,
+ atmel_lcdfb_update_dma2d(sinfo, var);
+ }
+
++#if defined(CONFIG_BACKLIGHT_ATMEL_LCDC)
+ /* some bl->props field just changed */
+ static int atmel_bl_update_status(struct backlight_device *bl)
+ {
+@@ -123,11 +124,6 @@ static int atmel_bl_get_brightness(struct backlight_device *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' */
+@@ -138,6 +134,24 @@ static void atmel_lcdfb_init_contrast(struct atmel_lcdfb_info *sinfo)
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+ }
++#else
++static int atmel_bl_update_status(struct backlight_device *bl)
++{
++ return 0;
++}
++
++static int atmel_bl_get_brightness(struct backlight_device *bl)
++{
++ return ATMEL_LCDC_CVAL_DEFAULT;
++}
++
++static void atmel_lcdfb_init_contrast(struct atmel_lcdfb_info *sinfo) {}
++#endif
++
++static const struct backlight_ops atmel_lcdc_bl_ops = {
++ .update_status = atmel_bl_update_status,
++ .get_brightness = atmel_bl_get_brightness,
++};
+
+ void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
+ {
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0126-ARM-at91-9x5-modify-consistent-DMA-size.patch b/patches.at91/0126-ARM-at91-9x5-modify-consistent-DMA-size.patch
new file mode 100644
index 00000000000000..28b3ae3463c365
--- /dev/null
+++ b/patches.at91/0126-ARM-at91-9x5-modify-consistent-DMA-size.patch
@@ -0,0 +1,27 @@
+From fe1559cee6d0716c401e9ae3d621f3ec4964982b Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 16 Oct 2012 18:21:15 +0200
+Subject: ARM: at91/9x5: modify consistent DMA size
+
+update to 8M
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/at91sam9x5.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
+index c949dc7..7eb00c53 100644
+--- a/arch/arm/mach-at91/at91sam9x5.c
++++ b/arch/arm/mach-at91/at91sam9x5.c
+@@ -302,6 +302,7 @@ static void __init at91sam9x5_register_clocks(void)
+ static void __init at91sam9x5_map_io(void)
+ {
+ at91_init_sram(0, AT91SAM9X5_SRAM_BASE, AT91SAM9X5_SRAM_SIZE);
++ init_consistent_dma_size(SZ_8M);
+ }
+
+ void __init at91sam9x5_initialize(void)
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0127-video-atmel_lcdfb-adapt-to-all-IP-configurations.patch b/patches.at91/0127-video-atmel_lcdfb-adapt-to-all-IP-configurations.patch
new file mode 100644
index 00000000000000..73d0832e574e20
--- /dev/null
+++ b/patches.at91/0127-video-atmel_lcdfb-adapt-to-all-IP-configurations.patch
@@ -0,0 +1,63 @@
+From 564ee162bc8282b9ce6989d2338dcca66d5fbaec Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 16 Oct 2012 18:23:00 +0200
+Subject: video: atmel_lcdfb: adapt to all IP configurations
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/include/mach/atmel_hlcdc.h | 3 +--
+ drivers/video/atmel_hlcdfb.c | 14 ++++++++++++--
+ 2 files changed, 13 insertions(+), 4 deletions(-)
+
+diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdc.h b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
+index 738a853..71ccb96 100644
+--- a/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
++++ b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
+@@ -157,8 +157,7 @@
+ #define LCDC_LCDISR_BASE (0x1 << 8)
+ #define LCDC_LCDISR_OVR1 (0x1 << 9)
+ #define LCDC_LCDISR_OVR2 (0x1 << 10)
+-#define LCDC_LCDISR_HEO (0x1 << 10)
+-#define LCDC2_LCDISR_HEO (0x1 << 11)
++#define LCDC_LCDISR_HEO (0x1 << 11)
+ #define LCDC_LCDISR_HCR (0x1 << 12)
+ #define LCDC_LCDISR_PP (0x1 << 13)
+
+diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c
+index db6ec3e..262c15b 100644
+--- a/drivers/video/atmel_hlcdfb.c
++++ b/drivers/video/atmel_hlcdfb.c
+@@ -370,6 +370,16 @@ static int atmel_hlcdfb_setup_core_ovl(struct fb_info *info)
+ }
+ static void atmelfb_limit_screeninfo(struct fb_var_screeninfo *var)
+ {
++ u32 hbpw, hfpw;
++
++ if (cpu_is_at91sam9x5()) {
++ hbpw = LCDC_LCDCFG3_HBPW;
++ hfpw = LCDC_LCDCFG3_HFPW;
++ } else {
++ hbpw = LCDC2_LCDCFG3_HBPW;
++ hfpw = LCDC2_LCDCFG3_HFPW;
++ }
++
+ /* 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);
+@@ -378,11 +388,11 @@ static void atmelfb_limit_screeninfo(struct fb_var_screeninfo *var)
+ 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,
+- (LCDC2_LCDCFG3_HBPW >> LCDC_LCDCFG3_HBPW_OFFSET) + 1);
++ (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,
+- (LCDC2_LCDCFG3_HFPW >> LCDC_LCDCFG3_HFPW_OFFSET) + 1);
++ (hfpw >> LCDC_LCDCFG3_HFPW_OFFSET) + 1);
+
+ }
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0128-media-at91sam9x5-video-cleanup-modifications.patch b/patches.at91/0128-media-at91sam9x5-video-cleanup-modifications.patch
new file mode 100644
index 00000000000000..1ab43917919d56
--- /dev/null
+++ b/patches.at91/0128-media-at91sam9x5-video-cleanup-modifications.patch
@@ -0,0 +1,100 @@
+From 139db41120d5755f7a086fb8dc6d7080d10fd135 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 16 Oct 2012 18:26:10 +0200
+Subject: media/at91sam9x5-video: cleanup modifications
+
+pdata not used: remove them for now: ease transition to DT
+one type, one static, and one debug message modifications
+
+Can we squashed in another patch...
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/media/video/at91sam9x5-video.c | 22 ++++++++++++++--------
+ 1 file changed, 14 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/media/video/at91sam9x5-video.c b/drivers/media/video/at91sam9x5-video.c
+index 26ce376..c83dad1 100644
+--- a/drivers/media/video/at91sam9x5-video.c
++++ b/drivers/media/video/at91sam9x5-video.c
+@@ -347,8 +347,7 @@ static irqreturn_t at91sam9x5_video_irq(int irq, void *data)
+ 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));
++ debug("HEOIMR = 0x%08x, HEOCHSR = 0x%08x\n", heoimr, handled);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+@@ -475,7 +474,7 @@ static void at91sam9x5_video_show_buf(struct at91sam9x5_video_priv *priv,
+ priv->next.plane_size[2] = priv->plane_size[2];
+ }
+
+-static int experimental;
++static bool experimental;
+ module_param(experimental, bool, 0644);
+ MODULE_PARM_DESC(experimental, "enable experimental features");
+
+@@ -1155,8 +1154,8 @@ static int at91sam9x5_video_register(struct at91sam9x5_video_priv *priv,
+ int ret = -ENOMEM;
+ struct platform_device *pdev = priv->pdev;
+ struct resource *res;
+- const struct at91sam9x5_video_pdata *pdata =
+- dev_get_platdata(&pdev->dev);
++ /*const struct at91sam9x5_video_pdata *pdata =
++ dev_get_platdata(&pdev->dev);*/
+ struct vb2_queue *q = &priv->queue;
+ unsigned long flags;
+
+@@ -1171,10 +1170,13 @@ static int at91sam9x5_video_register(struct at91sam9x5_video_priv *priv,
+ /* XXX: this doesn't belong here, does it? */
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
++ /* Not used for now */
++#if 0
+ if (!pdata) {
+ dev_err(&pdev->dev, "failed to get platform data\n");
+ goto err_get_pdata;
+ }
++#endif
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+@@ -1272,10 +1274,14 @@ err_queue_init:
+ iounmap(priv->regbase);
+
+ priv->fbinfo = NULL;
++ } else {
++ dev_info(&pdev->dev,
++ "video device registered @ 0x%08x, irq = %d\n",
++ (unsigned int)priv->regbase, priv->irq);
+ }
+ err_ioremap:
+ err_get_regbase:
+- err_get_pdata:
++/* err_get_pdata:*/
+
+ return ret;
+ }
+@@ -1369,7 +1375,7 @@ err_alloc_priv:
+ return 0;
+ }
+
+-int __devexit at91sam9x5_video_remove(struct platform_device *pdev)
++static int __devexit at91sam9x5_video_remove(struct platform_device *pdev)
+ {
+ struct at91sam9x5_video_priv *priv = platform_get_drvdata(pdev);
+
+@@ -1386,7 +1392,7 @@ static struct platform_driver at91sam9x5_video_driver = {
+ .owner = THIS_MODULE,
+ },
+ .probe = at91sam9x5_video_probe,
+- .remove = at91sam9x5_video_remove,
++ .remove = __devexit_p(at91sam9x5_video_remove),
+ };
+
+ static struct platform_device *at91sam9x5_video_device;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0129-media-at91sam9x5-video-align-DMA-descriptors-on-64-b.patch b/patches.at91/0129-media-at91sam9x5-video-align-DMA-descriptors-on-64-b.patch
new file mode 100644
index 00000000000000..81ae75b4bbf6a5
--- /dev/null
+++ b/patches.at91/0129-media-at91sam9x5-video-align-DMA-descriptors-on-64-b.patch
@@ -0,0 +1,134 @@
+From 92851e65d9f4db640eecc9e6b7d547396244b6c9 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 16 Oct 2012 18:29:45 +0200
+Subject: media/at91sam9x5-video: align DMA descriptors on 64 bits
+
+Needed for future revisions of the LCD ip
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/media/video/at91sam9x5-video.c | 46 ++++++++++++++++++++--------------
+ 1 file changed, 27 insertions(+), 19 deletions(-)
+
+diff --git a/drivers/media/video/at91sam9x5-video.c b/drivers/media/video/at91sam9x5-video.c
+index c83dad1..9d7e6c5 100644
+--- a/drivers/media/video/at91sam9x5-video.c
++++ b/drivers/media/video/at91sam9x5-video.c
+@@ -375,7 +375,7 @@ static void at91sam9x5_video_show_buf(struct at91sam9x5_video_priv *priv,
+ 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);
++ ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2, 64);
+ u32 *dmadesc = vaddr + offset_dmadesc;
+ u32 heocher;
+
+@@ -388,23 +388,30 @@ static void at91sam9x5_video_show_buf(struct at91sam9x5_video_priv *priv,
+ }
+
+ debug("vout=%ux%u, heocher=%08x\n", pix->width, pix->height, heocher);
++ debug("dmadesc @ 0x%08x\n", dmadesc);
++ debug("dmadesc u @ 0x%08x\n", &dmadesc[4]);
++ debug("dmadesc v @ 0x%08x\n", &dmadesc[8]);
+
+ dmadesc[0] = buffer + priv->y_offset;
+ dmadesc[1] = REG_HEOxCTRL_DFETCH;
+ dmadesc[2] = buffer + offset_dmadesc;
++ /* dmadesc[3] not used to align U plane descriptor */
+
+ if (priv->u_planeno >= 0) {
+- dmadesc[3] = vb2_dma_contig_plane_dma_addr(vb, priv->u_planeno) +
++ dmadesc[4] = vb2_dma_contig_plane_dma_addr(vb, priv->u_planeno) +
+ priv->u_offset;
+- dmadesc[4] = REG_HEOxCTRL_DFETCH;
+- dmadesc[5] = buffer + offset_dmadesc + 3 * 4;
++ dmadesc[5] = REG_HEOxCTRL_DFETCH;
++ /* link to physical address of this U descriptor */
++ dmadesc[6] = buffer + offset_dmadesc + 4 * 4;
+ }
++ /* dmadesc[7] not used to align V plane descriptor */
+
+ if (priv->v_planeno >= 0) {
+- dmadesc[6] = vb2_dma_contig_plane_dma_addr(vb, priv->v_planeno) +
++ dmadesc[8] = vb2_dma_contig_plane_dma_addr(vb, priv->v_planeno) +
+ priv->v_offset;
+- dmadesc[7] = REG_HEOxCTRL_DFETCH;
+- dmadesc[8] = buffer + offset_dmadesc + 6 * 4;
++ dmadesc[9] = REG_HEOxCTRL_DFETCH;
++ /* link to physical address of this V descriptor */
++ dmadesc[10] = buffer + offset_dmadesc + 8 * 4;
+ }
+
+
+@@ -415,11 +422,11 @@ static void at91sam9x5_video_show_buf(struct at91sam9x5_video_priv *priv,
+
+ if (priv->u_planeno >= 0)
+ at91sam9x5_video_write32(priv,
+- REG_HEOUHEAD, dmadesc[5]);
++ REG_HEOUHEAD, dmadesc[6]);
+
+ if (priv->v_planeno >= 0)
+ at91sam9x5_video_write32(priv,
+- REG_HEOVHEAD, dmadesc[8]);
++ REG_HEOVHEAD, dmadesc[10]);
+
+ at91sam9x5_video_write32(priv,
+ REG_HEOCHER, heocher | REG_HEOCHER_A2QEN);
+@@ -432,20 +439,20 @@ static void at91sam9x5_video_show_buf(struct at91sam9x5_video_priv *priv,
+
+ if (priv->u_planeno >= 0) {
+ at91sam9x5_video_write32(priv,
+- REG_HEOUADDR, dmadesc[3]);
++ REG_HEOUADDR, dmadesc[4]);
+ at91sam9x5_video_write32(priv,
+- REG_HEOUCTRL, dmadesc[4]);
++ REG_HEOUCTRL, dmadesc[5]);
+ at91sam9x5_video_write32(priv,
+- REG_HEOUNEXT, dmadesc[5]);
++ REG_HEOUNEXT, dmadesc[6]);
+ }
+
+ if (priv->v_planeno >= 0) {
+ at91sam9x5_video_write32(priv,
+- REG_HEOVADDR, dmadesc[6]);
++ REG_HEOVADDR, dmadesc[8]);
+ at91sam9x5_video_write32(priv,
+- REG_HEOVCTRL, dmadesc[7]);
++ REG_HEOVCTRL, dmadesc[9]);
+ at91sam9x5_video_write32(priv,
+- REG_HEOVNEXT, dmadesc[8]);
++ REG_HEOVNEXT, dmadesc[10]);
+ }
+
+ at91sam9x5_video_write32(priv, REG_HEOCHER,
+@@ -713,14 +720,15 @@ static int at91sam9x5_video_vb_queue_setup(struct vb2_queue *q,
+ *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.
++ * The last 9 (64 bits aligned) words are used for the 3 dma
++ * descriptors (3 * 32-bit words each).
++ * The additional 64 + 2 * 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;
++ 9 * 32 + 128;
+ priv->plane_size[0] = sizes[0];
+
+ alloc_ctxs[0] = priv->alloc_ctx;
+@@ -787,7 +795,7 @@ static int at91sam9x5_video_vb_buf_prepare(struct vb2_buffer *vb)
+ /* XXX: format-dependant */
+ if (vb->v4l2_planes[0].length < pix->width * pix->height +
+ ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2 +
+- 10 * 32)
++ 9 * 32 + 128)
+ return -EINVAL;
+
+ return 0;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0130-media-at91sam9x5-video-change-scaling-factor-calcula.patch b/patches.at91/0130-media-at91sam9x5-video-change-scaling-factor-calcula.patch
new file mode 100644
index 00000000000000..496f8567b42dcc
--- /dev/null
+++ b/patches.at91/0130-media-at91sam9x5-video-change-scaling-factor-calcula.patch
@@ -0,0 +1,76 @@
+From 08e62ea4aa3af6791f58ccf1012a80682bf7b517 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 16 Oct 2012 18:30:47 +0200
+Subject: media/at91sam9x5-video: change scaling factor calculation
+
+Useful for future revision of the HEO IP
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/media/video/at91sam9x5-video.c | 36 ++++++++++++++++++++++++++++------
+ 1 file changed, 30 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/media/video/at91sam9x5-video.c b/drivers/media/video/at91sam9x5-video.c
+index 9d7e6c5..1e5a0a7 100644
+--- a/drivers/media/video/at91sam9x5-video.c
++++ b/drivers/media/video/at91sam9x5-video.c
+@@ -518,6 +518,19 @@ static void at91sam9x5_video_params(unsigned width, unsigned height,
+ *tloffset = e[ro(0)];
+ }
+
++static void at91sam9x5_video_setup_scaling_coef(
++ struct at91sam9x5_video_priv *priv,
++ unsigned hwxmem_size, unsigned hwxsize,
++ unsigned hwymem_size, unsigned hwysize,
++ unsigned *xphidef, unsigned *yphidef) {}
++
++static void at91sam9x5_video_setup_scaling_factor(
++ unsigned hwmem_size, unsigned hwsize,
++ unsigned phidef, unsigned *factor)
++{
++ *factor = 1024 * hwmem_size / hwsize;
++}
++
+ static void at91sam9x5_video_update_config_real(
+ struct at91sam9x5_video_priv *priv)
+ {
+@@ -529,6 +542,9 @@ static void at91sam9x5_video_update_config_real(
+
+ unsigned hwxpos, hwypos, hwxsize, hwysize;
+ unsigned hwxmem_size, hwymem_size;
++ unsigned xphidef = 0;
++ unsigned yphidef = 0;
++ unsigned xfactor, yfactor;
+ s32 hwxstride, hwpstride;
+ s32 hwuvxstride, hwuvpstride;
+ s32 rotated_pixwidth, rotated_pixheight;
+@@ -600,12 +616,20 @@ static void at91sam9x5_video_update_config_real(
+ 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_setup_scaling_coef(priv,
++ hwxmem_size, hwxsize,
++ hwymem_size, hwysize,
++ &xphidef, &yphidef);
++
++ at91sam9x5_video_setup_scaling_factor(hwxmem_size - 1, hwxsize - 1,
++ xphidef, &xfactor);
++
++ at91sam9x5_video_setup_scaling_factor(hwymem_size - 1, hwysize - 1,
++ yphidef, &yfactor);
++
++ at91sam9x5_video_write32(priv, REG_HEOCFG13, REG_HEOCFG13_SCALEN
++ | valtomask(xfactor, REG_HEOCFG13_XFACTOR)
++ | valtomask(yfactor, REG_HEOCFG13_YFACTOR));
+
+ at91sam9x5_video_params(pix->width, pix->height, priv->rotation,
+ &hwxstride, &hwpstride, &priv->y_offset);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0131-media-at91sam9x5-video-add-device-tree-support.patch b/patches.at91/0131-media-at91sam9x5-video-add-device-tree-support.patch
new file mode 100644
index 00000000000000..97c546f872a985
--- /dev/null
+++ b/patches.at91/0131-media-at91sam9x5-video-add-device-tree-support.patch
@@ -0,0 +1,102 @@
+From 5317bf1e9672b9a7e540e701a724d7d73910a87b Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 16 Oct 2012 18:46:07 +0200
+Subject: media/at91sam9x5-video: add device tree support
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/media/video/at91sam9x5-video.c | 55 +++++++++++-----------------------
+ 1 file changed, 18 insertions(+), 37 deletions(-)
+
+diff --git a/drivers/media/video/at91sam9x5-video.c b/drivers/media/video/at91sam9x5-video.c
+index 1e5a0a7..548aebc 100644
+--- a/drivers/media/video/at91sam9x5-video.c
++++ b/drivers/media/video/at91sam9x5-video.c
+@@ -21,6 +21,8 @@
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
+
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-dev.h>
+@@ -1418,59 +1420,38 @@ static int __devexit at91sam9x5_video_remove(struct platform_device *pdev)
+ return 0;
+ }
+
++#if defined(CONFIG_OF)
++static const struct of_device_id atmel_heo_dt_ids[] = {
++ {
++ .compatible = "atmel,at91sam9x5-heo",
++ .data = (void *)0,
++ }, {
++ /* sentinel */
++ }
++};
++
++MODULE_DEVICE_TABLE(of, atmel_heo_dt_ids);
++#endif
++
+ static struct platform_driver at91sam9x5_video_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(atmel_heo_dt_ids),
+ },
+ .probe = at91sam9x5_video_probe,
+ .remove = __devexit_p(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;
++ return platform_driver_probe(&at91sam9x5_video_driver,
++ &at91sam9x5_video_probe);
+ }
+ 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);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0132-ARM-at91-video-Atmel-HLCD-is-only-selected-by-newer-.patch b/patches.at91/0132-ARM-at91-video-Atmel-HLCD-is-only-selected-by-newer-.patch
new file mode 100644
index 00000000000000..51e04c6ab858a9
--- /dev/null
+++ b/patches.at91/0132-ARM-at91-video-Atmel-HLCD-is-only-selected-by-newer-.patch
@@ -0,0 +1,59 @@
+From 25f953cbb8bf107346227628c0554f9b142b637b Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 18 Jun 2012 14:14:57 +0200
+Subject: ARM: at91/video: Atmel HLCD is only selected by newer products
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/Kconfig | 4 ++--
+ drivers/video/Kconfig | 5 ++++-
+ 2 files changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
+index c8050b1..79d08ed 100644
+--- a/arch/arm/mach-at91/Kconfig
++++ b/arch/arm/mach-at91/Kconfig
+@@ -86,7 +86,7 @@ config SOC_AT91SAM9X5
+ bool "AT91SAM9x5 family"
+ select SOC_AT91SAM9
+ select HAVE_AT91_DBGU0
+- select HAVE_FB_ATMEL
++ select HAVE_FB_ATMEL_HLCD
+ select HAVE_NET_MACB
+ help
+ Select this if you are using one of Atmel's AT91SAM9x5 family SoC.
+@@ -99,7 +99,7 @@ config SOC_AT91SAM9N12
+ bool "AT91SAM9N12 family"
+ select SOC_AT91SAM9
+ select HAVE_AT91_DBGU0
+- select HAVE_FB_ATMEL
++ select HAVE_FB_ATMEL_HLCD
+ help
+ Select this if you are using Atmel's AT91SAM9N12 SoC.
+
+diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
+index ceccaa3..0928c36 100644
+--- a/drivers/video/Kconfig
++++ b/drivers/video/Kconfig
+@@ -8,6 +8,9 @@ menu "Graphics support"
+ config HAVE_FB_ATMEL
+ bool
+
++config HAVE_FB_ATMEL_HLCD
++ bool
++
+ config SH_MIPI_DSI
+ tristate
+ depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK
+@@ -1030,7 +1033,7 @@ config FB_ATMEL_STN
+
+ config FB_ATMEL_HLCD
+ tristate "AT91 HLCD Controller support"
+- depends on FB && HAVE_FB_ATMEL
++ depends on FB && HAVE_FB_ATMEL_HLCD
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0133-mmc-atmel-mci-the-r-w-proof-capability-lack-was-not-.patch b/patches.at91/0133-mmc-atmel-mci-the-r-w-proof-capability-lack-was-not-.patch
new file mode 100644
index 00000000000000..cf0ad036e3099c
--- /dev/null
+++ b/patches.at91/0133-mmc-atmel-mci-the-r-w-proof-capability-lack-was-not-.patch
@@ -0,0 +1,208 @@
+From 3ea2cbea34f1de73412b06cfc95e2c7a06a6aa04 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 16 May 2012 15:25:58 +0200
+Subject: mmc: atmel-mci: the r/w proof capability lack was not well managed
+
+First mci IPs (mainly on rm9200 and 9261) don't have the r/w proof
+capability. The driver didn't work correctly without this capability
+in PDC mode because of the double buffer switch which is too slow
+even if we stop the transfer to perform this switch.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Chris Ball <cjb@laptop.org>
+---
+ drivers/mmc/host/atmel-mci.c | 92 +++++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 78 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index e94476b..6f56ef0 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -91,6 +91,11 @@ struct atmel_mci_dma {
+ * @regs: Pointer to MMIO registers.
+ * @sg: Scatterlist entry currently being processed by PIO or PDC code.
+ * @pio_offset: Offset into the current scatterlist entry.
++ * @buffer: Buffer used if we don't have the r/w proof capability. We
++ * don't have the time to switch pdc buffers so we have to use only
++ * one buffer for the full transaction.
++ * @buf_size: size of the buffer.
++ * @phys_buf_addr: buffer address needed for pdc.
+ * @cur_slot: The slot which is currently using the controller.
+ * @mrq: The request currently being processed on @cur_slot,
+ * or NULL if the controller is idle.
+@@ -166,6 +171,9 @@ struct atmel_mci {
+
+ struct scatterlist *sg;
+ unsigned int pio_offset;
++ unsigned int *buffer;
++ unsigned int buf_size;
++ dma_addr_t buf_phys_addr;
+
+ struct atmel_mci_slot *cur_slot;
+ struct mmc_request *mrq;
+@@ -480,6 +488,11 @@ err:
+ dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
+ }
+
++static inline unsigned int atmci_get_version(struct atmel_mci *host)
++{
++ return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
++}
++
+ static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host,
+ unsigned int ns)
+ {
+@@ -603,6 +616,7 @@ static void atmci_pdc_set_single_buf(struct atmel_mci *host,
+ enum atmci_xfer_dir dir, enum atmci_pdc_buf buf_nb)
+ {
+ u32 pointer_reg, counter_reg;
++ unsigned int buf_size;
+
+ if (dir == XFER_RECEIVE) {
+ pointer_reg = ATMEL_PDC_RPR;
+@@ -617,8 +631,15 @@ static void atmci_pdc_set_single_buf(struct atmel_mci *host,
+ counter_reg += ATMEL_PDC_SCND_BUF_OFF;
+ }
+
+- atmci_writel(host, pointer_reg, sg_dma_address(host->sg));
+- if (host->data_size <= sg_dma_len(host->sg)) {
++ if (!host->caps.has_rwproof) {
++ buf_size = host->buf_size;
++ atmci_writel(host, pointer_reg, host->buf_phys_addr);
++ } else {
++ buf_size = sg_dma_len(host->sg);
++ atmci_writel(host, pointer_reg, sg_dma_address(host->sg));
++ }
++
++ if (host->data_size <= buf_size) {
+ if (host->data_size & 0x3) {
+ /* If size is different from modulo 4, transfer bytes */
+ atmci_writel(host, counter_reg, host->data_size);
+@@ -670,7 +691,15 @@ static void atmci_pdc_cleanup(struct atmel_mci *host)
+ */
+ static void atmci_pdc_complete(struct atmel_mci *host)
+ {
++ int transfer_size = host->data->blocks * host->data->blksz;
++
+ atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
++
++ if ((!host->caps.has_rwproof)
++ && (host->data->flags & MMC_DATA_READ))
++ sg_copy_from_buffer(host->data->sg, host->data->sg_len,
++ host->buffer, transfer_size);
++
+ atmci_pdc_cleanup(host);
+
+ /*
+@@ -818,6 +847,12 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
+ /* Configure PDC */
+ host->data_size = data->blocks * data->blksz;
+ sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, dir);
++
++ if ((!host->caps.has_rwproof)
++ && (host->data->flags & MMC_DATA_WRITE))
++ sg_copy_to_buffer(host->data->sg, host->data->sg_len,
++ host->buffer, host->data_size);
++
+ if (host->data_size)
+ atmci_pdc_set_both_buf(host,
+ ((dir == DMA_FROM_DEVICE) ? XFER_RECEIVE : XFER_TRANSMIT));
+@@ -1877,13 +1912,26 @@ static int __init atmci_init_slot(struct atmel_mci *host,
+ mmc->caps |= MMC_CAP_SDIO_IRQ;
+ if (host->caps.has_highspeed)
+ mmc->caps |= MMC_CAP_SD_HIGHSPEED;
+- if (slot_data->bus_width >= 4)
++ /*
++ * Without the read/write proof capability, it is strongly suggested to
++ * use only one bit for data to prevent fifo underruns and overruns
++ * which will corrupt data.
++ */
++ if ((slot_data->bus_width >= 4) && host->caps.has_rwproof)
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+
+- mmc->max_segs = 64;
+- mmc->max_req_size = 32768 * 512;
+- mmc->max_blk_size = 32768;
+- mmc->max_blk_count = 512;
++ if (atmci_get_version(host) < 0x200) {
++ mmc->max_segs = 256;
++ mmc->max_blk_size = 4095;
++ mmc->max_blk_count = 256;
++ mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
++ mmc->max_seg_size = mmc->max_blk_size * mmc->max_segs;
++ } else {
++ mmc->max_segs = 64;
++ mmc->max_req_size = 32768 * 512;
++ mmc->max_blk_size = 32768;
++ mmc->max_blk_count = 512;
++ }
+
+ /* Assume card is present initially */
+ set_bit(ATMCI_CARD_PRESENT, &slot->flags);
+@@ -2007,11 +2055,6 @@ static bool atmci_configure_dma(struct atmel_mci *host)
+ }
+ }
+
+-static inline unsigned int atmci_get_version(struct atmel_mci *host)
+-{
+- return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
+-}
+-
+ /*
+ * HSMCI (High Speed MCI) module is not fully compatible with MCI module.
+ * HSMCI provides DMA support and a new config register but no more supports
+@@ -2138,14 +2181,20 @@ static int __init atmci_probe(struct platform_device *pdev)
+ if (pdata->slot[0].bus_width) {
+ ret = atmci_init_slot(host, &pdata->slot[0],
+ 0, ATMCI_SDCSEL_SLOT_A, ATMCI_SDIOIRQA);
+- if (!ret)
++ if (!ret) {
+ nr_slots++;
++ host->buf_size = host->slot[0]->mmc->max_req_size;
++ }
+ }
+ if (pdata->slot[1].bus_width) {
+ ret = atmci_init_slot(host, &pdata->slot[1],
+ 1, ATMCI_SDCSEL_SLOT_B, ATMCI_SDIOIRQB);
+- if (!ret)
++ if (!ret) {
+ nr_slots++;
++ if (host->slot[1]->mmc->max_req_size > host->buf_size)
++ host->buf_size =
++ host->slot[1]->mmc->max_req_size;
++ }
+ }
+
+ if (!nr_slots) {
+@@ -2153,6 +2202,17 @@ static int __init atmci_probe(struct platform_device *pdev)
+ goto err_init_slot;
+ }
+
++ if (!host->caps.has_rwproof) {
++ host->buffer = dma_alloc_coherent(&pdev->dev, host->buf_size,
++ &host->buf_phys_addr,
++ GFP_KERNEL);
++ if (!host->buffer) {
++ ret = -ENOMEM;
++ dev_err(&pdev->dev, "buffer allocation failed\n");
++ goto err_init_slot;
++ }
++ }
++
+ dev_info(&pdev->dev,
+ "Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
+ host->mapbase, irq, nr_slots);
+@@ -2179,6 +2239,10 @@ static int __exit atmci_remove(struct platform_device *pdev)
+
+ platform_set_drvdata(pdev, NULL);
+
++ if (host->buffer)
++ dma_free_coherent(&pdev->dev, host->buf_size,
++ host->buffer, host->buf_phys_addr);
++
+ for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
+ if (host->slot[i])
+ atmci_cleanup_slot(host->slot[i], i);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0134-mmc-atmel-mci-change-the-state-machine-for-compatibi.patch b/patches.at91/0134-mmc-atmel-mci-change-the-state-machine-for-compatibi.patch
new file mode 100644
index 00000000000000..b05b19e9bfd16d
--- /dev/null
+++ b/patches.at91/0134-mmc-atmel-mci-change-the-state-machine-for-compatibi.patch
@@ -0,0 +1,469 @@
+From 9f4aec64067d8c95e8f71489090fbf0d04947675 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 16 May 2012 15:25:59 +0200
+Subject: mmc: atmel-mci: change the state machine for compatibility with old
+ IP
+
+The state machine use in atmel-mci can't work with old IP versions
+(< 0x200). This patch allows to have a common state machine for all
+versions in order to remove at91-mci driver only used for old versions.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Chris Ball <cjb@laptop.org>
+---
+ drivers/mmc/host/atmel-mci.c | 278 +++++++++++++++++++++++++------------------
+ 1 file changed, 162 insertions(+), 116 deletions(-)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index 6f56ef0..1baaaebb 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -45,19 +45,19 @@
+ #define ATMCI_DMA_THRESHOLD 16
+
+ enum {
+- EVENT_CMD_COMPLETE = 0,
++ EVENT_CMD_RDY = 0,
+ EVENT_XFER_COMPLETE,
+- EVENT_DATA_COMPLETE,
++ EVENT_NOTBUSY,
+ EVENT_DATA_ERROR,
+ };
+
+ enum atmel_mci_state {
+ STATE_IDLE = 0,
+ STATE_SENDING_CMD,
+- STATE_SENDING_DATA,
+- STATE_DATA_BUSY,
++ STATE_DATA_XFER,
++ STATE_WAITING_NOTBUSY,
+ STATE_SENDING_STOP,
+- STATE_DATA_ERROR,
++ STATE_END_REQUEST,
+ };
+
+ enum atmci_xfer_dir {
+@@ -709,7 +709,6 @@ static void atmci_pdc_complete(struct atmel_mci *host)
+ if (host->data) {
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
+ tasklet_schedule(&host->tasklet);
+- atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
+ }
+ }
+
+@@ -835,7 +834,7 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
+ iflags |= ATMCI_ENDRX | ATMCI_RXBUFF;
+ } else {
+ dir = DMA_TO_DEVICE;
+- iflags |= ATMCI_ENDTX | ATMCI_TXBUFE;
++ iflags |= ATMCI_ENDTX | ATMCI_TXBUFE | ATMCI_BLKE;
+ }
+
+ /* Set BLKLEN */
+@@ -975,8 +974,7 @@ static void atmci_stop_transfer(struct atmel_mci *host)
+ */
+ static void atmci_stop_transfer_pdc(struct atmel_mci *host)
+ {
+- atmci_set_pending(host, EVENT_XFER_COMPLETE);
+- atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
++ atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
+ }
+
+ static void atmci_stop_transfer_dma(struct atmel_mci *host)
+@@ -1012,6 +1010,7 @@ static void atmci_start_request(struct atmel_mci *host,
+
+ host->pending_events = 0;
+ host->completed_events = 0;
++ host->cmd_status = 0;
+ host->data_status = 0;
+
+ if (host->need_reset) {
+@@ -1029,7 +1028,7 @@ static void atmci_start_request(struct atmel_mci *host,
+
+ iflags = atmci_readl(host, ATMCI_IMR);
+ if (iflags & ~(ATMCI_SDIOIRQA | ATMCI_SDIOIRQB))
+- dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n",
++ dev_dbg(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n",
+ iflags);
+
+ if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) {
+@@ -1367,19 +1366,6 @@ static void atmci_command_complete(struct atmel_mci *host,
+ cmd->error = -EIO;
+ else
+ cmd->error = 0;
+-
+- if (cmd->error) {
+- dev_dbg(&host->pdev->dev,
+- "command error: status=0x%08x\n", status);
+-
+- if (cmd->data) {
+- host->stop_transfer(host);
+- host->data = NULL;
+- atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY
+- | ATMCI_TXRDY | ATMCI_RXRDY
+- | ATMCI_DATA_ERROR_FLAGS);
+- }
+- }
+ }
+
+ static void atmci_detect_change(unsigned long data)
+@@ -1442,23 +1428,21 @@ static void atmci_detect_change(unsigned long data)
+ break;
+ case STATE_SENDING_CMD:
+ mrq->cmd->error = -ENOMEDIUM;
+- if (!mrq->data)
+- break;
+- /* fall through */
+- case STATE_SENDING_DATA:
++ if (mrq->data)
++ host->stop_transfer(host);
++ break;
++ case STATE_DATA_XFER:
+ mrq->data->error = -ENOMEDIUM;
+ host->stop_transfer(host);
+ break;
+- case STATE_DATA_BUSY:
+- case STATE_DATA_ERROR:
+- if (mrq->data->error == -EINPROGRESS)
+- mrq->data->error = -ENOMEDIUM;
+- if (!mrq->stop)
+- break;
+- /* fall through */
++ case STATE_WAITING_NOTBUSY:
++ mrq->data->error = -ENOMEDIUM;
++ break;
+ case STATE_SENDING_STOP:
+ mrq->stop->error = -ENOMEDIUM;
+ break;
++ case STATE_END_REQUEST:
++ break;
+ }
+
+ atmci_request_end(host, mrq);
+@@ -1486,7 +1470,6 @@ static void atmci_tasklet_func(unsigned long priv)
+ struct atmel_mci *host = (struct atmel_mci *)priv;
+ struct mmc_request *mrq = host->mrq;
+ struct mmc_data *data = host->data;
+- struct mmc_command *cmd = host->cmd;
+ enum atmel_mci_state state = host->state;
+ enum atmel_mci_state prev_state;
+ u32 status;
+@@ -1508,101 +1491,164 @@ static void atmci_tasklet_func(unsigned long priv)
+ break;
+
+ case STATE_SENDING_CMD:
++ /*
++ * Command has been sent, we are waiting for command
++ * ready. Then we have three next states possible:
++ * END_REQUEST by default, WAITING_NOTBUSY if it's a
++ * command needing it or DATA_XFER if there is data.
++ */
+ if (!atmci_test_and_clear_pending(host,
+- EVENT_CMD_COMPLETE))
++ EVENT_CMD_RDY))
+ break;
+
+ host->cmd = NULL;
+- atmci_set_completed(host, EVENT_CMD_COMPLETE);
++ atmci_set_completed(host, EVENT_CMD_RDY);
+ atmci_command_complete(host, mrq->cmd);
+- if (!mrq->data || cmd->error) {
+- atmci_request_end(host, host->mrq);
+- goto unlock;
+- }
++ if (mrq->data) {
++ /*
++ * If there is a command error don't start
++ * data transfer.
++ */
++ if (mrq->cmd->error) {
++ host->stop_transfer(host);
++ host->data = NULL;
++ atmci_writel(host, ATMCI_IDR,
++ ATMCI_TXRDY | ATMCI_RXRDY
++ | ATMCI_DATA_ERROR_FLAGS);
++ state = STATE_END_REQUEST;
++ } else
++ state = STATE_DATA_XFER;
++ } else if ((!mrq->data) && (mrq->cmd->flags & MMC_RSP_BUSY)) {
++ atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
++ state = STATE_WAITING_NOTBUSY;
++ } else
++ state = STATE_END_REQUEST;
+
+- prev_state = state = STATE_SENDING_DATA;
+- /* fall through */
++ break;
+
+- case STATE_SENDING_DATA:
++ case STATE_DATA_XFER:
+ if (atmci_test_and_clear_pending(host,
+ EVENT_DATA_ERROR)) {
+- host->stop_transfer(host);
+- if (data->stop)
+- atmci_send_stop_cmd(host, data);
+- state = STATE_DATA_ERROR;
++ atmci_set_completed(host, EVENT_DATA_ERROR);
++ state = STATE_END_REQUEST;
+ break;
+ }
+
++ /*
++ * A data transfer is in progress. The event expected
++ * to move to the next state depends of data transfer
++ * type (PDC or DMA). Once transfer done we can move
++ * to the next step which is WAITING_NOTBUSY in write
++ * case and directly SENDING_STOP in read case.
++ */
+ if (!atmci_test_and_clear_pending(host,
+ EVENT_XFER_COMPLETE))
+ break;
+
+ atmci_set_completed(host, EVENT_XFER_COMPLETE);
+- prev_state = state = STATE_DATA_BUSY;
+- /* fall through */
+
+- case STATE_DATA_BUSY:
+- if (!atmci_test_and_clear_pending(host,
+- EVENT_DATA_COMPLETE))
+- break;
+-
+- host->data = NULL;
+- atmci_set_completed(host, EVENT_DATA_COMPLETE);
+- status = host->data_status;
+- if (unlikely(status & ATMCI_DATA_ERROR_FLAGS)) {
+- if (status & ATMCI_DTOE) {
+- dev_dbg(&host->pdev->dev,
+- "data timeout error\n");
+- data->error = -ETIMEDOUT;
+- } else if (status & ATMCI_DCRCE) {
+- dev_dbg(&host->pdev->dev,
+- "data CRC error\n");
+- data->error = -EILSEQ;
+- } else {
+- dev_dbg(&host->pdev->dev,
+- "data FIFO error (status=%08x)\n",
+- status);
+- data->error = -EIO;
+- }
++ if (host->data->flags & MMC_DATA_WRITE) {
++ atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
++ state = STATE_WAITING_NOTBUSY;
++ } else if (host->mrq->stop) {
++ atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY);
++ atmci_send_stop_cmd(host, data);
++ state = STATE_SENDING_STOP;
+ } else {
++ host->data = NULL;
+ data->bytes_xfered = data->blocks * data->blksz;
+ data->error = 0;
+- atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS);
++ state = STATE_END_REQUEST;
+ }
++ break;
+
+- if (!data->stop) {
+- atmci_request_end(host, host->mrq);
+- goto unlock;
+- }
++ case STATE_WAITING_NOTBUSY:
++ /*
++ * We can be in the state for two reasons: a command
++ * requiring waiting not busy signal (stop command
++ * included) or a write operation. In the latest case,
++ * we need to send a stop command.
++ */
++ if (!atmci_test_and_clear_pending(host,
++ EVENT_NOTBUSY))
++ break;
+
+- prev_state = state = STATE_SENDING_STOP;
+- if (!data->error)
+- atmci_send_stop_cmd(host, data);
+- /* fall through */
++ atmci_set_completed(host, EVENT_NOTBUSY);
++
++ if (host->data) {
++ /*
++ * For some commands such as CMD53, even if
++ * there is data transfer, there is no stop
++ * command to send.
++ */
++ if (host->mrq->stop) {
++ atmci_writel(host, ATMCI_IER,
++ ATMCI_CMDRDY);
++ atmci_send_stop_cmd(host, data);
++ state = STATE_SENDING_STOP;
++ } else {
++ host->data = NULL;
++ data->bytes_xfered = data->blocks
++ * data->blksz;
++ data->error = 0;
++ state = STATE_END_REQUEST;
++ }
++ } else
++ state = STATE_END_REQUEST;
++ break;
+
+ case STATE_SENDING_STOP:
++ /*
++ * In this state, it is important to set host->data to
++ * NULL (which is tested in the waiting notbusy state)
++ * in order to go to the end request state instead of
++ * sending stop again.
++ */
+ if (!atmci_test_and_clear_pending(host,
+- EVENT_CMD_COMPLETE))
++ EVENT_CMD_RDY))
+ break;
+
+ host->cmd = NULL;
++ host->data = NULL;
++ data->bytes_xfered = data->blocks * data->blksz;
++ data->error = 0;
+ atmci_command_complete(host, mrq->stop);
+- atmci_request_end(host, host->mrq);
+- goto unlock;
++ if (mrq->stop->error) {
++ host->stop_transfer(host);
++ atmci_writel(host, ATMCI_IDR,
++ ATMCI_TXRDY | ATMCI_RXRDY
++ | ATMCI_DATA_ERROR_FLAGS);
++ state = STATE_END_REQUEST;
++ } else {
++ atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
++ state = STATE_WAITING_NOTBUSY;
++ }
++ break;
+
+- case STATE_DATA_ERROR:
+- if (!atmci_test_and_clear_pending(host,
+- EVENT_XFER_COMPLETE))
+- break;
++ case STATE_END_REQUEST:
++ atmci_writel(host, ATMCI_IDR, ATMCI_TXRDY | ATMCI_RXRDY
++ | ATMCI_DATA_ERROR_FLAGS);
++ status = host->data_status;
++ if (unlikely(status)) {
++ host->stop_transfer(host);
++ host->data = NULL;
++ if (status & ATMCI_DTOE) {
++ data->error = -ETIMEDOUT;
++ } else if (status & ATMCI_DCRCE) {
++ data->error = -EILSEQ;
++ } else {
++ data->error = -EIO;
++ }
++ }
+
+- state = STATE_DATA_BUSY;
++ atmci_request_end(host, host->mrq);
++ state = STATE_IDLE;
+ break;
+ }
+ } while (state != prev_state);
+
+ host->state = state;
+
+-unlock:
+ spin_unlock(&host->lock);
+ }
+
+@@ -1655,9 +1701,6 @@ static void atmci_read_data_pio(struct atmel_mci *host)
+ | ATMCI_DATA_ERROR_FLAGS));
+ host->data_status = status;
+ data->bytes_xfered += nbytes;
+- smp_wmb();
+- atmci_set_pending(host, EVENT_DATA_ERROR);
+- tasklet_schedule(&host->tasklet);
+ return;
+ }
+ } while (status & ATMCI_RXRDY);
+@@ -1726,9 +1769,6 @@ static void atmci_write_data_pio(struct atmel_mci *host)
+ | ATMCI_DATA_ERROR_FLAGS));
+ host->data_status = status;
+ data->bytes_xfered += nbytes;
+- smp_wmb();
+- atmci_set_pending(host, EVENT_DATA_ERROR);
+- tasklet_schedule(&host->tasklet);
+ return;
+ }
+ } while (status & ATMCI_TXRDY);
+@@ -1746,16 +1786,6 @@ done:
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
+ }
+
+-static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status)
+-{
+- atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY);
+-
+- host->cmd_status = status;
+- smp_wmb();
+- atmci_set_pending(host, EVENT_CMD_COMPLETE);
+- tasklet_schedule(&host->tasklet);
+-}
+-
+ static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status)
+ {
+ int i;
+@@ -1784,8 +1814,9 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
+
+ if (pending & ATMCI_DATA_ERROR_FLAGS) {
+ atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS
+- | ATMCI_RXRDY | ATMCI_TXRDY);
+- pending &= atmci_readl(host, ATMCI_IMR);
++ | ATMCI_RXRDY | ATMCI_TXRDY
++ | ATMCI_ENDRX | ATMCI_ENDTX
++ | ATMCI_RXBUFF | ATMCI_TXBUFE);
+
+ host->data_status = status;
+ smp_wmb();
+@@ -1843,23 +1874,38 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
+ }
+ }
+
++ /*
++ * First mci IPs, so mainly the ones having pdc, have some
++ * issues with the notbusy signal. You can't get it after
++ * data transmission if you have not sent a stop command.
++ * The appropriate workaround is to use the BLKE signal.
++ */
++ if (pending & ATMCI_BLKE) {
++ atmci_writel(host, ATMCI_IDR, ATMCI_BLKE);
++ smp_wmb();
++ atmci_set_pending(host, EVENT_NOTBUSY);
++ tasklet_schedule(&host->tasklet);
++ }
+
+ if (pending & ATMCI_NOTBUSY) {
+- atmci_writel(host, ATMCI_IDR,
+- ATMCI_DATA_ERROR_FLAGS | ATMCI_NOTBUSY);
+- if (!host->data_status)
+- host->data_status = status;
++ atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY);
+ smp_wmb();
+- atmci_set_pending(host, EVENT_DATA_COMPLETE);
++ atmci_set_pending(host, EVENT_NOTBUSY);
+ tasklet_schedule(&host->tasklet);
+ }
++
+ if (pending & ATMCI_RXRDY)
+ atmci_read_data_pio(host);
+ if (pending & ATMCI_TXRDY)
+ atmci_write_data_pio(host);
+
+- if (pending & ATMCI_CMDRDY)
+- atmci_cmd_interrupt(host, status);
++ if (pending & ATMCI_CMDRDY) {
++ atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY);
++ host->cmd_status = status;
++ smp_wmb();
++ atmci_set_pending(host, EVENT_CMD_RDY);
++ tasklet_schedule(&host->tasklet);
++ }
+
+ if (pending & (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB))
+ atmci_sdio_interrupt(host, status);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0135-mmc-atmel-mci-add-support-for-version-lower-than-v2x.patch b/patches.at91/0135-mmc-atmel-mci-add-support-for-version-lower-than-v2x.patch
new file mode 100644
index 00000000000000..2ebd933ba7e085
--- /dev/null
+++ b/patches.at91/0135-mmc-atmel-mci-add-support-for-version-lower-than-v2x.patch
@@ -0,0 +1,189 @@
+From d243a7c47bee93f8dc2544dbd26ce7b5dd879e96 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 16 May 2012 15:26:00 +0200
+Subject: mmc: atmel-mci: add support for version lower than v2xx
+
+Fix mci IP bugs and endianness issue.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Chris Ball <cjb@laptop.org>
+---
+ drivers/mmc/host/atmel-mci.c | 62 +++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 58 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index 1baaaebb..5fe8300 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -78,6 +78,9 @@ struct atmel_mci_caps {
+ bool has_highspeed;
+ bool has_rwproof;
+ bool has_odd_clk_div;
++ bool has_bad_data_ordering;
++ bool need_reset_after_xfer;
++ bool need_blksz_mul_4;
+ };
+
+ struct atmel_mci_dma {
+@@ -121,6 +124,7 @@ struct atmel_mci_dma {
+ * @queue: List of slots waiting for access to the controller.
+ * @need_clock_update: Update the clock rate before the next request.
+ * @need_reset: Reset controller before next request.
++ * @timer: Timer to balance the data timeout error flag which cannot rise.
+ * @mode_reg: Value of the MR register.
+ * @cfg_reg: Value of the CFG register.
+ * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus
+@@ -197,6 +201,7 @@ struct atmel_mci {
+
+ bool need_clock_update;
+ bool need_reset;
++ struct timer_list timer;
+ u32 mode_reg;
+ u32 cfg_reg;
+ unsigned long bus_hz;
+@@ -493,6 +498,27 @@ static inline unsigned int atmci_get_version(struct atmel_mci *host)
+ return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
+ }
+
++static void atmci_timeout_timer(unsigned long data)
++{
++ struct atmel_mci *host;
++
++ host = (struct atmel_mci *)data;
++
++ dev_dbg(&host->pdev->dev, "software timeout\n");
++
++ if (host->mrq->cmd->data) {
++ host->mrq->cmd->data->error = -ETIMEDOUT;
++ host->data = NULL;
++ } else {
++ host->mrq->cmd->error = -ETIMEDOUT;
++ host->cmd = NULL;
++ }
++ host->need_reset = 1;
++ host->state = STATE_END_REQUEST;
++ smp_wmb();
++ tasklet_schedule(&host->tasklet);
++}
++
+ static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host,
+ unsigned int ns)
+ {
+@@ -692,13 +718,18 @@ static void atmci_pdc_cleanup(struct atmel_mci *host)
+ static void atmci_pdc_complete(struct atmel_mci *host)
+ {
+ int transfer_size = host->data->blocks * host->data->blksz;
++ int i;
+
+ atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
+
+ if ((!host->caps.has_rwproof)
+- && (host->data->flags & MMC_DATA_READ))
++ && (host->data->flags & MMC_DATA_READ)) {
++ if (host->caps.has_bad_data_ordering)
++ for (i = 0; i < transfer_size; i++)
++ host->buffer[i] = swab32(host->buffer[i]);
+ sg_copy_from_buffer(host->data->sg, host->data->sg_len,
+ host->buffer, transfer_size);
++ }
+
+ atmci_pdc_cleanup(host);
+
+@@ -819,6 +850,7 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
+ u32 iflags, tmp;
+ unsigned int sg_len;
+ enum dma_data_direction dir;
++ int i;
+
+ data->error = -EINPROGRESS;
+
+@@ -848,9 +880,13 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
+ sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, dir);
+
+ if ((!host->caps.has_rwproof)
+- && (host->data->flags & MMC_DATA_WRITE))
++ && (host->data->flags & MMC_DATA_WRITE)) {
+ sg_copy_to_buffer(host->data->sg, host->data->sg_len,
+ host->buffer, host->data_size);
++ if (host->caps.has_bad_data_ordering)
++ for (i = 0; i < host->data_size; i++)
++ host->buffer[i] = swab32(host->buffer[i]);
++ }
+
+ if (host->data_size)
+ atmci_pdc_set_both_buf(host,
+@@ -1013,7 +1049,7 @@ static void atmci_start_request(struct atmel_mci *host,
+ host->cmd_status = 0;
+ host->data_status = 0;
+
+- if (host->need_reset) {
++ if (host->need_reset || host->caps.need_reset_after_xfer) {
+ iflags = atmci_readl(host, ATMCI_IMR);
+ iflags &= (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB);
+ atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
+@@ -1077,6 +1113,8 @@ static void atmci_start_request(struct atmel_mci *host,
+ * prepared yet.)
+ */
+ atmci_writel(host, ATMCI_IER, iflags);
++
++ mod_timer(&host->timer, jiffies + msecs_to_jiffies(2000));
+ }
+
+ static void atmci_queue_request(struct atmel_mci *host,
+@@ -1342,6 +1380,8 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)
+ host->state = STATE_IDLE;
+ }
+
++ del_timer(&host->timer);
++
+ spin_unlock(&host->lock);
+ mmc_request_done(prev_mmc, mrq);
+ spin_lock(&host->lock);
+@@ -1364,7 +1404,12 @@ static void atmci_command_complete(struct atmel_mci *host,
+ cmd->error = -EILSEQ;
+ else if (status & (ATMCI_RINDE | ATMCI_RDIRE | ATMCI_RENDE))
+ cmd->error = -EIO;
+- else
++ else if (host->mrq->data && (host->mrq->data->blksz & 3)) {
++ if (host->caps.need_blksz_mul_4) {
++ cmd->error = -EINVAL;
++ host->need_reset = 1;
++ }
++ } else
+ cmd->error = 0;
+ }
+
+@@ -2121,6 +2166,9 @@ static void __init atmci_get_cap(struct atmel_mci *host)
+ host->caps.has_highspeed = 0;
+ host->caps.has_rwproof = 0;
+ host->caps.has_odd_clk_div = 0;
++ host->caps.has_bad_data_ordering = 1;
++ host->caps.need_reset_after_xfer = 1;
++ host->caps.need_blksz_mul_4 = 1;
+
+ /* keep only major version number */
+ switch (version & 0xf00) {
+@@ -2140,7 +2188,11 @@ static void __init atmci_get_cap(struct atmel_mci *host)
+ host->caps.has_highspeed = 1;
+ case 0x200:
+ host->caps.has_rwproof = 1;
++ host->caps.need_blksz_mul_4 = 0;
+ case 0x100:
++ host->caps.has_bad_data_ordering = 0;
++ host->caps.need_reset_after_xfer = 0;
++ case 0x0:
+ break;
+ default:
+ host->caps.has_pdc = 0;
+@@ -2259,6 +2311,8 @@ static int __init atmci_probe(struct platform_device *pdev)
+ }
+ }
+
++ setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host);
++
+ dev_info(&pdev->dev,
+ "Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
+ host->mapbase, irq, nr_slots);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0136-mmc-atmel-mci-add-debug-logs.patch b/patches.at91/0136-mmc-atmel-mci-add-debug-logs.patch
new file mode 100644
index 00000000000000..f3108718390678
--- /dev/null
+++ b/patches.at91/0136-mmc-atmel-mci-add-debug-logs.patch
@@ -0,0 +1,250 @@
+From 630d7210859cec33916489d29cced3150b017bee Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 16 May 2012 15:26:01 +0200
+Subject: mmc: atmel-mci: add debug logs
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Chris Ball <cjb@laptop.org>
+---
+ drivers/mmc/host/atmel-mci.c | 41 +++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 41 insertions(+)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index 5fe8300..420aca6 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -630,6 +630,7 @@ static void atmci_send_command(struct atmel_mci *host,
+
+ static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data)
+ {
++ dev_dbg(&host->pdev->dev, "send stop command\n");
+ atmci_send_command(host, data->stop, host->stop_cmdr);
+ atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY);
+ }
+@@ -738,6 +739,8 @@ static void atmci_pdc_complete(struct atmel_mci *host)
+ * to send the stop command or waiting for NBUSY in this case.
+ */
+ if (host->data) {
++ dev_dbg(&host->pdev->dev,
++ "(%s) set pending xfer complete\n", __func__);
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
+ tasklet_schedule(&host->tasklet);
+ }
+@@ -775,6 +778,8 @@ static void atmci_dma_complete(void *arg)
+ * to send the stop command or waiting for NBUSY in this case.
+ */
+ if (data) {
++ dev_dbg(&host->pdev->dev,
++ "(%s) set pending xfer complete\n", __func__);
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
+ tasklet_schedule(&host->tasklet);
+
+@@ -1001,6 +1006,8 @@ atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)
+
+ static void atmci_stop_transfer(struct atmel_mci *host)
+ {
++ dev_dbg(&host->pdev->dev,
++ "(%s) set pending xfer complete\n", __func__);
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
+ atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
+ }
+@@ -1022,6 +1029,8 @@ static void atmci_stop_transfer_dma(struct atmel_mci *host)
+ atmci_dma_cleanup(host);
+ } else {
+ /* Data transfer was stopped by the interrupt handler */
++ dev_dbg(&host->pdev->dev,
++ "(%s) set pending xfer complete\n", __func__);
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
+ atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
+ }
+@@ -1049,6 +1058,8 @@ static void atmci_start_request(struct atmel_mci *host,
+ host->cmd_status = 0;
+ host->data_status = 0;
+
++ dev_dbg(&host->pdev->dev, "start request: cmd %u\n", mrq->cmd->opcode);
++
+ if (host->need_reset || host->caps.need_reset_after_xfer) {
+ iflags = atmci_readl(host, ATMCI_IMR);
+ iflags &= (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB);
+@@ -1129,6 +1140,7 @@ static void atmci_queue_request(struct atmel_mci *host,
+ host->state = STATE_SENDING_CMD;
+ atmci_start_request(host, slot);
+ } else {
++ dev_dbg(&host->pdev->dev, "queue request\n");
+ list_add_tail(&slot->queue_node, &host->queue);
+ }
+ spin_unlock_bh(&host->lock);
+@@ -1141,6 +1153,7 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+ struct mmc_data *data;
+
+ WARN_ON(slot->mrq);
++ dev_dbg(&host->pdev->dev, "MRQ: cmd %u\n", mrq->cmd->opcode);
+
+ /*
+ * We may "know" the card is gone even though there's still an
+@@ -1530,6 +1543,7 @@ static void atmci_tasklet_func(unsigned long priv)
+
+ do {
+ prev_state = state;
++ dev_dbg(&host->pdev->dev, "FSM: state=%d\n", state);
+
+ switch (state) {
+ case STATE_IDLE:
+@@ -1542,14 +1556,18 @@ static void atmci_tasklet_func(unsigned long priv)
+ * END_REQUEST by default, WAITING_NOTBUSY if it's a
+ * command needing it or DATA_XFER if there is data.
+ */
++ dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n");
+ if (!atmci_test_and_clear_pending(host,
+ EVENT_CMD_RDY))
+ break;
+
++ dev_dbg(&host->pdev->dev, "set completed cmd ready\n");
+ host->cmd = NULL;
+ atmci_set_completed(host, EVENT_CMD_RDY);
+ atmci_command_complete(host, mrq->cmd);
+ if (mrq->data) {
++ dev_dbg(&host->pdev->dev,
++ "command with data transfer");
+ /*
+ * If there is a command error don't start
+ * data transfer.
+@@ -1564,6 +1582,8 @@ static void atmci_tasklet_func(unsigned long priv)
+ } else
+ state = STATE_DATA_XFER;
+ } else if ((!mrq->data) && (mrq->cmd->flags & MMC_RSP_BUSY)) {
++ dev_dbg(&host->pdev->dev,
++ "command response need waiting notbusy");
+ atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
+ state = STATE_WAITING_NOTBUSY;
+ } else
+@@ -1574,6 +1594,7 @@ static void atmci_tasklet_func(unsigned long priv)
+ case STATE_DATA_XFER:
+ if (atmci_test_and_clear_pending(host,
+ EVENT_DATA_ERROR)) {
++ dev_dbg(&host->pdev->dev, "set completed data error\n");
+ atmci_set_completed(host, EVENT_DATA_ERROR);
+ state = STATE_END_REQUEST;
+ break;
+@@ -1586,10 +1607,14 @@ static void atmci_tasklet_func(unsigned long priv)
+ * to the next step which is WAITING_NOTBUSY in write
+ * case and directly SENDING_STOP in read case.
+ */
++ dev_dbg(&host->pdev->dev, "FSM: xfer complete?\n");
+ if (!atmci_test_and_clear_pending(host,
+ EVENT_XFER_COMPLETE))
+ break;
+
++ dev_dbg(&host->pdev->dev,
++ "(%s) set completed xfer complete\n",
++ __func__);
+ atmci_set_completed(host, EVENT_XFER_COMPLETE);
+
+ if (host->data->flags & MMC_DATA_WRITE) {
+@@ -1614,10 +1639,12 @@ static void atmci_tasklet_func(unsigned long priv)
+ * included) or a write operation. In the latest case,
+ * we need to send a stop command.
+ */
++ dev_dbg(&host->pdev->dev, "FSM: not busy?\n");
+ if (!atmci_test_and_clear_pending(host,
+ EVENT_NOTBUSY))
+ break;
+
++ dev_dbg(&host->pdev->dev, "set completed not busy\n");
+ atmci_set_completed(host, EVENT_NOTBUSY);
+
+ if (host->data) {
+@@ -1649,10 +1676,12 @@ static void atmci_tasklet_func(unsigned long priv)
+ * in order to go to the end request state instead of
+ * sending stop again.
+ */
++ dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n");
+ if (!atmci_test_and_clear_pending(host,
+ EVENT_CMD_RDY))
+ break;
+
++ dev_dbg(&host->pdev->dev, "FSM: cmd ready\n");
+ host->cmd = NULL;
+ host->data = NULL;
+ data->bytes_xfered = data->blocks * data->blksz;
+@@ -1858,18 +1887,21 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
+ break;
+
+ if (pending & ATMCI_DATA_ERROR_FLAGS) {
++ dev_dbg(&host->pdev->dev, "IRQ: data error\n");
+ atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS
+ | ATMCI_RXRDY | ATMCI_TXRDY
+ | ATMCI_ENDRX | ATMCI_ENDTX
+ | ATMCI_RXBUFF | ATMCI_TXBUFE);
+
+ host->data_status = status;
++ dev_dbg(&host->pdev->dev, "set pending data error\n");
+ smp_wmb();
+ atmci_set_pending(host, EVENT_DATA_ERROR);
+ tasklet_schedule(&host->tasklet);
+ }
+
+ if (pending & ATMCI_TXBUFE) {
++ dev_dbg(&host->pdev->dev, "IRQ: tx buffer empty\n");
+ atmci_writel(host, ATMCI_IDR, ATMCI_TXBUFE);
+ atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX);
+ /*
+@@ -1885,6 +1917,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
+ atmci_pdc_complete(host);
+ }
+ } else if (pending & ATMCI_ENDTX) {
++ dev_dbg(&host->pdev->dev, "IRQ: end of tx buffer\n");
+ atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX);
+
+ if (host->data_size) {
+@@ -1895,6 +1928,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
+ }
+
+ if (pending & ATMCI_RXBUFF) {
++ dev_dbg(&host->pdev->dev, "IRQ: rx buffer full\n");
+ atmci_writel(host, ATMCI_IDR, ATMCI_RXBUFF);
+ atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX);
+ /*
+@@ -1910,6 +1944,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
+ atmci_pdc_complete(host);
+ }
+ } else if (pending & ATMCI_ENDRX) {
++ dev_dbg(&host->pdev->dev, "IRQ: end of rx buffer\n");
+ atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX);
+
+ if (host->data_size) {
+@@ -1926,15 +1961,19 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
+ * The appropriate workaround is to use the BLKE signal.
+ */
+ if (pending & ATMCI_BLKE) {
++ dev_dbg(&host->pdev->dev, "IRQ: blke\n");
+ atmci_writel(host, ATMCI_IDR, ATMCI_BLKE);
+ smp_wmb();
++ dev_dbg(&host->pdev->dev, "set pending notbusy\n");
+ atmci_set_pending(host, EVENT_NOTBUSY);
+ tasklet_schedule(&host->tasklet);
+ }
+
+ if (pending & ATMCI_NOTBUSY) {
++ dev_dbg(&host->pdev->dev, "IRQ: not_busy\n");
+ atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY);
+ smp_wmb();
++ dev_dbg(&host->pdev->dev, "set pending notbusy\n");
+ atmci_set_pending(host, EVENT_NOTBUSY);
+ tasklet_schedule(&host->tasklet);
+ }
+@@ -1945,9 +1984,11 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
+ atmci_write_data_pio(host);
+
+ if (pending & ATMCI_CMDRDY) {
++ dev_dbg(&host->pdev->dev, "IRQ: cmd ready\n");
+ atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY);
+ host->cmd_status = status;
+ smp_wmb();
++ dev_dbg(&host->pdev->dev, "set pending cmd rdy\n");
+ atmci_set_pending(host, EVENT_CMD_RDY);
+ tasklet_schedule(&host->tasklet);
+ }
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0137-mmc-atmel-mci-fix-data-timeout-issue.patch b/patches.at91/0137-mmc-atmel-mci-fix-data-timeout-issue.patch
new file mode 100644
index 00000000000000..6963d4f412ae5c
--- /dev/null
+++ b/patches.at91/0137-mmc-atmel-mci-fix-data-timeout-issue.patch
@@ -0,0 +1,39 @@
+From 20b33d7617155ab35517ac63b8a2f839ca3f935b Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 23 May 2012 15:46:00 +0200
+Subject: mmc: atmel-mci: fix data timeout issue
+
+The data timeout timer was configured after mmc_add_host call. So, with bad
+timings, it was possible to have a mmc request causing mod_timer call on a
+non setup timer.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ drivers/mmc/host/atmel-mci.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index 420aca6..456c077 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -2314,6 +2314,8 @@ static int __init atmci_probe(struct platform_device *pdev)
+
+ platform_set_drvdata(pdev, host);
+
++ setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host);
++
+ /* We need at least one slot to succeed */
+ nr_slots = 0;
+ ret = -ENODEV;
+@@ -2352,8 +2354,6 @@ static int __init atmci_probe(struct platform_device *pdev)
+ }
+ }
+
+- setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host);
+-
+ dev_info(&pdev->dev,
+ "Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
+ host->mapbase, irq, nr_slots);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0138-ARM-at91-add-atmel-mci-support-for-chips-and-boards-.patch b/patches.at91/0138-ARM-at91-add-atmel-mci-support-for-chips-and-boards-.patch
new file mode 100644
index 00000000000000..30d19734e188eb
--- /dev/null
+++ b/patches.at91/0138-ARM-at91-add-atmel-mci-support-for-chips-and-boards-.patch
@@ -0,0 +1,1554 @@
+From aeb632c71d6bdbf80b969863edb9f4a0b5b02945 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Mon, 21 May 2012 12:23:27 +0200
+Subject: ARM: at91: add atmel-mci support for chips and boards which can use
+ it
+
+Since atmel-mci driver supports all atmel mci versions,
+use it instead of the deprecated at91_mci driver.
+Platform data and all related configuration are removed.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+[nicolas.ferre@atmel.com: remove at91_mci platform data]
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/at91rm9200_devices.c | 92 ++++++++++--------
+ arch/arm/mach-at91/at91sam9260_devices.c | 84 +---------------
+ arch/arm/mach-at91/at91sam9261_devices.c | 60 ++++++------
+ arch/arm/mach-at91/at91sam9263.c | 4 +-
+ arch/arm/mach-at91/at91sam9263_devices.c | 161 ++++++++++++++++++-------------
+ arch/arm/mach-at91/at91sam9rl_devices.c | 60 ++++++------
+ arch/arm/mach-at91/board-afeb-9260v1.c | 14 +--
+ arch/arm/mach-at91/board-carmeva.c | 14 +--
+ arch/arm/mach-at91/board-cpu9krea.c | 14 +--
+ arch/arm/mach-at91/board-cpuat91.c | 13 +--
+ arch/arm/mach-at91/board-csb337.c | 14 +--
+ arch/arm/mach-at91/board-eb9200.c | 14 +--
+ arch/arm/mach-at91/board-ecbat91.c | 14 +--
+ arch/arm/mach-at91/board-eco920.c | 14 +--
+ arch/arm/mach-at91/board-flexibity.c | 14 +--
+ arch/arm/mach-at91/board-foxg20.c | 16 +--
+ arch/arm/mach-at91/board-kb9202.c | 14 +--
+ arch/arm/mach-at91/board-neocore926.c | 13 +--
+ arch/arm/mach-at91/board-picotux200.c | 14 +--
+ arch/arm/mach-at91/board-qil-a9260.c | 14 +--
+ arch/arm/mach-at91/board-rm9200dk.c | 14 +--
+ arch/arm/mach-at91/board-rm9200ek.c | 14 +--
+ arch/arm/mach-at91/board-rsi-ews.c | 13 +--
+ arch/arm/mach-at91/board-sam9-l9260.c | 16 +--
+ arch/arm/mach-at91/board-sam9260ek.c | 16 +--
+ arch/arm/mach-at91/board-sam9261ek.c | 13 +--
+ arch/arm/mach-at91/board-sam9263ek.c | 13 +--
+ arch/arm/mach-at91/board-sam9g20ek.c | 16 +--
+ arch/arm/mach-at91/board-sam9rlek.c | 13 +--
+ arch/arm/mach-at91/board-stamp9g20.c | 14 ---
+ arch/arm/mach-at91/board-usb-a926x.c | 2 -
+ arch/arm/mach-at91/board-yl-9200.c | 13 +--
+ 32 files changed, 375 insertions(+), 439 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
+index 01fb732..9ac427a 100644
+--- a/arch/arm/mach-at91/at91rm9200_devices.c
++++ b/arch/arm/mach-at91/at91rm9200_devices.c
+@@ -294,9 +294,9 @@ void __init at91_add_device_cf(struct at91_cf_data *data) {}
+ * MMC / SD
+ * -------------------------------------------------------------------- */
+
+-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
++#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
+ static u64 mmc_dmamask = DMA_BIT_MASK(32);
+-static struct at91_mmc_data mmc_data;
++static struct mci_platform_data mmc_data;
+
+ static struct resource mmc_resources[] = {
+ [0] = {
+@@ -312,7 +312,7 @@ static struct resource mmc_resources[] = {
+ };
+
+ static struct platform_device at91rm9200_mmc_device = {
+- .name = "at91_mci",
++ .name = "atmel_mci",
+ .id = -1,
+ .dev = {
+ .dma_mask = &mmc_dmamask,
+@@ -323,53 +323,69 @@ static struct platform_device at91rm9200_mmc_device = {
+ .num_resources = ARRAY_SIZE(mmc_resources),
+ };
+
+-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
++void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
+ {
++ unsigned int i;
++ unsigned int slot_count = 0;
++
+ if (!data)
+ return;
+
+- /* input/irq */
+- if (gpio_is_valid(data->det_pin)) {
+- at91_set_gpio_input(data->det_pin, 1);
+- at91_set_deglitch(data->det_pin, 1);
+- }
+- if (gpio_is_valid(data->wp_pin))
+- at91_set_gpio_input(data->wp_pin, 1);
+- if (gpio_is_valid(data->vcc_pin))
+- at91_set_gpio_output(data->vcc_pin, 0);
+-
+- /* CLK */
+- at91_set_A_periph(AT91_PIN_PA27, 0);
++ for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
+
+- if (data->slot_b) {
+- /* CMD */
+- at91_set_B_periph(AT91_PIN_PA8, 1);
++ if (!data->slot[i].bus_width)
++ continue;
+
+- /* DAT0, maybe DAT1..DAT3 */
+- at91_set_B_periph(AT91_PIN_PA9, 1);
+- if (data->wire4) {
+- at91_set_B_periph(AT91_PIN_PA10, 1);
+- at91_set_B_periph(AT91_PIN_PA11, 1);
+- at91_set_B_periph(AT91_PIN_PA12, 1);
++ /* input/irq */
++ if (gpio_is_valid(data->slot[i].detect_pin)) {
++ at91_set_gpio_input(data->slot[i].detect_pin, 1);
++ at91_set_deglitch(data->slot[i].detect_pin, 1);
+ }
+- } else {
+- /* CMD */
+- at91_set_A_periph(AT91_PIN_PA28, 1);
+-
+- /* DAT0, maybe DAT1..DAT3 */
+- at91_set_A_periph(AT91_PIN_PA29, 1);
+- if (data->wire4) {
+- at91_set_B_periph(AT91_PIN_PB3, 1);
+- at91_set_B_periph(AT91_PIN_PB4, 1);
+- at91_set_B_periph(AT91_PIN_PB5, 1);
++ if (gpio_is_valid(data->slot[i].wp_pin))
++ at91_set_gpio_input(data->slot[i].wp_pin, 1);
++
++ switch (i) {
++ case 0: /* slot A */
++ /* CMD */
++ at91_set_A_periph(AT91_PIN_PA28, 1);
++ /* DAT0, maybe DAT1..DAT3 */
++ at91_set_A_periph(AT91_PIN_PA29, 1);
++ if (data->slot[i].bus_width == 4) {
++ at91_set_B_periph(AT91_PIN_PB3, 1);
++ at91_set_B_periph(AT91_PIN_PB4, 1);
++ at91_set_B_periph(AT91_PIN_PB5, 1);
++ }
++ slot_count++;
++ break;
++ case 1: /* slot B */
++ /* CMD */
++ at91_set_B_periph(AT91_PIN_PA8, 1);
++ /* DAT0, maybe DAT1..DAT3 */
++ at91_set_B_periph(AT91_PIN_PA9, 1);
++ if (data->slot[i].bus_width == 4) {
++ at91_set_B_periph(AT91_PIN_PA10, 1);
++ at91_set_B_periph(AT91_PIN_PA11, 1);
++ at91_set_B_periph(AT91_PIN_PA12, 1);
++ }
++ slot_count++;
++ break;
++ default:
++ printk(KERN_ERR
++ "AT91: SD/MMC slot %d not available\n", i);
++ break;
++ }
++ if (slot_count) {
++ /* CLK */
++ at91_set_A_periph(AT91_PIN_PA27, 0);
++
++ mmc_data = *data;
++ platform_device_register(&at91rm9200_mmc_device);
+ }
+ }
+
+- mmc_data = *data;
+- platform_device_register(&at91rm9200_mmc_device);
+ }
+ #else
+-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
++void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
+ #endif
+
+
+diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
+index 43e60fb..2c54662 100644
+--- a/arch/arm/mach-at91/at91sam9260_devices.c
++++ b/arch/arm/mach-at91/at91sam9260_devices.c
+@@ -206,92 +206,10 @@ void __init at91_add_device_eth(struct macb_platform_data *data) {}
+
+
+ /* --------------------------------------------------------------------
+- * MMC / SD
+- * -------------------------------------------------------------------- */
+-
+-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
+-static u64 mmc_dmamask = DMA_BIT_MASK(32);
+-static struct at91_mmc_data mmc_data;
+-
+-static struct resource mmc_resources[] = {
+- [0] = {
+- .start = AT91SAM9260_BASE_MCI,
+- .end = AT91SAM9260_BASE_MCI + SZ_16K - 1,
+- .flags = IORESOURCE_MEM,
+- },
+- [1] = {
+- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
+- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
+- .flags = IORESOURCE_IRQ,
+- },
+-};
+-
+-static struct platform_device at91sam9260_mmc_device = {
+- .name = "at91_mci",
+- .id = -1,
+- .dev = {
+- .dma_mask = &mmc_dmamask,
+- .coherent_dma_mask = DMA_BIT_MASK(32),
+- .platform_data = &mmc_data,
+- },
+- .resource = mmc_resources,
+- .num_resources = ARRAY_SIZE(mmc_resources),
+-};
+-
+-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
+-{
+- if (!data)
+- return;
+-
+- /* input/irq */
+- if (gpio_is_valid(data->det_pin)) {
+- at91_set_gpio_input(data->det_pin, 1);
+- at91_set_deglitch(data->det_pin, 1);
+- }
+- if (gpio_is_valid(data->wp_pin))
+- at91_set_gpio_input(data->wp_pin, 1);
+- if (gpio_is_valid(data->vcc_pin))
+- at91_set_gpio_output(data->vcc_pin, 0);
+-
+- /* CLK */
+- at91_set_A_periph(AT91_PIN_PA8, 0);
+-
+- if (data->slot_b) {
+- /* CMD */
+- at91_set_B_periph(AT91_PIN_PA1, 1);
+-
+- /* DAT0, maybe DAT1..DAT3 */
+- at91_set_B_periph(AT91_PIN_PA0, 1);
+- if (data->wire4) {
+- at91_set_B_periph(AT91_PIN_PA5, 1);
+- at91_set_B_periph(AT91_PIN_PA4, 1);
+- at91_set_B_periph(AT91_PIN_PA3, 1);
+- }
+- } else {
+- /* CMD */
+- at91_set_A_periph(AT91_PIN_PA7, 1);
+-
+- /* DAT0, maybe DAT1..DAT3 */
+- at91_set_A_periph(AT91_PIN_PA6, 1);
+- if (data->wire4) {
+- at91_set_A_periph(AT91_PIN_PA9, 1);
+- at91_set_A_periph(AT91_PIN_PA10, 1);
+- at91_set_A_periph(AT91_PIN_PA11, 1);
+- }
+- }
+-
+- mmc_data = *data;
+- platform_device_register(&at91sam9260_mmc_device);
+-}
+-#else
+-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
+-#endif
+-
+-/* --------------------------------------------------------------------
+ * MMC / SD Slot for Atmel MCI Driver
+ * -------------------------------------------------------------------- */
+
+-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
++#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
+ static u64 mmc_dmamask = DMA_BIT_MASK(32);
+ static struct mci_platform_data mmc_data;
+
+diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
+index 1eecff8..08b3b02 100644
+--- a/arch/arm/mach-at91/at91sam9261_devices.c
++++ b/arch/arm/mach-at91/at91sam9261_devices.c
+@@ -139,9 +139,9 @@ void __init at91_add_device_udc(struct at91_udc_data *data) {}
+ * MMC / SD
+ * -------------------------------------------------------------------- */
+
+-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
++#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
+ static u64 mmc_dmamask = DMA_BIT_MASK(32);
+-static struct at91_mmc_data mmc_data;
++static struct mci_platform_data mmc_data;
+
+ static struct resource mmc_resources[] = {
+ [0] = {
+@@ -157,7 +157,7 @@ static struct resource mmc_resources[] = {
+ };
+
+ static struct platform_device at91sam9261_mmc_device = {
+- .name = "at91_mci",
++ .name = "atmel_mci",
+ .id = -1,
+ .dev = {
+ .dma_mask = &mmc_dmamask,
+@@ -168,40 +168,40 @@ static struct platform_device at91sam9261_mmc_device = {
+ .num_resources = ARRAY_SIZE(mmc_resources),
+ };
+
+-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
++void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
+ {
+ if (!data)
+ return;
+
+- /* input/irq */
+- if (gpio_is_valid(data->det_pin)) {
+- at91_set_gpio_input(data->det_pin, 1);
+- at91_set_deglitch(data->det_pin, 1);
+- }
+- if (gpio_is_valid(data->wp_pin))
+- at91_set_gpio_input(data->wp_pin, 1);
+- if (gpio_is_valid(data->vcc_pin))
+- at91_set_gpio_output(data->vcc_pin, 0);
+-
+- /* CLK */
+- at91_set_B_periph(AT91_PIN_PA2, 0);
+-
+- /* CMD */
+- at91_set_B_periph(AT91_PIN_PA1, 1);
+-
+- /* DAT0, maybe DAT1..DAT3 */
+- at91_set_B_periph(AT91_PIN_PA0, 1);
+- if (data->wire4) {
+- at91_set_B_periph(AT91_PIN_PA4, 1);
+- at91_set_B_periph(AT91_PIN_PA5, 1);
+- at91_set_B_periph(AT91_PIN_PA6, 1);
+- }
++ if (data->slot[0].bus_width) {
++ /* input/irq */
++ if (gpio_is_valid(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 (gpio_is_valid(data->slot[0].wp_pin))
++ at91_set_gpio_input(data->slot[0].wp_pin, 1);
++
++ /* CLK */
++ at91_set_B_periph(AT91_PIN_PA2, 0);
+
+- mmc_data = *data;
+- platform_device_register(&at91sam9261_mmc_device);
++ /* CMD */
++ at91_set_B_periph(AT91_PIN_PA1, 1);
++
++ /* DAT0, maybe DAT1..DAT3 */
++ at91_set_B_periph(AT91_PIN_PA0, 1);
++ if (data->slot[0].bus_width == 4) {
++ at91_set_B_periph(AT91_PIN_PA4, 1);
++ at91_set_B_periph(AT91_PIN_PA5, 1);
++ at91_set_B_periph(AT91_PIN_PA6, 1);
++ }
++
++ mmc_data = *data;
++ platform_device_register(&at91sam9261_mmc_device);
++ }
+ }
+ #else
+-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
++void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
+ #endif
+
+
+diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
+index 84b3810..144ef5d 100644
+--- a/arch/arm/mach-at91/at91sam9263.c
++++ b/arch/arm/mach-at91/at91sam9263.c
+@@ -188,8 +188,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_ID("hclk", &macb_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+- CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk),
+- CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk),
++ CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.0", &mmc0_clk),
++ CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.1", &mmc1_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
+diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
+index f0318e9..a111315 100644
+--- a/arch/arm/mach-at91/at91sam9263_devices.c
++++ b/arch/arm/mach-at91/at91sam9263_devices.c
+@@ -220,9 +220,9 @@ void __init at91_add_device_eth(struct macb_platform_data *data) {}
+ * MMC / SD
+ * -------------------------------------------------------------------- */
+
+-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
++#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
+ static u64 mmc_dmamask = DMA_BIT_MASK(32);
+-static struct at91_mmc_data mmc0_data, mmc1_data;
++static struct mci_platform_data mmc0_data, mmc1_data;
+
+ static struct resource mmc0_resources[] = {
+ [0] = {
+@@ -238,7 +238,7 @@ static struct resource mmc0_resources[] = {
+ };
+
+ static struct platform_device at91sam9263_mmc0_device = {
+- .name = "at91_mci",
++ .name = "atmel_mci",
+ .id = 0,
+ .dev = {
+ .dma_mask = &mmc_dmamask,
+@@ -263,7 +263,7 @@ static struct resource mmc1_resources[] = {
+ };
+
+ static struct platform_device at91sam9263_mmc1_device = {
+- .name = "at91_mci",
++ .name = "atmel_mci",
+ .id = 1,
+ .dev = {
+ .dma_mask = &mmc_dmamask,
+@@ -274,85 +274,110 @@ static struct platform_device at91sam9263_mmc1_device = {
+ .num_resources = ARRAY_SIZE(mmc1_resources),
+ };
+
+-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
++void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
+ {
++ unsigned int i;
++ unsigned int slot_count = 0;
++
+ if (!data)
+ return;
+
+- /* input/irq */
+- if (gpio_is_valid(data->det_pin)) {
+- at91_set_gpio_input(data->det_pin, 1);
+- at91_set_deglitch(data->det_pin, 1);
+- }
+- if (gpio_is_valid(data->wp_pin))
+- at91_set_gpio_input(data->wp_pin, 1);
+- if (gpio_is_valid(data->vcc_pin))
+- at91_set_gpio_output(data->vcc_pin, 0);
++ for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
+
+- if (mmc_id == 0) { /* MCI0 */
+- /* CLK */
+- at91_set_A_periph(AT91_PIN_PA12, 0);
++ if (!data->slot[i].bus_width)
++ continue;
+
+- if (data->slot_b) {
+- /* CMD */
+- at91_set_A_periph(AT91_PIN_PA16, 1);
++ /* input/irq */
++ if (gpio_is_valid(data->slot[i].detect_pin)) {
++ at91_set_gpio_input(data->slot[i].detect_pin,
++ 1);
++ at91_set_deglitch(data->slot[i].detect_pin,
++ 1);
++ }
++ if (gpio_is_valid(data->slot[i].wp_pin))
++ at91_set_gpio_input(data->slot[i].wp_pin, 1);
++
++ if (mmc_id == 0) { /* MCI0 */
++ switch (i) {
++ case 0: /* slot A */
++ /* CMD */
++ at91_set_A_periph(AT91_PIN_PA1, 1);
++ /* DAT0, maybe DAT1..DAT3 */
++ at91_set_A_periph(AT91_PIN_PA0, 1);
++ if (data->slot[i].bus_width == 4) {
++ at91_set_A_periph(AT91_PIN_PA3, 1);
++ at91_set_A_periph(AT91_PIN_PA4, 1);
++ at91_set_A_periph(AT91_PIN_PA5, 1);
++ }
++ slot_count++;
++ break;
++ case 1: /* slot B */
++ /* CMD */
++ at91_set_A_periph(AT91_PIN_PA16, 1);
++ /* DAT0, maybe DAT1..DAT3 */
++ at91_set_A_periph(AT91_PIN_PA17, 1);
++ if (data->slot[i].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);
++ }
++ slot_count++;
++ break;
++ default:
++ printk(KERN_ERR
++ "AT91: SD/MMC slot %d not available\n", i);
++ break;
++ }
++ if (slot_count) {
++ /* CLK */
++ at91_set_A_periph(AT91_PIN_PA12, 0);
+
+- /* DAT0, maybe DAT1..DAT3 */
+- at91_set_A_periph(AT91_PIN_PA17, 1);
+- if (data->wire4) {
+- 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;
++ platform_device_register(&at91sam9263_mmc0_device);
+ }
+- } else {
+- /* CMD */
+- at91_set_A_periph(AT91_PIN_PA1, 1);
+-
+- /* DAT0, maybe DAT1..DAT3 */
+- at91_set_A_periph(AT91_PIN_PA0, 1);
+- if (data->wire4) {
+- at91_set_A_periph(AT91_PIN_PA3, 1);
+- at91_set_A_periph(AT91_PIN_PA4, 1);
+- at91_set_A_periph(AT91_PIN_PA5, 1);
++ } else if (mmc_id == 1) { /* MCI1 */
++ switch (i) {
++ case 0: /* slot A */
++ /* CMD */
++ at91_set_A_periph(AT91_PIN_PA7, 1);
++ /* DAT0, maybe DAT1..DAT3 */
++ at91_set_A_periph(AT91_PIN_PA8, 1);
++ if (data->slot[i].bus_width == 4) {
++ at91_set_A_periph(AT91_PIN_PA9, 1);
++ at91_set_A_periph(AT91_PIN_PA10, 1);
++ at91_set_A_periph(AT91_PIN_PA11, 1);
++ }
++ slot_count++;
++ break;
++ case 1: /* slot B */
++ /* CMD */
++ at91_set_A_periph(AT91_PIN_PA21, 1);
++ /* DAT0, maybe DAT1..DAT3 */
++ at91_set_A_periph(AT91_PIN_PA22, 1);
++ if (data->slot[i].bus_width == 4) {
++ at91_set_A_periph(AT91_PIN_PA23, 1);
++ at91_set_A_periph(AT91_PIN_PA24, 1);
++ at91_set_A_periph(AT91_PIN_PA25, 1);
++ }
++ slot_count++;
++ break;
++ default:
++ printk(KERN_ERR
++ "AT91: SD/MMC slot %d not available\n", i);
++ break;
+ }
+- }
++ if (slot_count) {
++ /* CLK */
++ at91_set_A_periph(AT91_PIN_PA6, 0);
+
+- mmc0_data = *data;
+- platform_device_register(&at91sam9263_mmc0_device);
+- } else { /* MCI1 */
+- /* CLK */
+- at91_set_A_periph(AT91_PIN_PA6, 0);
+-
+- if (data->slot_b) {
+- /* CMD */
+- at91_set_A_periph(AT91_PIN_PA21, 1);
+-
+- /* DAT0, maybe DAT1..DAT3 */
+- at91_set_A_periph(AT91_PIN_PA22, 1);
+- if (data->wire4) {
+- at91_set_A_periph(AT91_PIN_PA23, 1);
+- at91_set_A_periph(AT91_PIN_PA24, 1);
+- at91_set_A_periph(AT91_PIN_PA25, 1);
+- }
+- } else {
+- /* CMD */
+- at91_set_A_periph(AT91_PIN_PA7, 1);
+-
+- /* DAT0, maybe DAT1..DAT3 */
+- at91_set_A_periph(AT91_PIN_PA8, 1);
+- if (data->wire4) {
+- at91_set_A_periph(AT91_PIN_PA9, 1);
+- at91_set_A_periph(AT91_PIN_PA10, 1);
+- at91_set_A_periph(AT91_PIN_PA11, 1);
++ mmc1_data = *data;
++ platform_device_register(&at91sam9263_mmc1_device);
+ }
+ }
+-
+- mmc1_data = *data;
+- platform_device_register(&at91sam9263_mmc1_device);
+ }
+ }
+ #else
+-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
++void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
+ #endif
+
+ /* --------------------------------------------------------------------
+diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
+index 0d1b76f..88687b9 100644
+--- a/arch/arm/mach-at91/at91sam9rl_devices.c
++++ b/arch/arm/mach-at91/at91sam9rl_devices.c
+@@ -163,9 +163,9 @@ void __init at91_add_device_usba(struct usba_platform_data *data) {}
+ * MMC / SD
+ * -------------------------------------------------------------------- */
+
+-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
++#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
+ static u64 mmc_dmamask = DMA_BIT_MASK(32);
+-static struct at91_mmc_data mmc_data;
++static struct mci_platform_data mmc_data;
+
+ static struct resource mmc_resources[] = {
+ [0] = {
+@@ -181,7 +181,7 @@ static struct resource mmc_resources[] = {
+ };
+
+ static struct platform_device at91sam9rl_mmc_device = {
+- .name = "at91_mci",
++ .name = "atmel_mci",
+ .id = -1,
+ .dev = {
+ .dma_mask = &mmc_dmamask,
+@@ -192,40 +192,40 @@ static struct platform_device at91sam9rl_mmc_device = {
+ .num_resources = ARRAY_SIZE(mmc_resources),
+ };
+
+-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
++void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
+ {
+ if (!data)
+ return;
+
+- /* input/irq */
+- if (gpio_is_valid(data->det_pin)) {
+- at91_set_gpio_input(data->det_pin, 1);
+- at91_set_deglitch(data->det_pin, 1);
+- }
+- if (gpio_is_valid(data->wp_pin))
+- at91_set_gpio_input(data->wp_pin, 1);
+- if (gpio_is_valid(data->vcc_pin))
+- at91_set_gpio_output(data->vcc_pin, 0);
+-
+- /* CLK */
+- at91_set_A_periph(AT91_PIN_PA2, 0);
+-
+- /* CMD */
+- at91_set_A_periph(AT91_PIN_PA1, 1);
+-
+- /* DAT0, maybe DAT1..DAT3 */
+- at91_set_A_periph(AT91_PIN_PA0, 1);
+- if (data->wire4) {
+- at91_set_A_periph(AT91_PIN_PA3, 1);
+- at91_set_A_periph(AT91_PIN_PA4, 1);
+- at91_set_A_periph(AT91_PIN_PA5, 1);
++ if (data->slot[0].bus_width) {
++ /* input/irq */
++ if (gpio_is_valid(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 (gpio_is_valid(data->slot[0].wp_pin))
++ at91_set_gpio_input(data->slot[0].wp_pin, 1);
++
++ /* CLK */
++ at91_set_A_periph(AT91_PIN_PA2, 0);
++
++ /* CMD */
++ at91_set_A_periph(AT91_PIN_PA1, 1);
++
++ /* DAT0, maybe DAT1..DAT3 */
++ at91_set_A_periph(AT91_PIN_PA0, 1);
++ if (data->slot[0].bus_width == 4) {
++ at91_set_A_periph(AT91_PIN_PA3, 1);
++ at91_set_A_periph(AT91_PIN_PA4, 1);
++ at91_set_A_periph(AT91_PIN_PA5, 1);
++ }
++
++ mmc_data = *data;
++ platform_device_register(&at91sam9rl_mmc_device);
+ }
+-
+- mmc_data = *data;
+- platform_device_register(&at91sam9rl_mmc_device);
+ }
+ #else
+-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
++void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
+ #endif
+
+
+diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c
+index de7be19..93a832f 100644
+--- a/arch/arm/mach-at91/board-afeb-9260v1.c
++++ b/arch/arm/mach-at91/board-afeb-9260v1.c
+@@ -133,12 +133,12 @@ static struct atmel_nand_data __initdata afeb9260_nand_data = {
+ /*
+ * MCI (SD/MMC)
+ */
+-static struct at91_mmc_data __initdata afeb9260_mmc_data = {
+- .det_pin = AT91_PIN_PC9,
+- .wp_pin = AT91_PIN_PC4,
+- .slot_b = 1,
+- .wire4 = 1,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata afeb9260_mci0_data = {
++ .slot[1] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PC9,
++ .wp_pin = AT91_PIN_PC4,
++ },
+ };
+
+
+@@ -199,7 +199,7 @@ static void __init afeb9260_board_init(void)
+ at91_set_B_periph(AT91_PIN_PA10, 0); /* ETX2 */
+ at91_set_B_periph(AT91_PIN_PA11, 0); /* ETX3 */
+ /* MMC */
+- at91_add_device_mmc(0, &afeb9260_mmc_data);
++ at91_add_device_mci(0, &afeb9260_mci0_data);
+ /* I2C */
+ at91_add_device_i2c(afeb9260_i2c_devices,
+ ARRAY_SIZE(afeb9260_i2c_devices));
+diff --git a/arch/arm/mach-at91/board-carmeva.c b/arch/arm/mach-at91/board-carmeva.c
+index a5b002f..71d8f36 100644
+--- a/arch/arm/mach-at91/board-carmeva.c
++++ b/arch/arm/mach-at91/board-carmeva.c
+@@ -71,12 +71,12 @@ static struct at91_udc_data __initdata carmeva_udc_data = {
+ // .vcc_pin = -EINVAL,
+ // };
+
+-static struct at91_mmc_data __initdata carmeva_mmc_data = {
+- .slot_b = 0,
+- .wire4 = 1,
+- .det_pin = AT91_PIN_PB10,
+- .wp_pin = AT91_PIN_PC14,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata carmeva_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PB10,
++ .wp_pin = AT91_PIN_PC14,
++ },
+ };
+
+ static struct spi_board_info carmeva_spi_devices[] = {
+@@ -150,7 +150,7 @@ static void __init carmeva_board_init(void)
+ /* Compact Flash */
+ // at91_add_device_cf(&carmeva_cf_data);
+ /* MMC */
+- at91_add_device_mmc(0, &carmeva_mmc_data);
++ at91_add_device_mci(0, &carmeva_mci0_data);
+ /* LEDs */
+ at91_gpio_leds(carmeva_leds, ARRAY_SIZE(carmeva_leds));
+ }
+diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c
+index 7ddc219..e71c473 100644
+--- a/arch/arm/mach-at91/board-cpu9krea.c
++++ b/arch/arm/mach-at91/board-cpu9krea.c
+@@ -311,12 +311,12 @@ static void __init cpu9krea_add_device_buttons(void)
+ /*
+ * MCI (SD/MMC)
+ */
+-static struct at91_mmc_data __initdata cpu9krea_mmc_data = {
+- .slot_b = 0,
+- .wire4 = 1,
+- .det_pin = AT91_PIN_PA29,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata cpu9krea_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PA29,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+ static void __init cpu9krea_board_init(void)
+@@ -358,7 +358,7 @@ static void __init cpu9krea_board_init(void)
+ /* Ethernet */
+ at91_add_device_eth(&cpu9krea_macb_data);
+ /* MMC */
+- at91_add_device_mmc(0, &cpu9krea_mmc_data);
++ at91_add_device_mci(0, &cpu9krea_mci0_data);
+ /* I2C */
+ at91_add_device_i2c(cpu9krea_i2c_devices,
+ ARRAY_SIZE(cpu9krea_i2c_devices));
+diff --git a/arch/arm/mach-at91/board-cpuat91.c b/arch/arm/mach-at91/board-cpuat91.c
+index 2e6d043..2cbd1a2 100644
+--- a/arch/arm/mach-at91/board-cpuat91.c
++++ b/arch/arm/mach-at91/board-cpuat91.c
+@@ -78,11 +78,12 @@ static struct at91_udc_data __initdata cpuat91_udc_data = {
+ .pullup_pin = AT91_PIN_PC14,
+ };
+
+-static struct at91_mmc_data __initdata cpuat91_mmc_data = {
+- .det_pin = AT91_PIN_PC2,
+- .wire4 = 1,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata cpuat91_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PC2,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+ static struct physmap_flash_data cpuat91_flash_data = {
+@@ -168,7 +169,7 @@ static void __init cpuat91_board_init(void)
+ /* USB Device */
+ at91_add_device_udc(&cpuat91_udc_data);
+ /* MMC */
+- at91_add_device_mmc(0, &cpuat91_mmc_data);
++ at91_add_device_mci(0, &cpuat91_mci0_data);
+ /* I2C */
+ at91_add_device_i2c(NULL, 0);
+ /* Platform devices */
+diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
+index 462bc31..81a8bc4 100644
+--- a/arch/arm/mach-at91/board-csb337.c
++++ b/arch/arm/mach-at91/board-csb337.c
+@@ -87,12 +87,12 @@ static struct at91_cf_data __initdata csb337_cf_data = {
+ .rst_pin = AT91_PIN_PD2,
+ };
+
+-static struct at91_mmc_data __initdata csb337_mmc_data = {
+- .det_pin = AT91_PIN_PD5,
+- .slot_b = 0,
+- .wire4 = 1,
+- .wp_pin = AT91_PIN_PD6,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata csb337_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PD5,
++ .wp_pin = AT91_PIN_PD6,
++ },
+ };
+
+ static struct spi_board_info csb337_spi_devices[] = {
+@@ -240,7 +240,7 @@ static void __init csb337_board_init(void)
+ /* SPI */
+ at91_add_device_spi(csb337_spi_devices, ARRAY_SIZE(csb337_spi_devices));
+ /* MMC */
+- at91_add_device_mmc(0, &csb337_mmc_data);
++ at91_add_device_mci(0, &csb337_mci0_data);
+ /* NOR flash */
+ platform_device_register(&csb_flash);
+ /* LEDs */
+diff --git a/arch/arm/mach-at91/board-eb9200.c b/arch/arm/mach-at91/board-eb9200.c
+index d1e1f3f..0cfac16 100644
+--- a/arch/arm/mach-at91/board-eb9200.c
++++ b/arch/arm/mach-at91/board-eb9200.c
+@@ -70,12 +70,12 @@ static struct at91_cf_data __initdata eb9200_cf_data = {
+ .rst_pin = AT91_PIN_PC5,
+ };
+
+-static struct at91_mmc_data __initdata eb9200_mmc_data = {
+- .slot_b = 0,
+- .wire4 = 1,
+- .det_pin = -EINVAL,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata eb9200_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = -EINVAL,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+ static struct i2c_board_info __initdata eb9200_i2c_devices[] = {
+@@ -113,7 +113,7 @@ static void __init eb9200_board_init(void)
+ at91_add_device_spi(NULL, 0);
+ /* MMC */
+ /* only supports 1 or 4 bit interface, not wired through to SPI */
+- at91_add_device_mmc(0, &eb9200_mmc_data);
++ at91_add_device_mci(0, &eb9200_mci0_data);
+ }
+
+ MACHINE_START(ATEB9200, "Embest ATEB9200")
+diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c
+index 9c24cb2..a9d50fc 100644
+--- a/arch/arm/mach-at91/board-ecbat91.c
++++ b/arch/arm/mach-at91/board-ecbat91.c
+@@ -64,12 +64,12 @@ static struct at91_usbh_data __initdata ecb_at91usbh_data = {
+ .overcurrent_pin= {-EINVAL, -EINVAL},
+ };
+
+-static struct at91_mmc_data __initdata ecb_at91mmc_data = {
+- .slot_b = 0,
+- .wire4 = 1,
+- .det_pin = -EINVAL,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata ecbat91_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = -EINVAL,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+
+@@ -161,7 +161,7 @@ static void __init ecb_at91board_init(void)
+ at91_add_device_i2c(NULL, 0);
+
+ /* MMC */
+- at91_add_device_mmc(0, &ecb_at91mmc_data);
++ at91_add_device_mci(0, &ecbat91_mci0_data);
+
+ /* SPI */
+ at91_add_device_spi(ecb_at91spi_devices, ARRAY_SIZE(ecb_at91spi_devices));
+diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c
+index 82bdfde..aaf7015 100644
+--- a/arch/arm/mach-at91/board-eco920.c
++++ b/arch/arm/mach-at91/board-eco920.c
+@@ -56,12 +56,12 @@ static struct at91_udc_data __initdata eco920_udc_data = {
+ .pullup_pin = AT91_PIN_PB13,
+ };
+
+-static struct at91_mmc_data __initdata eco920_mmc_data = {
+- .slot_b = 0,
+- .wire4 = 0,
+- .det_pin = -EINVAL,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata eco920_mci0_data = {
++ .slot[0] = {
++ .bus_width = 1,
++ .detect_pin = -EINVAL,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+ static struct physmap_flash_data eco920_flash_data = {
+@@ -104,7 +104,7 @@ static void __init eco920_board_init(void)
+ at91_add_device_usbh(&eco920_usbh_data);
+ at91_add_device_udc(&eco920_udc_data);
+
+- at91_add_device_mmc(0, &eco920_mmc_data);
++ at91_add_device_mci(0, &eco920_mci0_data);
+ platform_device_register(&eco920_flash);
+
+ at91_ramc_write(0, AT91_SMC_CSR(7), AT91_SMC_RWHOLD_(1)
+diff --git a/arch/arm/mach-at91/board-flexibity.c b/arch/arm/mach-at91/board-flexibity.c
+index 6cc83a8..fa98aba 100644
+--- a/arch/arm/mach-at91/board-flexibity.c
++++ b/arch/arm/mach-at91/board-flexibity.c
+@@ -75,12 +75,12 @@ static struct spi_board_info flexibity_spi_devices[] = {
+ };
+
+ /* MCI (SD/MMC) */
+-static struct at91_mmc_data __initdata flexibity_mmc_data = {
+- .slot_b = 0,
+- .wire4 = 1,
+- .det_pin = AT91_PIN_PC9,
+- .wp_pin = AT91_PIN_PC4,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata flexibity_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PC9,
++ .wp_pin = AT91_PIN_PC4,
++ },
+ };
+
+ /* LEDs */
+@@ -152,7 +152,7 @@ static void __init flexibity_board_init(void)
+ at91_add_device_spi(flexibity_spi_devices,
+ ARRAY_SIZE(flexibity_spi_devices));
+ /* MMC */
+- at91_add_device_mmc(0, &flexibity_mmc_data);
++ at91_add_device_mci(0, &flexibity_mci0_data);
+ /* LEDs */
+ at91_gpio_leds(flexibity_leds, ARRAY_SIZE(flexibity_leds));
+ }
+diff --git a/arch/arm/mach-at91/board-foxg20.c b/arch/arm/mach-at91/board-foxg20.c
+index 69ab124..6e47071 100644
+--- a/arch/arm/mach-at91/board-foxg20.c
++++ b/arch/arm/mach-at91/board-foxg20.c
+@@ -86,7 +86,7 @@ static struct at91_udc_data __initdata foxg20_udc_data = {
+ * SPI devices.
+ */
+ static struct spi_board_info foxg20_spi_devices[] = {
+-#if !defined(CONFIG_MMC_AT91)
++#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
+ {
+ .modalias = "mtd_dataflash",
+ .chip_select = 1,
+@@ -109,12 +109,12 @@ static struct macb_platform_data __initdata foxg20_macb_data = {
+ * MCI (SD/MMC)
+ * det_pin, wp_pin and vcc_pin are not connected
+ */
+-static struct at91_mmc_data __initdata foxg20_mmc_data = {
+- .slot_b = 1,
+- .wire4 = 1,
+- .det_pin = -EINVAL,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata foxg20_mci0_data = {
++ .slot[1] = {
++ .bus_width = 4,
++ .detect_pin = -EINVAL,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+
+@@ -247,7 +247,7 @@ static void __init foxg20_board_init(void)
+ /* Ethernet */
+ at91_add_device_eth(&foxg20_macb_data);
+ /* MMC */
+- at91_add_device_mmc(0, &foxg20_mmc_data);
++ at91_add_device_mci(0, &foxg20_mci0_data);
+ /* I2C */
+ at91_add_device_i2c(foxg20_i2c_devices, ARRAY_SIZE(foxg20_i2c_devices));
+ /* LEDs */
+diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c
+index 5d96cb8..330d603 100644
+--- a/arch/arm/mach-at91/board-kb9202.c
++++ b/arch/arm/mach-at91/board-kb9202.c
+@@ -69,12 +69,12 @@ static struct at91_udc_data __initdata kb9202_udc_data = {
+ .pullup_pin = AT91_PIN_PB22,
+ };
+
+-static struct at91_mmc_data __initdata kb9202_mmc_data = {
+- .det_pin = AT91_PIN_PB2,
+- .slot_b = 0,
+- .wire4 = 1,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata kb9202_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PB2,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+ static struct mtd_partition __initdata kb9202_nand_partition[] = {
+@@ -121,7 +121,7 @@ static void __init kb9202_board_init(void)
+ /* USB Device */
+ at91_add_device_udc(&kb9202_udc_data);
+ /* MMC */
+- at91_add_device_mmc(0, &kb9202_mmc_data);
++ at91_add_device_mci(0, &kb9202_mci0_data);
+ /* I2C */
+ at91_add_device_i2c(NULL, 0);
+ /* SPI */
+diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
+index 5d3b4d6..7fb2a8f 100644
+--- a/arch/arm/mach-at91/board-neocore926.c
++++ b/arch/arm/mach-at91/board-neocore926.c
+@@ -140,11 +140,12 @@ static struct spi_board_info neocore926_spi_devices[] = {
+ /*
+ * MCI (SD/MMC)
+ */
+-static struct at91_mmc_data __initdata neocore926_mmc_data = {
+- .wire4 = 1,
+- .det_pin = AT91_PIN_PE18,
+- .wp_pin = AT91_PIN_PE19,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata neocore926_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PE18,
++ .wp_pin = AT91_PIN_PE19,
++ },
+ };
+
+
+@@ -356,7 +357,7 @@ static void __init neocore926_board_init(void)
+ neocore926_add_device_ts();
+
+ /* MMC */
+- at91_add_device_mmc(1, &neocore926_mmc_data);
++ at91_add_device_mci(0, &neocore926_mci0_data);
+
+ /* Ethernet */
+ at91_add_device_eth(&neocore926_macb_data);
+diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c
+index 1270655..f83e1de 100644
+--- a/arch/arm/mach-at91/board-picotux200.c
++++ b/arch/arm/mach-at91/board-picotux200.c
+@@ -62,12 +62,12 @@ static struct at91_usbh_data __initdata picotux200_usbh_data = {
+ .overcurrent_pin= {-EINVAL, -EINVAL},
+ };
+
+-static struct at91_mmc_data __initdata picotux200_mmc_data = {
+- .det_pin = AT91_PIN_PB27,
+- .slot_b = 0,
+- .wire4 = 1,
+- .wp_pin = AT91_PIN_PA17,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata picotux200_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PB27,
++ .wp_pin = AT91_PIN_PA17,
++ },
+ };
+
+ #define PICOTUX200_FLASH_BASE AT91_CHIPSELECT_0
+@@ -112,7 +112,7 @@ static void __init picotux200_board_init(void)
+ at91_add_device_i2c(NULL, 0);
+ /* MMC */
+ at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */
+- at91_add_device_mmc(0, &picotux200_mmc_data);
++ at91_add_device_mci(0, &picotux200_mci0_data);
+ /* NOR Flash */
+ platform_device_register(&picotux200_flash);
+ }
+diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c
+index bf351e2..799f214 100644
+--- a/arch/arm/mach-at91/board-qil-a9260.c
++++ b/arch/arm/mach-at91/board-qil-a9260.c
+@@ -156,12 +156,12 @@ static void __init ek_add_device_nand(void)
+ /*
+ * MCI (SD/MMC)
+ */
+-static struct at91_mmc_data __initdata ek_mmc_data = {
+- .slot_b = 0,
+- .wire4 = 1,
+- .det_pin = -EINVAL,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata ek_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = -EINVAL,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+ /*
+@@ -245,7 +245,7 @@ static void __init ek_board_init(void)
+ /* Ethernet */
+ at91_add_device_eth(&ek_macb_data);
+ /* MMC */
+- at91_add_device_mmc(0, &ek_mmc_data);
++ at91_add_device_mci(0, &ek_mci0_data);
+ /* Push Buttons */
+ ek_add_device_buttons();
+ /* LEDs */
+diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c
+index cc2bf97..54733ec 100644
+--- a/arch/arm/mach-at91/board-rm9200dk.c
++++ b/arch/arm/mach-at91/board-rm9200dk.c
+@@ -77,12 +77,12 @@ static struct at91_cf_data __initdata dk_cf_data = {
+ };
+
+ #ifndef CONFIG_MTD_AT91_DATAFLASH_CARD
+-static struct at91_mmc_data __initdata dk_mmc_data = {
+- .slot_b = 0,
+- .wire4 = 1,
+- .det_pin = -EINVAL,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata dk_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = -EINVAL,
++ .wp_pin = -EINVAL,
++ },
+ };
+ #endif
+
+@@ -208,7 +208,7 @@ static void __init dk_board_init(void)
+ #else
+ /* MMC */
+ at91_set_gpio_output(AT91_PIN_PB7, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */
+- at91_add_device_mmc(0, &dk_mmc_data);
++ at91_add_device_mci(0, &dk_mci0_data);
+ #endif
+ /* NAND */
+ at91_add_device_nand(&dk_nand_data);
+diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c
+index 62e19e6..69ef141 100644
+--- a/arch/arm/mach-at91/board-rm9200ek.c
++++ b/arch/arm/mach-at91/board-rm9200ek.c
+@@ -70,12 +70,12 @@ static struct at91_udc_data __initdata ek_udc_data = {
+ };
+
+ #ifndef CONFIG_MTD_AT91_DATAFLASH_CARD
+-static struct at91_mmc_data __initdata ek_mmc_data = {
+- .det_pin = AT91_PIN_PB27,
+- .slot_b = 0,
+- .wire4 = 1,
+- .wp_pin = AT91_PIN_PA17,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata ek_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PB27,
++ .wp_pin = AT91_PIN_PA17,
++ }
+ };
+ #endif
+
+@@ -177,7 +177,7 @@ static void __init ek_board_init(void)
+ #else
+ /* MMC */
+ at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */
+- at91_add_device_mmc(0, &ek_mmc_data);
++ at91_add_device_mci(0, &ek_mci0_data);
+ #endif
+ /* NOR Flash */
+ platform_device_register(&ek_flash);
+diff --git a/arch/arm/mach-at91/board-rsi-ews.c b/arch/arm/mach-at91/board-rsi-ews.c
+index c3b43ae..806d0c3 100644
+--- a/arch/arm/mach-at91/board-rsi-ews.c
++++ b/arch/arm/mach-at91/board-rsi-ews.c
+@@ -58,11 +58,12 @@ static struct at91_usbh_data rsi_ews_usbh_data __initdata = {
+ /*
+ * SD/MC
+ */
+-static struct at91_mmc_data rsi_ews_mmc_data __initdata = {
+- .slot_b = 0,
+- .wire4 = 1,
+- .det_pin = AT91_PIN_PB27,
+- .wp_pin = AT91_PIN_PB29,
++static struct mci_platform_data __initdata rsi_ews_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PB27,
++ .wp_pin = AT91_PIN_PB29,
++ },
+ };
+
+ /*
+@@ -215,7 +216,7 @@ static void __init rsi_ews_board_init(void)
+ at91_add_device_spi(rsi_ews_spi_devices,
+ ARRAY_SIZE(rsi_ews_spi_devices));
+ /* MMC */
+- at91_add_device_mmc(0, &rsi_ews_mmc_data);
++ at91_add_device_mci(0, &rsi_ews_mci0_data);
+ /* NOR Flash */
+ platform_device_register(&rsiews_nor_flash);
+ /* LEDs */
+diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c
+index 7bf6da7..3573f10 100644
+--- a/arch/arm/mach-at91/board-sam9-l9260.c
++++ b/arch/arm/mach-at91/board-sam9-l9260.c
+@@ -73,7 +73,7 @@ static struct at91_udc_data __initdata ek_udc_data = {
+ * SPI devices.
+ */
+ static struct spi_board_info ek_spi_devices[] = {
+-#if !defined(CONFIG_MMC_AT91)
++#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
+ { /* DataFlash chip */
+ .modalias = "mtd_dataflash",
+ .chip_select = 1,
+@@ -158,12 +158,12 @@ static void __init ek_add_device_nand(void)
+ /*
+ * MCI (SD/MMC)
+ */
+-static struct at91_mmc_data __initdata ek_mmc_data = {
+- .slot_b = 1,
+- .wire4 = 1,
+- .det_pin = AT91_PIN_PC8,
+- .wp_pin = AT91_PIN_PC4,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata ek_mci0_data = {
++ .slot[1] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PC8,
++ .wp_pin = AT91_PIN_PC4,
++ },
+ };
+
+ static void __init ek_board_init(void)
+@@ -194,7 +194,7 @@ static void __init ek_board_init(void)
+ /* Ethernet */
+ at91_add_device_eth(&ek_macb_data);
+ /* MMC */
+- at91_add_device_mmc(0, &ek_mmc_data);
++ at91_add_device_mci(0, &ek_mci0_data);
+ /* I2C */
+ at91_add_device_i2c(NULL, 0);
+ }
+diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
+index 889c1bf..8cd6e67 100644
+--- a/arch/arm/mach-at91/board-sam9260ek.c
++++ b/arch/arm/mach-at91/board-sam9260ek.c
+@@ -108,7 +108,7 @@ static void __init at73c213_set_clk(struct at73c213_board_info *info) {}
+ * SPI devices.
+ */
+ static struct spi_board_info ek_spi_devices[] = {
+-#if !defined(CONFIG_MMC_AT91)
++#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
+ { /* DataFlash chip */
+ .modalias = "mtd_dataflash",
+ .chip_select = 1,
+@@ -211,12 +211,12 @@ static void __init ek_add_device_nand(void)
+ /*
+ * MCI (SD/MMC)
+ */
+-static struct at91_mmc_data __initdata ek_mmc_data = {
+- .slot_b = 1,
+- .wire4 = 1,
+- .det_pin = -EINVAL,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata ek_mci0_data = {
++ .slot[1] = {
++ .bus_width = 4,
++ .detect_pin = -EINVAL,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+
+@@ -329,7 +329,7 @@ static void __init ek_board_init(void)
+ /* Ethernet */
+ at91_add_device_eth(&ek_macb_data);
+ /* MMC */
+- at91_add_device_mmc(0, &ek_mmc_data);
++ at91_add_device_mci(0, &ek_mci0_data);
+ /* I2C */
+ at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
+ /* SSC (to AT73C213) */
+diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
+index 2e1c9c5..b8900d5 100644
+--- a/arch/arm/mach-at91/board-sam9261ek.c
++++ b/arch/arm/mach-at91/board-sam9261ek.c
+@@ -342,11 +342,12 @@ static struct spi_board_info ek_spi_devices[] = {
+ * MCI (SD/MMC)
+ * det_pin, wp_pin and vcc_pin are not connected
+ */
+-static struct at91_mmc_data __initdata ek_mmc_data = {
+- .wire4 = 1,
+- .det_pin = -EINVAL,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = -EINVAL,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+ #endif /* CONFIG_SPI_ATMEL_* */
+@@ -600,7 +601,7 @@ static void __init ek_board_init(void)
+ at91_add_device_ssc(AT91SAM9261_ID_SSC1, ATMEL_SSC_TX);
+ #else
+ /* MMC */
+- at91_add_device_mmc(0, &ek_mmc_data);
++ at91_add_device_mci(0, &mci0_data);
+ #endif
+ /* LCD Controller */
+ at91_add_device_lcdc(&ek_lcdc_data);
+diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
+index 7c34908..d4dd017 100644
+--- a/arch/arm/mach-at91/board-sam9263ek.c
++++ b/arch/arm/mach-at91/board-sam9263ek.c
+@@ -143,11 +143,12 @@ static struct spi_board_info ek_spi_devices[] = {
+ /*
+ * MCI (SD/MMC)
+ */
+-static struct at91_mmc_data __initdata ek_mmc_data = {
+- .wire4 = 1,
+- .det_pin = AT91_PIN_PE18,
+- .wp_pin = AT91_PIN_PE19,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata mci1_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PE18,
++ .wp_pin = AT91_PIN_PE19,
++ },
+ };
+
+
+@@ -422,7 +423,7 @@ static void __init ek_board_init(void)
+ /* Touchscreen */
+ ek_add_device_ts();
+ /* MMC */
+- at91_add_device_mmc(1, &ek_mmc_data);
++ at91_add_device_mci(1, &mci1_data);
+ /* Ethernet */
+ at91_add_device_eth(&ek_macb_data);
+ /* NAND */
+diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
+index da6d019..50dc86d 100644
+--- a/arch/arm/mach-at91/board-sam9g20ek.c
++++ b/arch/arm/mach-at91/board-sam9g20ek.c
+@@ -90,7 +90,7 @@ static struct at91_udc_data __initdata ek_udc_data = {
+ * SPI devices.
+ */
+ static struct spi_board_info ek_spi_devices[] = {
+-#if !(defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_AT91))
++#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
+ { /* DataFlash chip */
+ .modalias = "mtd_dataflash",
+ .chip_select = 1,
+@@ -197,7 +197,6 @@ static void __init ek_add_device_nand(void)
+ * MCI (SD/MMC)
+ * wp_pin and vcc_pin are not connected
+ */
+-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+ static struct mci_platform_data __initdata ek_mmc_data = {
+ .slot[1] = {
+ .bus_width = 4,
+@@ -206,28 +205,15 @@ static struct mci_platform_data __initdata ek_mmc_data = {
+ },
+
+ };
+-#else
+-static struct at91_mmc_data __initdata ek_mmc_data = {
+- .slot_b = 1, /* Only one slot so use slot B */
+- .wire4 = 1,
+- .det_pin = AT91_PIN_PC9,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
+-};
+-#endif
+
+ static void __init ek_add_device_mmc(void)
+ {
+-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+ if (ek_have_2mmc()) {
+ ek_mmc_data.slot[0].bus_width = 4;
+ ek_mmc_data.slot[0].detect_pin = AT91_PIN_PC2;
+ ek_mmc_data.slot[0].wp_pin = -1;
+ }
+ at91_add_device_mci(0, &ek_mmc_data);
+-#else
+- at91_add_device_mmc(0, &ek_mmc_data);
+-#endif
+ }
+
+ /*
+diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
+index 81d82be..628fec9 100644
+--- a/arch/arm/mach-at91/board-sam9rlek.c
++++ b/arch/arm/mach-at91/board-sam9rlek.c
+@@ -58,11 +58,12 @@ static struct usba_platform_data __initdata ek_usba_udc_data = {
+ /*
+ * MCI (SD/MMC)
+ */
+-static struct at91_mmc_data __initdata ek_mmc_data = {
+- .wire4 = 1,
+- .det_pin = AT91_PIN_PA15,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PA15,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+
+@@ -305,7 +306,7 @@ static void __init ek_board_init(void)
+ /* SPI */
+ at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
+ /* MMC */
+- at91_add_device_mmc(0, &ek_mmc_data);
++ at91_add_device_mci(0, &mci0_data);
+ /* LCD Controller */
+ at91_add_device_lcdc(&ek_lcdc_data);
+ /* AC97 */
+diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c
+index 29eae16..c3fb31d 100644
+--- a/arch/arm/mach-at91/board-stamp9g20.c
++++ b/arch/arm/mach-at91/board-stamp9g20.c
+@@ -83,7 +83,6 @@ static void __init add_device_nand(void)
+ * MCI (SD/MMC)
+ * det_pin, wp_pin and vcc_pin are not connected
+ */
+-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+ static struct mci_platform_data __initdata mmc_data = {
+ .slot[0] = {
+ .bus_width = 4,
+@@ -91,15 +90,6 @@ static struct mci_platform_data __initdata mmc_data = {
+ .wp_pin = -1,
+ },
+ };
+-#else
+-static struct at91_mmc_data __initdata mmc_data = {
+- .slot_b = 0,
+- .wire4 = 1,
+- .det_pin = -EINVAL,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
+-};
+-#endif
+
+
+ /*
+@@ -223,11 +213,7 @@ void __init stamp9g20_board_init(void)
+ /* NAND */
+ add_device_nand();
+ /* MMC */
+-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+ at91_add_device_mci(0, &mmc_data);
+-#else
+- at91_add_device_mmc(0, &mmc_data);
+-#endif
+ /* W1 */
+ add_w1();
+ }
+diff --git a/arch/arm/mach-at91/board-usb-a926x.c b/arch/arm/mach-at91/board-usb-a926x.c
+index c1476b9..6ea069b 100644
+--- a/arch/arm/mach-at91/board-usb-a926x.c
++++ b/arch/arm/mach-at91/board-usb-a926x.c
+@@ -109,14 +109,12 @@ static struct mmc_spi_platform_data at91_mmc_spi_pdata = {
+ * SPI devices.
+ */
+ static struct spi_board_info usb_a9263_spi_devices[] = {
+-#if !defined(CONFIG_MMC_AT91)
+ { /* DataFlash chip */
+ .modalias = "mtd_dataflash",
+ .chip_select = 0,
+ .max_speed_hz = 15 * 1000 * 1000,
+ .bus_num = 0,
+ }
+-#endif
+ };
+
+ static struct spi_board_info usb_a9g20_spi_devices[] = {
+diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c
+index 516d340..2355de2 100644
+--- a/arch/arm/mach-at91/board-yl-9200.c
++++ b/arch/arm/mach-at91/board-yl-9200.c
+@@ -119,11 +119,12 @@ static struct at91_udc_data __initdata yl9200_udc_data = {
+ /*
+ * MMC
+ */
+-static struct at91_mmc_data __initdata yl9200_mmc_data = {
+- .det_pin = AT91_PIN_PB9,
+- .wire4 = 1,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata yl9200_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PB9,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+ /*
+@@ -568,7 +569,7 @@ static void __init yl9200_board_init(void)
+ /* I2C */
+ at91_add_device_i2c(yl9200_i2c_devices, ARRAY_SIZE(yl9200_i2c_devices));
+ /* MMC */
+- at91_add_device_mmc(0, &yl9200_mmc_data);
++ at91_add_device_mci(0, &yl9200_mci0_data);
+ /* NAND */
+ at91_add_device_nand(&yl9200_nand_data);
+ /* NOR Flash */
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0139-ARM-at91-defconfig-change-the-MCI-driver-to-use-in-d.patch b/patches.at91/0139-ARM-at91-defconfig-change-the-MCI-driver-to-use-in-d.patch
new file mode 100644
index 00000000000000..520ada50fc6298
--- /dev/null
+++ b/patches.at91/0139-ARM-at91-defconfig-change-the-MCI-driver-to-use-in-d.patch
@@ -0,0 +1,140 @@
+From 646f4f7426dbbc1814d2d7935562bdf46ffc8e0f Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 2 Jul 2012 17:15:58 +0200
+Subject: ARM: at91/defconfig: change the MCI driver to use in defconfigs
+
+Since atmel-mci driver supports all atmel mci versions,
+use it instead of the deprecated at91_mci driver.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/configs/at91rm9200_defconfig | 2 +-
+ arch/arm/configs/at91sam9261_defconfig | 2 +-
+ arch/arm/configs/at91sam9263_defconfig | 2 +-
+ arch/arm/configs/at91sam9g20_defconfig | 2 +-
+ arch/arm/configs/at91sam9rl_defconfig | 2 +-
+ arch/arm/configs/cpu9260_defconfig | 2 +-
+ arch/arm/configs/cpu9g20_defconfig | 2 +-
+ arch/arm/configs/qil-a9260_defconfig | 2 +-
+ arch/arm/configs/stamp9g20_defconfig | 1 -
+ 9 files changed, 8 insertions(+), 9 deletions(-)
+
+diff --git a/arch/arm/configs/at91rm9200_defconfig b/arch/arm/configs/at91rm9200_defconfig
+index d54e2ac..4ae57a3 100644
+--- a/arch/arm/configs/at91rm9200_defconfig
++++ b/arch/arm/configs/at91rm9200_defconfig
+@@ -232,7 +232,7 @@ CONFIG_USB_GADGET=y
+ CONFIG_USB_ETH=m
+ CONFIG_USB_MASS_STORAGE=m
+ CONFIG_MMC=y
+-CONFIG_MMC_AT91=y
++CONFIG_MMC_ATMELMCI=y
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_CLASS=y
+ CONFIG_LEDS_GPIO=y
+diff --git a/arch/arm/configs/at91sam9261_defconfig b/arch/arm/configs/at91sam9261_defconfig
+index ade6b2f..1e8712e 100644
+--- a/arch/arm/configs/at91sam9261_defconfig
++++ b/arch/arm/configs/at91sam9261_defconfig
+@@ -128,7 +128,7 @@ CONFIG_USB_GADGETFS=m
+ CONFIG_USB_FILE_STORAGE=m
+ CONFIG_USB_G_SERIAL=m
+ CONFIG_MMC=y
+-CONFIG_MMC_AT91=m
++CONFIG_MMC_ATMELMCI=m
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_CLASS=y
+ CONFIG_LEDS_GPIO=y
+diff --git a/arch/arm/configs/at91sam9263_defconfig b/arch/arm/configs/at91sam9263_defconfig
+index 585e7e0..d2050ca 100644
+--- a/arch/arm/configs/at91sam9263_defconfig
++++ b/arch/arm/configs/at91sam9263_defconfig
+@@ -137,7 +137,7 @@ CONFIG_USB_FILE_STORAGE=m
+ CONFIG_USB_G_SERIAL=m
+ CONFIG_MMC=y
+ CONFIG_SDIO_UART=m
+-CONFIG_MMC_AT91=m
++CONFIG_MMC_ATMELMCI=m
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_CLASS=y
+ CONFIG_LEDS_ATMEL_PWM=y
+diff --git a/arch/arm/configs/at91sam9g20_defconfig b/arch/arm/configs/at91sam9g20_defconfig
+index 994d331..e1b0e80 100644
+--- a/arch/arm/configs/at91sam9g20_defconfig
++++ b/arch/arm/configs/at91sam9g20_defconfig
+@@ -99,7 +99,7 @@ CONFIG_USB_GADGETFS=m
+ CONFIG_USB_FILE_STORAGE=m
+ CONFIG_USB_G_SERIAL=m
+ CONFIG_MMC=y
+-CONFIG_MMC_AT91=m
++CONFIG_MMC_ATMELMCI=m
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_CLASS=y
+ CONFIG_LEDS_GPIO=y
+diff --git a/arch/arm/configs/at91sam9rl_defconfig b/arch/arm/configs/at91sam9rl_defconfig
+index ad562ee..7cf8785 100644
+--- a/arch/arm/configs/at91sam9rl_defconfig
++++ b/arch/arm/configs/at91sam9rl_defconfig
+@@ -60,7 +60,7 @@ CONFIG_AT91SAM9X_WATCHDOG=y
+ CONFIG_FB=y
+ CONFIG_FB_ATMEL=y
+ CONFIG_MMC=y
+-CONFIG_MMC_AT91=m
++CONFIG_MMC_ATMELMCI=m
+ CONFIG_RTC_CLASS=y
+ CONFIG_RTC_DRV_AT91SAM9=y
+ CONFIG_EXT2_FS=y
+diff --git a/arch/arm/configs/cpu9260_defconfig b/arch/arm/configs/cpu9260_defconfig
+index bbf729e..921480c 100644
+--- a/arch/arm/configs/cpu9260_defconfig
++++ b/arch/arm/configs/cpu9260_defconfig
+@@ -82,7 +82,7 @@ CONFIG_USB_STORAGE=y
+ CONFIG_USB_GADGET=y
+ CONFIG_USB_ETH=m
+ CONFIG_MMC=y
+-CONFIG_MMC_AT91=m
++CONFIG_MMC_ATMELMCI=m
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_CLASS=y
+ CONFIG_LEDS_GPIO=y
+diff --git a/arch/arm/configs/cpu9g20_defconfig b/arch/arm/configs/cpu9g20_defconfig
+index e7d7942..ea116cb 100644
+--- a/arch/arm/configs/cpu9g20_defconfig
++++ b/arch/arm/configs/cpu9g20_defconfig
+@@ -82,7 +82,7 @@ CONFIG_USB_STORAGE=y
+ CONFIG_USB_GADGET=y
+ CONFIG_USB_ETH=m
+ CONFIG_MMC=y
+-CONFIG_MMC_AT91=m
++CONFIG_MMC_ATMELMCI=m
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_CLASS=y
+ CONFIG_LEDS_GPIO=y
+diff --git a/arch/arm/configs/qil-a9260_defconfig b/arch/arm/configs/qil-a9260_defconfig
+index 2bb100b..42d5db1 100644
+--- a/arch/arm/configs/qil-a9260_defconfig
++++ b/arch/arm/configs/qil-a9260_defconfig
+@@ -86,7 +86,7 @@ CONFIG_USB_STORAGE=y
+ CONFIG_USB_GADGET=y
+ CONFIG_USB_ETH=m
+ CONFIG_MMC=y
+-CONFIG_MMC_AT91=m
++CONFIG_MMC_ATMELMCI=m
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_CLASS=y
+ CONFIG_LEDS_GPIO=y
+diff --git a/arch/arm/configs/stamp9g20_defconfig b/arch/arm/configs/stamp9g20_defconfig
+index d5e260b..52f1488 100644
+--- a/arch/arm/configs/stamp9g20_defconfig
++++ b/arch/arm/configs/stamp9g20_defconfig
+@@ -100,7 +100,6 @@ CONFIG_USB_ETH=m
+ CONFIG_USB_FILE_STORAGE=m
+ CONFIG_USB_G_SERIAL=m
+ CONFIG_MMC=y
+-# CONFIG_MMC_AT91 is not set
+ CONFIG_MMC_ATMELMCI=y
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_CLASS=y
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0140-mmc-atmel-mci-fix-burst-chunk-size-modification.patch b/patches.at91/0140-mmc-atmel-mci-fix-burst-chunk-size-modification.patch
new file mode 100644
index 00000000000000..4eba7949f7b48a
--- /dev/null
+++ b/patches.at91/0140-mmc-atmel-mci-fix-burst-chunk-size-modification.patch
@@ -0,0 +1,75 @@
+From b50d6057cf77fe331626efe31cd1814f69e13747 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 24 Apr 2012 16:46:26 +0200
+Subject: mmc: atmel-mci: fix burst/chunk size modification
+
+The use of DMA slave config operation requires that the burst size
+(aka chunk size) is specified through this interface.
+Modify atmel-mci slave driver to use this specification on its side.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/mmc/host/atmel-mci-regs.h | 14 ++++++++++++++
+ drivers/mmc/host/atmel-mci.c | 8 +++++---
+ 2 files changed, 19 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h
+index 787aba1..ab56f7d 100644
+--- a/drivers/mmc/host/atmel-mci-regs.h
++++ b/drivers/mmc/host/atmel-mci-regs.h
+@@ -140,4 +140,18 @@
+ #define atmci_writel(port,reg,value) \
+ __raw_writel((value), (port)->regs + reg)
+
++/*
++ * Fix sconfig's burst size according to atmel MCI. We need to convert them as:
++ * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
++ *
++ * This can be done by finding most significant bit set.
++ */
++static inline unsigned int atmci_convert_chksize(unsigned int maxburst)
++{
++ if (maxburst > 1)
++ return fls(maxburst) - 2;
++ else
++ return 0;
++}
++
+ #endif /* __DRIVERS_MMC_ATMEL_MCI_H__ */
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index 456c077..f2c115e 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -910,6 +910,7 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
+ enum dma_data_direction direction;
+ enum dma_transfer_direction slave_dirn;
+ unsigned int sglen;
++ u32 maxburst;
+ u32 iflags;
+
+ data->error = -EINPROGRESS;
+@@ -943,17 +944,18 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
+ if (!chan)
+ return -ENODEV;
+
+- if (host->caps.has_dma)
+- atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(3) | ATMCI_DMAEN);
+-
+ if (data->flags & MMC_DATA_READ) {
+ direction = DMA_FROM_DEVICE;
+ host->dma_conf.direction = slave_dirn = DMA_DEV_TO_MEM;
++ maxburst = atmci_convert_chksize(host->dma_conf.src_maxburst);
+ } else {
+ direction = DMA_TO_DEVICE;
+ host->dma_conf.direction = slave_dirn = DMA_MEM_TO_DEV;
++ maxburst = atmci_convert_chksize(host->dma_conf.dst_maxburst);
+ }
+
++ atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(maxburst) | ATMCI_DMAEN);
++
+ sglen = dma_map_sg(chan->device->dev, data->sg,
+ data->sg_len, direction);
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0141-mmc-atmel-mci-add-device-tree-support.patch b/patches.at91/0141-mmc-atmel-mci-add-device-tree-support.patch
new file mode 100644
index 00000000000000..ac074187dc919c
--- /dev/null
+++ b/patches.at91/0141-mmc-atmel-mci-add-device-tree-support.patch
@@ -0,0 +1,212 @@
+From abcc103a1d98b3b91596e068deef52032756cbfc Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Tue, 20 Mar 2012 18:41:48 +0100
+Subject: mmc: atmel-mci: add device tree support
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ .../devicetree/bindings/mmc/atmel-hsmci.txt | 67 +++++++++++++++++
+ drivers/mmc/host/atmel-mci.c | 85 +++++++++++++++++++++-
+ 2 files changed, 150 insertions(+), 2 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
+
+diff --git a/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt b/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
+new file mode 100644
+index 0000000..81c20cc
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
+@@ -0,0 +1,67 @@
++* Atmel High Speed MultiMedia Card Interface
++
++This controller on atmel products provides an interface for MMC, SD and SDIO
++types of memory cards.
++
++1) MCI node
++
++Required properties:
++- compatible: no blank "atmel,hsmci"
++- reg: should contain HSMCI registers location and length
++- interrupts: should contain HSMCI interrupt number
++- #address-cells: should be one. The cell is the slot id.
++- #size-cells: should be zero.
++- at least one slot node
++
++The node contains child nodes for each slot that the platform uses
++
++Example MCI node:
++
++mmc0: mmc@f0008000 {
++ compatible = "atmel,hsmci";
++ reg = <0xf0008000 0x600>;
++ interrupts = <12 4>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ [ child node definitions...]
++};
++
++2) slot nodes
++
++Required properties:
++- reg: should contain the slot id.
++- bus-width: number of data lines connected to the controller
++
++Optional properties:
++- cd-gpios: specify GPIOs for card detection
++- cd-inverted: invert the value of external card detect gpio line
++- wp-gpios: specify GPIOs for write protection
++
++Example slot node:
++
++slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioD 15 0>
++ cd-inverted;
++};
++
++Example full MCI node:
++mmc0: mmc@f0008000 {
++ compatible = "atmel,hsmci";
++ reg = <0xf0008000 0x600>;
++ interrupts = <12 4>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioD 15 0>
++ cd-inverted;
++ };
++ slot@1 {
++ reg = <1>;
++ bus-width = <4>;
++ };
++};
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index f2c115e..47421fc 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -19,6 +19,9 @@
+ #include <linux/interrupt.h>
+ #include <linux/ioport.h>
+ #include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/of_gpio.h>
+ #include <linux/platform_device.h>
+ #include <linux/scatterlist.h>
+ #include <linux/seq_file.h>
+@@ -493,6 +496,70 @@ err:
+ dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
+ }
+
++#if defined(CONFIG_OF)
++static const struct of_device_id atmci_dt_ids[] = {
++ { .compatible = "atmel,hsmci" },
++ { /* sentinel */ }
++};
++
++MODULE_DEVICE_TABLE(of, atmci_dt_ids);
++
++static struct mci_platform_data __devinit*
++atmci_of_init(struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ struct device_node *cnp;
++ struct mci_platform_data *pdata;
++ u32 slot_id;
++
++ if (!np) {
++ dev_err(&pdev->dev, "device node not found\n");
++ return ERR_PTR(-EINVAL);
++ }
++
++ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
++ if (!pdata) {
++ dev_err(&pdev->dev, "could not allocate memory for pdata\n");
++ return ERR_PTR(-ENOMEM);
++ }
++
++ for_each_child_of_node(np, cnp) {
++ if (of_property_read_u32(cnp, "reg", &slot_id)) {
++ dev_warn(&pdev->dev, "reg property is missing for %s\n",
++ cnp->full_name);
++ continue;
++ }
++
++ if (slot_id >= ATMCI_MAX_NR_SLOTS) {
++ dev_warn(&pdev->dev, "can't have more than %d slots\n",
++ ATMCI_MAX_NR_SLOTS);
++ break;
++ }
++
++ if (of_property_read_u32(cnp, "bus-width",
++ &pdata->slot[slot_id].bus_width))
++ pdata->slot[slot_id].bus_width = 1;
++
++ pdata->slot[slot_id].detect_pin =
++ of_get_named_gpio(cnp, "cd-gpios", 0);
++
++ pdata->slot[slot_id].detect_is_active_high =
++ of_property_read_bool(cnp, "cd-inverted");
++
++ pdata->slot[slot_id].wp_pin =
++ of_get_named_gpio(cnp, "wp-gpios", 0);
++ }
++
++ return pdata;
++}
++#else /* CONFIG_OF */
++static inline struct mci_platform_data*
++atmci_of_init(struct platform_device *dev)
++{
++ return ERR_PTR(-EINVAL);
++}
++#endif
++
+ static inline unsigned int atmci_get_version(struct atmel_mci *host)
+ {
+ return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
+@@ -2038,6 +2105,13 @@ static int __init atmci_init_slot(struct atmel_mci *host,
+ slot->sdc_reg = sdc_reg;
+ slot->sdio_irq = sdio_irq;
+
++ dev_dbg(&mmc->class_dev,
++ "slot[%u]: bus_width=%u, detect_pin=%d, "
++ "detect_is_active_high=%s, wp_pin=%d\n",
++ id, slot_data->bus_width, slot_data->detect_pin,
++ slot_data->detect_is_active_high ? "true" : "false",
++ slot_data->wp_pin);
++
+ mmc->ops = &atmci_ops;
+ mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512);
+ mmc->f_max = host->bus_hz / 2;
+@@ -2258,8 +2332,14 @@ static int __init atmci_probe(struct platform_device *pdev)
+ if (!regs)
+ return -ENXIO;
+ pdata = pdev->dev.platform_data;
+- if (!pdata)
+- return -ENXIO;
++ if (!pdata) {
++ pdata = atmci_of_init(pdev);
++ if (IS_ERR(pdata)) {
++ dev_err(&pdev->dev, "platform data not available\n");
++ return PTR_ERR(pdata);
++ }
++ }
++
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+@@ -2477,6 +2557,7 @@ static struct platform_driver atmci_driver = {
+ .driver = {
+ .name = "atmel_mci",
+ .pm = ATMCI_PM_OPS,
++ .of_match_table = of_match_ptr(atmci_dt_ids),
+ },
+ };
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0142-ARM-at91-add-clocks-for-DT-entries.patch b/patches.at91/0142-ARM-at91-add-clocks-for-DT-entries.patch
new file mode 100644
index 00000000000000..c068b20389ffa2
--- /dev/null
+++ b/patches.at91/0142-ARM-at91-add-clocks-for-DT-entries.patch
@@ -0,0 +1,83 @@
+From 1061326519a35f8af1b07fff6f80b9f217bb8097 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Tue, 22 May 2012 11:38:26 +0200
+Subject: ARM: at91: add clocks for DT entries
+
+Add clocks to clock lookup table for DT entries.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/mach-at91/at91sam9260.c | 1 +
+ arch/arm/mach-at91/at91sam9263.c | 2 ++
+ arch/arm/mach-at91/at91sam9g45.c | 2 ++
+ arch/arm/mach-at91/at91sam9n12.c | 1 +
+ arch/arm/mach-at91/at91sam9x5.c | 2 ++
+ 5 files changed, 8 insertions(+)
+
+diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
+index c644131..4696729 100644
+--- a/arch/arm/mach-at91/at91sam9260.c
++++ b/arch/arm/mach-at91/at91sam9260.c
+@@ -219,6 +219,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("t1_clk", "fffdc000.timer", &tc4_clk),
+ CLKDEV_CON_DEV_ID("t2_clk", "fffdc000.timer", &tc5_clk),
+ CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &ohci_clk),
++ CLKDEV_CON_DEV_ID("mci_clk", "fffa8000.mmc", &mmc_clk),
+ /* fake hclk clock */
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
+index 144ef5d..c82d521 100644
+--- a/arch/arm/mach-at91/at91sam9263.c
++++ b/arch/arm/mach-at91/at91sam9263.c
+@@ -210,6 +210,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("hclk", "a00000.ohci", &ohci_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "fffa4000.spi", &spi0_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "fffa8000.spi", &spi1_clk),
++ CLKDEV_CON_DEV_ID("mci_clk", "fff80000.mmc", &mmc0_clk),
++ CLKDEV_CON_DEV_ID("mci_clk", "fff84000.mmc", &mmc1_clk),
+ };
+
+ static struct clk_lookup usart_clocks_lookups[] = {
+diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
+index 55d2959..f6d0eab 100644
+--- a/arch/arm/mach-at91/at91sam9g45.c
++++ b/arch/arm/mach-at91/at91sam9g45.c
+@@ -236,6 +236,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("t0_clk", "fffd4000.timer", &tcb0_clk),
+ CLKDEV_CON_DEV_ID("hclk", "700000.ohci", &uhphs_clk),
+ CLKDEV_CON_DEV_ID("ehci_clk", "800000.ehci", &uhphs_clk),
++ CLKDEV_CON_DEV_ID("mci_clk", "fff80000.mmc", &mmc0_clk),
++ CLKDEV_CON_DEV_ID("mci_clk", "fffd0000.mmc", &mmc1_clk),
+ /* fake hclk clock */
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
+index 0849466..cce4e0f 100644
+--- a/arch/arm/mach-at91/at91sam9n12.c
++++ b/arch/arm/mach-at91/at91sam9n12.c
+@@ -168,6 +168,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("usart", "f8028000.serial", &usart3_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "f8008000.timer", &tcb_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb_clk),
++ CLKDEV_CON_DEV_ID("mci_clk", "f0008000.mmc", &mmc_clk),
+ CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma_clk),
+ CLKDEV_CON_ID("pioA", &pioAB_clk),
+ CLKDEV_CON_ID("pioB", &pioAB_clk),
+diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
+index 7eb00c53..796b3c0 100644
+--- a/arch/arm/mach-at91/at91sam9x5.c
++++ b/arch/arm/mach-at91/at91sam9x5.c
+@@ -225,6 +225,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb0_clk),
+ CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma0_clk),
+ CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_clk),
++ CLKDEV_CON_DEV_ID("mci_clk", "f0008000.mmc", &mmc0_clk),
++ CLKDEV_CON_DEV_ID("mci_clk", "f000c000.mmc", &mmc1_clk),
+ CLKDEV_CON_ID("pioA", &pioAB_clk),
+ CLKDEV_CON_ID("pioB", &pioAB_clk),
+ CLKDEV_CON_ID("pioC", &pioCD_clk),
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0143-ARM-dts-add-nodes-for-atmel-hsmci-controllers-for-at.patch b/patches.at91/0143-ARM-dts-add-nodes-for-atmel-hsmci-controllers-for-at.patch
new file mode 100644
index 00000000000000..bb912527fea773
--- /dev/null
+++ b/patches.at91/0143-ARM-dts-add-nodes-for-atmel-hsmci-controllers-for-at.patch
@@ -0,0 +1,152 @@
+From 5447e89571ef3242d7452e0d13051e27ceb31a07 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Thu, 24 May 2012 16:58:42 +0200
+Subject: ARM: dts: add nodes for atmel hsmci controllers for atmel SOCs
+
+Add mci controller nodes to atmel SOCs.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+
+Conflicts:
+
+ arch/arm/boot/dts/at91sam9260.dtsi
+ arch/arm/boot/dts/at91sam9g45.dtsi
+ arch/arm/boot/dts/at91sam9x5.dtsi
+---
+ arch/arm/boot/dts/at91sam9260.dtsi | 9 +++++++++
+ arch/arm/boot/dts/at91sam9263.dtsi | 18 ++++++++++++++++++
+ arch/arm/boot/dts/at91sam9g45.dtsi | 18 ++++++++++++++++++
+ arch/arm/boot/dts/at91sam9n12.dtsi | 9 +++++++++
+ arch/arm/boot/dts/at91sam9x5.dtsi | 18 ++++++++++++++++++
+ 5 files changed, 72 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
+index 12df8ca..1f2c7d0 100644
+--- a/arch/arm/boot/dts/at91sam9260.dtsi
++++ b/arch/arm/boot/dts/at91sam9260.dtsi
+@@ -201,6 +201,15 @@
+ interrupts = <10 4 2>;
+ status = "disabled";
+ };
++
++ mmc0: mmc@fffa8000 {
++ compatible = "atmel,hsmci";
++ reg = <0xfffa800 0x600>;
++ interrupts = <9 4>;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
+index 195019b..a76f6cd 100644
+--- a/arch/arm/boot/dts/at91sam9263.dtsi
++++ b/arch/arm/boot/dts/at91sam9263.dtsi
+@@ -185,6 +185,24 @@
+ interrupts = <24 4 2>;
+ status = "disabled";
+ };
++
++ mmc0: mmc@fff80000 {
++ compatible = "atmel,hsmci";
++ reg = <0xfff80000 0x600>;
++ interrupts = <10 4>;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ mmc1: mmc@fff84000 {
++ compatible = "atmel,hsmci";
++ reg = <0xfff84000 0x600>;
++ interrupts = <11 4>;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
+index 6a3ed54..4b833d4 100644
+--- a/arch/arm/boot/dts/at91sam9g45.dtsi
++++ b/arch/arm/boot/dts/at91sam9g45.dtsi
+@@ -205,6 +205,24 @@
+ interrupts = <25 4 3>;
+ status = "disabled";
+ };
++
++ mmc0: mmc@fff80000 {
++ compatible = "atmel,hsmci";
++ reg = <0xfff80000 0x600>;
++ interrupts = <11 4>;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ mmc1: mmc@fffd0000 {
++ compatible = "atmel,hsmci";
++ reg = <0xfffd0000 0x600>;
++ interrupts = <29 4>;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
+index ef9336a..aead257 100644
+--- a/arch/arm/boot/dts/at91sam9n12.dtsi
++++ b/arch/arm/boot/dts/at91sam9n12.dtsi
+@@ -82,6 +82,15 @@
+ reg = <0xfffffe10 0x10>;
+ };
+
++ mmc0: mmc@f0008000 {
++ compatible = "atmel,hsmci";
++ reg = <0xf0008000 0x600>;
++ interrupts = <12 4>;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
+ tcb0: timer@f8008000 {
+ compatible = "atmel,at91sam9x5-tcb";
+ reg = <0xf8008000 0x100>;
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index fc38d21..1be3df7 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -195,6 +195,24 @@
+ interrupts = <27 4 3>;
+ status = "disabled";
+ };
++
++ mmc0: mmc@f0008000 {
++ compatible = "atmel,hsmci";
++ reg = <0xf0008000 0x600>;
++ interrupts = <12 4>;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ mmc1: mmc@f000c000 {
++ compatible = "atmel,hsmci";
++ reg = <0xf000c000 0x600>;
++ interrupts = <26 4>;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
+ };
+
+ nand0: nand@40000000 {
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0144-ARM-dts-add-nodes-for-atmel-hsmci-controllers-for-at.patch b/patches.at91/0144-ARM-dts-add-nodes-for-atmel-hsmci-controllers-for-at.patch
new file mode 100644
index 00000000000000..0a6fc2bc7a9104
--- /dev/null
+++ b/patches.at91/0144-ARM-dts-add-nodes-for-atmel-hsmci-controllers-for-at.patch
@@ -0,0 +1,163 @@
+From c8564440b52c2ad6a6adc3e826adc0c5dc7035af Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Thu, 24 May 2012 17:01:19 +0200
+Subject: ARM: dts: add nodes for atmel hsmci controllers for atmel boards
+
+Add mci controller nodes to atmel boards.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9263ek.dts | 10 ++++++++++
+ arch/arm/boot/dts/at91sam9g20ek_2mmc.dts | 12 ++++++++++++
+ arch/arm/boot/dts/at91sam9g20ek_common.dtsi | 9 +++++++++
+ arch/arm/boot/dts/at91sam9g25ek.dts | 18 ++++++++++++++++++
+ arch/arm/boot/dts/at91sam9m10g45ek.dts | 19 +++++++++++++++++++
+ arch/arm/boot/dts/at91sam9n12ek.dts | 9 +++++++++
+ 6 files changed, 77 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9263ek.dts b/arch/arm/boot/dts/at91sam9263ek.dts
+index f86ac4b..05028ed 100644
+--- a/arch/arm/boot/dts/at91sam9263ek.dts
++++ b/arch/arm/boot/dts/at91sam9263ek.dts
+@@ -50,6 +50,16 @@
+ atmel,vbus-gpio = <&pioA 25 0>;
+ status = "okay";
+ };
++
++ mmc0: mmc@fff80000 {
++ status = "okay";
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioE 18 0>;
++ wp-gpios = <&pioE 19 0>;
++ };
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts b/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts
+index f1b2e14..684b229 100644
+--- a/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts
++++ b/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts
+@@ -12,6 +12,18 @@
+ model = "Atmel at91sam9g20ek 2 mmc";
+ compatible = "atmel,at91sam9g20ek_2mmc", "atmel,at91sam9g20", "atmel,at91sam9";
+
++ ahb {
++ apb{
++ mmc0: mmc@fffa8000 {
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioC 2 0>;
++ };
++ };
++ };
++ };
++
+ leds {
+ compatible = "gpio-leds";
+
+diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+index b06c0db..7da326a 100644
+--- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
++++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+@@ -51,6 +51,15 @@
+ atmel,vbus-gpio = <&pioC 5 0>;
+ status = "okay";
+ };
++
++ mmc0: mmc@fffa8000 {
++ status = "okay";
++ slot@1 {
++ reg = <1>;
++ bus-width = <4>;
++ cd-gpios = <&pioC 9 0>;
++ };
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts
+index 96514c1..4857e6c 100644
+--- a/arch/arm/boot/dts/at91sam9g25ek.dts
++++ b/arch/arm/boot/dts/at91sam9g25ek.dts
+@@ -32,6 +32,24 @@
+ phy-mode = "rmii";
+ status = "okay";
+ };
++
++ mmc0: mmc@f0008000 {
++ status = "okay";
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioD 15 0>;
++ };
++ };
++
++ mmc1: mmc@f000c000 {
++ status = "okay";
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioD 14 0>;
++ };
++ };
+ };
+
+ usb0: ohci@00600000 {
+diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts
+index a3633bd..7a7b571 100644
+--- a/arch/arm/boot/dts/at91sam9m10g45ek.dts
++++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts
+@@ -46,6 +46,25 @@
+ phy-mode = "rmii";
+ status = "okay";
+ };
++
++ mmc0: mmc@fff80000 {
++ status = "okay";
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioD 10 0>;
++ };
++ };
++
++ mmc1: mmc@fffd0000 {
++ status = "okay";
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioD 11 0>;
++ wp-gpios = <&pioD 29 0>;
++ };
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts
+index f4e43e3..44b42d9 100644
+--- a/arch/arm/boot/dts/at91sam9n12ek.dts
++++ b/arch/arm/boot/dts/at91sam9n12ek.dts
+@@ -37,6 +37,15 @@
+ dbgu: serial@fffff200 {
+ status = "okay";
+ };
++
++ mmc0: mmc@f0008000 {
++ status = "okay";
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioA 7 0>;
++ };
++ };
+ };
+
+ nand0: nand@40000000 {
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0145-mmc-atmel-mci-remove-not-needed-DMA-capability-test.patch b/patches.at91/0145-mmc-atmel-mci-remove-not-needed-DMA-capability-test.patch
new file mode 100644
index 00000000000000..d65baa1e50f304
--- /dev/null
+++ b/patches.at91/0145-mmc-atmel-mci-remove-not-needed-DMA-capability-test.patch
@@ -0,0 +1,32 @@
+From 9149e1f9aea1ca2e58c803467ee43a345b5b6645 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 7 Jun 2012 10:54:33 +0200
+Subject: mmc: atmel-mci: remove not needed DMA capability test
+
+The test about DMA capability is not needed as it is
+performed in DMA-only functions: so remove it.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/mmc/host/atmel-mci.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index 47421fc..7d9812c 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -834,9 +834,8 @@ static void atmci_dma_complete(void *arg)
+
+ dev_vdbg(&host->pdev->dev, "DMA complete\n");
+
+- if (host->caps.has_dma)
+- /* Disable DMA hardware handshaking on MCI */
+- atmci_writel(host, ATMCI_DMA, atmci_readl(host, ATMCI_DMA) & ~ATMCI_DMAEN);
++ /* Disable DMA hardware handshaking on MCI */
++ atmci_writel(host, ATMCI_DMA, atmci_readl(host, ATMCI_DMA) & ~ATMCI_DMAEN);
+
+ atmci_dma_cleanup(host);
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0146-ARM-at91-atmel-mci-remove-unused-setup_dma_addr-macr.patch b/patches.at91/0146-ARM-at91-atmel-mci-remove-unused-setup_dma_addr-macr.patch
new file mode 100644
index 00000000000000..a995d815741207
--- /dev/null
+++ b/patches.at91/0146-ARM-at91-atmel-mci-remove-unused-setup_dma_addr-macr.patch
@@ -0,0 +1,39 @@
+From 0de76cf9cfdc7f9285768b599e54fca430693623 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 14 Mar 2012 12:46:18 +0100
+Subject: ARM: at91/atmel-mci: remove unused setup_dma_addr() macro
+
+This macro is not used anymove in atmel-mci driver. It has been removed
+by a patch that was dealing with dw_dmac.c e2b35f3:
+(dmaengine/dw_dmac: Fix dw_dmac user drivers to adapt to slave_config changes)
+
+We are now using the dmaengine API to specify the slave DMA parameters:
+dmaengine_slave_config().
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Cc: Chris Ball <cjb@laptop.org>
+Cc: <linux-mmc@vger.kernel.org>
+---
+ arch/arm/mach-at91/include/mach/atmel-mci.h | 7 -------
+ 1 file changed, 7 deletions(-)
+
+diff --git a/arch/arm/mach-at91/include/mach/atmel-mci.h b/arch/arm/mach-at91/include/mach/atmel-mci.h
+index 998cb0c..5d84fe3 100644
+--- a/arch/arm/mach-at91/include/mach/atmel-mci.h
++++ b/arch/arm/mach-at91/include/mach/atmel-mci.h
+@@ -14,11 +14,4 @@ struct mci_dma_data {
+ #define slave_data_ptr(s) (&(s)->sdata)
+ #define find_slave_dev(s) ((s)->sdata.dma_dev)
+
+-#define setup_dma_addr(s, t, r) do { \
+- if (s) { \
+- (s)->sdata.tx_reg = (t); \
+- (s)->sdata.rx_reg = (r); \
+- } \
+-} while (0)
+-
+ #endif /* __MACH_ATMEL_MCI_H */
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0147-mmc-atmel-mci-remove-the-need-for-CONFIG_MMC_ATMELMC.patch b/patches.at91/0147-mmc-atmel-mci-remove-the-need-for-CONFIG_MMC_ATMELMC.patch
new file mode 100644
index 00000000000000..f16fcf81625c44
--- /dev/null
+++ b/patches.at91/0147-mmc-atmel-mci-remove-the-need-for-CONFIG_MMC_ATMELMC.patch
@@ -0,0 +1,57 @@
+From a9f7179d7975807f1f56be9d94495c8ac4bc1b53 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 15 Mar 2012 14:28:58 +0100
+Subject: mmc: atmel-mci: remove the need for CONFIG_MMC_ATMELMCI_DMA
+
+This Kconfig option is not needed anymore, so remove it.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+
+Conflicts:
+
+ drivers/mmc/host/Kconfig
+---
+ drivers/mmc/host/Kconfig | 10 ----------
+ drivers/mmc/host/atmel-mci.c | 2 --
+ 2 files changed, 12 deletions(-)
+
+diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
+index 2bc06e7..dbdd907 100644
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -297,16 +297,6 @@ config MMC_ATMELMCI
+
+ endchoice
+
+-config MMC_ATMELMCI_DMA
+- bool "Atmel MCI DMA support"
+- depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE
+- help
+- Say Y here to have the Atmel MCI driver use a DMA engine to
+- do data transfers and thus increase the throughput and
+- reduce the CPU utilization.
+-
+- If unsure, say N.
+-
+ config MMC_IMX
+ tristate "Motorola i.MX Multimedia Card Interface support"
+ depends on ARCH_MX1
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index 7d9812c..cc81ef8 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -2476,10 +2476,8 @@ static int __exit atmci_remove(struct platform_device *pdev)
+ atmci_readl(host, ATMCI_SR);
+ clk_disable(host->mck);
+
+-#ifdef CONFIG_MMC_ATMELMCI_DMA
+ if (host->dma.chan)
+ dma_release_channel(host->dma.chan);
+-#endif
+
+ free_irq(platform_get_irq(pdev, 0), host);
+ iounmap(host->regs);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0148-ARM-dts-fix-add-mmc-irq-priority.patch b/patches.at91/0148-ARM-dts-fix-add-mmc-irq-priority.patch
new file mode 100644
index 00000000000000..d1bb11b17c0705
--- /dev/null
+++ b/patches.at91/0148-ARM-dts-fix-add-mmc-irq-priority.patch
@@ -0,0 +1,109 @@
+From 426627d4be46a018b2ed24272befcfb64eea04c6 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Fri, 22 Jun 2012 16:41:08 +0200
+Subject: ARM: dts: fix add mmc irq priority
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9260.dtsi | 2 +-
+ arch/arm/boot/dts/at91sam9263.dtsi | 4 ++--
+ arch/arm/boot/dts/at91sam9g45.dtsi | 4 ++--
+ arch/arm/boot/dts/at91sam9n12.dtsi | 2 +-
+ arch/arm/boot/dts/at91sam9x5.dtsi | 4 ++--
+ 5 files changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
+index 1f2c7d0..8d95e83c 100644
+--- a/arch/arm/boot/dts/at91sam9260.dtsi
++++ b/arch/arm/boot/dts/at91sam9260.dtsi
+@@ -205,7 +205,7 @@
+ mmc0: mmc@fffa8000 {
+ compatible = "atmel,hsmci";
+ reg = <0xfffa800 0x600>;
+- interrupts = <9 4>;
++ interrupts = <9 4 0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
+index a76f6cd..54e6984 100644
+--- a/arch/arm/boot/dts/at91sam9263.dtsi
++++ b/arch/arm/boot/dts/at91sam9263.dtsi
+@@ -189,7 +189,7 @@
+ mmc0: mmc@fff80000 {
+ compatible = "atmel,hsmci";
+ reg = <0xfff80000 0x600>;
+- interrupts = <10 4>;
++ interrupts = <10 4 0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+@@ -198,7 +198,7 @@
+ mmc1: mmc@fff84000 {
+ compatible = "atmel,hsmci";
+ reg = <0xfff84000 0x600>;
+- interrupts = <11 4>;
++ interrupts = <11 4 0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
+index 4b833d4..da135f9 100644
+--- a/arch/arm/boot/dts/at91sam9g45.dtsi
++++ b/arch/arm/boot/dts/at91sam9g45.dtsi
+@@ -209,7 +209,7 @@
+ mmc0: mmc@fff80000 {
+ compatible = "atmel,hsmci";
+ reg = <0xfff80000 0x600>;
+- interrupts = <11 4>;
++ interrupts = <11 4 0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+@@ -218,7 +218,7 @@
+ mmc1: mmc@fffd0000 {
+ compatible = "atmel,hsmci";
+ reg = <0xfffd0000 0x600>;
+- interrupts = <29 4>;
++ interrupts = <29 4 0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
+index aead257..42d5fc2 100644
+--- a/arch/arm/boot/dts/at91sam9n12.dtsi
++++ b/arch/arm/boot/dts/at91sam9n12.dtsi
+@@ -85,7 +85,7 @@
+ mmc0: mmc@f0008000 {
+ compatible = "atmel,hsmci";
+ reg = <0xf0008000 0x600>;
+- interrupts = <12 4>;
++ interrupts = <12 4 0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 1be3df7..ad7016a 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -199,7 +199,7 @@
+ mmc0: mmc@f0008000 {
+ compatible = "atmel,hsmci";
+ reg = <0xf0008000 0x600>;
+- interrupts = <12 4>;
++ interrupts = <12 4 0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+@@ -208,7 +208,7 @@
+ mmc1: mmc@f000c000 {
+ compatible = "atmel,hsmci";
+ reg = <0xf000c000 0x600>;
+- interrupts = <26 4>;
++ interrupts = <26 4 0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0149-mmc-atmel-mci-support-8-bit-buswidth.patch b/patches.at91/0149-mmc-atmel-mci-support-8-bit-buswidth.patch
new file mode 100644
index 00000000000000..61f22aeb84b565
--- /dev/null
+++ b/patches.at91/0149-mmc-atmel-mci-support-8-bit-buswidth.patch
@@ -0,0 +1,32 @@
+From 5269cb6e428f2d3678304517ec43d9fd0982d05b Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 6 Sep 2011 17:49:35 +0200
+Subject: mmc: atmel-mci: support 8-bit buswidth
+
+This patch adds support for 8-bit buswidth.
+Relevant SDCR value modified.
+
+Derived from a patch by Jaehoon Chung on dw_mmc.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/mmc/host/atmel-mci.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index cc81ef8..b626d1e 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -1261,6 +1261,9 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+ case MMC_BUS_WIDTH_4:
+ slot->sdc_reg |= ATMCI_SDCBUS_4BIT;
+ break;
++ case MMC_BUS_WIDTH_8:
++ slot->sdc_reg |= ATMCI_SDCBUS_8BIT;
++ break;
+ }
+
+ if (ios->clock) {
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0150-mmc-atmel-mci-fix-incorrect-setting-of-host-data-to-.patch b/patches.at91/0150-mmc-atmel-mci-fix-incorrect-setting-of-host-data-to-.patch
new file mode 100644
index 00000000000000..d124a4651dbfdd
--- /dev/null
+++ b/patches.at91/0150-mmc-atmel-mci-fix-incorrect-setting-of-host-data-to-.patch
@@ -0,0 +1,40 @@
+From fe76a21fcd710c2e3da0072676d7d01b23247a24 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Fri, 6 Jul 2012 11:49:05 +0200
+Subject: mmc: atmel-mci: fix incorrect setting of host->data to NULL
+
+Setting host->data to NULL is incorrect sequence in STATE_SENDING_STOP
+state of FSM: This early setting leads to the skip of dma_unmap_sg()
+in atmci_dma_cleanup() which is a bug.
+
+Idea taken form dw_mmc by Seungwon Jeon.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Cc: Seungwon Jeon <tgih.jun@samsung.com>
+---
+ drivers/mmc/host/atmel-mci.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index b626d1e..90df83b 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -1754,7 +1754,6 @@ static void atmci_tasklet_func(unsigned long priv)
+
+ dev_dbg(&host->pdev->dev, "FSM: cmd ready\n");
+ host->cmd = NULL;
+- host->data = NULL;
+ data->bytes_xfered = data->blocks * data->blksz;
+ data->error = 0;
+ atmci_command_complete(host, mrq->stop);
+@@ -1768,6 +1767,7 @@ static void atmci_tasklet_func(unsigned long priv)
+ atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
+ state = STATE_WAITING_NOTBUSY;
+ }
++ host->data = NULL;
+ break;
+
+ case STATE_END_REQUEST:
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0151-mmc-block-fix-the-data-timeout-issue-with-ACMD22.patch b/patches.at91/0151-mmc-block-fix-the-data-timeout-issue-with-ACMD22.patch
new file mode 100644
index 00000000000000..2518b687566835
--- /dev/null
+++ b/patches.at91/0151-mmc-block-fix-the-data-timeout-issue-with-ACMD22.patch
@@ -0,0 +1,71 @@
+From abb226194272a5844bdbdcd04e3a8e1b1762e256 Mon Sep 17 00:00:00 2001
+From: Subhash Jadavani <subhashj@codeaurora.org>
+Date: Wed, 13 Jun 2012 17:10:43 +0530
+Subject: mmc: block: fix the data timeout issue with ACMD22
+
+If multi block write operation fails for SD card, during
+error handling we send the SD_APP_SEND_NUM_WR_BLKS (ACMD22)
+to know how many blocks were already programmed by card.
+
+But mmc_sd_num_wr_blocks() function which sends the ACMD22
+calculates the data timeout value from csd.tacc_ns and
+csd.tacc_clks parameters which will be 0 for block addressed
+(>2GB cards) SD card. This would result in timeout_ns and
+timeout_clks being 0 in the mmc_request passed to host driver.
+This means host controller would program its data timeout timer
+value with 0 which could result in DATA TIMEOUT errors from
+controller.
+
+To fix this issue, mmc_sd_num_wr_blocks() should instead
+just call the mmc_set_data_timeout() to calculate the
+data timeout value. mmc_set_data_timeout() function
+ensures that non zero timeout value is set even for
+block addressed SD cards.
+
+Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
+Reviewed-by: Venkatraman S <svenkatr@ti.com>
+Signed-off-by: Chris Ball <cjb@laptop.org>
+---
+ drivers/mmc/card/block.c | 14 +-------------
+ 1 file changed, 1 insertion(+), 13 deletions(-)
+
+diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
+index dabec55..d8f802e 100644
+--- a/drivers/mmc/card/block.c
++++ b/drivers/mmc/card/block.c
+@@ -553,7 +553,6 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
+ struct mmc_request mrq = {NULL};
+ struct mmc_command cmd = {0};
+ struct mmc_data data = {0};
+- unsigned int timeout_us;
+
+ struct scatterlist sg;
+
+@@ -573,23 +572,12 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+
+- data.timeout_ns = card->csd.tacc_ns * 100;
+- data.timeout_clks = card->csd.tacc_clks * 100;
+-
+- timeout_us = data.timeout_ns / 1000;
+- timeout_us += data.timeout_clks * 1000 /
+- (card->host->ios.clock / 1000);
+-
+- if (timeout_us > 100000) {
+- data.timeout_ns = 100000000;
+- data.timeout_clks = 0;
+- }
+-
+ data.blksz = 4;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
++ mmc_set_data_timeout(&data, card);
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0152-mmc-atmel-mci-modify-CLKDIV-displaying-in-debugfs.patch b/patches.at91/0152-mmc-atmel-mci-modify-CLKDIV-displaying-in-debugfs.patch
new file mode 100644
index 00000000000000..e848423656839c
--- /dev/null
+++ b/patches.at91/0152-mmc-atmel-mci-modify-CLKDIV-displaying-in-debugfs.patch
@@ -0,0 +1,42 @@
+From 7a25326f9063c55c62944a8890ec061f2e86bea3 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Fri, 6 Jul 2012 12:11:51 +0200
+Subject: mmc: atmel-mci: modify CLKDIV displaying in debugfs
+
+Modify clock division displaying in debugfs for matching
+the new CLKDIV,CLKODD user interface arrangement.
+Is using the has_odd_clk_div property to choose the proper format.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/mmc/host/atmel-mci.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index 90df83b..e03367c 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -394,11 +394,17 @@ static int atmci_regs_show(struct seq_file *s, void *v)
+ clk_disable(host->mck);
+ spin_unlock_bh(&host->lock);
+
+- seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n",
++ seq_printf(s, "MR:\t0x%08x%s%s ",
+ buf[ATMCI_MR / 4],
+ buf[ATMCI_MR / 4] & ATMCI_MR_RDPROOF ? " RDPROOF" : "",
+- buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : "",
+- buf[ATMCI_MR / 4] & 0xff);
++ buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : "");
++ if (host->caps.has_odd_clk_div)
++ seq_printf(s, "{CLKDIV,CLKODD}=%u\n",
++ ((buf[ATMCI_MR / 4] & 0xff) << 1)
++ | ((buf[ATMCI_MR / 4] >> 16) & 1));
++ else
++ seq_printf(s, "CLKDIV=%u\n",
++ (buf[ATMCI_MR / 4] & 0xff));
+ seq_printf(s, "DTOR:\t0x%08x\n", buf[ATMCI_DTOR / 4]);
+ seq_printf(s, "SDCR:\t0x%08x\n", buf[ATMCI_SDCR / 4]);
+ seq_printf(s, "ARGR:\t0x%08x\n", buf[ATMCI_ARGR / 4]);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0153-mmc-atmel-mci-increase-dma-threshold.patch b/patches.at91/0153-mmc-atmel-mci-increase-dma-threshold.patch
new file mode 100644
index 00000000000000..362ec2a042e578
--- /dev/null
+++ b/patches.at91/0153-mmc-atmel-mci-increase-dma-threshold.patch
@@ -0,0 +1,31 @@
+From 3903e1f7186f676dcce3a631624cf7ece8b9fbfd Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Mon, 9 Jul 2012 08:51:50 +0200
+Subject: mmc: atmel-mci: increase dma threshold
+
+There are some issues with some SD cards when dma is used. DMA transfer
+during cmd6 seems to hang for an unknown reason. Since using PIO prevents from
+this issue, the dma threshold has been increased to not use dma for this
+command.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ drivers/mmc/host/atmel-mci.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index e03367c..05a293e 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -45,7 +45,7 @@
+ #include "atmel-mci-regs.h"
+
+ #define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE)
+-#define ATMCI_DMA_THRESHOLD 16
++#define ATMCI_DMA_THRESHOLD 65
+
+ enum {
+ EVENT_CMD_RDY = 0,
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0154-mmc-atmel-mci-not-busy-flag-has-also-to-be-used-for-.patch b/patches.at91/0154-mmc-atmel-mci-not-busy-flag-has-also-to-be-used-for-.patch
new file mode 100644
index 00000000000000..32ca75a4c78f80
--- /dev/null
+++ b/patches.at91/0154-mmc-atmel-mci-not-busy-flag-has-also-to-be-used-for-.patch
@@ -0,0 +1,56 @@
+From 07e35236641fb67d7ca946a68335141989d5c8a1 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Tue, 24 Jul 2012 09:32:29 +0200
+Subject: mmc: atmel-mci: not busy flag has also to be used for read operations
+
+Even if the datasheet says that the not busy flag has to be used only for
+write operations, it's false excepted for version lesser than v2xx.
+Not waiting the not busy flag for read operations can cause the controller to
+hang-up during some SD card initialization.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ drivers/mmc/host/atmel-mci.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index 05a293e..3d9c7b8 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -84,6 +84,7 @@ struct atmel_mci_caps {
+ bool has_bad_data_ordering;
+ bool need_reset_after_xfer;
+ bool need_blksz_mul_4;
++ bool need_notbusy_for_read_ops;
+ };
+
+ struct atmel_mci_dma {
+@@ -1694,7 +1695,8 @@ static void atmci_tasklet_func(unsigned long priv)
+ __func__);
+ atmci_set_completed(host, EVENT_XFER_COMPLETE);
+
+- if (host->data->flags & MMC_DATA_WRITE) {
++ if (host->caps.need_notbusy_for_read_ops
++ || (host->data->flags & MMC_DATA_WRITE)) {
+ atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
+ state = STATE_WAITING_NOTBUSY;
+ } else if (host->mrq->stop) {
+@@ -2294,6 +2296,7 @@ static void __init atmci_get_cap(struct atmel_mci *host)
+ host->caps.has_bad_data_ordering = 1;
+ host->caps.need_reset_after_xfer = 1;
+ host->caps.need_blksz_mul_4 = 1;
++ host->caps.need_notbusy_for_read_ops = 0;
+
+ /* keep only major version number */
+ switch (version & 0xf00) {
+@@ -2314,6 +2317,7 @@ static void __init atmci_get_cap(struct atmel_mci *host)
+ case 0x200:
+ host->caps.has_rwproof = 1;
+ host->caps.need_blksz_mul_4 = 0;
++ host->caps.need_notbusy_for_read_ops = 1;
+ case 0x100:
+ host->caps.has_bad_data_ordering = 0;
+ host->caps.need_reset_after_xfer = 0;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0155-Replace-clk_lookup.con_id-with-clk_lookup.dev_id-ent.patch b/patches.at91/0155-Replace-clk_lookup.con_id-with-clk_lookup.dev_id-ent.patch
new file mode 100644
index 00000000000000..bf54a48103a57f
--- /dev/null
+++ b/patches.at91/0155-Replace-clk_lookup.con_id-with-clk_lookup.dev_id-ent.patch
@@ -0,0 +1,116 @@
+From e10db2b8116769c8b0ccdd53c424fac0bd7a2c64 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 22 Oct 2012 15:52:48 +0200
+Subject: Replace clk_lookup.con_id with clk_lookup.dev_id entries for twi clk
+
+The old driver used con_id clock entries. Convert to use dev_id
+for clock lookup via standard method.
+
+Signed-off-by: Nikolaus Voss <n.voss@weinmann.de>
+Tested-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Reviewed-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+
+Conflicts:
+ arch/arm/mach-at91/at91sam9x5.c
+---
+ arch/arm/mach-at91/at91rm9200.c | 1 +
+ arch/arm/mach-at91/at91sam9260.c | 1 +
+ arch/arm/mach-at91/at91sam9261.c | 1 +
+ arch/arm/mach-at91/at91sam9263.c | 1 +
+ arch/arm/mach-at91/at91sam9g45.c | 2 ++
+ arch/arm/mach-at91/at91sam9rl.c | 2 ++
+ arch/arm/mach-at91/at91sam9x5.c | 3 +++
+ 7 files changed, 11 insertions(+)
+
+diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
+index 6f50c67..f2112f9 100644
+--- a/arch/arm/mach-at91/at91rm9200.c
++++ b/arch/arm/mach-at91/at91rm9200.c
+@@ -187,6 +187,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
+ /* fake hclk clock */
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
+index 4696729..d824b0e 100644
+--- a/arch/arm/mach-at91/at91sam9260.c
++++ b/arch/arm/mach-at91/at91sam9260.c
+@@ -203,6 +203,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
+ CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc_clk),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
+ /* more usart lookup table for DT entries */
+ CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
+ CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk),
+diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
+index f40762c..71ca1e0 100644
+--- a/arch/arm/mach-at91/at91sam9261.c
++++ b/arch/arm/mach-at91/at91sam9261.c
+@@ -178,6 +178,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &hck0),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+ CLKDEV_CON_ID("pioB", &pioB_clk),
+ CLKDEV_CON_ID("pioC", &pioC_clk),
+diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
+index c82d521..00c947e 100644
+--- a/arch/arm/mach-at91/at91sam9263.c
++++ b/arch/arm/mach-at91/at91sam9263.c
+@@ -193,6 +193,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
+ /* fake hclk clock */
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
+index f6d0eab..5de8b00 100644
+--- a/arch/arm/mach-at91/at91sam9g45.c
++++ b/arch/arm/mach-at91/at91sam9g45.c
+@@ -222,6 +222,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb0_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tcb0_clk),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.0", &twi0_clk),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk),
+diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
+index 72ce50a..bf79c1f 100644
+--- a/arch/arm/mach-at91/at91sam9rl.c
++++ b/arch/arm/mach-at91/at91sam9rl.c
+@@ -186,6 +186,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.0", &twi0_clk),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+ CLKDEV_CON_ID("pioB", &pioB_clk),
+ CLKDEV_CON_ID("pioC", &pioC_clk),
+diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
+index 796b3c0..15ac57b 100644
+--- a/arch/arm/mach-at91/at91sam9x5.c
++++ b/arch/arm/mach-at91/at91sam9x5.c
+@@ -227,6 +227,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "f0008000.mmc", &mmc0_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "f000c000.mmc", &mmc1_clk),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.0", &twi0_clk),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.2", &twi2_clk),
+ CLKDEV_CON_ID("pioA", &pioAB_clk),
+ CLKDEV_CON_ID("pioB", &pioAB_clk),
+ CLKDEV_CON_ID("pioC", &pioCD_clk),
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0156-i2c-at91-remove-old-polling-driver.patch b/patches.at91/0156-i2c-at91-remove-old-polling-driver.patch
new file mode 100644
index 00000000000000..6344648882d190
--- /dev/null
+++ b/patches.at91/0156-i2c-at91-remove-old-polling-driver.patch
@@ -0,0 +1,432 @@
+From 191188312560199aab82f13568cc1532035a3cf1 Mon Sep 17 00:00:00 2001
+From: Nikolaus Voss <n.voss@weinmann.de>
+Date: Tue, 8 Nov 2011 11:49:24 +0100
+Subject: i2c: at91: remove old polling driver
+
+It will get replaced by a superior one. Safe to remove since this one
+depends on BROKEN anyhow.
+
+Signed-off-by: Nikolaus Voss <n.voss@weinmann.de>
+Tested-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Reviewed-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+
+[wsa: added commit message]
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+---
+ arch/arm/mach-at91/include/mach/at91_twi.h | 68 -------
+ drivers/i2c/busses/Makefile | 1 -
+ drivers/i2c/busses/i2c-at91.c | 314 -----------------------------
+ 3 files changed, 383 deletions(-)
+ delete mode 100644 arch/arm/mach-at91/include/mach/at91_twi.h
+ delete mode 100644 drivers/i2c/busses/i2c-at91.c
+
+diff --git a/arch/arm/mach-at91/include/mach/at91_twi.h b/arch/arm/mach-at91/include/mach/at91_twi.h
+deleted file mode 100644
+index bb2880f..0000000
+--- a/arch/arm/mach-at91/include/mach/at91_twi.h
++++ /dev/null
+@@ -1,68 +0,0 @@
+-/*
+- * arch/arm/mach-at91/include/mach/at91_twi.h
+- *
+- * Copyright (C) 2005 Ivan Kokshaysky
+- * Copyright (C) SAN People
+- *
+- * Two-wire Interface (TWI) registers.
+- * Based on AT91RM9200 datasheet revision E.
+- *
+- * 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 AT91_TWI_H
+-#define AT91_TWI_H
+-
+-#define AT91_TWI_CR 0x00 /* Control Register */
+-#define AT91_TWI_START (1 << 0) /* Send a Start Condition */
+-#define AT91_TWI_STOP (1 << 1) /* Send a Stop Condition */
+-#define AT91_TWI_MSEN (1 << 2) /* Master Transfer Enable */
+-#define AT91_TWI_MSDIS (1 << 3) /* Master Transfer Disable */
+-#define AT91_TWI_SVEN (1 << 4) /* Slave Transfer Enable [SAM9260 only] */
+-#define AT91_TWI_SVDIS (1 << 5) /* Slave Transfer Disable [SAM9260 only] */
+-#define AT91_TWI_SWRST (1 << 7) /* Software Reset */
+-
+-#define AT91_TWI_MMR 0x04 /* Master Mode Register */
+-#define AT91_TWI_IADRSZ (3 << 8) /* Internal Device Address Size */
+-#define AT91_TWI_IADRSZ_NO (0 << 8)
+-#define AT91_TWI_IADRSZ_1 (1 << 8)
+-#define AT91_TWI_IADRSZ_2 (2 << 8)
+-#define AT91_TWI_IADRSZ_3 (3 << 8)
+-#define AT91_TWI_MREAD (1 << 12) /* Master Read Direction */
+-#define AT91_TWI_DADR (0x7f << 16) /* Device Address */
+-
+-#define AT91_TWI_SMR 0x08 /* Slave Mode Register [SAM9260 only] */
+-#define AT91_TWI_SADR (0x7f << 16) /* Slave Address */
+-
+-#define AT91_TWI_IADR 0x0c /* Internal Address Register */
+-
+-#define AT91_TWI_CWGR 0x10 /* Clock Waveform Generator Register */
+-#define AT91_TWI_CLDIV (0xff << 0) /* Clock Low Divisor */
+-#define AT91_TWI_CHDIV (0xff << 8) /* Clock High Divisor */
+-#define AT91_TWI_CKDIV (7 << 16) /* Clock Divider */
+-
+-#define AT91_TWI_SR 0x20 /* Status Register */
+-#define AT91_TWI_TXCOMP (1 << 0) /* Transmission Complete */
+-#define AT91_TWI_RXRDY (1 << 1) /* Receive Holding Register Ready */
+-#define AT91_TWI_TXRDY (1 << 2) /* Transmit Holding Register Ready */
+-#define AT91_TWI_SVREAD (1 << 3) /* Slave Read [SAM9260 only] */
+-#define AT91_TWI_SVACC (1 << 4) /* Slave Access [SAM9260 only] */
+-#define AT91_TWI_GACC (1 << 5) /* General Call Access [SAM9260 only] */
+-#define AT91_TWI_OVRE (1 << 6) /* Overrun Error [AT91RM9200 only] */
+-#define AT91_TWI_UNRE (1 << 7) /* Underrun Error [AT91RM9200 only] */
+-#define AT91_TWI_NACK (1 << 8) /* Not Acknowledged */
+-#define AT91_TWI_ARBLST (1 << 9) /* Arbitration Lost [SAM9260 only] */
+-#define AT91_TWI_SCLWS (1 << 10) /* Clock Wait State [SAM9260 only] */
+-#define AT91_TWI_EOSACC (1 << 11) /* End of Slave Address [SAM9260 only] */
+-
+-#define AT91_TWI_IER 0x24 /* Interrupt Enable Register */
+-#define AT91_TWI_IDR 0x28 /* Interrupt Disable Register */
+-#define AT91_TWI_IMR 0x2c /* Interrupt Mask Register */
+-#define AT91_TWI_RHR 0x30 /* Receive Holding Register */
+-#define AT91_TWI_THR 0x34 /* Transmit Holding Register */
+-
+-#endif
+-
+diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
+index 569567b..b74c801 100644
+--- a/drivers/i2c/busses/Makefile
++++ b/drivers/i2c/busses/Makefile
+@@ -28,7 +28,6 @@ obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
+ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
+
+ # Embedded system I2C/SMBus host controller drivers
+-obj-$(CONFIG_I2C_AT91) += i2c-at91.o
+ obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
+ obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
+ obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
+diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
+deleted file mode 100644
+index 1679dee..0000000
+--- a/drivers/i2c/busses/i2c-at91.c
++++ /dev/null
+@@ -1,314 +0,0 @@
+-/*
+- i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
+-
+- Copyright (C) 2004 Rick Bronson
+- Converted to 2.6 by Andrew Victor <andrew@sanpeople.com>
+-
+- Borrowed heavily from original work by:
+- Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.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.
+-*/
+-
+-#include <linux/module.h>
+-#include <linux/kernel.h>
+-#include <linux/err.h>
+-#include <linux/slab.h>
+-#include <linux/types.h>
+-#include <linux/delay.h>
+-#include <linux/i2c.h>
+-#include <linux/init.h>
+-#include <linux/clk.h>
+-#include <linux/platform_device.h>
+-#include <linux/io.h>
+-
+-#include <mach/at91_twi.h>
+-#include <mach/board.h>
+-#include <mach/cpu.h>
+-
+-#define TWI_CLOCK 100000 /* Hz. max 400 Kbits/sec */
+-
+-
+-static struct clk *twi_clk;
+-static void __iomem *twi_base;
+-
+-#define at91_twi_read(reg) __raw_readl(twi_base + (reg))
+-#define at91_twi_write(reg, val) __raw_writel((val), twi_base + (reg))
+-
+-
+-/*
+- * Initialize the TWI hardware registers.
+- */
+-static void __devinit at91_twi_hwinit(void)
+-{
+- unsigned long cdiv, ckdiv;
+-
+- at91_twi_write(AT91_TWI_IDR, 0xffffffff); /* Disable all interrupts */
+- at91_twi_write(AT91_TWI_CR, AT91_TWI_SWRST); /* Reset peripheral */
+- at91_twi_write(AT91_TWI_CR, AT91_TWI_MSEN); /* Set Master mode */
+-
+- /* Calcuate clock dividers */
+- cdiv = (clk_get_rate(twi_clk) / (2 * TWI_CLOCK)) - 3;
+- cdiv = cdiv + 1; /* round up */
+- ckdiv = 0;
+- while (cdiv > 255) {
+- ckdiv++;
+- cdiv = cdiv >> 1;
+- }
+-
+- if (cpu_is_at91rm9200()) { /* AT91RM9200 Errata #22 */
+- if (ckdiv > 5) {
+- printk(KERN_ERR "AT91 I2C: Invalid TWI_CLOCK value!\n");
+- ckdiv = 5;
+- }
+- }
+-
+- at91_twi_write(AT91_TWI_CWGR, (ckdiv << 16) | (cdiv << 8) | cdiv);
+-}
+-
+-/*
+- * Poll the i2c status register until the specified bit is set.
+- * Returns 0 if timed out (100 msec).
+- */
+-static short at91_poll_status(unsigned long bit)
+-{
+- int loop_cntr = 10000;
+-
+- do {
+- udelay(10);
+- } while (!(at91_twi_read(AT91_TWI_SR) & bit) && (--loop_cntr > 0));
+-
+- return (loop_cntr > 0);
+-}
+-
+-static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
+-{
+- /* Send Start */
+- at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
+-
+- /* Read data */
+- while (length--) {
+- if (!length) /* need to send Stop before reading last byte */
+- at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
+- if (!at91_poll_status(AT91_TWI_RXRDY)) {
+- dev_dbg(&adap->dev, "RXRDY timeout\n");
+- return -ETIMEDOUT;
+- }
+- *buf++ = (at91_twi_read(AT91_TWI_RHR) & 0xff);
+- }
+-
+- return 0;
+-}
+-
+-static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length)
+-{
+- /* Load first byte into transmitter */
+- at91_twi_write(AT91_TWI_THR, *buf++);
+-
+- /* Send Start */
+- at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
+-
+- do {
+- if (!at91_poll_status(AT91_TWI_TXRDY)) {
+- dev_dbg(&adap->dev, "TXRDY timeout\n");
+- return -ETIMEDOUT;
+- }
+-
+- length--; /* byte was transmitted */
+-
+- if (length > 0) /* more data to send? */
+- at91_twi_write(AT91_TWI_THR, *buf++);
+- } while (length);
+-
+- /* Send Stop */
+- at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
+-
+- return 0;
+-}
+-
+-/*
+- * Generic i2c master transfer entrypoint.
+- *
+- * Note: We do not use Atmel's feature of storing the "internal device address".
+- * Instead the "internal device address" has to be written using a separate
+- * i2c message.
+- * http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2004-September/024411.html
+- */
+-static int at91_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num)
+-{
+- int i, ret;
+-
+- dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num);
+-
+- for (i = 0; i < num; i++) {
+- dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i,
+- pmsg->flags & I2C_M_RD ? "read" : "writ",
+- pmsg->len, pmsg->len > 1 ? "s" : "",
+- pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr);
+-
+- at91_twi_write(AT91_TWI_MMR, (pmsg->addr << 16)
+- | ((pmsg->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0));
+-
+- if (pmsg->len && pmsg->buf) { /* sanity check */
+- if (pmsg->flags & I2C_M_RD)
+- ret = xfer_read(adap, pmsg->buf, pmsg->len);
+- else
+- ret = xfer_write(adap, pmsg->buf, pmsg->len);
+-
+- if (ret)
+- return ret;
+-
+- /* Wait until transfer is finished */
+- if (!at91_poll_status(AT91_TWI_TXCOMP)) {
+- dev_dbg(&adap->dev, "TXCOMP timeout\n");
+- return -ETIMEDOUT;
+- }
+- }
+- dev_dbg(&adap->dev, "transfer complete\n");
+- pmsg++; /* next message */
+- }
+- return i;
+-}
+-
+-/*
+- * Return list of supported functionality.
+- */
+-static u32 at91_func(struct i2c_adapter *adapter)
+-{
+- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+-}
+-
+-static struct i2c_algorithm at91_algorithm = {
+- .master_xfer = at91_xfer,
+- .functionality = at91_func,
+-};
+-
+-/*
+- * Main initialization routine.
+- */
+-static int __devinit at91_i2c_probe(struct platform_device *pdev)
+-{
+- struct i2c_adapter *adapter;
+- struct resource *res;
+- int rc;
+-
+- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- if (!res)
+- return -ENXIO;
+-
+- if (!request_mem_region(res->start, resource_size(res), "at91_i2c"))
+- return -EBUSY;
+-
+- twi_base = ioremap(res->start, resource_size(res));
+- if (!twi_base) {
+- rc = -ENOMEM;
+- goto fail0;
+- }
+-
+- twi_clk = clk_get(NULL, "twi_clk");
+- if (IS_ERR(twi_clk)) {
+- dev_err(&pdev->dev, "no clock defined\n");
+- rc = -ENODEV;
+- goto fail1;
+- }
+-
+- adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+- if (adapter == NULL) {
+- dev_err(&pdev->dev, "can't allocate inteface!\n");
+- rc = -ENOMEM;
+- goto fail2;
+- }
+- snprintf(adapter->name, sizeof(adapter->name), "AT91");
+- adapter->algo = &at91_algorithm;
+- adapter->class = I2C_CLASS_HWMON;
+- adapter->dev.parent = &pdev->dev;
+- /* adapter->id == 0 ... only one TWI controller for now */
+-
+- platform_set_drvdata(pdev, adapter);
+-
+- clk_enable(twi_clk); /* enable peripheral clock */
+- at91_twi_hwinit(); /* initialize TWI controller */
+-
+- rc = i2c_add_numbered_adapter(adapter);
+- if (rc) {
+- dev_err(&pdev->dev, "Adapter %s registration failed\n",
+- adapter->name);
+- goto fail3;
+- }
+-
+- dev_info(&pdev->dev, "AT91 i2c bus driver.\n");
+- return 0;
+-
+-fail3:
+- platform_set_drvdata(pdev, NULL);
+- kfree(adapter);
+- clk_disable(twi_clk);
+-fail2:
+- clk_put(twi_clk);
+-fail1:
+- iounmap(twi_base);
+-fail0:
+- release_mem_region(res->start, resource_size(res));
+-
+- return rc;
+-}
+-
+-static int __devexit at91_i2c_remove(struct platform_device *pdev)
+-{
+- struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+- struct resource *res;
+- int rc;
+-
+- rc = i2c_del_adapter(adapter);
+- platform_set_drvdata(pdev, NULL);
+-
+- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- iounmap(twi_base);
+- release_mem_region(res->start, resource_size(res));
+-
+- clk_disable(twi_clk); /* disable peripheral clock */
+- clk_put(twi_clk);
+-
+- return rc;
+-}
+-
+-#ifdef CONFIG_PM
+-
+-/* NOTE: could save a few mA by keeping clock off outside of at91_xfer... */
+-
+-static int at91_i2c_suspend(struct platform_device *pdev, pm_message_t mesg)
+-{
+- clk_disable(twi_clk);
+- return 0;
+-}
+-
+-static int at91_i2c_resume(struct platform_device *pdev)
+-{
+- return clk_enable(twi_clk);
+-}
+-
+-#else
+-#define at91_i2c_suspend NULL
+-#define at91_i2c_resume NULL
+-#endif
+-
+-static struct platform_driver at91_i2c_driver = {
+- .probe = at91_i2c_probe,
+- .remove = __devexit_p(at91_i2c_remove),
+- .suspend = at91_i2c_suspend,
+- .resume = at91_i2c_resume,
+- .driver = {
+- .name = "at91_i2c",
+- .owner = THIS_MODULE,
+- },
+-};
+-
+-module_platform_driver(at91_i2c_driver);
+-
+-MODULE_AUTHOR("Rick Bronson");
+-MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
+-MODULE_LICENSE("GPL");
+-MODULE_ALIAS("platform:at91_i2c");
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0157-i2c-at91-add-new-driver.patch b/patches.at91/0157-i2c-at91-add-new-driver.patch
new file mode 100644
index 00000000000000..b2590271424a38
--- /dev/null
+++ b/patches.at91/0157-i2c-at91-add-new-driver.patch
@@ -0,0 +1,774 @@
+From 1762cb01f6be4ddf6560eca0b2529901736d6cbb Mon Sep 17 00:00:00 2001
+From: Nikolaus Voss <n.voss@weinmann.de>
+Date: Tue, 8 Nov 2011 11:49:46 +0100
+Subject: i2c: at91: add new driver
+
+This driver has the following properties compared to the old driver:
+1. Support for multiple interfaces.
+2. Interrupt driven I/O as opposed to polling/busy waiting.
+3. Support for _one_ repeated start (Sr) condition, which is enough
+ for most real-world applications including all SMBus transfer types.
+ (The hardware does not support issuing arbitrary Sr conditions on the
+ bus.)
+
+testing: SoC: at91sam9g45
+ - BQ20Z80 battery SMBus client.
+ - on a 2.6.38 kernel with several i2c clients (temp-sensor,
+ audio-codec, touchscreen-controller, w1-bridge, io-expanders)
+
+Signed-off-by: Nikolaus Voss <n.voss@weinmann.de>
+Reviewed-by: Felipe Balbi <balbi@ti.com>
+Tested-by: Hubert Feurstein <h.feurstein@gmail.com>
+Tested-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Reviewed-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+
+[wsa: squashed with the following patches from Ludovic to have some flaws
+fixed:
+ i2c: at91: use managed resources
+ i2c: at91: add warning about transmission issues for some devices
+ i2c: at91: use an id table for SoC dependent parameters
+]
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+---
+ arch/arm/mach-at91/at91rm9200.c | 2
+ arch/arm/mach-at91/at91rm9200_devices.c | 2
+ arch/arm/mach-at91/at91sam9260.c | 3
+ arch/arm/mach-at91/at91sam9260_devices.c | 8
+ arch/arm/mach-at91/at91sam9261.c | 3
+ arch/arm/mach-at91/at91sam9261_devices.c | 8
+ arch/arm/mach-at91/at91sam9263.c | 2
+ arch/arm/mach-at91/at91sam9263_devices.c | 2
+ arch/arm/mach-at91/at91sam9g45.c | 4
+ arch/arm/mach-at91/at91sam9g45_devices.c | 4
+ arch/arm/mach-at91/at91sam9rl.c | 4
+ arch/arm/mach-at91/at91sam9rl_devices.c | 2
+ drivers/i2c/busses/Kconfig | 17 -
+ drivers/i2c/busses/Makefile | 1
+ drivers/i2c/busses/i2c-at91.c | 505 +++++++++++++++++++++++++++++++
+ 15 files changed, 545 insertions(+), 22 deletions(-)
+ create mode 100644 drivers/i2c/busses/i2c-at91.c
+
+--- a/arch/arm/mach-at91/at91rm9200.c
++++ b/arch/arm/mach-at91/at91rm9200.c
+@@ -187,7 +187,7 @@ static struct clk_lookup periph_clocks_l
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200", &twi_clk),
+ /* fake hclk clock */
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+--- a/arch/arm/mach-at91/at91rm9200_devices.c
++++ b/arch/arm/mach-at91/at91rm9200_devices.c
+@@ -511,7 +511,7 @@ static struct resource twi_resources[] =
+ };
+
+ static struct platform_device at91rm9200_twi_device = {
+- .name = "at91_i2c",
++ .name = "i2c-at91rm9200",
+ .id = -1,
+ .resource = twi_resources,
+ .num_resources = ARRAY_SIZE(twi_resources),
+--- a/arch/arm/mach-at91/at91sam9260.c
++++ b/arch/arm/mach-at91/at91sam9260.c
+@@ -203,7 +203,8 @@ static struct clk_lookup periph_clocks_l
+ CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
+ CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc_clk),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20", &twi_clk),
+ /* more usart lookup table for DT entries */
+ CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
+ CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk),
+--- a/arch/arm/mach-at91/at91sam9260_devices.c
++++ b/arch/arm/mach-at91/at91sam9260_devices.c
+@@ -418,7 +418,6 @@ static struct resource twi_resources[] =
+ };
+
+ static struct platform_device at91sam9260_twi_device = {
+- .name = "at91_i2c",
+ .id = -1,
+ .resource = twi_resources,
+ .num_resources = ARRAY_SIZE(twi_resources),
+@@ -426,6 +425,13 @@ static struct platform_device at91sam926
+
+ void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
+ {
++ /* IP version is not the same on 9260 and g20 */
++ if (cpu_is_at91sam9g20()) {
++ at91sam9260_twi_device.name = "i2c-at91sam9g20";
++ } else {
++ at91sam9260_twi_device.name = "i2c-at91sam9260";
++ }
++
+ /* pins used for TWI interface */
+ at91_set_A_periph(AT91_PIN_PA23, 0); /* TWD */
+ at91_set_multi_drive(AT91_PIN_PA23, 1);
+--- a/arch/arm/mach-at91/at91sam9261.c
++++ b/arch/arm/mach-at91/at91sam9261.c
+@@ -178,7 +178,8 @@ static struct clk_lookup periph_clocks_l
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &hck0),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9261", &twi_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10", &twi_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+ CLKDEV_CON_ID("pioB", &pioB_clk),
+ CLKDEV_CON_ID("pioC", &pioC_clk),
+--- a/arch/arm/mach-at91/at91sam9261_devices.c
++++ b/arch/arm/mach-at91/at91sam9261_devices.c
+@@ -319,7 +319,6 @@ static struct resource twi_resources[] =
+ };
+
+ static struct platform_device at91sam9261_twi_device = {
+- .name = "at91_i2c",
+ .id = -1,
+ .resource = twi_resources,
+ .num_resources = ARRAY_SIZE(twi_resources),
+@@ -327,6 +326,13 @@ static struct platform_device at91sam926
+
+ void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
+ {
++ /* IP version is not the same on 9261 and g10 */
++ if (cpu_is_at91sam9g10()) {
++ at91sam9261_twi_device.name = "i2c-at91sam9g10";
++ } else {
++ at91sam9261_twi_device.name = "i2c-at91sam9261";
++ }
++
+ /* pins used for TWI interface */
+ at91_set_A_periph(AT91_PIN_PA7, 0); /* TWD */
+ at91_set_multi_drive(AT91_PIN_PA7, 1);
+--- a/arch/arm/mach-at91/at91sam9263.c
++++ b/arch/arm/mach-at91/at91sam9263.c
+@@ -193,7 +193,7 @@ static struct clk_lookup periph_clocks_l
+ CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk),
+ /* fake hclk clock */
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+--- a/arch/arm/mach-at91/at91sam9263_devices.c
++++ b/arch/arm/mach-at91/at91sam9263_devices.c
+@@ -601,7 +601,7 @@ static struct resource twi_resources[] =
+ };
+
+ static struct platform_device at91sam9263_twi_device = {
+- .name = "at91_i2c",
++ .name = "i2c-at91sam9260",
+ .id = -1,
+ .resource = twi_resources,
+ .num_resources = ARRAY_SIZE(twi_resources),
+--- a/arch/arm/mach-at91/at91sam9g45.c
++++ b/arch/arm/mach-at91/at91sam9g45.c
+@@ -222,8 +222,8 @@ static struct clk_lookup periph_clocks_l
+ CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb0_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tcb0_clk),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.0", &twi0_clk),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.0", &twi0_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.1", &twi1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk),
+--- a/arch/arm/mach-at91/at91sam9g45_devices.c
++++ b/arch/arm/mach-at91/at91sam9g45_devices.c
+@@ -651,7 +651,7 @@ static struct resource twi0_resources[]
+ };
+
+ static struct platform_device at91sam9g45_twi0_device = {
+- .name = "at91_i2c",
++ .name = "i2c-at91sam9g10",
+ .id = 0,
+ .resource = twi0_resources,
+ .num_resources = ARRAY_SIZE(twi0_resources),
+@@ -671,7 +671,7 @@ static struct resource twi1_resources[]
+ };
+
+ static struct platform_device at91sam9g45_twi1_device = {
+- .name = "at91_i2c",
++ .name = "i2c-at91sam9g10",
+ .id = 1,
+ .resource = twi1_resources,
+ .num_resources = ARRAY_SIZE(twi1_resources),
+--- a/arch/arm/mach-at91/at91sam9rl.c
++++ b/arch/arm/mach-at91/at91sam9rl.c
+@@ -186,8 +186,8 @@ static struct clk_lookup periph_clocks_l
+ CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.0", &twi0_clk),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi0_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.1", &twi1_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+ CLKDEV_CON_ID("pioB", &pioB_clk),
+ CLKDEV_CON_ID("pioC", &pioC_clk),
+--- a/arch/arm/mach-at91/at91sam9rl_devices.c
++++ b/arch/arm/mach-at91/at91sam9rl_devices.c
+@@ -348,7 +348,7 @@ static struct resource twi_resources[] =
+ };
+
+ static struct platform_device at91sam9rl_twi_device = {
+- .name = "at91_i2c",
++ .name = "i2c-at91sam9g20",
+ .id = -1,
+ .resource = twi_resources,
+ .num_resources = ARRAY_SIZE(twi_resources),
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -287,18 +287,21 @@ comment "I2C system bus drivers (mostly
+
+ config I2C_AT91
+ tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
+- depends on ARCH_AT91 && EXPERIMENTAL && BROKEN
++ depends on ARCH_AT91 && EXPERIMENTAL
+ help
+ This supports the use of the I2C interface on Atmel AT91
+ processors.
+
+- This driver is BROKEN because the controller which it uses
+- will easily trigger RX overrun and TX underrun errors. Using
+- low I2C clock rates may partially work around those issues
+- on some systems. Another serious problem is that there is no
+- documented way to issue repeated START conditions, as needed
++ A serious problem is that there is no documented way to issue
++ repeated START conditions for more than two messages, as needed
+ to support combined I2C messages. Use the i2c-gpio driver
+- unless your system can cope with those limitations.
++ unless your system can cope with this limitation.
++
++ Caution! at91rm9200, at91sam9261, at91sam9260, at91sam9263 devices
++ don't have clock stretching in transmission mode. For that reason,
++ you can encounter underrun issues causing premature stop sendings if
++ the latency to fill the transmission register is too long. If you
++ are facing this situation, use the i2c-gpio driver.
+
+ config I2C_AU1550
+ tristate "Au1550/Au1200/Au1300 SMBus interface"
+--- a/drivers/i2c/busses/Makefile
++++ b/drivers/i2c/busses/Makefile
+@@ -28,6 +28,7 @@ obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
+ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
+
+ # Embedded system I2C/SMBus host controller drivers
++obj-$(CONFIG_I2C_AT91) += i2c-at91.o
+ obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
+ obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
+ obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
+--- /dev/null
++++ b/drivers/i2c/busses/i2c-at91.c
+@@ -0,0 +1,505 @@
++/*
++ * i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
++ *
++ * Copyright (C) 2011 Weinmann Medical GmbH
++ * Author: Nikolaus Voss <n.voss@weinmann.de>
++ *
++ * Evolved from original work by:
++ * Copyright (C) 2004 Rick Bronson
++ * Converted to 2.6 by Andrew Victor <andrew@sanpeople.com>
++ *
++ * Borrowed heavily from original work by:
++ * Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.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.
++ */
++
++#include <linux/clk.h>
++#include <linux/completion.h>
++#include <linux/err.h>
++#include <linux/i2c.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#define TWI_CLK_HZ 100000 /* max 400 Kbits/s */
++#define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */
++
++/* AT91 TWI register definitions */
++#define AT91_TWI_CR 0x0000 /* Control Register */
++#define AT91_TWI_START 0x0001 /* Send a Start Condition */
++#define AT91_TWI_STOP 0x0002 /* Send a Stop Condition */
++#define AT91_TWI_MSEN 0x0004 /* Master Transfer Enable */
++#define AT91_TWI_SVDIS 0x0020 /* Slave Transfer Disable */
++#define AT91_TWI_SWRST 0x0080 /* Software Reset */
++
++#define AT91_TWI_MMR 0x0004 /* Master Mode Register */
++#define AT91_TWI_IADRSZ_1 0x0100 /* Internal Device Address Size */
++#define AT91_TWI_MREAD 0x1000 /* Master Read Direction */
++
++#define AT91_TWI_IADR 0x000c /* Internal Address Register */
++
++#define AT91_TWI_CWGR 0x0010 /* Clock Waveform Generator Reg */
++
++#define AT91_TWI_SR 0x0020 /* Status Register */
++#define AT91_TWI_TXCOMP 0x0001 /* Transmission Complete */
++#define AT91_TWI_RXRDY 0x0002 /* Receive Holding Register Ready */
++#define AT91_TWI_TXRDY 0x0004 /* Transmit Holding Register Ready */
++
++#define AT91_TWI_OVRE 0x0040 /* Overrun Error */
++#define AT91_TWI_UNRE 0x0080 /* Underrun Error */
++#define AT91_TWI_NACK 0x0100 /* Not Acknowledged */
++
++#define AT91_TWI_IER 0x0024 /* Interrupt Enable Register */
++#define AT91_TWI_IDR 0x0028 /* Interrupt Disable Register */
++#define AT91_TWI_IMR 0x002c /* Interrupt Mask Register */
++#define AT91_TWI_RHR 0x0030 /* Receive Holding Register */
++#define AT91_TWI_THR 0x0034 /* Transmit Holding Register */
++
++struct at91_twi_pdata {
++ unsigned clk_max_div;
++ unsigned clk_offset;
++ bool has_unre_flag;
++};
++
++struct at91_twi_dev {
++ struct device *dev;
++ void __iomem *base;
++ struct completion cmd_complete;
++ struct clk *clk;
++ u8 *buf;
++ size_t buf_len;
++ struct i2c_msg *msg;
++ int irq;
++ unsigned transfer_status;
++ struct i2c_adapter adapter;
++ unsigned twi_cwgr_reg;
++ struct at91_twi_pdata *pdata;
++};
++
++static unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg)
++{
++ return readl_relaxed(dev->base + reg);
++}
++
++static void at91_twi_write(struct at91_twi_dev *dev, unsigned reg, unsigned val)
++{
++ writel_relaxed(val, dev->base + reg);
++}
++
++static void at91_disable_twi_interrupts(struct at91_twi_dev *dev)
++{
++ at91_twi_write(dev, AT91_TWI_IDR,
++ AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY);
++}
++
++static void at91_init_twi_bus(struct at91_twi_dev *dev)
++{
++ at91_disable_twi_interrupts(dev);
++ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SWRST);
++ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_MSEN);
++ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SVDIS);
++ at91_twi_write(dev, AT91_TWI_CWGR, dev->twi_cwgr_reg);
++}
++
++/*
++ * Calculate symmetric clock as stated in datasheet:
++ * twi_clk = F_MAIN / (2 * (cdiv * (1 << ckdiv) + offset))
++ */
++static void __devinit at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
++{
++ int ckdiv, cdiv, div;
++ struct at91_twi_pdata *pdata = dev->pdata;
++ int offset = pdata->clk_offset;
++ int max_ckdiv = pdata->clk_max_div;
++
++ div = max(0, (int)DIV_ROUND_UP(clk_get_rate(dev->clk),
++ 2 * twi_clk) - offset);
++ ckdiv = fls(div >> 8);
++ cdiv = div >> ckdiv;
++
++ if (ckdiv > max_ckdiv) {
++ dev_warn(dev->dev, "%d exceeds ckdiv max value which is %d.\n",
++ ckdiv, max_ckdiv);
++ ckdiv = max_ckdiv;
++ cdiv = 255;
++ }
++
++ dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv;
++ dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv);
++}
++
++static void at91_twi_write_next_byte(struct at91_twi_dev *dev)
++{
++ if (dev->buf_len <= 0)
++ return;
++
++ at91_twi_write(dev, AT91_TWI_THR, *dev->buf);
++
++ /* send stop when last byte has been written */
++ if (--dev->buf_len == 0)
++ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
++
++ dev_dbg(dev->dev, "wrote 0x%x, to go %d\n", *dev->buf, dev->buf_len);
++
++ ++dev->buf;
++}
++
++static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
++{
++ if (dev->buf_len <= 0)
++ return;
++
++ *dev->buf = at91_twi_read(dev, AT91_TWI_RHR) & 0xff;
++ --dev->buf_len;
++
++ /* handle I2C_SMBUS_BLOCK_DATA */
++ if (unlikely(dev->msg->flags & I2C_M_RECV_LEN)) {
++ dev->msg->flags &= ~I2C_M_RECV_LEN;
++ dev->buf_len += *dev->buf;
++ dev->msg->len = dev->buf_len + 1;
++ dev_dbg(dev->dev, "received block length %d\n", dev->buf_len);
++ }
++
++ /* send stop if second but last byte has been read */
++ if (dev->buf_len == 1)
++ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
++
++ dev_dbg(dev->dev, "read 0x%x, to go %d\n", *dev->buf, dev->buf_len);
++
++ ++dev->buf;
++}
++
++static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
++{
++ struct at91_twi_dev *dev = dev_id;
++ const unsigned status = at91_twi_read(dev, AT91_TWI_SR);
++ const unsigned irqstatus = status & at91_twi_read(dev, AT91_TWI_IMR);
++
++ if (!irqstatus)
++ return IRQ_NONE;
++ else if (irqstatus & AT91_TWI_RXRDY)
++ at91_twi_read_next_byte(dev);
++ else if (irqstatus & AT91_TWI_TXRDY)
++ at91_twi_write_next_byte(dev);
++
++ /* catch error flags */
++ dev->transfer_status |= status;
++
++ if (irqstatus & AT91_TWI_TXCOMP) {
++ at91_disable_twi_interrupts(dev);
++ complete(&dev->cmd_complete);
++ }
++
++ return IRQ_HANDLED;
++}
++
++static int at91_do_twi_transfer(struct at91_twi_dev *dev)
++{
++ int ret;
++ bool has_unre_flag = dev->pdata->has_unre_flag;
++
++ dev_dbg(dev->dev, "transfer: %s %d bytes.\n",
++ (dev->msg->flags & I2C_M_RD) ? "read" : "write", dev->buf_len);
++
++ INIT_COMPLETION(dev->cmd_complete);
++ dev->transfer_status = 0;
++ if (dev->msg->flags & I2C_M_RD) {
++ unsigned start_flags = AT91_TWI_START;
++
++ if (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY) {
++ dev_err(dev->dev, "RXRDY still set!");
++ at91_twi_read(dev, AT91_TWI_RHR);
++ }
++
++ /* if only one byte is to be read, immediately stop transfer */
++ if (dev->buf_len <= 1 && !(dev->msg->flags & I2C_M_RECV_LEN))
++ start_flags |= AT91_TWI_STOP;
++ at91_twi_write(dev, AT91_TWI_CR, start_flags);
++ at91_twi_write(dev, AT91_TWI_IER,
++ AT91_TWI_TXCOMP | AT91_TWI_RXRDY);
++ } else {
++ at91_twi_write_next_byte(dev);
++ at91_twi_write(dev, AT91_TWI_IER,
++ AT91_TWI_TXCOMP | AT91_TWI_TXRDY);
++ }
++
++ ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
++ dev->adapter.timeout);
++ if (ret == 0) {
++ dev_err(dev->dev, "controller timed out\n");
++ at91_init_twi_bus(dev);
++ return -ETIMEDOUT;
++ }
++ if (dev->transfer_status & AT91_TWI_NACK) {
++ dev_dbg(dev->dev, "received nack\n");
++ return -EREMOTEIO;
++ }
++ if (dev->transfer_status & AT91_TWI_OVRE) {
++ dev_err(dev->dev, "overrun while reading\n");
++ return -EIO;
++ }
++ if (has_unre_flag && dev->transfer_status & AT91_TWI_UNRE) {
++ dev_err(dev->dev, "underrun while writing\n");
++ return -EIO;
++ }
++ dev_dbg(dev->dev, "transfer complete\n");
++
++ return 0;
++}
++
++static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
++{
++ struct at91_twi_dev *dev = i2c_get_adapdata(adap);
++ int ret;
++ unsigned int_addr_flag = 0;
++ struct i2c_msg *m_start = msg;
++
++ dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num);
++
++ /*
++ * The hardware can handle at most two messages concatenated by a
++ * repeated start via it's internal address feature.
++ */
++ if (num > 2) {
++ dev_err(dev->dev,
++ "cannot handle more than two concatenated messages.\n");
++ return 0;
++ } else if (num == 2) {
++ int internal_address = 0;
++ int i;
++
++ if (msg->flags & I2C_M_RD) {
++ dev_err(dev->dev, "first transfer must be write.\n");
++ return -EINVAL;
++ }
++ if (msg->len > 3) {
++ dev_err(dev->dev, "first message size must be <= 3.\n");
++ return -EINVAL;
++ }
++
++ /* 1st msg is put into the internal address, start with 2nd */
++ m_start = &msg[1];
++ for (i = 0; i < msg->len; ++i) {
++ const unsigned addr = msg->buf[msg->len - 1 - i];
++
++ internal_address |= addr << (8 * i);
++ int_addr_flag += AT91_TWI_IADRSZ_1;
++ }
++ at91_twi_write(dev, AT91_TWI_IADR, internal_address);
++ }
++
++ at91_twi_write(dev, AT91_TWI_MMR, (m_start->addr << 16) | int_addr_flag
++ | ((m_start->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0));
++
++ dev->buf_len = m_start->len;
++ dev->buf = m_start->buf;
++ dev->msg = m_start;
++
++ ret = at91_do_twi_transfer(dev);
++
++ return (ret < 0) ? ret : num;
++}
++
++static u32 at91_twi_func(struct i2c_adapter *adapter)
++{
++ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
++ | I2C_FUNC_SMBUS_READ_BLOCK_DATA;
++}
++
++static struct i2c_algorithm at91_twi_algorithm = {
++ .master_xfer = at91_twi_xfer,
++ .functionality = at91_twi_func,
++};
++
++static struct at91_twi_pdata at91rm9200_config = {
++ .clk_max_div = 5,
++ .clk_offset = 3,
++ .has_unre_flag = true,
++};
++
++static struct at91_twi_pdata at91sam9261_config = {
++ .clk_max_div = 5,
++ .clk_offset = 4,
++ .has_unre_flag = false,
++};
++
++static struct at91_twi_pdata at91sam9260_config = {
++ .clk_max_div = 7,
++ .clk_offset = 4,
++ .has_unre_flag = false,
++};
++
++static struct at91_twi_pdata at91sam9g20_config = {
++ .clk_max_div = 7,
++ .clk_offset = 4,
++ .has_unre_flag = false,
++};
++
++static struct at91_twi_pdata at91sam9g10_config = {
++ .clk_max_div = 7,
++ .clk_offset = 4,
++ .has_unre_flag = false,
++};
++
++static const struct platform_device_id at91_twi_devtypes[] = {
++ {
++ .name = "i2c-at91rm9200",
++ .driver_data = (unsigned long) &at91rm9200_config,
++ }, {
++ .name = "i2c-at91sam9261",
++ .driver_data = (unsigned long) &at91sam9261_config,
++ }, {
++ .name = "i2c-at91sam9260",
++ .driver_data = (unsigned long) &at91sam9260_config,
++ }, {
++ .name = "i2c-at91sam9g20",
++ .driver_data = (unsigned long) &at91sam9g20_config,
++ }, {
++ .name = "i2c-at91sam9g10",
++ .driver_data = (unsigned long) &at91sam9g10_config,
++ }, {
++ /* sentinel */
++ }
++};
++
++static int __devinit at91_twi_probe(struct platform_device *pdev)
++{
++ struct at91_twi_dev *dev;
++ struct resource *mem;
++ int rc;
++
++ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
++ if (!dev)
++ return -ENOMEM;
++ init_completion(&dev->cmd_complete);
++ dev->dev = &pdev->dev;
++
++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!mem)
++ return -ENODEV;
++
++ dev->pdata = at91_twi_get_driver_data(pdev);
++ if (!dev->pdata)
++ return -ENODEV;
++
++ dev->base = devm_request_and_ioremap(&pdev->dev, mem);
++ if (!dev->base)
++ return -EBUSY;
++
++ dev->irq = platform_get_irq(pdev, 0);
++ if (dev->irq < 0)
++ return dev->irq;
++
++ rc = devm_request_irq(&pdev->dev, dev->irq, atmel_twi_interrupt, 0,
++ dev_name(dev->dev), dev);
++ if (rc) {
++ dev_err(dev->dev, "Cannot get irq %d: %d\n", dev->irq, rc);
++ return rc;
++ }
++
++ platform_set_drvdata(pdev, dev);
++
++ dev->clk = devm_clk_get(dev->dev, NULL);
++ if (IS_ERR(dev->clk)) {
++ dev_err(dev->dev, "no clock defined\n");
++ return -ENODEV;
++ }
++ clk_prepare_enable(dev->clk);
++
++ at91_calc_twi_clock(dev, TWI_CLK_HZ);
++ at91_init_twi_bus(dev);
++
++ snprintf(dev->adapter.name, sizeof(dev->adapter.name), "AT91");
++ i2c_set_adapdata(&dev->adapter, dev);
++ dev->adapter.owner = THIS_MODULE;
++ dev->adapter.class = I2C_CLASS_HWMON;
++ dev->adapter.algo = &at91_twi_algorithm;
++ dev->adapter.dev.parent = dev->dev;
++ dev->adapter.nr = pdev->id;
++ dev->adapter.timeout = AT91_I2C_TIMEOUT;
++
++ rc = i2c_add_numbered_adapter(&dev->adapter);
++ if (rc) {
++ dev_err(dev->dev, "Adapter %s registration failed\n",
++ dev->adapter.name);
++ clk_disable_unprepare(dev->clk);
++ return rc;
++ }
++
++ dev_info(dev->dev, "AT91 i2c bus driver.\n");
++ return 0;
++}
++
++static int __devexit at91_twi_remove(struct platform_device *pdev)
++{
++ struct at91_twi_dev *dev = platform_get_drvdata(pdev);
++ int rc;
++
++ rc = i2c_del_adapter(&dev->adapter);
++ clk_disable_unprepare(dev->clk);
++
++ return rc;
++}
++
++#ifdef CONFIG_PM
++
++static int at91_twi_runtime_suspend(struct device *dev)
++{
++ struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
++
++ clk_disable(twi_dev->clk);
++
++ return 0;
++}
++
++static int at91_twi_runtime_resume(struct device *dev)
++{
++ struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
++
++ return clk_enable(twi_dev->clk);
++}
++
++static const struct dev_pm_ops at91_twi_pm = {
++ .runtime_suspend = at91_twi_runtime_suspend,
++ .runtime_resume = at91_twi_runtime_resume,
++};
++
++#define at91_twi_pm_ops (&at91_twi_pm)
++#else
++#define at91_twi_pm_ops NULL
++#endif
++
++static struct platform_driver at91_twi_driver = {
++ .probe = at91_twi_probe,
++ .remove = __devexit_p(at91_twi_remove),
++ .id_table = at91_twi_devtypes,
++ .driver = {
++ .name = "at91_i2c",
++ .owner = THIS_MODULE,
++ .pm = at91_twi_pm_ops,
++ },
++};
++
++static int __init at91_twi_init(void)
++{
++ return platform_driver_register(&at91_twi_driver);
++}
++
++static void __exit at91_twi_exit(void)
++{
++ platform_driver_unregister(&at91_twi_driver);
++}
++
++subsys_initcall(at91_twi_init);
++module_exit(at91_twi_exit);
++
++MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>");
++MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:at91_i2c");
diff --git a/patches.at91/0158-arm-at91-G45-TWI-remove-open-drain-setting-for-twi-f.patch b/patches.at91/0158-arm-at91-G45-TWI-remove-open-drain-setting-for-twi-f.patch
new file mode 100644
index 00000000000000..1bab30a731353e
--- /dev/null
+++ b/patches.at91/0158-arm-at91-G45-TWI-remove-open-drain-setting-for-twi-f.patch
@@ -0,0 +1,42 @@
+From 2994ada46baa5d0444b4ac86a50addd9550480e6 Mon Sep 17 00:00:00 2001
+From: Nikolaus Voss <n.voss@weinmann.de>
+Date: Tue, 8 Nov 2011 12:11:03 +0100
+Subject: arm: at91: G45 TWI: remove open drain setting for twi function gpios
+
+The G45 datasheets explicitly states that setting the open drain property
+on peripheral function gpios is not allowed. (How about other A91 chips?)
+
+Signed-off-by: Nikolaus Voss <n.voss@weinmann.de>
+Tested-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Reviewed-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+---
+ arch/arm/mach-at91/at91sam9g45_devices.c | 6 ------
+ 1 file changed, 6 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
+index 4223d28..29f334c 100644
+--- a/arch/arm/mach-at91/at91sam9g45_devices.c
++++ b/arch/arm/mach-at91/at91sam9g45_devices.c
+@@ -684,18 +684,12 @@ void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, in
+ /* pins used for TWI interface */
+ if (i2c_id == 0) {
+ at91_set_A_periph(AT91_PIN_PA20, 0); /* TWD */
+- at91_set_multi_drive(AT91_PIN_PA20, 1);
+-
+ at91_set_A_periph(AT91_PIN_PA21, 0); /* TWCK */
+- at91_set_multi_drive(AT91_PIN_PA21, 1);
+
+ platform_device_register(&at91sam9g45_twi0_device);
+ } else {
+ at91_set_A_periph(AT91_PIN_PB10, 0); /* TWD */
+- at91_set_multi_drive(AT91_PIN_PB10, 1);
+-
+ at91_set_A_periph(AT91_PIN_PB11, 0); /* TWCK */
+- at91_set_multi_drive(AT91_PIN_PB11, 1);
+
+ platform_device_register(&at91sam9g45_twi1_device);
+ }
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0159-ARM-at91-do-not-configure-at91sam9g10-twi-pio-as-ope.patch b/patches.at91/0159-ARM-at91-do-not-configure-at91sam9g10-twi-pio-as-ope.patch
new file mode 100644
index 00000000000000..54fa4e23231e4f
--- /dev/null
+++ b/patches.at91/0159-ARM-at91-do-not-configure-at91sam9g10-twi-pio-as-ope.patch
@@ -0,0 +1,43 @@
+From c4eb8fe58495048f1bde1cb26dcab0e8db89b552 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 12 Sep 2012 08:42:13 +0200
+Subject: ARM: at91: do not configure at91sam9g10 twi pio as open-drain
+
+As indicated in the datasheet, TWD and TWCK must not be programmed as
+open-drain.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Acked-by: Nikolaus Voss <n.voss@weinmann.de>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+---
+ arch/arm/mach-at91/at91sam9261_devices.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
+index 3d7b2f4..d2ae522 100644
+--- a/arch/arm/mach-at91/at91sam9261_devices.c
++++ b/arch/arm/mach-at91/at91sam9261_devices.c
+@@ -329,16 +329,16 @@ void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
+ /* IP version is not the same on 9261 and g10 */
+ if (cpu_is_at91sam9g10()) {
+ at91sam9261_twi_device.name = "i2c-at91sam9g10";
++ /* I2C PIO must not be configured as open-drain on this chip */
+ } else {
+ at91sam9261_twi_device.name = "i2c-at91sam9261";
++ at91_set_multi_drive(AT91_PIN_PA7, 1);
++ at91_set_multi_drive(AT91_PIN_PA8, 1);
+ }
+
+ /* pins used for TWI interface */
+ at91_set_A_periph(AT91_PIN_PA7, 0); /* TWD */
+- at91_set_multi_drive(AT91_PIN_PA7, 1);
+-
+ at91_set_A_periph(AT91_PIN_PA8, 0); /* TWCK */
+- at91_set_multi_drive(AT91_PIN_PA8, 1);
+
+ i2c_register_board_info(0, devices, nr_devices);
+ platform_device_register(&at91sam9261_twi_device);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0160-i2c-at91-add-dt-support-to-i2c-at91.patch b/patches.at91/0160-i2c-at91-add-dt-support-to-i2c-at91.patch
new file mode 100644
index 00000000000000..da445e204b00e0
--- /dev/null
+++ b/patches.at91/0160-i2c-at91-add-dt-support-to-i2c-at91.patch
@@ -0,0 +1,149 @@
+From 2f7c847b1fc49780a3d9d963864a105cdca96c62 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 12 Sep 2012 08:42:14 +0200
+Subject: i2c: at91: add dt support to i2c-at91
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Acked-by: Nikolaus Voss <n.voss@weinmann.de>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+---
+ .../devicetree/bindings/i2c/atmel-i2c.txt | 30 +++++++++++++
+ drivers/i2c/busses/i2c-at91.c | 49 ++++++++++++++++++++++
+ 2 files changed, 79 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/i2c/atmel-i2c.txt
+
+diff --git a/Documentation/devicetree/bindings/i2c/atmel-i2c.txt b/Documentation/devicetree/bindings/i2c/atmel-i2c.txt
+new file mode 100644
+index 0000000..b689a0d
+--- /dev/null
++++ b/Documentation/devicetree/bindings/i2c/atmel-i2c.txt
+@@ -0,0 +1,30 @@
++I2C for Atmel platforms
++
++Required properties :
++- compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c",
++ "atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c"
++ or "atmel,at91sam9x5-i2c"
++- reg: physical base address of the controller and length of memory mapped
++ region.
++- interrupts: interrupt number to the cpu.
++- #address-cells = <1>;
++- #size-cells = <0>;
++
++Optional properties:
++- Child nodes conforming to i2c bus binding
++
++Examples :
++
++i2c0: i2c@fff84000 {
++ compatible = "atmel,at91sam9g20-i2c";
++ reg = <0xfff84000 0x100>;
++ interrupts = <12 4 6>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ 24c512@50 {
++ compatible = "24c512";
++ reg = <0x50>;
++ pagesize = <128>;
++ }
++}
+diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
+index 78bcad0..aa59a25 100644
+--- a/drivers/i2c/busses/i2c-at91.c
++++ b/drivers/i2c/busses/i2c-at91.c
+@@ -24,6 +24,9 @@
+ #include <linux/interrupt.h>
+ #include <linux/io.h>
+ #include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/of_i2c.h>
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
+
+@@ -347,6 +350,12 @@ static struct at91_twi_pdata at91sam9g10_config = {
+ .has_unre_flag = false,
+ };
+
++static struct at91_twi_pdata at91sam9x5_config = {
++ .clk_max_div = 7,
++ .clk_offset = 4,
++ .has_unre_flag = false,
++};
++
+ static const struct platform_device_id at91_twi_devtypes[] = {
+ {
+ .name = "i2c-at91rm9200",
+@@ -368,6 +377,42 @@ static const struct platform_device_id at91_twi_devtypes[] = {
+ }
+ };
+
++#if defined(CONFIG_OF)
++static const struct of_device_id atmel_twi_dt_ids[] = {
++ {
++ .compatible = "atmel,at91sam9260-i2c",
++ .data = &at91sam9260_config,
++ } , {
++ .compatible = "atmel,at91sam9g20-i2c",
++ .data = &at91sam9g20_config,
++ } , {
++ .compatible = "atmel,at91sam9g10-i2c",
++ .data = &at91sam9g10_config,
++ }, {
++ .compatible = "atmel,at91sam9x5-i2c",
++ .data = &at91sam9x5_config,
++ }, {
++ /* sentinel */
++ }
++};
++MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids);
++#else
++#define atmel_twi_dt_ids NULL
++#endif
++
++static struct at91_twi_pdata * __devinit at91_twi_get_driver_data(
++ struct platform_device *pdev)
++{
++ if (pdev->dev.of_node) {
++ const struct of_device_id *match;
++ match = of_match_node(atmel_twi_dt_ids, pdev->dev.of_node);
++ if (!match)
++ return NULL;
++ return match->data;
++ }
++ return (struct at91_twi_pdata *) platform_get_device_id(pdev)->driver_data;
++}
++
+ static int __devinit at91_twi_probe(struct platform_device *pdev)
+ {
+ struct at91_twi_dev *dev;
+@@ -423,6 +468,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
+ dev->adapter.dev.parent = dev->dev;
+ dev->adapter.nr = pdev->id;
+ dev->adapter.timeout = AT91_I2C_TIMEOUT;
++ dev->adapter.dev.of_node = pdev->dev.of_node;
+
+ rc = i2c_add_numbered_adapter(&dev->adapter);
+ if (rc) {
+@@ -432,6 +478,8 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
+ return rc;
+ }
+
++ of_i2c_register_devices(&dev->adapter);
++
+ dev_info(dev->dev, "AT91 i2c bus driver.\n");
+ return 0;
+ }
+@@ -482,6 +530,7 @@ static struct platform_driver at91_twi_driver = {
+ .driver = {
+ .name = "at91_i2c",
+ .owner = THIS_MODULE,
++ .of_match_table = atmel_twi_dt_ids,
+ .pm = at91_twi_pm_ops,
+ },
+ };
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0161-ARM-at91-add-clocks-for-I2C-DT-entries.patch b/patches.at91/0161-ARM-at91-add-clocks-for-I2C-DT-entries.patch
new file mode 100644
index 00000000000000..56157945cb8440
--- /dev/null
+++ b/patches.at91/0161-ARM-at91-add-clocks-for-I2C-DT-entries.patch
@@ -0,0 +1,89 @@
+From 16a2fab8b00700750c3bf55d9ae47142bcd62cbc Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 22 Oct 2012 15:53:10 +0200
+Subject: ARM: at91: add clocks for I2C DT entries
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Acked-by: Nikolaus Voss <n.voss@weinmann.de>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+
+Conflicts:
+ arch/arm/mach-at91/at91sam9263.c
+ arch/arm/mach-at91/at91sam9g45.c
+ arch/arm/mach-at91/at91sam9x5.c
+---
+ arch/arm/mach-at91/at91sam9260.c | 1 +
+ arch/arm/mach-at91/at91sam9263.c | 1 +
+ arch/arm/mach-at91/at91sam9g45.c | 2 ++
+ arch/arm/mach-at91/at91sam9n12.c | 2 ++
+ arch/arm/mach-at91/at91sam9x5.c | 3 +++
+ 5 files changed, 9 insertions(+)
+
+diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
+index a936c15..040f79a 100644
+--- a/arch/arm/mach-at91/at91sam9260.c
++++ b/arch/arm/mach-at91/at91sam9260.c
+@@ -213,6 +213,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("usart", "fffd0000.serial", &usart3_clk),
+ CLKDEV_CON_DEV_ID("usart", "fffd4000.serial", &usart4_clk),
+ CLKDEV_CON_DEV_ID("usart", "fffd8000.serial", &usart5_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffac000.i2c", &twi_clk),
+ /* more tc lookup table for DT entries */
+ CLKDEV_CON_DEV_ID("t0_clk", "fffa0000.timer", &tc0_clk),
+ CLKDEV_CON_DEV_ID("t1_clk", "fffa0000.timer", &tc1_clk),
+diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
+index d49cfe9..00723ec 100644
+--- a/arch/arm/mach-at91/at91sam9263.c
++++ b/arch/arm/mach-at91/at91sam9263.c
+@@ -213,6 +213,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("spi_clk", "fffa8000.spi", &spi1_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "fff80000.mmc", &mmc0_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "fff84000.mmc", &mmc1_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi_clk),
+ };
+
+ static struct clk_lookup usart_clocks_lookups[] = {
+diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
+index 7d5ac91..7ccbf9c 100644
+--- a/arch/arm/mach-at91/at91sam9g45.c
++++ b/arch/arm/mach-at91/at91sam9g45.c
+@@ -240,6 +240,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("ehci_clk", "800000.ehci", &uhphs_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "fff80000.mmc", &mmc0_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "fffd0000.mmc", &mmc1_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fff84000.i2c", &twi0_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi1_clk),
+ /* fake hclk clock */
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
+index cce4e0f..ebe94bb 100644
+--- a/arch/arm/mach-at91/at91sam9n12.c
++++ b/arch/arm/mach-at91/at91sam9n12.c
+@@ -170,6 +170,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "f0008000.mmc", &mmc_clk),
+ CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma_clk),
++ CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
++ CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
+ CLKDEV_CON_ID("pioA", &pioAB_clk),
+ CLKDEV_CON_ID("pioB", &pioAB_clk),
+ CLKDEV_CON_ID("pioC", &pioCD_clk),
+diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
+index 15ac57b..f40c1ab 100644
+--- a/arch/arm/mach-at91/at91sam9x5.c
++++ b/arch/arm/mach-at91/at91sam9x5.c
+@@ -230,6 +230,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.0", &twi0_clk),
+ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk),
+ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.2", &twi2_clk),
++ CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
++ CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
++ CLKDEV_CON_DEV_ID(NULL, "f8018000.i2c", &twi2_clk),
+ CLKDEV_CON_ID("pioA", &pioAB_clk),
+ CLKDEV_CON_ID("pioB", &pioAB_clk),
+ CLKDEV_CON_ID("pioC", &pioCD_clk),
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0162-ARM-dts-add-twi-nodes-for-atmel-SoCs.patch b/patches.at91/0162-ARM-dts-add-twi-nodes-for-atmel-SoCs.patch
new file mode 100644
index 00000000000000..e9e18e418c3ff4
--- /dev/null
+++ b/patches.at91/0162-ARM-dts-add-twi-nodes-for-atmel-SoCs.patch
@@ -0,0 +1,220 @@
+From cfd444af2516de03e37de245cf8b926d2bfe9738 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 12 Sep 2012 08:42:16 +0200
+Subject: ARM: dts: add twi nodes for atmel SoCs
+
+Add TWI nodes for atmel SoCs but keep i2c-gpio ones in order to let the
+choice to the user in dts files.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+---
+ arch/arm/boot/dts/at91sam9260.dtsi | 10 ++++++++++
+ arch/arm/boot/dts/at91sam9263.dtsi | 10 ++++++++++
+ arch/arm/boot/dts/at91sam9g20.dtsi | 8 ++++++++
+ arch/arm/boot/dts/at91sam9g45.dtsi | 20 ++++++++++++++++++++
+ arch/arm/boot/dts/at91sam9n12.dtsi | 20 ++++++++++++++++++++
+ arch/arm/boot/dts/at91sam9x5.dtsi | 30 ++++++++++++++++++++++++++++++
+ 6 files changed, 98 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
+index 8d95e83c..0352bf8 100644
+--- a/arch/arm/boot/dts/at91sam9260.dtsi
++++ b/arch/arm/boot/dts/at91sam9260.dtsi
+@@ -28,6 +28,7 @@
+ gpio2 = &pioC;
+ tcb0 = &tcb0;
+ tcb1 = &tcb1;
++ i2c0 = &i2c0;
+ };
+ cpus {
+ cpu@0 {
+@@ -210,6 +211,15 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
++
++ i2c0: i2c@fffac000 {
++ compatible = "atmel,at91sam9260-i2c";
++ reg = <0xfffac000 0x100>;
++ interrupts = <11 4 6>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
+index 54e6984..26ab452 100644
+--- a/arch/arm/boot/dts/at91sam9263.dtsi
++++ b/arch/arm/boot/dts/at91sam9263.dtsi
+@@ -24,6 +24,7 @@
+ gpio3 = &pioD;
+ gpio4 = &pioE;
+ tcb0 = &tcb0;
++ i2c0 = &i2c0;
+ };
+ cpus {
+ cpu@0 {
+@@ -203,6 +204,15 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
++
++ i2c0: i2c@fff88000 {
++ compatible = "atmel,at91sam9263-i2c";
++ reg = <0xfff88000 0x100>;
++ interrupts = <13 4 6>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9g20.dtsi b/arch/arm/boot/dts/at91sam9g20.dtsi
+index 0eb1a75..4537a74 100644
+--- a/arch/arm/boot/dts/at91sam9g20.dtsi
++++ b/arch/arm/boot/dts/at91sam9g20.dtsi
+@@ -15,4 +15,12 @@
+ memory {
+ reg = <0x20000000 0x08000000>;
+ };
++
++ ahb {
++ apb {
++ i2c0: i2c@fffac000 {
++ compatible = "atmel,at91sam9g20-i2c";
++ };
++ };
++ };
+ };
+diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
+index da135f9..b032a8c 100644
+--- a/arch/arm/boot/dts/at91sam9g45.dtsi
++++ b/arch/arm/boot/dts/at91sam9g45.dtsi
+@@ -29,6 +29,8 @@
+ gpio4 = &pioE;
+ tcb0 = &tcb0;
+ tcb1 = &tcb1;
++ i2c0 = &i2c0;
++ i2c1 = &i2c1;
+ };
+ cpus {
+ cpu@0 {
+@@ -223,6 +225,24 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
++
++ i2c0: i2c@fff84000 {
++ compatible = "atmel,at91sam9g10-i2c";
++ reg = <0xfff84000 0x100>;
++ interrupts = <12 4 6>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c1: i2c@fff88000 {
++ compatible = "atmel,at91sam9g10-i2c";
++ reg = <0xfff88000 0x100>;
++ interrupts = <13 4 6>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
+index 42d5fc2..0d08c4e 100644
+--- a/arch/arm/boot/dts/at91sam9n12.dtsi
++++ b/arch/arm/boot/dts/at91sam9n12.dtsi
+@@ -26,6 +26,8 @@
+ gpio3 = &pioD;
+ tcb0 = &tcb0;
+ tcb1 = &tcb1;
++ i2c0 = &i2c0;
++ i2c1 = &i2c1;
+ };
+ cpus {
+ cpu@0 {
+@@ -191,6 +193,24 @@
+ atmel,use-dma-tx;
+ status = "disabled";
+ };
++
++ i2c0: i2c@f8010000 {
++ compatible = "atmel,at91sam9x5-i2c";
++ reg = <0xf8010000 0x100>;
++ interrupts = <9 4 6>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c1: i2c@f8014000 {
++ compatible = "atmel,at91sam9x5-i2c";
++ reg = <0xf8014000 0x100>;
++ interrupts = <10 4 6>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index ad7016a..fec3316 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -27,6 +27,9 @@
+ gpio3 = &pioD;
+ tcb0 = &tcb0;
+ tcb1 = &tcb1;
++ i2c0 = &i2c0;
++ i2c1 = &i2c1;
++ i2c2 = &i2c2;
+ };
+ cpus {
+ cpu@0 {
+@@ -213,6 +216,33 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
++
++ i2c0: i2c@f8010000 {
++ compatible = "atmel,at91sam9x5-i2c";
++ reg = <0xf8010000 0x100>;
++ interrupts = <9 4 6>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c1: i2c@f8014000 {
++ compatible = "atmel,at91sam9x5-i2c";
++ reg = <0xf8014000 0x100>;
++ interrupts = <10 4 6>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c2: i2c@f8018000 {
++ compatible = "atmel,at91sam9x5-i2c";
++ reg = <0xf8018000 0x100>;
++ interrupts = <11 4 6>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
+ };
+
+ nand0: nand@40000000 {
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0163-ARM-dts-add-twi-nodes-for-atmel-boards.patch b/patches.at91/0163-ARM-dts-add-twi-nodes-for-atmel-boards.patch
new file mode 100644
index 00000000000000..7272e41efaecc5
--- /dev/null
+++ b/patches.at91/0163-ARM-dts-add-twi-nodes-for-atmel-boards.patch
@@ -0,0 +1,86 @@
+From 4b10c24b6a6aa99991c10c670e22b95cc0520d7c Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 22 Oct 2012 15:53:27 +0200
+Subject: ARM: dts: add twi nodes for atmel boards
+
+Still use i2c-gpio on boards which have a SoC with a TWI IP which
+doesn't have clock stretching in transmission mode.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+
+Conflicts:
+ arch/arm/boot/dts/at91sam9g25ek.dts
+ arch/arm/boot/dts/at91sam9m10g45ek.dts
+ arch/arm/boot/dts/at91sam9n12ek.dts
+---
+ arch/arm/boot/dts/at91sam9g25ek.dts | 12 ++++++++++++
+ arch/arm/boot/dts/at91sam9m10g45ek.dts | 8 ++++++++
+ arch/arm/boot/dts/at91sam9n12ek.dts | 8 ++++++++
+ 3 files changed, 28 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts
+index 4857e6c..5b054e4 100644
+--- a/arch/arm/boot/dts/at91sam9g25ek.dts
++++ b/arch/arm/boot/dts/at91sam9g25ek.dts
+@@ -50,6 +50,18 @@
+ cd-gpios = <&pioD 14 0>;
+ };
+ };
++
++ i2c0: i2c@f8010000 {
++ status = "okay";
++ };
++
++ i2c1: i2c@f8014000 {
++ status = "okay";
++ };
++
++ i2c2: i2c@f8018000 {
++ status = "okay";
++ };
+ };
+
+ usb0: ohci@00600000 {
+diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts
+index 7a7b571..6a4aedd 100644
+--- a/arch/arm/boot/dts/at91sam9m10g45ek.dts
++++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts
+@@ -65,6 +65,14 @@
+ wp-gpios = <&pioD 29 0>;
+ };
+ };
++
++ i2c0: i2c@fff84000 {
++ status = "okay";
++ };
++
++ i2c1: i2c@fff88000 {
++ status = "okay";
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts
+index 44b42d9..ccc94de 100644
+--- a/arch/arm/boot/dts/at91sam9n12ek.dts
++++ b/arch/arm/boot/dts/at91sam9n12ek.dts
+@@ -46,6 +46,14 @@
+ cd-gpios = <&pioA 7 0>;
+ };
+ };
++
++ i2c0: i2c@f8010000 {
++ status = "okay";
++ };
++
++ i2c1: i2c@f8014000 {
++ status = "okay";
++ };
+ };
+
+ nand0: nand@40000000 {
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0164-i2c-at91-add-dma-support.patch b/patches.at91/0164-i2c-at91-add-dma-support.patch
new file mode 100644
index 00000000000000..1c81f5e4db4835
--- /dev/null
+++ b/patches.at91/0164-i2c-at91-add-dma-support.patch
@@ -0,0 +1,504 @@
+From 38916c66f279b3c86d4c018154a6d6c4f3de0316 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Fri, 14 Sep 2012 16:04:55 +0200
+Subject: i2c: at91: add dma support
+
+Add dma support for Atmel TWI which is available on sam9x5 and later.
+
+When using dma for reception, you have to read only n-2 bytes. The last
+two bytes are read manually. Don't doing this should cause to send the
+STOP command too late and then to get extra data in the receive
+register.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ drivers/i2c/busses/i2c-at91.c | 326 ++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 314 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
+index aa59a25..33219f8 100644
+--- a/drivers/i2c/busses/i2c-at91.c
++++ b/drivers/i2c/busses/i2c-at91.c
+@@ -19,6 +19,8 @@
+
+ #include <linux/clk.h>
+ #include <linux/completion.h>
++#include <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
+ #include <linux/err.h>
+ #include <linux/i2c.h>
+ #include <linux/interrupt.h>
+@@ -30,6 +32,8 @@
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
+
++#include <mach/at_hdmac.h>
++
+ #define TWI_CLK_HZ 100000 /* max 400 Kbits/s */
+ #define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */
+
+@@ -65,9 +69,21 @@
+ #define AT91_TWI_THR 0x0034 /* Transmit Holding Register */
+
+ struct at91_twi_pdata {
+- unsigned clk_max_div;
+- unsigned clk_offset;
+- bool has_unre_flag;
++ unsigned clk_max_div;
++ unsigned clk_offset;
++ bool has_unre_flag;
++ bool has_dma_support;
++ struct at_dma_slave dma_slave;
++};
++
++struct at91_twi_dma {
++ struct dma_chan *chan_rx;
++ struct dma_chan *chan_tx;
++ struct scatterlist sg;
++ struct dma_async_tx_descriptor *data_desc;
++ enum dma_data_direction direction;
++ bool buf_mapped;
++ bool xfer_in_progress;
+ };
+
+ struct at91_twi_dev {
+@@ -79,10 +95,13 @@ struct at91_twi_dev {
+ size_t buf_len;
+ struct i2c_msg *msg;
+ int irq;
++ unsigned imr;
+ unsigned transfer_status;
+ struct i2c_adapter adapter;
+ unsigned twi_cwgr_reg;
+ struct at91_twi_pdata *pdata;
++ bool use_dma;
++ struct at91_twi_dma dma;
+ };
+
+ static unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg)
+@@ -98,7 +117,18 @@ static void at91_twi_write(struct at91_twi_dev *dev, unsigned reg, unsigned val)
+ static void at91_disable_twi_interrupts(struct at91_twi_dev *dev)
+ {
+ at91_twi_write(dev, AT91_TWI_IDR,
+- AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY);
++ AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY);
++}
++
++static void at91_twi_irq_save(struct at91_twi_dev *dev)
++{
++ dev->imr = at91_twi_read(dev, AT91_TWI_IMR) & 0x7;
++ at91_disable_twi_interrupts(dev);
++}
++
++static void at91_twi_irq_restore(struct at91_twi_dev *dev)
++{
++ at91_twi_write(dev, AT91_TWI_IER, dev->imr);
+ }
+
+ static void at91_init_twi_bus(struct at91_twi_dev *dev)
+@@ -137,6 +167,30 @@ static void __devinit at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
+ dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv);
+ }
+
++static void at91_twi_dma_cleanup(struct at91_twi_dev *dev)
++{
++ struct at91_twi_dma *dma = &dev->dma;
++
++ at91_twi_irq_save(dev);
++
++ if (dma->xfer_in_progress) {
++ if (dma->direction == DMA_FROM_DEVICE)
++ dma->chan_rx->device->device_control(dma->chan_rx,
++ DMA_TERMINATE_ALL, 0);
++ else
++ dma->chan_tx->device->device_control(dma->chan_tx,
++ DMA_TERMINATE_ALL, 0);
++ dma->xfer_in_progress = false;
++ }
++ if (dma->buf_mapped) {
++ dma_unmap_single(dev->dev, sg_dma_address(&dma->sg),
++ dev->buf_len, dma->direction);
++ dma->buf_mapped = false;
++ }
++
++ at91_twi_irq_restore(dev);
++}
++
+ static void at91_twi_write_next_byte(struct at91_twi_dev *dev)
+ {
+ if (dev->buf_len <= 0)
+@@ -153,6 +207,65 @@ static void at91_twi_write_next_byte(struct at91_twi_dev *dev)
+ ++dev->buf;
+ }
+
++static void at91_twi_write_data_dma_callback(void *data)
++{
++ struct at91_twi_dev *dev = (struct at91_twi_dev *)data;
++
++ dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg),
++ dev->buf_len, DMA_TO_DEVICE);
++
++ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
++}
++
++static void at91_twi_write_data_dma(struct at91_twi_dev *dev)
++{
++ dma_addr_t dma_addr;
++ dma_cookie_t cookie;
++ struct dma_async_tx_descriptor *txdesc;
++ struct at91_twi_dma *dma = &dev->dma;
++ struct dma_chan *chan_tx = dma->chan_tx;
++
++ if (dev->buf_len <= 0)
++ return;
++
++ dma->direction = DMA_TO_DEVICE;
++
++ at91_twi_irq_save(dev);
++ dma_addr = dma_map_single(dev->dev, dev->buf, dev->buf_len,
++ DMA_TO_DEVICE);
++ if (dma_mapping_error(dev->dev, dma_addr)) {
++ dev_err(dev->dev, "dma map failed\n");
++ return;
++ }
++ dma->buf_mapped = true;
++ at91_twi_irq_restore(dev);
++ sg_dma_len(&dma->sg) = dev->buf_len;
++ sg_dma_address(&dma->sg) = dma_addr;
++
++ txdesc = chan_tx->device->device_prep_slave_sg(chan_tx, &dma->sg,
++ 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK, NULL);
++ if (!txdesc) {
++ dev_err(dev->dev, "dma prep slave sg failed\n");
++ goto error;
++ }
++
++ txdesc->callback = at91_twi_write_data_dma_callback;
++ txdesc->callback_param = dev;
++
++ dma->xfer_in_progress = true;
++ cookie = txdesc->tx_submit(txdesc);
++ if (dma_submit_error(cookie)) {
++ dev_err(dev->dev, "dma submit error\n");
++ goto error;
++ }
++ dma->chan_tx->device->device_issue_pending(chan_tx);
++
++ return;
++
++error:
++ at91_twi_dma_cleanup(dev);
++}
++
+ static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
+ {
+ if (dev->buf_len <= 0)
+@@ -178,6 +291,66 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
+ ++dev->buf;
+ }
+
++static void at91_twi_read_data_dma_callback(void *data)
++{
++ struct at91_twi_dev *dev = (struct at91_twi_dev *)data;
++
++ dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg),
++ dev->buf_len, DMA_FROM_DEVICE);
++
++ /* The last two bytes have to be read without using dma */
++ dev->buf += dev->buf_len - 2;
++ dev->buf_len = 2;
++ at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_RXRDY);
++}
++
++static void at91_twi_read_data_dma(struct at91_twi_dev *dev)
++{
++ dma_addr_t dma_addr;
++ dma_cookie_t cookie;
++ struct dma_async_tx_descriptor *rxdesc;
++ struct at91_twi_dma *dma = &dev->dma;
++ struct dma_chan *chan_rx = dma->chan_rx;
++
++ dma->direction = DMA_FROM_DEVICE;
++
++ /* Keep in mind that we won't use dma to read the last two bytes */
++ at91_twi_irq_save(dev);
++ dma_addr = dma_map_single(dev->dev, dev->buf, dev->buf_len - 2,
++ DMA_FROM_DEVICE);
++ if (dma_mapping_error(dev->dev, dma_addr)) {
++ dev_err(dev->dev, "dma map failed\n");
++ return;
++ }
++ dma->buf_mapped = true;
++ at91_twi_irq_restore(dev);
++ dma->sg.dma_address = dma_addr;
++ sg_dma_len(&dma->sg) = dev->buf_len - 2;
++
++ rxdesc = chan_rx->device->device_prep_slave_sg(chan_rx, &dma->sg,
++ 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK, NULL);
++ if (!rxdesc) {
++ dev_err(dev->dev, "dma prep slave sg failed\n");
++ goto error;
++ }
++
++ rxdesc->callback = at91_twi_read_data_dma_callback;
++ rxdesc->callback_param = dev;
++
++ dma->xfer_in_progress = true;
++ cookie = rxdesc->tx_submit(rxdesc);
++ if (dma_submit_error(cookie)) {
++ dev_err(dev->dev, "dma submit error\n");
++ goto error;
++ }
++ dma->chan_rx->device->device_issue_pending(dma->chan_rx);
++
++ return;
++
++error:
++ at91_twi_dma_cleanup(dev);
++}
++
+ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
+ {
+ struct at91_twi_dev *dev = dev_id;
+@@ -224,12 +397,36 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
+ if (dev->buf_len <= 1 && !(dev->msg->flags & I2C_M_RECV_LEN))
+ start_flags |= AT91_TWI_STOP;
+ at91_twi_write(dev, AT91_TWI_CR, start_flags);
+- at91_twi_write(dev, AT91_TWI_IER,
++ /*
++ * When using dma, the last byte has to be read manually in
++ * order to not send the stop command too late and then
++ * to receive extra data. In practice, there are some issues
++ * if you use the dma to read n-1 bytes because of latency.
++ * Reading n-2 bytes with dma and the two last ones manually
++ * seems to be the best solution.
++ */
++ if (dev->use_dma && (dev->buf_len > 2)) {
++ at91_twi_read_data_dma(dev);
++ /*
++ * It is important to enable TXCOMP irq here because
++ * doing it only when transferring the last two bytes
++ * will mask NACK errors since TXCOMP is set when a
++ * NACK occurs.
++ */
++ at91_twi_write(dev, AT91_TWI_IER,
++ AT91_TWI_TXCOMP);
++ } else
++ at91_twi_write(dev, AT91_TWI_IER,
+ AT91_TWI_TXCOMP | AT91_TWI_RXRDY);
+ } else {
+- at91_twi_write_next_byte(dev);
+- at91_twi_write(dev, AT91_TWI_IER,
+- AT91_TWI_TXCOMP | AT91_TWI_TXRDY);
++ if (dev->use_dma) {
++ at91_twi_write_data_dma(dev);
++ at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP);
++ } else {
++ at91_twi_write_next_byte(dev);
++ at91_twi_write(dev, AT91_TWI_IER,
++ AT91_TWI_TXCOMP | AT91_TWI_TXRDY);
++ }
+ }
+
+ ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+@@ -237,23 +434,31 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
+ if (ret == 0) {
+ dev_err(dev->dev, "controller timed out\n");
+ at91_init_twi_bus(dev);
+- return -ETIMEDOUT;
++ ret = -ETIMEDOUT;
++ goto error;
+ }
+ if (dev->transfer_status & AT91_TWI_NACK) {
+ dev_dbg(dev->dev, "received nack\n");
+- return -EREMOTEIO;
++ ret = -EREMOTEIO;
++ goto error;
+ }
+ if (dev->transfer_status & AT91_TWI_OVRE) {
+ dev_err(dev->dev, "overrun while reading\n");
+- return -EIO;
++ ret = -EIO;
++ goto error;
+ }
+ if (has_unre_flag && dev->transfer_status & AT91_TWI_UNRE) {
+ dev_err(dev->dev, "underrun while writing\n");
+- return -EIO;
++ ret = -EIO;
++ goto error;
+ }
+ dev_dbg(dev->dev, "transfer complete\n");
+
+ return 0;
++
++error:
++ at91_twi_dma_cleanup(dev);
++ return ret;
+ }
+
+ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
+@@ -324,36 +529,42 @@ static struct at91_twi_pdata at91rm9200_config = {
+ .clk_max_div = 5,
+ .clk_offset = 3,
+ .has_unre_flag = true,
++ .has_dma_support = false,
+ };
+
+ static struct at91_twi_pdata at91sam9261_config = {
+ .clk_max_div = 5,
+ .clk_offset = 4,
+ .has_unre_flag = false,
++ .has_dma_support = false,
+ };
+
+ static struct at91_twi_pdata at91sam9260_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+ .has_unre_flag = false,
++ .has_dma_support = false,
+ };
+
+ static struct at91_twi_pdata at91sam9g20_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+ .has_unre_flag = false,
++ .has_dma_support = false,
+ };
+
+ static struct at91_twi_pdata at91sam9g10_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+ .has_unre_flag = false,
++ .has_dma_support = false,
+ };
+
+ static struct at91_twi_pdata at91sam9x5_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+ .has_unre_flag = false,
++ .has_dma_support = true,
+ };
+
+ static const struct platform_device_id at91_twi_devtypes[] = {
+@@ -400,6 +611,90 @@ MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids);
+ #define atmel_twi_dt_ids NULL
+ #endif
+
++static bool __devinit 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 __devinit at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr)
++{
++ int ret = 0;
++ struct at_dma_slave *sdata;
++ struct dma_slave_config slave_config;
++ struct at91_twi_dma *dma = &dev->dma;
++
++ sdata = &dev->pdata->dma_slave;
++
++ memset(&slave_config, 0, sizeof(slave_config));
++ slave_config.src_addr = (dma_addr_t)phy_addr + AT91_TWI_RHR;
++ slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
++ slave_config.src_maxburst = 1;
++ slave_config.dst_addr = (dma_addr_t)phy_addr + AT91_TWI_THR;
++ slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
++ slave_config.dst_maxburst = 1;
++ slave_config.device_fc = false;
++
++ if (sdata && sdata->dma_dev) {
++ dma_cap_mask_t mask;
++
++ dma_cap_zero(mask);
++ dma_cap_set(DMA_SLAVE, mask);
++ dma->chan_tx = dma_request_channel(mask, filter, sdata);
++ if (!dma->chan_tx) {
++ dev_err(dev->dev, "no DMA channel available for tx\n");
++ ret = -EBUSY;
++ goto error;
++ }
++ dma->chan_rx = dma_request_channel(mask, filter, sdata);
++ if (!dma->chan_rx) {
++ dev_err(dev->dev, "no DMA channel available for rx\n");
++ ret = -EBUSY;
++ goto error;
++ }
++ } else {
++ ret = -EINVAL;
++ goto error;
++ }
++
++ slave_config.direction = DMA_TO_DEVICE;
++ if (dmaengine_slave_config(dma->chan_tx, &slave_config)) {
++ dev_err(dev->dev, "failed to configure tx channel\n");
++ ret = -EINVAL;
++ goto error;
++ }
++
++ slave_config.direction = DMA_FROM_DEVICE;
++ if (dmaengine_slave_config(dma->chan_rx, &slave_config)) {
++ dev_err(dev->dev, "failed to configure rx channel\n");
++ ret = -EINVAL;
++ goto error;
++ }
++
++ sg_init_table(&dma->sg, 1);
++ dma->buf_mapped = false;
++ dma->xfer_in_progress = false;
++
++ dev_info(dev->dev, "using %s (tx) and %s (rx) for DMA transfers\n",
++ dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx));
++
++ return ret;
++
++error:
++ dev_info(dev->dev, "can't use DMA\n");
++ if (dma->chan_rx)
++ dma_release_channel(dma->chan_rx);
++ if (dma->chan_tx)
++ dma_release_channel(dma->chan_tx);
++ return ret;
++}
++
+ static struct at91_twi_pdata * __devinit at91_twi_get_driver_data(
+ struct platform_device *pdev)
+ {
+@@ -418,6 +713,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
+ struct at91_twi_dev *dev;
+ struct resource *mem;
+ int rc;
++ u32 phy_addr;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+@@ -428,6 +724,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem)
+ return -ENODEV;
++ phy_addr = mem->start;
+
+ dev->pdata = at91_twi_get_driver_data(pdev);
+ if (!dev->pdata)
+@@ -457,6 +754,11 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
+ }
+ clk_prepare_enable(dev->clk);
+
++ if (dev->pdata->has_dma_support) {
++ if (at91_twi_configure_dma(dev, phy_addr) == 0)
++ dev->use_dma = true;
++ }
++
+ at91_calc_twi_clock(dev, TWI_CLK_HZ);
+ at91_init_twi_bus(dev);
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0165-i2c-at91-backport-fix-for-devm_clk_get.patch b/patches.at91/0165-i2c-at91-backport-fix-for-devm_clk_get.patch
new file mode 100644
index 00000000000000..4a548a12419d48
--- /dev/null
+++ b/patches.at91/0165-i2c-at91-backport-fix-for-devm_clk_get.patch
@@ -0,0 +1,45 @@
+From b98bff151c11efa7c7c80613b25c1d4890e84cf2 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Tue, 18 Sep 2012 18:32:38 +0200
+Subject: i2c: at91: backport fix for devm_clk_get
+
+i2c-at91 is backported from a 3.6, devm_clk_get is not yet implemented
+on 3.4.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ drivers/i2c/busses/i2c-at91.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
+index 33219f8..296c430 100644
+--- a/drivers/i2c/busses/i2c-at91.c
++++ b/drivers/i2c/busses/i2c-at91.c
+@@ -747,7 +747,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
+
+ platform_set_drvdata(pdev, dev);
+
+- dev->clk = devm_clk_get(dev->dev, NULL);
++ dev->clk = clk_get(dev->dev, NULL);
+ if (IS_ERR(dev->clk)) {
+ dev_err(dev->dev, "no clock defined\n");
+ return -ENODEV;
+@@ -777,6 +777,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
+ dev_err(dev->dev, "Adapter %s registration failed\n",
+ dev->adapter.name);
+ clk_disable_unprepare(dev->clk);
++ clk_put(dev->clk);
+ return rc;
+ }
+
+@@ -793,6 +794,7 @@ static int __devexit at91_twi_remove(struct platform_device *pdev)
+
+ rc = i2c_del_adapter(&dev->adapter);
+ clk_disable_unprepare(dev->clk);
++ clk_put(dev->clk);
+
+ return rc;
+ }
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0166-i2c-at91-add-dt-property-for-DMA-configuration.patch b/patches.at91/0166-i2c-at91-add-dt-property-for-DMA-configuration.patch
new file mode 100644
index 00000000000000..fe5b5721d1ae36
--- /dev/null
+++ b/patches.at91/0166-i2c-at91-add-dt-property-for-DMA-configuration.patch
@@ -0,0 +1,141 @@
+From 9c0c6f313b432d8ae6effe769df5712508d00622 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 22 Oct 2012 16:00:47 +0200
+Subject: i2c: at91: add dt property for DMA configuration
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+
+Conflicts:
+ arch/arm/boot/dts/at91sam9x5.dtsi
+---
+ arch/arm/boot/dts/at91sam9x5.dtsi | 5 ++++
+ drivers/i2c/busses/i2c-at91.c | 56 ++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 60 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index fec3316..79718e7 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -103,12 +103,14 @@
+ compatible = "atmel,at91sam9g45-dma";
+ reg = <0xffffec00 0x200>;
+ interrupts = <20 4 0>;
++ #dma-cells = <1>;
+ };
+
+ dma1: dma-controller@ffffee00 {
+ compatible = "atmel,at91sam9g45-dma";
+ reg = <0xffffee00 0x200>;
+ interrupts = <21 4 0>;
++ #dma-cells = <1>;
+ };
+
+ pioA: gpio@fffff400 {
+@@ -221,6 +223,7 @@
+ compatible = "atmel,at91sam9x5-i2c";
+ reg = <0xf8010000 0x100>;
+ interrupts = <9 4 6>;
++ dma = <&dma0 0x10002278>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+@@ -230,6 +233,7 @@
+ compatible = "atmel,at91sam9x5-i2c";
+ reg = <0xf8014000 0x100>;
+ interrupts = <10 4 6>;
++ dma = <&dma1 0x10002256>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+@@ -239,6 +243,7 @@
+ compatible = "atmel,at91sam9x5-i2c";
+ reg = <0xf8018000 0x100>;
+ interrupts = <11 4 6>;
++ dma = <&dma0 0x1000229A>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
+index 296c430..c004b34 100644
+--- a/drivers/i2c/busses/i2c-at91.c
++++ b/drivers/i2c/busses/i2c-at91.c
+@@ -589,6 +589,55 @@ static const struct platform_device_id at91_twi_devtypes[] = {
+ };
+
+ #if defined(CONFIG_OF)
++static int at91_twi_of_init(struct device_node *np, struct at_dma_slave *atslave)
++{
++ struct of_phandle_args dma_spec;
++ struct device_node *dmac_np;
++ struct platform_device *dmac_pdev;
++ const __be32 *nbcells;
++ int ret;
++
++ ret = of_parse_phandle_with_args(np, "dma", "#dma-cells", 0, &dma_spec);
++ if (ret || !dma_spec.np) {
++ pr_err("%s: can't parse dma property (%d)\n", np->full_name, ret);
++ goto err0;
++ }
++ dmac_np = dma_spec.np;
++
++ /* check property format */
++ nbcells = of_get_property(dmac_np, "#dma-cells", NULL);
++ if (!nbcells) {
++ pr_err("%s: #dma-cells property is required\n", np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ if (dma_spec.args_count != be32_to_cpup(nbcells)
++ || dma_spec.args_count != 1) {
++ pr_err("%s: wrong #dma-cells for %s\n",
++ np->full_name, dmac_np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ dmac_pdev = of_find_device_by_node(dmac_np);
++ if (!dmac_pdev) {
++ pr_err("%s: unable to find pdev from DMA controller\n",
++ dmac_np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ atslave->dma_dev = &dmac_pdev->dev;
++ atslave->cfg = dma_spec.args[0];
++
++err1:
++ of_node_put(dma_spec.np);
++err0:
++ pr_debug("%s exited with status %d\n", __func__, ret);
++ return ret;
++}
++
+ static const struct of_device_id atmel_twi_dt_ids[] = {
+ {
+ .compatible = "atmel,at91sam9260-i2c",
+@@ -608,6 +657,10 @@ static const struct of_device_id atmel_twi_dt_ids[] = {
+ };
+ MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids);
+ #else
++static int at91_twi_of_init(struct device_node *np, struct at_dma_slave *atslave)
++{
++ return -ENODEV;
++}
+ #define atmel_twi_dt_ids NULL
+ #endif
+
+@@ -755,7 +808,8 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
+ clk_prepare_enable(dev->clk);
+
+ if (dev->pdata->has_dma_support) {
+- if (at91_twi_configure_dma(dev, phy_addr) == 0)
++ if ( at91_twi_of_init(pdev->dev.of_node, &dev->pdata->dma_slave) == 0
++ && at91_twi_configure_dma(dev, phy_addr) == 0)
+ dev->use_dma = true;
+ }
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0167-ARM-at91-add-MCI-DMA-for-at91sam9x5.dtsi.patch b/patches.at91/0167-ARM-at91-add-MCI-DMA-for-at91sam9x5.dtsi.patch
new file mode 100644
index 00000000000000..ddb7adc15f9c6a
--- /dev/null
+++ b/patches.at91/0167-ARM-at91-add-MCI-DMA-for-at91sam9x5.dtsi.patch
@@ -0,0 +1,35 @@
+From a26a550bb2339e928d60bcb4bf200eb0380ca6cc Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 24 Sep 2012 12:12:27 +0200
+Subject: ARM: at91: add MCI DMA for at91sam9x5.dtsi
+
+Temporary cfg hack
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9x5.dtsi | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 79718e7..88907db 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -208,6 +208,7 @@
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
++ dma = <&dma0 0x10002200>;
+ };
+
+ mmc1: mmc@f000c000 {
+@@ -217,6 +218,7 @@
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
++ dma = <&dma1 0x10002200>;
+ };
+
+ i2c0: i2c@f8010000 {
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0168-ARM-at91-add-i2c-and-qt1070-pin-muxing.patch b/patches.at91/0168-ARM-at91-add-i2c-and-qt1070-pin-muxing.patch
new file mode 100644
index 00000000000000..7143451676f391
--- /dev/null
+++ b/patches.at91/0168-ARM-at91-add-i2c-and-qt1070-pin-muxing.patch
@@ -0,0 +1,34 @@
+From 9ee686bef09cb282f384de19a8d0d8d0b96d9119 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 19 Sep 2012 09:27:02 +0200
+Subject: ARM: at91: add i2c and qt1070 pin muxing
+
+Pin mux is temporary done in board-dt file.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ arch/arm/mach-at91/board-dt.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
+index e8f45c4..9355d77 100644
+--- a/arch/arm/mach-at91/board-dt.c
++++ b/arch/arm/mach-at91/board-dt.c
+@@ -43,6 +43,14 @@ static void __init at91_dt_init_irq(void)
+ static void __init at91_dt_device_init(void)
+ {
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
++ /* Temporary pin mux stuff */
++ if (of_machine_is_compatible("atmel,at91sam9x5")) {
++ at91_set_A_periph(AT91_PIN_PA30, 0); /* TWD */
++ at91_set_A_periph(AT91_PIN_PA31, 0); /* TWCK */
++ printk("AT91: i2c pin mux done\n");
++ at91_set_gpio_input(AT91_PIN_PA7, 1);
++ printk("AT91: qt1070 pin mux done\n");
++ }
+ }
+
+ static const char *at91_dt_board_compat[] __initdata = {
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0169-AT91-board-dt-add-mci-pinmux-for-9x5.patch b/patches.at91/0169-AT91-board-dt-add-mci-pinmux-for-9x5.patch
new file mode 100644
index 00000000000000..ee7f27824d69fc
--- /dev/null
+++ b/patches.at91/0169-AT91-board-dt-add-mci-pinmux-for-9x5.patch
@@ -0,0 +1,48 @@
+From ee1a2b1fec441a9e821c3c6d0198e4b68545caf8 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 24 Sep 2012 12:27:10 +0200
+Subject: AT91: board-dt add mci pinmux for 9x5
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/board-dt.c | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
+index 9355d77..15830cb 100644
+--- a/arch/arm/mach-at91/board-dt.c
++++ b/arch/arm/mach-at91/board-dt.c
+@@ -50,6 +50,30 @@ static void __init at91_dt_device_init(void)
+ printk("AT91: i2c pin mux done\n");
+ at91_set_gpio_input(AT91_PIN_PA7, 1);
+ printk("AT91: qt1070 pin mux done\n");
++
++ at91_set_gpio_input(AT91_PIN_PD14, 1);
++ at91_set_deglitch(AT91_PIN_PD14, 1);
++ at91_set_gpio_input(AT91_PIN_PD15, 1);
++ at91_set_deglitch(AT91_PIN_PD15, 1);
++ /* CLK */
++ at91_set_A_periph(AT91_PIN_PA17, 0);
++ /* CMD */
++ at91_set_A_periph(AT91_PIN_PA16, 1);
++ /* DAT0, DAT1..DAT3 */
++ at91_set_A_periph(AT91_PIN_PA15, 1);
++ at91_set_A_periph(AT91_PIN_PA18, 1);
++ at91_set_A_periph(AT91_PIN_PA19, 1);
++ at91_set_A_periph(AT91_PIN_PA20, 1);
++ /* CLK */
++ at91_set_B_periph(AT91_PIN_PA13, 0);
++ /* CMD */
++ at91_set_B_periph(AT91_PIN_PA12, 1);
++ /* DAT0, DAT1..DAT3 */
++ at91_set_B_periph(AT91_PIN_PA11, 1);
++ at91_set_B_periph(AT91_PIN_PA2, 1);
++ at91_set_B_periph(AT91_PIN_PA3, 1);
++ at91_set_B_periph(AT91_PIN_PA4, 1);
++ printk("AT91: mci0/1 pin mux done\n");
+ }
+ }
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0170-mtd-atmel_nand-add-4k-page-nand-flash-support-for-PM.patch b/patches.at91/0170-mtd-atmel_nand-add-4k-page-nand-flash-support-for-PM.patch
new file mode 100644
index 00000000000000..5699167b8a1da4
--- /dev/null
+++ b/patches.at91/0170-mtd-atmel_nand-add-4k-page-nand-flash-support-for-PM.patch
@@ -0,0 +1,32 @@
+From 5447f10bde89a2237dabb7775d927911997f9d10 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Mon, 24 Sep 2012 14:50:45 +0800
+Subject: mtd: atmel_nand: add 4k page nand flash support for PMECC.
+
+---
+ drivers/mtd/nand/atmel_nand.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index b1158b4..431a8d9 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -952,6 +952,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
+ /* set ECC page size and oob layout */
+ switch (mtd->writesize) {
+ case 2048:
++ case 4096:
+ host->pmecc_degree = PMECC_GF_DIMENSION_13;
+ host->pmecc_cw_len = (1 << host->pmecc_degree) - 1;
+ host->pmecc_sector_number = mtd->writesize / sector_size;
+@@ -977,7 +978,6 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
+ break;
+ case 512:
+ case 1024:
+- case 4096:
+ /* TODO */
+ dev_warn(host->dev,
+ "Unsupported page size for PMECC, use Software ECC\n");
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0171-mtd-atmel_nand-incease-the-chip_delay-time-tR-for-su.patch b/patches.at91/0171-mtd-atmel_nand-incease-the-chip_delay-time-tR-for-su.patch
new file mode 100644
index 00000000000000..4f9475ad06ce76
--- /dev/null
+++ b/patches.at91/0171-mtd-atmel_nand-incease-the-chip_delay-time-tR-for-su.patch
@@ -0,0 +1,30 @@
+From 2631653caecceee1abc6643f4253f8a7e53d6284 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Mon, 24 Sep 2012 14:58:38 +0800
+Subject: mtd: atmel_nand: incease the chip_delay time(tR) for support big
+ flash chips such like MT29F8G08ABABA.
+
+---
+ drivers/mtd/nand/atmel_nand.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index 431a8d9..980ffdd 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -1415,7 +1415,11 @@ 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;
+- nand_chip->chip_delay = 20; /* 20us command delay time */
++
++ /* For support 4k-page flash, incease the delay time to 25us.
++ * In P.108 of MT29F8G08ABABA datasheet, tR max is 25us.
++ */
++ nand_chip->chip_delay = 25;
+
+ if (host->board.bus_width_16) /* 16-bit bus width */
+ nand_chip->options |= NAND_BUSWIDTH_16;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0172-at91-9x5-add-DT-parameters-to-enable-PMECC.patch b/patches.at91/0172-at91-9x5-add-DT-parameters-to-enable-PMECC.patch
new file mode 100644
index 00000000000000..594b3c1165ca7c
--- /dev/null
+++ b/patches.at91/0172-at91-9x5-add-DT-parameters-to-enable-PMECC.patch
@@ -0,0 +1,46 @@
+From cd0c1e4a82957d9f21ad07efa5fcdb553ad28cb2 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Tue, 25 Sep 2012 10:40:22 +0800
+Subject: at91: 9x5: add DT parameters to enable PMECC
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9x5.dtsi | 4 ++++
+ arch/arm/boot/dts/at91sam9x5cm.dtsi | 5 ++++-
+ 2 files changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 88907db..2cefd49 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -257,7 +257,11 @@
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x40000000 0x10000000
++ 0xffffe000 0x600 /* PMECC Registers */
++ 0xffffe600 0x200 /* PMECC Error Location Registers */
++ 0x00100000 0x100000 /* ROM code */
+ >;
++ atmel,pmecc-lookup-table-offset = <0x8000 0x10000>;
+ atmel,nand-addr-offset = <21>;
+ atmel,nand-cmd-offset = <22>;
+ gpios = <&pioD 5 0
+diff --git a/arch/arm/boot/dts/at91sam9x5cm.dtsi b/arch/arm/boot/dts/at91sam9x5cm.dtsi
+index 31e7be2..4027ac7 100644
+--- a/arch/arm/boot/dts/at91sam9x5cm.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5cm.dtsi
+@@ -26,7 +26,10 @@
+ ahb {
+ nand0: nand@40000000 {
+ nand-bus-width = <8>;
+- nand-ecc-mode = "soft";
++ nand-ecc-mode = "hw";
++ atmel,has-pmecc; /* Enable PMECC */
++ atmel,pmecc-cap = <2>;
++ atmel,pmecc-sector-size = <512>;
+ nand-on-flash-bbt;
+ status = "okay";
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0173-ARM-at91-split-9x5-dts-dtsi-in-a-common-set-of-perip.patch b/patches.at91/0173-ARM-at91-split-9x5-dts-dtsi-in-a-common-set-of-perip.patch
new file mode 100644
index 00000000000000..e1f272c6dfd826
--- /dev/null
+++ b/patches.at91/0173-ARM-at91-split-9x5-dts-dtsi-in-a-common-set-of-perip.patch
@@ -0,0 +1,124 @@
+From 5656f4e07c7b30e26ecd3716c8ab1c9157946e80 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 2 Oct 2012 11:50:15 +0200
+Subject: ARM: at91: split 9x5 dts/dtsi in a "common" set of peripherals
+
+Creating this new at91sam9x5_common.dtsi, will allow to cover the
+whole at91sam9x5 family of SoCs without having to duplicate nodes.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+
+Conflicts:
+ arch/arm/boot/dts/at91sam9g25ek.dts
+---
+ arch/arm/boot/dts/at91sam9g25ek.dts | 19 +----------
+ arch/arm/boot/dts/at91sam9x5_common.dtsi | 54 ++++++++++++++++++++++++++++++++
+ 2 files changed, 55 insertions(+), 18 deletions(-)
+ create mode 100644 arch/arm/boot/dts/at91sam9x5_common.dtsi
+
+diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts
+index 5b054e4..91c0f02 100644
+--- a/arch/arm/boot/dts/at91sam9g25ek.dts
++++ b/arch/arm/boot/dts/at91sam9g25ek.dts
+@@ -7,8 +7,7 @@
+ * Licensed under GPLv2 or later.
+ */
+ /dts-v1/;
+-/include/ "at91sam9x5.dtsi"
+-/include/ "at91sam9x5cm.dtsi"
++/include/ "at91sam9x5_common.dtsi"
+
+ / {
+ model = "Atmel AT91SAM9G25-EK";
+@@ -20,10 +19,6 @@
+
+ ahb {
+ apb {
+- dbgu: serial@fffff200 {
+- status = "okay";
+- };
+-
+ usart0: serial@f801c000 {
+ status = "okay";
+ };
+@@ -63,17 +58,5 @@
+ status = "okay";
+ };
+ };
+-
+- usb0: ohci@00600000 {
+- status = "okay";
+- num-ports = <2>;
+- atmel,vbus-gpio = <&pioD 19 1
+- &pioD 20 1
+- >;
+- };
+-
+- usb1: ehci@00700000 {
+- status = "okay";
+- };
+ };
+ };
+diff --git a/arch/arm/boot/dts/at91sam9x5_common.dtsi b/arch/arm/boot/dts/at91sam9x5_common.dtsi
+new file mode 100644
+index 0000000..b805425
+--- /dev/null
++++ b/arch/arm/boot/dts/at91sam9x5_common.dtsi
+@@ -0,0 +1,54 @@
++/*
++ * at91sam9x5_common.dtsi - Device Tree Include file for AT91SAM9x5 Evaluation Kit:
++ * common peripherals.
++ *
++ * Copyright (C) 2012 Atmel,
++ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com>
++ *
++ * Licensed under GPLv2 or later.
++ */
++/include/ "at91sam9x5.dtsi"
++/include/ "at91sam9x5cm.dtsi"
++
++/ {
++ ahb {
++ apb {
++ dbgu: serial@fffff200 {
++ status = "okay";
++ };
++
++ mmc0: mmc@f0008000 {
++ status = "okay";
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioD 15 0>;
++ };
++ };
++
++ i2c0: i2c@f8010000 {
++ status = "okay";
++ };
++
++ i2c1: i2c@f8014000 {
++ status = "okay";
++ };
++
++ i2c2: i2c@f8018000 {
++ status = "okay";
++ };
++ };
++
++ usb0: ohci@00600000 {
++ status = "okay";
++ num-ports = <2>;
++ atmel,vbus-gpio = <&pioD 19 1
++ &pioD 20 1
++ >;
++ };
++
++ usb1: ehci@00700000 {
++ status = "okay";
++ };
++ };
++};
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0174-ARM-at91-9x5-family-add-at91sam9x25ek.dts.patch b/patches.at91/0174-ARM-at91-9x5-family-add-at91sam9x25ek.dts.patch
new file mode 100644
index 00000000000000..e0894417481942
--- /dev/null
+++ b/patches.at91/0174-ARM-at91-9x5-family-add-at91sam9x25ek.dts.patch
@@ -0,0 +1,76 @@
+From 632da89db09717d999cad5669385db5a85e876ab Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 2 Oct 2012 11:55:18 +0200
+Subject: ARM: at91/9x5 family: add at91sam9x25ek.dts
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9x25ek.dts | 46 +++++++++++++++++++++++++++++++++++++
+ arch/arm/mach-at91/Makefile.boot | 1 +
+ 2 files changed, 47 insertions(+)
+ create mode 100644 arch/arm/boot/dts/at91sam9x25ek.dts
+
+diff --git a/arch/arm/boot/dts/at91sam9x25ek.dts b/arch/arm/boot/dts/at91sam9x25ek.dts
+new file mode 100644
+index 0000000..cf903f5
+--- /dev/null
++++ b/arch/arm/boot/dts/at91sam9x25ek.dts
+@@ -0,0 +1,46 @@
++/*
++ * at91sam9x25ek.dts - Device Tree file for AT91SAM9X25-EK board
++ *
++ * Copyright (C) 2012 Atmel,
++ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com>
++ *
++ * Licensed under GPLv2 or later.
++ */
++/dts-v1/;
++/include/ "at91sam9x5_common.dtsi"
++
++/ {
++ model = "Atmel AT91SAM9X25-EK";
++ compatible = "atmel,at91sam9x25ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
++
++ chosen {
++ bootargs = "console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
++ };
++
++ ahb {
++ apb {
++ mmc1: mmc@f000c000 {
++ status = "okay";
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioD 14 0>;
++ };
++ };
++
++ usart0: serial@f801c000 {
++ status = "okay";
++ };
++
++ macb0: ethernet@f802c000 {
++ phy-mode = "rmii";
++ status = "okay";
++ };
++
++ macb1: ethernet@f8030000 {
++ phy-mode = "rmii";
++ status = "okay";
++ };
++ };
++ };
++};
+diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
+index 9e84fe4..9532f93 100644
+--- a/arch/arm/mach-at91/Makefile.boot
++++ b/arch/arm/mach-at91/Makefile.boot
+@@ -34,3 +34,4 @@ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9n12ek.dtb
+ # sam9x5
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g25ek.dtb
++dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9x25ek.dtb
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0175-ARM-at91-add-new-at91sam9g35ek.dts.patch b/patches.at91/0175-ARM-at91-add-new-at91sam9g35ek.dts.patch
new file mode 100644
index 00000000000000..867d9fb47688f8
--- /dev/null
+++ b/patches.at91/0175-ARM-at91-add-new-at91sam9g35ek.dts.patch
@@ -0,0 +1,109 @@
+From 4b171e9b798f8fc6ce79303691522c080b085c5c Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 16 Oct 2012 19:04:39 +0200
+Subject: ARM: at91: add new at91sam9g35ek.dts
+
+With LCD DT definition
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9g35ek.dts | 49 +++++++++++++++++++++++++++++++++++++
+ arch/arm/boot/dts/at91sam9x5.dtsi | 15 ++++++++++++
+ arch/arm/mach-at91/Makefile.boot | 1 +
+ 3 files changed, 65 insertions(+)
+ create mode 100644 arch/arm/boot/dts/at91sam9g35ek.dts
+
+diff --git a/arch/arm/boot/dts/at91sam9g35ek.dts b/arch/arm/boot/dts/at91sam9g35ek.dts
+new file mode 100644
+index 0000000..f2c3341
+--- /dev/null
++++ b/arch/arm/boot/dts/at91sam9g35ek.dts
+@@ -0,0 +1,49 @@
++/*
++ * at91sam9g35ek.dts - Device Tree file for AT91SAM9G35-EK board
++ *
++ * Copyright (C) 2012 Atmel,
++ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com>
++ *
++ * Licensed under GPLv2 or later.
++ */
++/dts-v1/;
++/include/ "at91sam9x5_common.dtsi"
++
++/ {
++ model = "Atmel AT91SAM9G35-EK";
++ compatible = "atmel,at91sam9g35ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
++
++ chosen {
++ bootargs = "console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
++ };
++
++ ahb {
++ apb {
++ mmc1: mmc@f000c000 {
++ status = "okay";
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioD 14 0>;
++ };
++ };
++
++ usart0: serial@f801c000 {
++ status = "okay";
++ };
++
++ macb0: ethernet@f802c000 {
++ phy-mode = "rmii";
++ status = "okay";
++ };
++
++ lcd@f8038000 {
++ status = "okay";
++ };
++
++ lcdovl1@f8038100 {
++ status = "okay";
++ };
++ };
++ };
++};
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 2cefd49..50388fd 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -250,6 +250,21 @@
+ #size-cells = <0>;
+ status = "disabled";
+ };
++
++ lcd@f8038000 {
++ compatible = "atmel,at91sam9x5-lcd";
++ reg = <0xf8038000 0xff
++ 0xf8038400 0x3ff>;
++ interrupts = <25 4 3>;
++ status = "disabled";
++ };
++
++ lcdovl1@f8038100 {
++ compatible = "atmel,at91sam9x5-lcd";
++ reg = <0xf8038100 0xff
++ 0xf8038800 0x3ff>;
++ status = "disabled";
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
+index 9532f93..410485a 100644
+--- a/arch/arm/mach-at91/Makefile.boot
++++ b/arch/arm/mach-at91/Makefile.boot
+@@ -34,4 +34,5 @@ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9n12ek.dtb
+ # sam9x5
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g25ek.dtb
++dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g35ek.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9x25ek.dtb
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0176-ARM-at91-add-pinmux-for-9x5-LCD.patch b/patches.at91/0176-ARM-at91-add-pinmux-for-9x5-LCD.patch
new file mode 100644
index 00000000000000..cd8efe71f2a230
--- /dev/null
+++ b/patches.at91/0176-ARM-at91-add-pinmux-for-9x5-LCD.patch
@@ -0,0 +1,143 @@
+From a9002e549702ca79f7bc946b3ec1072eca79a563 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 16 Oct 2012 19:05:25 +0200
+Subject: ARM: at91: add pinmux for 9x5 LCD
+
+Temporaty in board-dt
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/board-dt.c | 102 +++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 101 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
+index 15830cb..c0d242c 100644
+--- a/arch/arm/mach-at91/board-dt.c
++++ b/arch/arm/mach-at91/board-dt.c
+@@ -26,6 +26,103 @@
+
+ #include "generic.h"
+
++#include <linux/fb.h>
++
++#include <video/atmel_lcdfb.h>
++#include <mach/atmel_hlcdc.h>
++
++/*
++ * LCD Controller
++ */
++static struct fb_videomode at91_tft_vga_modes[] = {
++ {
++ .name = "LG",
++ .refresh = 60,
++ .xres = 800, .yres = 480,
++ .pixclock = KHZ2PICOS(33260),
++
++ .left_margin = 88, .right_margin = 168,
++ .upper_margin = 8, .lower_margin = 37,
++ .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 BPP_OUT_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 = 16,
++ /* Reserve enough memory for 32bpp */
++ .smem_len = 800 * 480 * 4,
++ /* default_lcdcon2 is used for LCDCFG5 */
++ .default_lcdcon2 = BPP_OUT_DEFAULT_LCDCFG5,
++ .default_monspecs = &at91fb_default_monspecs,
++ .guard_time = 9,
++ .lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB,
++};
++
++void __init at91sam9x5_pinmux_lcd(void)
++{
++ 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 */
++
++ printk("AT91: lcd pin mux done\n");
++}
++
++struct of_dev_auxdata at91_auxdata_lookup[] __initdata = {
++ OF_DEV_AUXDATA("atmel,at91sam9x5-lcd", 0xf8038000, "atmel_hlcdfb_base", &ek_lcdc_data),
++ OF_DEV_AUXDATA("atmel,at91sam9x5-lcd", 0xf8038100, "atmel_hlcdfb_ovl", &ek_lcdc_data),
++ { /* sentinel */ }
++};
+
+ static const struct of_device_id irq_of_match[] __initconst = {
+
+@@ -42,7 +139,6 @@ static void __init at91_dt_init_irq(void)
+
+ static void __init at91_dt_device_init(void)
+ {
+- of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+ /* Temporary pin mux stuff */
+ if (of_machine_is_compatible("atmel,at91sam9x5")) {
+ at91_set_A_periph(AT91_PIN_PA30, 0); /* TWD */
+@@ -74,7 +170,11 @@ static void __init at91_dt_device_init(void)
+ at91_set_B_periph(AT91_PIN_PA3, 1);
+ at91_set_B_periph(AT91_PIN_PA4, 1);
+ printk("AT91: mci0/1 pin mux done\n");
++
++ at91sam9x5_pinmux_lcd();
+ }
++
++ of_platform_populate(NULL, of_default_bus_match_table, at91_auxdata_lookup, NULL);
+ }
+
+ static const char *at91_dt_board_compat[] __initdata = {
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0177-ARM-at91-add-LCD-HEO-DT-entry-for-at91sam9x5.patch b/patches.at91/0177-ARM-at91-add-LCD-HEO-DT-entry-for-at91sam9x5.patch
new file mode 100644
index 00000000000000..949486e352d66f
--- /dev/null
+++ b/patches.at91/0177-ARM-at91-add-LCD-HEO-DT-entry-for-at91sam9x5.patch
@@ -0,0 +1,49 @@
+From e19f22bd4c8c9d63f777d58a38b6dd14b34c0b30 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 17 Oct 2012 10:14:48 +0200
+Subject: ARM: at91: add LCD HEO DT entry for at91sam9x5
+
+At91sam9x5.dtsi entry and activated in sam9g35ek.dts.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9g35ek.dts | 4 ++++
+ arch/arm/boot/dts/at91sam9x5.dtsi | 7 +++++++
+ 2 files changed, 11 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9g35ek.dts b/arch/arm/boot/dts/at91sam9g35ek.dts
+index f2c3341..0cb762e 100644
+--- a/arch/arm/boot/dts/at91sam9g35ek.dts
++++ b/arch/arm/boot/dts/at91sam9g35ek.dts
+@@ -44,6 +44,10 @@
+ lcdovl1@f8038100 {
+ status = "okay";
+ };
++
++ lcdheo1@f8038280 {
++ status = "okay";
++ };
+ };
+ };
+ };
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 50388fd..027b9eb 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -265,6 +265,13 @@
+ 0xf8038800 0x3ff>;
+ status = "disabled";
+ };
++
++ lcdheo1@f8038280 {
++ compatible = "atmel,at91sam9x5-heo";
++ reg = <0xf8038280 0xbf>;
++ interrupts = <25 4 3>;
++ status = "disabled";
++ };
+ };
+
+ nand0: nand@40000000 {
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0178-AT91SAM9G45-add-crypto-peripherals.patch b/patches.at91/0178-AT91SAM9G45-add-crypto-peripherals.patch
new file mode 100644
index 00000000000000..6f92f29532c65e
--- /dev/null
+++ b/patches.at91/0178-AT91SAM9G45-add-crypto-peripherals.patch
@@ -0,0 +1,248 @@
+From f0a167e19975fff4396904bf6c9521db525316e8 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 22 Oct 2012 16:04:42 +0200
+Subject: AT91SAM9G45: add crypto peripherals
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+
+Conflicts:
+ arch/arm/mach-at91/at91sam9g45.c
+---
+ arch/arm/mach-at91/at91sam9g45.c | 16 +++-
+ arch/arm/mach-at91/at91sam9g45_devices.c | 131 +++++++++++++++++++++++++-
+ arch/arm/mach-at91/include/mach/at91sam9g45.h | 2 +
+ 3 files changed, 147 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
+index 7ccbf9c..4b791bf 100644
+--- a/arch/arm/mach-at91/at91sam9g45.c
++++ b/arch/arm/mach-at91/at91sam9g45.c
+@@ -177,6 +177,13 @@ static struct clk vdec_clk = {
+ .type = CLK_TYPE_PERIPHERAL,
+ };
+
++/* AES/TDES/SHA clock - Only for sam9m11/sam9g56 */
++static struct clk aestdessha_clk = {
++ .name = "aestdessha_clk",
++ .pmc_mask = 1 << AT91SAM9G45_ID_AESTDESSHA,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++
+ static struct clk *periph_clocks[] __initdata = {
+ &pioA_clk,
+ &pioB_clk,
+@@ -205,6 +212,7 @@ static struct clk *periph_clocks[] __initdata = {
+ &isi_clk,
+ &udphs_clk,
+ &mmc1_clk,
++ &aestdessha_clk,
+ // irq0
+ };
+
+@@ -226,6 +234,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.1", &twi1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
++ CLKDEV_CON_DEV_ID("sha_clk", "atmel_sha", &aestdessha_clk),
++ CLKDEV_CON_DEV_ID("tdes_clk", "atmel_tdes", &aestdessha_clk),
++ CLKDEV_CON_DEV_ID("aes_clk", "atmel_aes", &aestdessha_clk),
+ CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk),
+ /* more usart lookup table for DT entries */
+ CLKDEV_CON_DEV_ID("usart", "ffffee00.serial", &mck),
+@@ -242,6 +253,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("mci_clk", "fffd0000.mmc", &mmc1_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fff84000.i2c", &twi0_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi1_clk),
++ CLKDEV_CON_DEV_ID("aes_clk", "fffc0000.aes", &aestdessha_clk),
++ CLKDEV_CON_DEV_ID("tdes_clk", "fffc4000.tdes", &aestdessha_clk),
++ CLKDEV_CON_DEV_ID("sha_clk", "fffc8000.sha", &aestdessha_clk),
+ /* fake hclk clock */
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+@@ -387,7 +401,7 @@ static unsigned int at91sam9g45_default_irq_priority[NR_AIC_IRQS] __initdata = {
+ 2, /* USB Device High speed port */
+ 0,
+ 0, /* Multimedia Card Interface 1 */
+- 0,
++ 0, /* AESTDESSHA Crypto HW Accelerators */
+ 0, /* Advanced Interrupt Controller (IRQ0) */
+ };
+
+diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
+index 29f334c..3d523f0 100644
+--- a/arch/arm/mach-at91/at91sam9g45_devices.c
++++ b/arch/arm/mach-at91/at91sam9g45_devices.c
+@@ -31,7 +31,7 @@
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at_hdmac.h>
+ #include <mach/atmel-mci.h>
+-
++#include <linux/platform_data/atmel-aes.h>
+ #include <media/atmel-isi.h>
+
+ #include "generic.h"
+@@ -514,6 +514,132 @@ void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
+
+
+ /* --------------------------------------------------------------------
++ * SHA1/SHA256
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_CRYPTO_DEV_ATMEL_SHA) || defined(CONFIG_CRYPTO_DEV_ATMEL_SHA_MODULE)
++static struct resource sha_resources[] = {
++ {
++ .start = AT91SAM9G45_BASE_SHA,
++ .end = AT91SAM9G45_BASE_SHA + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91sam9g45_sha_device = {
++ .name = "atmel_sha",
++ .id = -1,
++ .resource = sha_resources,
++ .num_resources = ARRAY_SIZE(sha_resources),
++};
++
++static void __init at91_add_device_sha(void)
++{
++ platform_device_register(&at91sam9g45_sha_device);
++}
++#else
++static void __init at91_add_device_sha(void) {}
++#endif
++
++/* --------------------------------------------------------------------
++ * DES/TDES
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_CRYPTO_DEV_ATMEL_TDES) || defined(CONFIG_CRYPTO_DEV_ATMEL_TDES_MODULE)
++static struct resource tdes_resources[] = {
++ [0] = {
++ .start = AT91SAM9G45_BASE_TDES,
++ .end = AT91SAM9G45_BASE_TDES + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91sam9g45_tdes_device = {
++ .name = "atmel_tdes",
++ .id = -1,
++ .resource = tdes_resources,
++ .num_resources = ARRAY_SIZE(tdes_resources),
++};
++
++static void __init at91_add_device_tdes(void)
++{
++ platform_device_register(&at91sam9g45_tdes_device);
++}
++#else
++static void __init at91_add_device_tdes(void) {}
++#endif
++
++/* --------------------------------------------------------------------
++ * AES
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_CRYPTO_DEV_ATMEL_AES) || defined(CONFIG_CRYPTO_DEV_ATMEL_AES_MODULE)
++static struct aes_platform_data aes_data;
++static u64 aes_dmamask = DMA_BIT_MASK(32);
++
++static struct resource aes_resources[] = {
++ [0] = {
++ .start = AT91SAM9G45_BASE_AES,
++ .end = AT91SAM9G45_BASE_AES + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91sam9g45_aes_device = {
++ .name = "atmel_aes",
++ .id = -1,
++ .dev = {
++ .dma_mask = &aes_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &aes_data,
++ },
++ .resource = aes_resources,
++ .num_resources = ARRAY_SIZE(aes_resources),
++};
++
++static void __init at91_add_device_aes(void)
++{
++ struct at_dma_slave *atslave;
++ struct aes_dma_data *alt_atslave;
++
++ alt_atslave = kzalloc(sizeof(struct aes_dma_data), GFP_KERNEL);
++
++ /* DMA TX slave channel configuration */
++ atslave = &alt_atslave->txdata;
++ atslave->dma_dev = &at_hdmac_device.dev;
++ atslave->cfg = ATC_FIFOCFG_ENOUGHSPACE | ATC_SRC_H2SEL_HW |
++ ATC_SRC_PER(AT_DMA_ID_AES_RX);
++
++ /* DMA RX slave channel configuration */
++ atslave = &alt_atslave->rxdata;
++ atslave->dma_dev = &at_hdmac_device.dev;
++ atslave->cfg = ATC_FIFOCFG_ENOUGHSPACE | ATC_DST_H2SEL_HW |
++ ATC_DST_PER(AT_DMA_ID_AES_TX);
++
++ aes_data.dma_slave = alt_atslave;
++ platform_device_register(&at91sam9g45_aes_device);
++}
++#else
++static void __init at91_add_device_aes(void) {}
++#endif
++
++
++/* --------------------------------------------------------------------
+ * NAND / SmartMedia
+ * -------------------------------------------------------------------- */
+
+@@ -1742,6 +1868,9 @@ static int __init at91_add_standard_devices(void)
+ at91_add_device_trng();
+ at91_add_device_watchdog();
+ at91_add_device_tc();
++ at91_add_device_sha();
++ at91_add_device_tdes();
++ at91_add_device_aes();
+ return 0;
+ }
+
+diff --git a/arch/arm/mach-at91/include/mach/at91sam9g45.h b/arch/arm/mach-at91/include/mach/at91sam9g45.h
+index 3a4da24..8eba102 100644
+--- a/arch/arm/mach-at91/include/mach/at91sam9g45.h
++++ b/arch/arm/mach-at91/include/mach/at91sam9g45.h
+@@ -136,6 +136,8 @@
+ #define AT_DMA_ID_SSC1_RX 8
+ #define AT_DMA_ID_AC97_TX 9
+ #define AT_DMA_ID_AC97_RX 10
++#define AT_DMA_ID_AES_TX 11
++#define AT_DMA_ID_AES_RX 12
+ #define AT_DMA_ID_MCI1 13
+
+ #endif
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0179-crypto-add-Atmel-AES-driver.patch b/patches.at91/0179-crypto-add-Atmel-AES-driver.patch
new file mode 100644
index 00000000000000..aee86623dac40c
--- /dev/null
+++ b/patches.at91/0179-crypto-add-Atmel-AES-driver.patch
@@ -0,0 +1,1369 @@
+From c6353d7b9b2b4b1d51e39f877f2ecf666c2c850d Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:04 +0200
+Subject: crypto: add Atmel AES driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ drivers/crypto/Kconfig | 17 +
+ drivers/crypto/Makefile | 1 +
+ drivers/crypto/atmel-aes-regs.h | 62 ++
+ drivers/crypto/atmel-aes.c | 1206 +++++++++++++++++++++++++++++++
+ include/linux/platform_data/atmel-aes.h | 22 +
+ 5 files changed, 1308 insertions(+)
+ create mode 100644 drivers/crypto/atmel-aes-regs.h
+ create mode 100644 drivers/crypto/atmel-aes.c
+ create mode 100644 include/linux/platform_data/atmel-aes.h
+
+diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
+index dd414d9..98c7da5 100644
+--- a/drivers/crypto/Kconfig
++++ b/drivers/crypto/Kconfig
+@@ -296,4 +296,21 @@ config CRYPTO_DEV_TEGRA_AES
+ To compile this driver as a module, choose M here: the module
+ will be called tegra-aes.
+
++config CRYPTO_DEV_ATMEL_AES
++ tristate "Support for Atmel AES hw accelerator"
++ depends on ARCH_AT91
++ select CRYPTO_CBC
++ select CRYPTO_ECB
++ select CRYPTO_AES
++ select CRYPTO_ALGAPI
++ select CRYPTO_BLKCIPHER
++ select AT_HDMAC
++ help
++ Some Atmel processors have AES hw accelerator.
++ Select this if you want to use the Atmel module for
++ AES algorithms.
++
++ To compile this driver as a module, choose M here: the module
++ will be called atmel-aes.
++
+ endif # CRYPTO_HW
+diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
+index f3e64ea..73ad830 100644
+--- a/drivers/crypto/Makefile
++++ b/drivers/crypto/Makefile
+@@ -14,3 +14,4 @@ obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
+ obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
+ obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
+ obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
++obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o
+diff --git a/drivers/crypto/atmel-aes-regs.h b/drivers/crypto/atmel-aes-regs.h
+new file mode 100644
+index 0000000..2786bb1
+--- /dev/null
++++ b/drivers/crypto/atmel-aes-regs.h
+@@ -0,0 +1,62 @@
++#ifndef __ATMEL_AES_REGS_H__
++#define __ATMEL_AES_REGS_H__
++
++#define AES_CR 0x00
++#define AES_CR_START (1 << 0)
++#define AES_CR_SWRST (1 << 8)
++#define AES_CR_LOADSEED (1 << 16)
++
++#define AES_MR 0x04
++#define AES_MR_CYPHER_DEC (0 << 0)
++#define AES_MR_CYPHER_ENC (1 << 0)
++#define AES_MR_DUALBUFF (1 << 3)
++#define AES_MR_PROCDLY_MASK (0xF << 4)
++#define AES_MR_PROCDLY_OFFSET 4
++#define AES_MR_SMOD_MASK (0x3 << 8)
++#define AES_MR_SMOD_MANUAL (0x0 << 8)
++#define AES_MR_SMOD_AUTO (0x1 << 8)
++#define AES_MR_SMOD_IDATAR0 (0x2 << 8)
++#define AES_MR_KEYSIZE_MASK (0x3 << 10)
++#define AES_MR_KEYSIZE_128 (0x0 << 10)
++#define AES_MR_KEYSIZE_192 (0x1 << 10)
++#define AES_MR_KEYSIZE_256 (0x2 << 10)
++#define AES_MR_OPMOD_MASK (0x7 << 12)
++#define AES_MR_OPMOD_ECB (0x0 << 12)
++#define AES_MR_OPMOD_CBC (0x1 << 12)
++#define AES_MR_OPMOD_OFB (0x2 << 12)
++#define AES_MR_OPMOD_CFB (0x3 << 12)
++#define AES_MR_OPMOD_CTR (0x4 << 12)
++#define AES_MR_LOD (0x1 << 15)
++#define AES_MR_CFBS_MASK (0x7 << 16)
++#define AES_MR_CFBS_128b (0x0 << 16)
++#define AES_MR_CFBS_64b (0x1 << 16)
++#define AES_MR_CFBS_32b (0x2 << 16)
++#define AES_MR_CFBS_16b (0x3 << 16)
++#define AES_MR_CFBS_8b (0x4 << 16)
++#define AES_MR_CKEY_MASK (0xF << 20)
++#define AES_MR_CKEY_OFFSET 20
++#define AES_MR_CMTYP_MASK (0x1F << 24)
++#define AES_MR_CMTYP_OFFSET 24
++
++#define AES_IER 0x10
++#define AES_IDR 0x14
++#define AES_IMR 0x18
++#define AES_ISR 0x1C
++#define AES_INT_DATARDY (1 << 0)
++#define AES_INT_URAD (1 << 8)
++#define AES_ISR_URAT_MASK (0xF << 12)
++#define AES_ISR_URAT_IDR_WR_PROC (0x0 << 12)
++#define AES_ISR_URAT_ODR_RD_PROC (0x1 << 12)
++#define AES_ISR_URAT_MR_WR_PROC (0x2 << 12)
++#define AES_ISR_URAT_ODR_RD_SUBK (0x3 << 12)
++#define AES_ISR_URAT_MR_WR_SUBK (0x4 << 12)
++#define AES_ISR_URAT_WOR_RD (0x5 << 12)
++
++#define AES_KEYWR(x) (0x20 + ((x) * 0x04))
++#define AES_IDATAR(x) (0x40 + ((x) * 0x04))
++#define AES_ODATAR(x) (0x50 + ((x) * 0x04))
++#define AES_IVR(x) (0x60 + ((x) * 0x04))
++
++#define AES_HW_VERSION 0xFC
++
++#endif /* __ATMEL_AES_REGS_H__ */
+diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
+new file mode 100644
+index 0000000..6bb20ff
+--- /dev/null
++++ b/drivers/crypto/atmel-aes.c
+@@ -0,0 +1,1206 @@
++/*
++ * Cryptographic API.
++ *
++ * Support for ATMEL AES HW acceleration.
++ *
++ * Copyright (c) 2012 Eukréa Electromatique - ATMEL
++ * Author: Nicolas Royer <nicolas@eukrea.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.
++ *
++ * Some ideas are from omap-aes.c driver.
++ */
++
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/err.h>
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/hw_random.h>
++#include <linux/platform_device.h>
++
++#include <linux/device.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/clk.h>
++#include <linux/irq.h>
++#include <linux/io.h>
++#include <linux/platform_device.h>
++#include <linux/scatterlist.h>
++#include <linux/dma-mapping.h>
++#include <linux/delay.h>
++#include <linux/crypto.h>
++#include <linux/cryptohash.h>
++#include <crypto/scatterwalk.h>
++#include <crypto/algapi.h>
++#include <crypto/aes.h>
++#include <crypto/hash.h>
++#include <crypto/internal/hash.h>
++#include <linux/platform_data/atmel-aes.h>
++#include "atmel-aes-regs.h"
++
++#define CFB8_BLOCK_SIZE 1
++#define CFB16_BLOCK_SIZE 2
++#define CFB32_BLOCK_SIZE 4
++#define CFB64_BLOCK_SIZE 8
++
++/* AES flags */
++#define AES_FLAGS_MODE_MASK 0x01ff
++#define AES_FLAGS_ENCRYPT BIT(0)
++#define AES_FLAGS_CBC BIT(1)
++#define AES_FLAGS_CFB BIT(2)
++#define AES_FLAGS_CFB8 BIT(3)
++#define AES_FLAGS_CFB16 BIT(4)
++#define AES_FLAGS_CFB32 BIT(5)
++#define AES_FLAGS_CFB64 BIT(6)
++#define AES_FLAGS_OFB BIT(7)
++#define AES_FLAGS_CTR BIT(8)
++
++#define AES_FLAGS_INIT BIT(16)
++#define AES_FLAGS_DMA BIT(17)
++#define AES_FLAGS_BUSY BIT(18)
++
++#define AES_FLAGS_DUALBUFF BIT(24)
++
++#define ATMEL_AES_QUEUE_LENGTH 1
++#define ATMEL_AES_CACHE_SIZE 0
++
++#define ATMEL_AES_DMA_THRESHOLD 16
++
++
++struct atmel_aes_dev;
++
++struct atmel_aes_ctx {
++ struct atmel_aes_dev *dd;
++
++ int keylen;
++ u32 key[AES_KEYSIZE_256 / sizeof(u32)];
++};
++
++struct atmel_aes_reqctx {
++ unsigned long mode;
++};
++
++struct atmel_aes_dma {
++ struct dma_chan *chan;
++ struct dma_slave_config dma_conf;
++};
++
++struct atmel_aes_dev {
++ struct list_head list;
++ unsigned long phys_base;
++ void __iomem *io_base;
++
++ struct atmel_aes_ctx *ctx;
++ struct device *dev;
++ struct clk *iclk;
++ int irq;
++
++ unsigned long flags;
++ int err;
++
++ spinlock_t lock;
++ struct crypto_queue queue;
++
++ struct tasklet_struct done_task;
++ struct tasklet_struct queue_task;
++
++ struct ablkcipher_request *req;
++ size_t total;
++
++ struct scatterlist *in_sg;
++ unsigned int nb_in_sg;
++
++ struct scatterlist *out_sg;
++ unsigned int nb_out_sg;
++
++ size_t bufcnt;
++
++ u8 buf_in[ATMEL_AES_DMA_THRESHOLD] __aligned(sizeof(u32));
++ int dma_in;
++ struct atmel_aes_dma dma_lch_in;
++
++ u8 buf_out[ATMEL_AES_DMA_THRESHOLD] __aligned(sizeof(u32));
++ int dma_out;
++ struct atmel_aes_dma dma_lch_out;
++
++ u32 hw_version;
++};
++
++struct atmel_aes_drv {
++ struct list_head dev_list;
++ spinlock_t lock;
++};
++
++static struct atmel_aes_drv atmel_aes = {
++ .dev_list = LIST_HEAD_INIT(atmel_aes.dev_list),
++ .lock = __SPIN_LOCK_UNLOCKED(atmel_aes.lock),
++};
++
++static int atmel_aes_sg_length(struct ablkcipher_request *req,
++ struct scatterlist *sg)
++{
++ unsigned int total = req->nbytes;
++ int sg_nb;
++ unsigned int len;
++ struct scatterlist *sg_list;
++
++ sg_nb = 0;
++ sg_list = sg;
++ total = req->nbytes;
++
++ while (total) {
++ len = min(sg_list->length, total);
++
++ sg_nb++;
++ total -= len;
++
++ sg_list = sg_next(sg_list);
++ if (!sg_list)
++ total = 0;
++ }
++
++ return sg_nb;
++}
++
++static inline u32 atmel_aes_read(struct atmel_aes_dev *dd, u32 offset)
++{
++ return readl_relaxed(dd->io_base + offset);
++}
++
++static inline void atmel_aes_write(struct atmel_aes_dev *dd,
++ u32 offset, u32 value)
++{
++ writel_relaxed(value, dd->io_base + offset);
++}
++
++static void atmel_aes_read_n(struct atmel_aes_dev *dd, u32 offset,
++ u32 *value, int count)
++{
++ for (; count--; value++, offset += 4)
++ *value = atmel_aes_read(dd, offset);
++}
++
++static void atmel_aes_write_n(struct atmel_aes_dev *dd, u32 offset,
++ u32 *value, int count)
++{
++ for (; count--; value++, offset += 4)
++ atmel_aes_write(dd, offset, *value);
++}
++
++static void atmel_aes_dualbuff_test(struct atmel_aes_dev *dd)
++{
++ atmel_aes_write(dd, AES_MR, AES_MR_DUALBUFF);
++
++ if (atmel_aes_read(dd, AES_MR) & AES_MR_DUALBUFF)
++ dd->flags |= AES_FLAGS_DUALBUFF;
++}
++
++static struct atmel_aes_dev *atmel_aes_find_dev(struct atmel_aes_ctx *ctx)
++{
++ struct atmel_aes_dev *aes_dd = NULL;
++ struct atmel_aes_dev *tmp;
++
++ spin_lock_bh(&atmel_aes.lock);
++ if (!ctx->dd) {
++ list_for_each_entry(tmp, &atmel_aes.dev_list, list) {
++ aes_dd = tmp;
++ break;
++ }
++ ctx->dd = aes_dd;
++ } else {
++ aes_dd = ctx->dd;
++ }
++
++ spin_unlock_bh(&atmel_aes.lock);
++
++ return aes_dd;
++}
++
++static int atmel_aes_hw_init(struct atmel_aes_dev *dd)
++{
++ clk_prepare_enable(dd->iclk);
++
++ if (!(dd->flags & AES_FLAGS_INIT)) {
++ atmel_aes_write(dd, AES_CR, AES_CR_SWRST);
++ atmel_aes_dualbuff_test(dd);
++ dd->flags |= AES_FLAGS_INIT;
++ dd->err = 0;
++ }
++
++ return 0;
++}
++
++static void atmel_aes_hw_version_init(struct atmel_aes_dev *dd)
++{
++ atmel_aes_hw_init(dd);
++
++ dd->hw_version = atmel_aes_read(dd, AES_HW_VERSION);
++
++ clk_disable_unprepare(dd->iclk);
++}
++
++static void atmel_aes_finish_req(struct atmel_aes_dev *dd, int err)
++{
++ struct ablkcipher_request *req = dd->req;
++
++ clk_disable_unprepare(dd->iclk);
++ dd->flags &= ~AES_FLAGS_BUSY;
++
++ req->base.complete(&req->base, err);
++}
++
++static void atmel_aes_dma_callback(void *data)
++{
++ struct atmel_aes_dev *dd = data;
++
++ /* dma_lch_out - completed */
++ tasklet_schedule(&dd->done_task);
++}
++
++static int atmel_aes_crypt_dma(struct atmel_aes_dev *dd)
++{
++ struct dma_async_tx_descriptor *in_desc, *out_desc;
++ int nb_dma_sg_in, nb_dma_sg_out;
++
++ dd->nb_in_sg = atmel_aes_sg_length(dd->req, dd->in_sg);
++ if (!dd->nb_in_sg)
++ goto exit_err;
++
++ nb_dma_sg_in = dma_map_sg(dd->dev, dd->in_sg, dd->nb_in_sg,
++ DMA_TO_DEVICE);
++ if (!nb_dma_sg_in)
++ goto exit_err;
++
++ in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, dd->in_sg,
++ nb_dma_sg_in, DMA_MEM_TO_DEV,
++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++
++ if (!in_desc)
++ goto unmap_in;
++
++ /* callback not needed */
++
++ dd->nb_out_sg = atmel_aes_sg_length(dd->req, dd->out_sg);
++ if (!dd->nb_out_sg)
++ goto unmap_in;
++
++ nb_dma_sg_out = dma_map_sg(dd->dev, dd->out_sg, dd->nb_out_sg,
++ DMA_FROM_DEVICE);
++ if (!nb_dma_sg_out)
++ goto unmap_out;
++
++ out_desc = dmaengine_prep_slave_sg(dd->dma_lch_out.chan, dd->out_sg,
++ nb_dma_sg_out, DMA_DEV_TO_MEM,
++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++
++ if (!out_desc)
++ goto unmap_out;
++
++ out_desc->callback = atmel_aes_dma_callback;
++ out_desc->callback_param = dd;
++
++ dd->total -= dd->req->nbytes;
++
++ dmaengine_submit(out_desc);
++ dma_async_issue_pending(dd->dma_lch_out.chan);
++
++ dmaengine_submit(in_desc);
++ dma_async_issue_pending(dd->dma_lch_in.chan);
++
++ return 0;
++
++unmap_out:
++ dma_unmap_sg(dd->dev, dd->out_sg, dd->nb_out_sg,
++ DMA_FROM_DEVICE);
++unmap_in:
++ dma_unmap_sg(dd->dev, dd->in_sg, dd->nb_in_sg,
++ DMA_TO_DEVICE);
++exit_err:
++ return -EINVAL;
++}
++
++static int atmel_aes_crypt_cpu_start(struct atmel_aes_dev *dd)
++{
++ dd->flags &= ~AES_FLAGS_DMA;
++
++ /* use cache buffers */
++ dd->nb_in_sg = atmel_aes_sg_length(dd->req, dd->in_sg);
++ if (!dd->nb_in_sg)
++ return -EINVAL;
++
++ dd->nb_out_sg = atmel_aes_sg_length(dd->req, dd->out_sg);
++ if (!dd->nb_in_sg)
++ return -EINVAL;
++
++ dd->bufcnt = sg_copy_to_buffer(dd->in_sg, dd->nb_in_sg,
++ dd->buf_in, dd->total);
++
++ if (!dd->bufcnt)
++ return -EINVAL;
++
++ dd->total -= dd->bufcnt;
++
++ atmel_aes_write(dd, AES_IER, AES_INT_DATARDY);
++ atmel_aes_write_n(dd, AES_IDATAR(0), (u32 *) dd->buf_in,
++ dd->bufcnt >> 2);
++
++ return 0;
++}
++
++static int atmel_aes_crypt_dma_start(struct atmel_aes_dev *dd)
++{
++ int err;
++
++ if (dd->flags & AES_FLAGS_CFB8) {
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_1_BYTE;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_1_BYTE;
++ } else if (dd->flags & AES_FLAGS_CFB16) {
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_2_BYTES;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_2_BYTES;
++ } else {
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ }
++
++ dmaengine_slave_config(dd->dma_lch_in.chan, &dd->dma_lch_in.dma_conf);
++ dmaengine_slave_config(dd->dma_lch_out.chan, &dd->dma_lch_out.dma_conf);
++
++ dd->flags |= AES_FLAGS_DMA;
++ err = atmel_aes_crypt_dma(dd);
++
++ return err;
++}
++
++static int atmel_aes_write_ctrl(struct atmel_aes_dev *dd)
++{
++ int err;
++ u32 valcr = 0, valmr = 0;
++
++ err = atmel_aes_hw_init(dd);
++
++ if (err)
++ return err;
++
++ /* MR register must be set before IV registers */
++ if (dd->ctx->keylen == AES_KEYSIZE_128)
++ valmr |= AES_MR_KEYSIZE_128;
++ else if (dd->ctx->keylen == AES_KEYSIZE_192)
++ valmr |= AES_MR_KEYSIZE_192;
++ else
++ valmr |= AES_MR_KEYSIZE_256;
++
++ if (dd->flags & AES_FLAGS_CBC) {
++ valmr |= AES_MR_OPMOD_CBC;
++ } else if (dd->flags & AES_FLAGS_CFB) {
++ valmr |= AES_MR_OPMOD_CFB;
++ if (dd->flags & AES_FLAGS_CFB8)
++ valmr |= AES_MR_CFBS_8b;
++ else if (dd->flags & AES_FLAGS_CFB16)
++ valmr |= AES_MR_CFBS_16b;
++ else if (dd->flags & AES_FLAGS_CFB32)
++ valmr |= AES_MR_CFBS_32b;
++ else if (dd->flags & AES_FLAGS_CFB64)
++ valmr |= AES_MR_CFBS_64b;
++ } else if (dd->flags & AES_FLAGS_OFB) {
++ valmr |= AES_MR_OPMOD_OFB;
++ } else if (dd->flags & AES_FLAGS_CTR) {
++ valmr |= AES_MR_OPMOD_CTR;
++ } else {
++ valmr |= AES_MR_OPMOD_ECB;
++ }
++
++ if (dd->flags & AES_FLAGS_ENCRYPT)
++ valmr |= AES_MR_CYPHER_ENC;
++
++ if (dd->total > ATMEL_AES_DMA_THRESHOLD) {
++ valmr |= AES_MR_SMOD_IDATAR0;
++ if (dd->flags & AES_FLAGS_DUALBUFF)
++ valmr |= AES_MR_DUALBUFF;
++ } else {
++ valmr |= AES_MR_SMOD_AUTO;
++ }
++
++ atmel_aes_write(dd, AES_CR, valcr);
++ atmel_aes_write(dd, AES_MR, valmr);
++
++ atmel_aes_write_n(dd, AES_KEYWR(0), dd->ctx->key,
++ dd->ctx->keylen >> 2);
++
++ if (((dd->flags & AES_FLAGS_CBC) || (dd->flags & AES_FLAGS_CFB) ||
++ (dd->flags & AES_FLAGS_OFB) || (dd->flags & AES_FLAGS_CTR)) &&
++ dd->req->info) {
++ atmel_aes_write_n(dd, AES_IVR(0), dd->req->info, 4);
++ }
++
++ return 0;
++}
++
++static int atmel_aes_handle_queue(struct atmel_aes_dev *dd,
++ struct ablkcipher_request *req)
++{
++ struct crypto_async_request *async_req, *backlog;
++ struct atmel_aes_ctx *ctx;
++ struct atmel_aes_reqctx *rctx;
++ unsigned long flags;
++ int err, ret = 0;
++
++ spin_lock_irqsave(&dd->lock, flags);
++ if (req)
++ ret = ablkcipher_enqueue_request(&dd->queue, req);
++ if (dd->flags & AES_FLAGS_BUSY) {
++ spin_unlock_irqrestore(&dd->lock, flags);
++ return ret;
++ }
++ backlog = crypto_get_backlog(&dd->queue);
++ async_req = crypto_dequeue_request(&dd->queue);
++ if (async_req)
++ dd->flags |= AES_FLAGS_BUSY;
++ spin_unlock_irqrestore(&dd->lock, flags);
++
++ if (!async_req)
++ return ret;
++
++ if (backlog)
++ backlog->complete(backlog, -EINPROGRESS);
++
++ req = ablkcipher_request_cast(async_req);
++
++ /* assign new request to device */
++ dd->req = req;
++ dd->total = req->nbytes;
++ dd->in_sg = req->src;
++ dd->out_sg = req->dst;
++
++ rctx = ablkcipher_request_ctx(req);
++ ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
++ rctx->mode &= AES_FLAGS_MODE_MASK;
++ dd->flags = (dd->flags & ~AES_FLAGS_MODE_MASK) | rctx->mode;
++ dd->ctx = ctx;
++ ctx->dd = dd;
++
++ err = atmel_aes_write_ctrl(dd);
++ if (!err) {
++ if (dd->total > ATMEL_AES_DMA_THRESHOLD)
++ err = atmel_aes_crypt_dma_start(dd);
++ else
++ err = atmel_aes_crypt_cpu_start(dd);
++ }
++ if (err) {
++ /* aes_task will not finish it, so do it here */
++ atmel_aes_finish_req(dd, err);
++ tasklet_schedule(&dd->queue_task);
++ }
++
++ return ret;
++}
++
++static int atmel_aes_crypt_dma_stop(struct atmel_aes_dev *dd)
++{
++ int err = -EINVAL;
++
++ if (dd->flags & AES_FLAGS_DMA) {
++ dma_unmap_sg(dd->dev, dd->out_sg,
++ dd->nb_out_sg, DMA_FROM_DEVICE);
++ dma_unmap_sg(dd->dev, dd->in_sg,
++ dd->nb_in_sg, DMA_TO_DEVICE);
++ err = 0;
++ }
++
++ return err;
++}
++
++static int atmel_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
++{
++ struct atmel_aes_ctx *ctx = crypto_ablkcipher_ctx(
++ crypto_ablkcipher_reqtfm(req));
++ struct atmel_aes_reqctx *rctx = ablkcipher_request_ctx(req);
++ struct atmel_aes_dev *dd;
++
++ if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) {
++ pr_err("request size is not exact amount of AES blocks\n");
++ return -EINVAL;
++ }
++
++ dd = atmel_aes_find_dev(ctx);
++ if (!dd)
++ return -ENODEV;
++
++ rctx->mode = mode;
++
++ return atmel_aes_handle_queue(dd, req);
++}
++
++static bool atmel_aes_filter(struct dma_chan *chan, void *slave)
++{
++ struct at_dma_slave *sl = slave;
++
++ if (sl && sl->dma_dev == chan->device->dev) {
++ chan->private = sl;
++ return true;
++ } else {
++ return false;
++ }
++}
++
++static int atmel_aes_dma_init(struct atmel_aes_dev *dd)
++{
++ int err = -ENOMEM;
++ struct aes_platform_data *pdata;
++ dma_cap_mask_t mask_in, mask_out;
++
++ pdata = dd->dev->platform_data;
++
++ if (pdata && pdata->dma_slave->txdata.dma_dev &&
++ pdata->dma_slave->rxdata.dma_dev) {
++
++ /* Try to grab 2 DMA channels */
++ dma_cap_zero(mask_in);
++ dma_cap_set(DMA_SLAVE, mask_in);
++
++ dd->dma_lch_in.chan = dma_request_channel(mask_in,
++ atmel_aes_filter, &pdata->dma_slave->rxdata);
++ if (!dd->dma_lch_in.chan)
++ goto err_dma_in;
++
++ dd->dma_lch_in.dma_conf.direction = DMA_MEM_TO_DEV;
++ dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base +
++ AES_IDATAR(0);
++ dd->dma_lch_in.dma_conf.src_maxburst = 1;
++ dd->dma_lch_in.dma_conf.dst_maxburst = 1;
++ dd->dma_lch_in.dma_conf.device_fc = false;
++
++ dma_cap_zero(mask_out);
++ dma_cap_set(DMA_SLAVE, mask_out);
++ dd->dma_lch_out.chan = dma_request_channel(mask_out,
++ atmel_aes_filter, &pdata->dma_slave->txdata);
++ if (!dd->dma_lch_out.chan)
++ goto err_dma_out;
++
++ dd->dma_lch_out.dma_conf.direction = DMA_DEV_TO_MEM;
++ dd->dma_lch_out.dma_conf.src_addr = dd->phys_base +
++ AES_ODATAR(0);
++ dd->dma_lch_out.dma_conf.src_maxburst = 1;
++ dd->dma_lch_out.dma_conf.dst_maxburst = 1;
++ dd->dma_lch_out.dma_conf.device_fc = false;
++
++ return 0;
++ } else {
++ return -ENODEV;
++ }
++
++err_dma_out:
++ dma_release_channel(dd->dma_lch_in.chan);
++err_dma_in:
++ return err;
++}
++
++static void atmel_aes_dma_cleanup(struct atmel_aes_dev *dd)
++{
++ dma_release_channel(dd->dma_lch_in.chan);
++ dma_release_channel(dd->dma_lch_out.chan);
++}
++
++static int atmel_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
++ unsigned int keylen)
++{
++ struct atmel_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
++
++ if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 &&
++ keylen != AES_KEYSIZE_256) {
++ crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
++ return -EINVAL;
++ }
++
++ memcpy(ctx->key, key, keylen);
++ ctx->keylen = keylen;
++
++ return 0;
++}
++
++static int atmel_aes_ecb_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_ENCRYPT);
++}
++
++static int atmel_aes_ecb_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ 0);
++}
++
++static int atmel_aes_cbc_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_ENCRYPT | AES_FLAGS_CBC);
++}
++
++static int atmel_aes_cbc_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_CBC);
++}
++
++static int atmel_aes_ofb_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_ENCRYPT | AES_FLAGS_OFB);
++}
++
++static int atmel_aes_ofb_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_OFB);
++}
++
++static int atmel_aes_cfb_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_ENCRYPT | AES_FLAGS_CFB);
++}
++
++static int atmel_aes_cfb_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_CFB);
++}
++
++static int atmel_aes_cfb64_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_ENCRYPT | AES_FLAGS_CFB | AES_FLAGS_CFB64);
++}
++
++static int atmel_aes_cfb64_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_CFB | AES_FLAGS_CFB64);
++}
++
++static int atmel_aes_cfb32_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_ENCRYPT | AES_FLAGS_CFB | AES_FLAGS_CFB32);
++}
++
++static int atmel_aes_cfb32_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_CFB | AES_FLAGS_CFB32);
++}
++
++static int atmel_aes_cfb16_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_ENCRYPT | AES_FLAGS_CFB | AES_FLAGS_CFB16);
++}
++
++static int atmel_aes_cfb16_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_CFB | AES_FLAGS_CFB16);
++}
++
++static int atmel_aes_cfb8_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_ENCRYPT | AES_FLAGS_CFB | AES_FLAGS_CFB8);
++}
++
++static int atmel_aes_cfb8_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_CFB | AES_FLAGS_CFB8);
++}
++
++static int atmel_aes_ctr_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_ENCRYPT | AES_FLAGS_CTR);
++}
++
++static int atmel_aes_ctr_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_CTR);
++}
++
++static int atmel_aes_cra_init(struct crypto_tfm *tfm)
++{
++ tfm->crt_ablkcipher.reqsize = sizeof(struct atmel_aes_reqctx);
++
++ return 0;
++}
++
++static void atmel_aes_cra_exit(struct crypto_tfm *tfm)
++{
++}
++
++static struct crypto_alg aes_algs[] = {
++{
++ .cra_name = "ecb(aes)",
++ .cra_driver_name = "atmel-ecb-aes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = AES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
++ .cra_alignmask = 0x0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_aes_cra_init,
++ .cra_exit = atmel_aes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .setkey = atmel_aes_setkey,
++ .encrypt = atmel_aes_ecb_encrypt,
++ .decrypt = atmel_aes_ecb_decrypt,
++ }
++},
++{
++ .cra_name = "cbc(aes)",
++ .cra_driver_name = "atmel-cbc-aes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = AES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
++ .cra_alignmask = 0x0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_aes_cra_init,
++ .cra_exit = atmel_aes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .setkey = atmel_aes_setkey,
++ .encrypt = atmel_aes_cbc_encrypt,
++ .decrypt = atmel_aes_cbc_decrypt,
++ }
++},
++{
++ .cra_name = "ofb(aes)",
++ .cra_driver_name = "atmel-ofb-aes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = AES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
++ .cra_alignmask = 0x0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_aes_cra_init,
++ .cra_exit = atmel_aes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .setkey = atmel_aes_setkey,
++ .encrypt = atmel_aes_ofb_encrypt,
++ .decrypt = atmel_aes_ofb_decrypt,
++ }
++},
++{
++ .cra_name = "cfb(aes)",
++ .cra_driver_name = "atmel-cfb-aes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = AES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
++ .cra_alignmask = 0x0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_aes_cra_init,
++ .cra_exit = atmel_aes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .setkey = atmel_aes_setkey,
++ .encrypt = atmel_aes_cfb_encrypt,
++ .decrypt = atmel_aes_cfb_decrypt,
++ }
++},
++{
++ .cra_name = "cfb32(aes)",
++ .cra_driver_name = "atmel-cfb32-aes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = CFB32_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
++ .cra_alignmask = 0x0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_aes_cra_init,
++ .cra_exit = atmel_aes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .setkey = atmel_aes_setkey,
++ .encrypt = atmel_aes_cfb32_encrypt,
++ .decrypt = atmel_aes_cfb32_decrypt,
++ }
++},
++{
++ .cra_name = "cfb16(aes)",
++ .cra_driver_name = "atmel-cfb16-aes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = CFB16_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
++ .cra_alignmask = 0x0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_aes_cra_init,
++ .cra_exit = atmel_aes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .setkey = atmel_aes_setkey,
++ .encrypt = atmel_aes_cfb16_encrypt,
++ .decrypt = atmel_aes_cfb16_decrypt,
++ }
++},
++{
++ .cra_name = "cfb8(aes)",
++ .cra_driver_name = "atmel-cfb8-aes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = CFB64_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
++ .cra_alignmask = 0x0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_aes_cra_init,
++ .cra_exit = atmel_aes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .setkey = atmel_aes_setkey,
++ .encrypt = atmel_aes_cfb8_encrypt,
++ .decrypt = atmel_aes_cfb8_decrypt,
++ }
++},
++{
++ .cra_name = "ctr(aes)",
++ .cra_driver_name = "atmel-ctr-aes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = AES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
++ .cra_alignmask = 0x0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_aes_cra_init,
++ .cra_exit = atmel_aes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .setkey = atmel_aes_setkey,
++ .encrypt = atmel_aes_ctr_encrypt,
++ .decrypt = atmel_aes_ctr_decrypt,
++ }
++},
++};
++
++static struct crypto_alg aes_cfb64_alg[] = {
++{
++ .cra_name = "cfb64(aes)",
++ .cra_driver_name = "atmel-cfb64-aes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = CFB64_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
++ .cra_alignmask = 0x0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_aes_cra_init,
++ .cra_exit = atmel_aes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .setkey = atmel_aes_setkey,
++ .encrypt = atmel_aes_cfb64_encrypt,
++ .decrypt = atmel_aes_cfb64_decrypt,
++ }
++},
++};
++
++static void atmel_aes_queue_task(unsigned long data)
++{
++ struct atmel_aes_dev *dd = (struct atmel_aes_dev *)data;
++
++ atmel_aes_handle_queue(dd, NULL);
++}
++
++static void atmel_aes_done_task(unsigned long data)
++{
++ struct atmel_aes_dev *dd = (struct atmel_aes_dev *) data;
++ int err;
++
++ if (!(dd->flags & AES_FLAGS_DMA)) {
++ atmel_aes_read_n(dd, AES_ODATAR(0), (u32 *) dd->buf_out,
++ dd->bufcnt >> 2);
++
++ if (sg_copy_from_buffer(dd->out_sg, dd->nb_out_sg,
++ dd->buf_out, dd->bufcnt))
++ err = 0;
++ else
++ err = -EINVAL;
++
++ goto cpu_end;
++ }
++
++ err = atmel_aes_crypt_dma_stop(dd);
++
++ err = dd->err ? : err;
++
++ if (dd->total && !err) {
++ err = atmel_aes_crypt_dma_start(dd);
++ if (!err)
++ return; /* DMA started. Not fininishing. */
++ }
++
++cpu_end:
++ atmel_aes_finish_req(dd, err);
++ atmel_aes_handle_queue(dd, NULL);
++}
++
++static irqreturn_t atmel_aes_irq(int irq, void *dev_id)
++{
++ struct atmel_aes_dev *aes_dd = dev_id;
++ u32 reg;
++
++ reg = atmel_aes_read(aes_dd, AES_ISR);
++ if (reg & atmel_aes_read(aes_dd, AES_IMR)) {
++ atmel_aes_write(aes_dd, AES_IDR, reg);
++ if (AES_FLAGS_BUSY & aes_dd->flags)
++ tasklet_schedule(&aes_dd->done_task);
++ else
++ dev_warn(aes_dd->dev, "AES interrupt when no active requests.\n");
++ return IRQ_HANDLED;
++ }
++
++ return IRQ_NONE;
++}
++
++static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(aes_algs); i++)
++ crypto_unregister_alg(&aes_algs[i]);
++ if (dd->hw_version >= 0x130)
++ crypto_unregister_alg(&aes_cfb64_alg[0]);
++}
++
++static int atmel_aes_register_algs(struct atmel_aes_dev *dd)
++{
++ int err, i, j;
++
++ for (i = 0; i < ARRAY_SIZE(aes_algs); i++) {
++ INIT_LIST_HEAD(&aes_algs[i].cra_list);
++ err = crypto_register_alg(&aes_algs[i]);
++ if (err)
++ goto err_aes_algs;
++ }
++
++ atmel_aes_hw_version_init(dd);
++
++ if (dd->hw_version >= 0x130) {
++ INIT_LIST_HEAD(&aes_cfb64_alg[0].cra_list);
++ err = crypto_register_alg(&aes_cfb64_alg[0]);
++ if (err)
++ goto err_aes_cfb64_alg;
++ }
++
++ return 0;
++
++err_aes_cfb64_alg:
++ i = ARRAY_SIZE(aes_algs);
++err_aes_algs:
++ for (j = 0; j < i; j++)
++ crypto_unregister_alg(&aes_algs[j]);
++
++ return err;
++}
++
++static int __devinit atmel_aes_probe(struct platform_device *pdev)
++{
++ struct atmel_aes_dev *aes_dd;
++ struct aes_platform_data *pdata;
++ struct device *dev = &pdev->dev;
++ struct resource *aes_res;
++ unsigned long aes_phys_size;
++ int err;
++
++ pdata = pdev->dev.platform_data;
++ if (!pdata) {
++ err = -ENXIO;
++ goto aes_dd_err;
++ }
++
++ aes_dd = kzalloc(sizeof(struct atmel_aes_dev), GFP_KERNEL);
++ if (aes_dd == NULL) {
++ dev_err(dev, "unable to alloc data struct.\n");
++ err = -ENOMEM;
++ goto aes_dd_err;
++ }
++
++ aes_dd->dev = dev;
++
++ platform_set_drvdata(pdev, aes_dd);
++
++ INIT_LIST_HEAD(&aes_dd->list);
++
++ tasklet_init(&aes_dd->done_task, atmel_aes_done_task,
++ (unsigned long)aes_dd);
++ tasklet_init(&aes_dd->queue_task, atmel_aes_queue_task,
++ (unsigned long)aes_dd);
++
++ crypto_init_queue(&aes_dd->queue, ATMEL_AES_QUEUE_LENGTH);
++
++ aes_dd->irq = -1;
++
++ /* Get the base address */
++ aes_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!aes_res) {
++ dev_err(dev, "no MEM resource info\n");
++ err = -ENODEV;
++ goto res_err;
++ }
++ aes_dd->phys_base = aes_res->start;
++ aes_phys_size = resource_size(aes_res);
++
++ /* Get the IRQ */
++ aes_dd->irq = platform_get_irq(pdev, 0);
++ if (aes_dd->irq < 0) {
++ dev_err(dev, "no IRQ resource info\n");
++ err = aes_dd->irq;
++ goto aes_irq_err;
++ }
++
++ err = request_irq(aes_dd->irq, atmel_aes_irq, IRQF_SHARED, "atmel-aes",
++ aes_dd);
++ if (err) {
++ dev_err(dev, "unable to request aes irq.\n");
++ goto aes_irq_err;
++ }
++
++ /* Initializing the clock */
++ aes_dd->iclk = clk_get(&pdev->dev, NULL);
++ if (IS_ERR(aes_dd->iclk)) {
++ dev_err(dev, "clock intialization failed.\n");
++ err = PTR_ERR(aes_dd->iclk);
++ goto clk_err;
++ }
++
++ aes_dd->io_base = ioremap(aes_dd->phys_base, aes_phys_size);
++ if (!aes_dd->io_base) {
++ dev_err(dev, "can't ioremap\n");
++ err = -ENOMEM;
++ goto aes_io_err;
++ }
++
++ err = atmel_aes_dma_init(aes_dd);
++ if (err)
++ goto err_aes_dma;
++
++ spin_lock(&atmel_aes.lock);
++ list_add_tail(&aes_dd->list, &atmel_aes.dev_list);
++ spin_unlock(&atmel_aes.lock);
++
++ err = atmel_aes_register_algs(aes_dd);
++ if (err)
++ goto err_algs;
++
++ dev_info(dev, "Atmel AES\n");
++
++ return 0;
++
++err_algs:
++ spin_lock(&atmel_aes.lock);
++ list_del(&aes_dd->list);
++ spin_unlock(&atmel_aes.lock);
++ atmel_aes_dma_cleanup(aes_dd);
++err_aes_dma:
++ iounmap(aes_dd->io_base);
++aes_io_err:
++ clk_put(aes_dd->iclk);
++clk_err:
++ free_irq(aes_dd->irq, aes_dd);
++aes_irq_err:
++res_err:
++ tasklet_kill(&aes_dd->done_task);
++ tasklet_kill(&aes_dd->queue_task);
++ kfree(aes_dd);
++ aes_dd = NULL;
++aes_dd_err:
++ dev_err(dev, "initialization failed.\n");
++
++ return err;
++}
++
++static int __devexit atmel_aes_remove(struct platform_device *pdev)
++{
++ static struct atmel_aes_dev *aes_dd;
++
++ aes_dd = platform_get_drvdata(pdev);
++ if (!aes_dd)
++ return -ENODEV;
++ spin_lock(&atmel_aes.lock);
++ list_del(&aes_dd->list);
++ spin_unlock(&atmel_aes.lock);
++
++ atmel_aes_unregister_algs(aes_dd);
++
++ tasklet_kill(&aes_dd->done_task);
++ tasklet_kill(&aes_dd->queue_task);
++
++ atmel_aes_dma_cleanup(aes_dd);
++
++ iounmap(aes_dd->io_base);
++
++ clk_put(aes_dd->iclk);
++
++ if (aes_dd->irq > 0)
++ free_irq(aes_dd->irq, aes_dd);
++
++ kfree(aes_dd);
++ aes_dd = NULL;
++
++ return 0;
++}
++
++static struct platform_driver atmel_aes_driver = {
++ .probe = atmel_aes_probe,
++ .remove = __devexit_p(atmel_aes_remove),
++ .driver = {
++ .name = "atmel_aes",
++ .owner = THIS_MODULE,
++ },
++};
++
++module_platform_driver(atmel_aes_driver);
++
++MODULE_DESCRIPTION("Atmel AES hw acceleration support.");
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Nicolas Royer - Eukréa Electromatique");
+diff --git a/include/linux/platform_data/atmel-aes.h b/include/linux/platform_data/atmel-aes.h
+new file mode 100644
+index 0000000..e7a1949
+--- /dev/null
++++ b/include/linux/platform_data/atmel-aes.h
+@@ -0,0 +1,22 @@
++#ifndef __LINUX_ATMEL_AES_H
++#define __LINUX_ATMEL_AES_H
++
++#include <mach/at_hdmac.h>
++
++/**
++ * struct aes_dma_data - DMA data for AES
++ */
++struct aes_dma_data {
++ struct at_dma_slave txdata;
++ struct at_dma_slave rxdata;
++};
++
++/**
++ * struct aes_platform_data - board-specific AES configuration
++ * @dma_slave: DMA slave interface to use in data transfers.
++ */
++struct aes_platform_data {
++ struct aes_dma_data *dma_slave;
++};
++
++#endif /* __LINUX_ATMEL_AES_H */
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0180-crypto-add-Atmel-DES-TDES-driver.patch b/patches.at91/0180-crypto-add-Atmel-DES-TDES-driver.patch
new file mode 100644
index 00000000000000..ea752b963ea19e
--- /dev/null
+++ b/patches.at91/0180-crypto-add-Atmel-DES-TDES-driver.patch
@@ -0,0 +1,1374 @@
+From 189348edb141027c8f6ba232380dda1dcfd56979 Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:05 +0200
+Subject: crypto: add Atmel DES/TDES driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ drivers/crypto/Kconfig | 16 +
+ drivers/crypto/Makefile | 1 +
+ drivers/crypto/atmel-tdes-regs.h | 89 +++
+ drivers/crypto/atmel-tdes.c | 1215 ++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 1321 insertions(+)
+ create mode 100644 drivers/crypto/atmel-tdes-regs.h
+ create mode 100644 drivers/crypto/atmel-tdes.c
+
+diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
+index 98c7da5..2124898 100644
+--- a/drivers/crypto/Kconfig
++++ b/drivers/crypto/Kconfig
+@@ -313,4 +313,20 @@ config CRYPTO_DEV_ATMEL_AES
+ To compile this driver as a module, choose M here: the module
+ will be called atmel-aes.
+
++config CRYPTO_DEV_ATMEL_TDES
++ tristate "Support for Atmel DES/TDES hw accelerator"
++ depends on ARCH_AT91
++ select CRYPTO_DES
++ select CRYPTO_CBC
++ select CRYPTO_ECB
++ select CRYPTO_ALGAPI
++ select CRYPTO_BLKCIPHER
++ help
++ Some Atmel processors have DES/TDES hw accelerator.
++ Select this if you want to use the Atmel module for
++ DES/TDES algorithms.
++
++ To compile this driver as a module, choose M here: the module
++ will be called atmel-tdes.
++
+ endif # CRYPTO_HW
+diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
+index 73ad830..443bf4d 100644
+--- a/drivers/crypto/Makefile
++++ b/drivers/crypto/Makefile
+@@ -15,3 +15,4 @@ obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
+ obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
+ obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
+ obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o
++obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o
+diff --git a/drivers/crypto/atmel-tdes-regs.h b/drivers/crypto/atmel-tdes-regs.h
+new file mode 100644
+index 0000000..5ac2a90
+--- /dev/null
++++ b/drivers/crypto/atmel-tdes-regs.h
+@@ -0,0 +1,89 @@
++#ifndef __ATMEL_TDES_REGS_H__
++#define __ATMEL_TDES_REGS_H__
++
++#define TDES_CR 0x00
++#define TDES_CR_START (1 << 0)
++#define TDES_CR_SWRST (1 << 8)
++#define TDES_CR_LOADSEED (1 << 16)
++
++#define TDES_MR 0x04
++#define TDES_MR_CYPHER_DEC (0 << 0)
++#define TDES_MR_CYPHER_ENC (1 << 0)
++#define TDES_MR_TDESMOD_MASK (0x3 << 1)
++#define TDES_MR_TDESMOD_DES (0x0 << 1)
++#define TDES_MR_TDESMOD_TDES (0x1 << 1)
++#define TDES_MR_TDESMOD_XTEA (0x2 << 1)
++#define TDES_MR_KEYMOD_3KEY (0 << 4)
++#define TDES_MR_KEYMOD_2KEY (1 << 4)
++#define TDES_MR_SMOD_MASK (0x3 << 8)
++#define TDES_MR_SMOD_MANUAL (0x0 << 8)
++#define TDES_MR_SMOD_AUTO (0x1 << 8)
++#define TDES_MR_SMOD_PDC (0x2 << 8)
++#define TDES_MR_OPMOD_MASK (0x3 << 12)
++#define TDES_MR_OPMOD_ECB (0x0 << 12)
++#define TDES_MR_OPMOD_CBC (0x1 << 12)
++#define TDES_MR_OPMOD_OFB (0x2 << 12)
++#define TDES_MR_OPMOD_CFB (0x3 << 12)
++#define TDES_MR_LOD (0x1 << 15)
++#define TDES_MR_CFBS_MASK (0x3 << 16)
++#define TDES_MR_CFBS_64b (0x0 << 16)
++#define TDES_MR_CFBS_32b (0x1 << 16)
++#define TDES_MR_CFBS_16b (0x2 << 16)
++#define TDES_MR_CFBS_8b (0x3 << 16)
++#define TDES_MR_CKEY_MASK (0xF << 20)
++#define TDES_MR_CKEY_OFFSET 20
++#define TDES_MR_CTYPE_MASK (0x3F << 24)
++#define TDES_MR_CTYPE_OFFSET 24
++
++#define TDES_IER 0x10
++#define TDES_IDR 0x14
++#define TDES_IMR 0x18
++#define TDES_ISR 0x1C
++#define TDES_INT_DATARDY (1 << 0)
++#define TDES_INT_ENDRX (1 << 1)
++#define TDES_INT_ENDTX (1 << 2)
++#define TDES_INT_RXBUFF (1 << 3)
++#define TDES_INT_TXBUFE (1 << 4)
++#define TDES_INT_URAD (1 << 8)
++#define TDES_ISR_URAT_MASK (0x3 << 12)
++#define TDES_ISR_URAT_IDR (0x0 << 12)
++#define TDES_ISR_URAT_ODR (0x1 << 12)
++#define TDES_ISR_URAT_MR (0x2 << 12)
++#define TDES_ISR_URAT_WO (0x3 << 12)
++
++
++#define TDES_KEY1W1R 0x20
++#define TDES_KEY1W2R 0x24
++#define TDES_KEY2W1R 0x28
++#define TDES_KEY2W2R 0x2C
++#define TDES_KEY3W1R 0x30
++#define TDES_KEY3W2R 0x34
++#define TDES_IDATA1R 0x40
++#define TDES_IDATA2R 0x44
++#define TDES_ODATA1R 0x50
++#define TDES_ODATA2R 0x54
++#define TDES_IV1R 0x60
++#define TDES_IV2R 0x64
++
++#define TDES_XTEARNDR 0x70
++#define TDES_XTEARNDR_XTEA_RNDS_MASK (0x3F << 0)
++#define TDES_XTEARNDR_XTEA_RNDS_OFFSET 0
++
++#define TDES_RPR 0x100
++#define TDES_RCR 0x104
++#define TDES_TPR 0x108
++#define TDES_TCR 0x10C
++#define TDES_RNPR 0x118
++#define TDES_RNCR 0x11C
++#define TDES_TNPR 0x118
++#define TDES_TNCR 0x11C
++#define TDES_PTCR 0x120
++#define TDES_PTCR_RXTEN (1 << 0)
++#define TDES_PTCR_RXTDIS (1 << 1)
++#define TDES_PTCR_TXTEN (1 << 8)
++#define TDES_PTCR_TXTDIS (1 << 9)
++#define TDES_PTSR 0x124
++#define TDES_PTSR_RXTEN (1 << 0)
++#define TDES_PTSR_TXTEN (1 << 8)
++
++#endif /* __ATMEL_TDES_REGS_H__ */
+diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c
+new file mode 100644
+index 0000000..eb2b61e
+--- /dev/null
++++ b/drivers/crypto/atmel-tdes.c
+@@ -0,0 +1,1215 @@
++/*
++ * Cryptographic API.
++ *
++ * Support for ATMEL DES/TDES HW acceleration.
++ *
++ * Copyright (c) 2012 Eukréa Electromatique - ATMEL
++ * Author: Nicolas Royer <nicolas@eukrea.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.
++ *
++ * Some ideas are from omap-aes.c drivers.
++ */
++
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/err.h>
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/hw_random.h>
++#include <linux/platform_device.h>
++
++#include <linux/device.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/clk.h>
++#include <linux/irq.h>
++#include <linux/io.h>
++#include <linux/platform_device.h>
++#include <linux/scatterlist.h>
++#include <linux/dma-mapping.h>
++#include <linux/delay.h>
++#include <linux/crypto.h>
++#include <linux/cryptohash.h>
++#include <crypto/scatterwalk.h>
++#include <crypto/algapi.h>
++#include <crypto/des.h>
++#include <crypto/hash.h>
++#include <crypto/internal/hash.h>
++#include "atmel-tdes-regs.h"
++
++/* TDES flags */
++#define TDES_FLAGS_MODE_MASK 0x007f
++#define TDES_FLAGS_ENCRYPT BIT(0)
++#define TDES_FLAGS_CBC BIT(1)
++#define TDES_FLAGS_CFB BIT(2)
++#define TDES_FLAGS_CFB8 BIT(3)
++#define TDES_FLAGS_CFB16 BIT(4)
++#define TDES_FLAGS_CFB32 BIT(5)
++#define TDES_FLAGS_OFB BIT(6)
++
++#define TDES_FLAGS_INIT BIT(16)
++#define TDES_FLAGS_FAST BIT(17)
++#define TDES_FLAGS_BUSY BIT(18)
++
++#define ATMEL_TDES_QUEUE_LENGTH 1
++
++#define CFB8_BLOCK_SIZE 1
++#define CFB16_BLOCK_SIZE 2
++#define CFB32_BLOCK_SIZE 4
++#define CFB64_BLOCK_SIZE 8
++
++
++struct atmel_tdes_dev;
++
++struct atmel_tdes_ctx {
++ struct atmel_tdes_dev *dd;
++
++ int keylen;
++ u32 key[3*DES_KEY_SIZE / sizeof(u32)];
++ unsigned long flags;
++};
++
++struct atmel_tdes_reqctx {
++ unsigned long mode;
++};
++
++struct atmel_tdes_dev {
++ struct list_head list;
++ unsigned long phys_base;
++ void __iomem *io_base;
++
++ struct atmel_tdes_ctx *ctx;
++ struct device *dev;
++ struct clk *iclk;
++ int irq;
++
++ unsigned long flags;
++ int err;
++
++ spinlock_t lock;
++ struct crypto_queue queue;
++
++ struct tasklet_struct done_task;
++ struct tasklet_struct queue_task;
++
++ struct ablkcipher_request *req;
++ size_t total;
++
++ struct scatterlist *in_sg;
++ size_t in_offset;
++ struct scatterlist *out_sg;
++ size_t out_offset;
++
++ size_t buflen;
++ size_t dma_size;
++
++ void *buf_in;
++ int dma_in;
++ dma_addr_t dma_addr_in;
++
++ void *buf_out;
++ int dma_out;
++ dma_addr_t dma_addr_out;
++};
++
++struct atmel_tdes_drv {
++ struct list_head dev_list;
++ spinlock_t lock;
++};
++
++static struct atmel_tdes_drv atmel_tdes = {
++ .dev_list = LIST_HEAD_INIT(atmel_tdes.dev_list),
++ .lock = __SPIN_LOCK_UNLOCKED(atmel_tdes.lock),
++};
++
++static int atmel_tdes_sg_copy(struct scatterlist **sg, size_t *offset,
++ void *buf, size_t buflen, size_t total, int out)
++{
++ unsigned int count, off = 0;
++
++ while (buflen && total) {
++ count = min((*sg)->length - *offset, total);
++ count = min(count, buflen);
++
++ if (!count)
++ return off;
++
++ scatterwalk_map_and_copy(buf + off, *sg, *offset, count, out);
++
++ off += count;
++ buflen -= count;
++ *offset += count;
++ total -= count;
++
++ if (*offset == (*sg)->length) {
++ *sg = sg_next(*sg);
++ if (*sg)
++ *offset = 0;
++ else
++ total = 0;
++ }
++ }
++
++ return off;
++}
++
++static inline u32 atmel_tdes_read(struct atmel_tdes_dev *dd, u32 offset)
++{
++ return readl_relaxed(dd->io_base + offset);
++}
++
++static inline void atmel_tdes_write(struct atmel_tdes_dev *dd,
++ u32 offset, u32 value)
++{
++ writel_relaxed(value, dd->io_base + offset);
++}
++
++static void atmel_tdes_write_n(struct atmel_tdes_dev *dd, u32 offset,
++ u32 *value, int count)
++{
++ for (; count--; value++, offset += 4)
++ atmel_tdes_write(dd, offset, *value);
++}
++
++static struct atmel_tdes_dev *atmel_tdes_find_dev(struct atmel_tdes_ctx *ctx)
++{
++ struct atmel_tdes_dev *tdes_dd = NULL;
++ struct atmel_tdes_dev *tmp;
++
++ spin_lock_bh(&atmel_tdes.lock);
++ if (!ctx->dd) {
++ list_for_each_entry(tmp, &atmel_tdes.dev_list, list) {
++ tdes_dd = tmp;
++ break;
++ }
++ ctx->dd = tdes_dd;
++ } else {
++ tdes_dd = ctx->dd;
++ }
++ spin_unlock_bh(&atmel_tdes.lock);
++
++ return tdes_dd;
++}
++
++static int atmel_tdes_hw_init(struct atmel_tdes_dev *dd)
++{
++ clk_prepare_enable(dd->iclk);
++
++ if (!(dd->flags & TDES_FLAGS_INIT)) {
++ atmel_tdes_write(dd, TDES_CR, TDES_CR_SWRST);
++ dd->flags |= TDES_FLAGS_INIT;
++ dd->err = 0;
++ }
++
++ return 0;
++}
++
++static int atmel_tdes_write_ctrl(struct atmel_tdes_dev *dd)
++{
++ int err;
++ u32 valcr = 0, valmr = TDES_MR_SMOD_PDC;
++
++ err = atmel_tdes_hw_init(dd);
++
++ if (err)
++ return err;
++
++ atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS);
++
++ /* MR register must be set before IV registers */
++ if (dd->ctx->keylen > (DES_KEY_SIZE << 1)) {
++ valmr |= TDES_MR_KEYMOD_3KEY;
++ valmr |= TDES_MR_TDESMOD_TDES;
++ } else if (dd->ctx->keylen > DES_KEY_SIZE) {
++ valmr |= TDES_MR_KEYMOD_2KEY;
++ valmr |= TDES_MR_TDESMOD_TDES;
++ } else {
++ valmr |= TDES_MR_TDESMOD_DES;
++ }
++
++ if (dd->flags & TDES_FLAGS_CBC) {
++ valmr |= TDES_MR_OPMOD_CBC;
++ } else if (dd->flags & TDES_FLAGS_CFB) {
++ valmr |= TDES_MR_OPMOD_CFB;
++
++ if (dd->flags & TDES_FLAGS_CFB8)
++ valmr |= TDES_MR_CFBS_8b;
++ else if (dd->flags & TDES_FLAGS_CFB16)
++ valmr |= TDES_MR_CFBS_16b;
++ else if (dd->flags & TDES_FLAGS_CFB32)
++ valmr |= TDES_MR_CFBS_32b;
++ } else if (dd->flags & TDES_FLAGS_OFB) {
++ valmr |= TDES_MR_OPMOD_OFB;
++ }
++
++ if ((dd->flags & TDES_FLAGS_ENCRYPT) || (dd->flags & TDES_FLAGS_OFB))
++ valmr |= TDES_MR_CYPHER_ENC;
++
++ atmel_tdes_write(dd, TDES_CR, valcr);
++ atmel_tdes_write(dd, TDES_MR, valmr);
++
++ atmel_tdes_write_n(dd, TDES_KEY1W1R, dd->ctx->key,
++ dd->ctx->keylen >> 2);
++
++ if (((dd->flags & TDES_FLAGS_CBC) || (dd->flags & TDES_FLAGS_CFB) ||
++ (dd->flags & TDES_FLAGS_OFB)) && dd->req->info) {
++ atmel_tdes_write_n(dd, TDES_IV1R, dd->req->info, 2);
++ }
++
++ return 0;
++}
++
++static int atmel_tdes_crypt_dma_stop(struct atmel_tdes_dev *dd)
++{
++ int err = 0;
++ size_t count;
++
++ atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS);
++
++ if (dd->flags & TDES_FLAGS_FAST) {
++ dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
++ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
++ } else {
++ dma_sync_single_for_device(dd->dev, dd->dma_addr_out,
++ dd->dma_size, DMA_FROM_DEVICE);
++
++ /* copy data */
++ count = atmel_tdes_sg_copy(&dd->out_sg, &dd->out_offset,
++ dd->buf_out, dd->buflen, dd->dma_size, 1);
++ if (count != dd->dma_size) {
++ err = -EINVAL;
++ pr_err("not all data converted: %u\n", count);
++ }
++ }
++
++ return err;
++}
++
++static int atmel_tdes_dma_init(struct atmel_tdes_dev *dd)
++{
++ int err = -ENOMEM;
++
++ dd->buf_in = (void *)__get_free_pages(GFP_KERNEL, 0);
++ dd->buf_out = (void *)__get_free_pages(GFP_KERNEL, 0);
++ dd->buflen = PAGE_SIZE;
++ dd->buflen &= ~(DES_BLOCK_SIZE - 1);
++
++ if (!dd->buf_in || !dd->buf_out) {
++ dev_err(dd->dev, "unable to alloc pages.\n");
++ goto err_alloc;
++ }
++
++ /* MAP here */
++ dd->dma_addr_in = dma_map_single(dd->dev, dd->buf_in,
++ dd->buflen, DMA_TO_DEVICE);
++ if (dma_mapping_error(dd->dev, dd->dma_addr_in)) {
++ dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
++ err = -EINVAL;
++ goto err_map_in;
++ }
++
++ dd->dma_addr_out = dma_map_single(dd->dev, dd->buf_out,
++ dd->buflen, DMA_FROM_DEVICE);
++ if (dma_mapping_error(dd->dev, dd->dma_addr_out)) {
++ dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
++ err = -EINVAL;
++ goto err_map_out;
++ }
++
++ return 0;
++
++err_map_out:
++ dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen,
++ DMA_TO_DEVICE);
++err_map_in:
++ free_page((unsigned long)dd->buf_out);
++ free_page((unsigned long)dd->buf_in);
++err_alloc:
++ if (err)
++ pr_err("error: %d\n", err);
++ return err;
++}
++
++static void atmel_tdes_dma_cleanup(struct atmel_tdes_dev *dd)
++{
++ dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
++ DMA_FROM_DEVICE);
++ dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen,
++ DMA_TO_DEVICE);
++ free_page((unsigned long)dd->buf_out);
++ free_page((unsigned long)dd->buf_in);
++}
++
++static int atmel_tdes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
++ dma_addr_t dma_addr_out, int length)
++{
++ struct atmel_tdes_ctx *ctx = crypto_tfm_ctx(tfm);
++ struct atmel_tdes_dev *dd = ctx->dd;
++ int len32;
++
++ dd->dma_size = length;
++
++ if (!(dd->flags & TDES_FLAGS_FAST)) {
++ dma_sync_single_for_device(dd->dev, dma_addr_in, length,
++ DMA_TO_DEVICE);
++ }
++
++ if ((dd->flags & TDES_FLAGS_CFB) && (dd->flags & TDES_FLAGS_CFB8))
++ len32 = DIV_ROUND_UP(length, sizeof(u8));
++ else if ((dd->flags & TDES_FLAGS_CFB) && (dd->flags & TDES_FLAGS_CFB16))
++ len32 = DIV_ROUND_UP(length, sizeof(u16));
++ else
++ len32 = DIV_ROUND_UP(length, sizeof(u32));
++
++ atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS);
++ atmel_tdes_write(dd, TDES_TPR, dma_addr_in);
++ atmel_tdes_write(dd, TDES_TCR, len32);
++ atmel_tdes_write(dd, TDES_RPR, dma_addr_out);
++ atmel_tdes_write(dd, TDES_RCR, len32);
++
++ /* Enable Interrupt */
++ atmel_tdes_write(dd, TDES_IER, TDES_INT_ENDRX);
++
++ /* Start DMA transfer */
++ atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTEN | TDES_PTCR_RXTEN);
++
++ return 0;
++}
++
++static int atmel_tdes_crypt_dma_start(struct atmel_tdes_dev *dd)
++{
++ struct crypto_tfm *tfm = crypto_ablkcipher_tfm(
++ crypto_ablkcipher_reqtfm(dd->req));
++ int err, fast = 0, in, out;
++ size_t count;
++ dma_addr_t addr_in, addr_out;
++
++ if (sg_is_last(dd->in_sg) && sg_is_last(dd->out_sg)) {
++ /* check for alignment */
++ in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32));
++ out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32));
++
++ fast = in && out;
++ }
++
++ if (fast) {
++ count = min(dd->total, sg_dma_len(dd->in_sg));
++ count = min(count, sg_dma_len(dd->out_sg));
++
++ if (count != dd->total) {
++ pr_err("request length != buffer length\n");
++ return -EINVAL;
++ }
++
++ err = dma_map_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
++ if (!err) {
++ dev_err(dd->dev, "dma_map_sg() error\n");
++ return -EINVAL;
++ }
++
++ err = dma_map_sg(dd->dev, dd->out_sg, 1,
++ DMA_FROM_DEVICE);
++ if (!err) {
++ dev_err(dd->dev, "dma_map_sg() error\n");
++ dma_unmap_sg(dd->dev, dd->in_sg, 1,
++ DMA_TO_DEVICE);
++ return -EINVAL;
++ }
++
++ addr_in = sg_dma_address(dd->in_sg);
++ addr_out = sg_dma_address(dd->out_sg);
++
++ dd->flags |= TDES_FLAGS_FAST;
++
++ } else {
++ /* use cache buffers */
++ count = atmel_tdes_sg_copy(&dd->in_sg, &dd->in_offset,
++ dd->buf_in, dd->buflen, dd->total, 0);
++
++ addr_in = dd->dma_addr_in;
++ addr_out = dd->dma_addr_out;
++
++ dd->flags &= ~TDES_FLAGS_FAST;
++
++ }
++
++ dd->total -= count;
++
++ err = atmel_tdes_crypt_dma(tfm, addr_in, addr_out, count);
++ if (err) {
++ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
++ dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_TO_DEVICE);
++ }
++
++ return err;
++}
++
++
++static void atmel_tdes_finish_req(struct atmel_tdes_dev *dd, int err)
++{
++ struct ablkcipher_request *req = dd->req;
++
++ clk_disable_unprepare(dd->iclk);
++
++ dd->flags &= ~TDES_FLAGS_BUSY;
++
++ req->base.complete(&req->base, err);
++}
++
++static int atmel_tdes_handle_queue(struct atmel_tdes_dev *dd,
++ struct ablkcipher_request *req)
++{
++ struct crypto_async_request *async_req, *backlog;
++ struct atmel_tdes_ctx *ctx;
++ struct atmel_tdes_reqctx *rctx;
++ unsigned long flags;
++ int err, ret = 0;
++
++ spin_lock_irqsave(&dd->lock, flags);
++ if (req)
++ ret = ablkcipher_enqueue_request(&dd->queue, req);
++ if (dd->flags & TDES_FLAGS_BUSY) {
++ spin_unlock_irqrestore(&dd->lock, flags);
++ return ret;
++ }
++ backlog = crypto_get_backlog(&dd->queue);
++ async_req = crypto_dequeue_request(&dd->queue);
++ if (async_req)
++ dd->flags |= TDES_FLAGS_BUSY;
++ spin_unlock_irqrestore(&dd->lock, flags);
++
++ if (!async_req)
++ return ret;
++
++ if (backlog)
++ backlog->complete(backlog, -EINPROGRESS);
++
++ req = ablkcipher_request_cast(async_req);
++
++ /* assign new request to device */
++ dd->req = req;
++ dd->total = req->nbytes;
++ dd->in_offset = 0;
++ dd->in_sg = req->src;
++ dd->out_offset = 0;
++ dd->out_sg = req->dst;
++
++ rctx = ablkcipher_request_ctx(req);
++ ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
++ rctx->mode &= TDES_FLAGS_MODE_MASK;
++ dd->flags = (dd->flags & ~TDES_FLAGS_MODE_MASK) | rctx->mode;
++ dd->ctx = ctx;
++ ctx->dd = dd;
++
++ err = atmel_tdes_write_ctrl(dd);
++ if (!err)
++ err = atmel_tdes_crypt_dma_start(dd);
++ if (err) {
++ /* des_task will not finish it, so do it here */
++ atmel_tdes_finish_req(dd, err);
++ tasklet_schedule(&dd->queue_task);
++ }
++
++ return ret;
++}
++
++
++static int atmel_tdes_crypt(struct ablkcipher_request *req, unsigned long mode)
++{
++ struct atmel_tdes_ctx *ctx = crypto_ablkcipher_ctx(
++ crypto_ablkcipher_reqtfm(req));
++ struct atmel_tdes_reqctx *rctx = ablkcipher_request_ctx(req);
++ struct atmel_tdes_dev *dd;
++
++ if (mode & TDES_FLAGS_CFB8) {
++ if (!IS_ALIGNED(req->nbytes, CFB8_BLOCK_SIZE)) {
++ pr_err("request size is not exact amount of CFB8 blocks\n");
++ return -EINVAL;
++ }
++ } else if (mode & TDES_FLAGS_CFB16) {
++ if (!IS_ALIGNED(req->nbytes, CFB16_BLOCK_SIZE)) {
++ pr_err("request size is not exact amount of CFB16 blocks\n");
++ return -EINVAL;
++ }
++ } else if (mode & TDES_FLAGS_CFB32) {
++ if (!IS_ALIGNED(req->nbytes, CFB32_BLOCK_SIZE)) {
++ pr_err("request size is not exact amount of CFB32 blocks\n");
++ return -EINVAL;
++ }
++ } else if (!IS_ALIGNED(req->nbytes, DES_BLOCK_SIZE)) {
++ pr_err("request size is not exact amount of DES blocks\n");
++ return -EINVAL;
++ }
++
++ dd = atmel_tdes_find_dev(ctx);
++ if (!dd)
++ return -ENODEV;
++
++ rctx->mode = mode;
++
++ return atmel_tdes_handle_queue(dd, req);
++}
++
++static int atmel_des_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
++ unsigned int keylen)
++{
++ u32 tmp[DES_EXPKEY_WORDS];
++ int err;
++ struct crypto_tfm *ctfm = crypto_ablkcipher_tfm(tfm);
++
++ struct atmel_tdes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
++
++ if (keylen != DES_KEY_SIZE) {
++ crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
++ return -EINVAL;
++ }
++
++ err = des_ekey(tmp, key);
++ if (err == 0 && (ctfm->crt_flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
++ ctfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY;
++ return -EINVAL;
++ }
++
++ memcpy(ctx->key, key, keylen);
++ ctx->keylen = keylen;
++
++ return 0;
++}
++
++static int atmel_tdes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
++ unsigned int keylen)
++{
++ struct atmel_tdes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
++ const char *alg_name;
++
++ alg_name = crypto_tfm_alg_name(crypto_ablkcipher_tfm(tfm));
++
++ /*
++ * HW bug in cfb 3-keys mode.
++ */
++ if (strstr(alg_name, "cfb") && (keylen != 2*DES_KEY_SIZE)) {
++ crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
++ return -EINVAL;
++ } else if ((keylen != 2*DES_KEY_SIZE) && (keylen != 3*DES_KEY_SIZE)) {
++ crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
++ return -EINVAL;
++ }
++
++ memcpy(ctx->key, key, keylen);
++ ctx->keylen = keylen;
++
++ return 0;
++}
++
++static int atmel_tdes_ecb_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT);
++}
++
++static int atmel_tdes_ecb_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, 0);
++}
++
++static int atmel_tdes_cbc_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_CBC);
++}
++
++static int atmel_tdes_cbc_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_CBC);
++}
++static int atmel_tdes_cfb_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_CFB);
++}
++
++static int atmel_tdes_cfb_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_CFB);
++}
++
++static int atmel_tdes_cfb8_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_CFB |
++ TDES_FLAGS_CFB8);
++}
++
++static int atmel_tdes_cfb8_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_CFB | TDES_FLAGS_CFB8);
++}
++
++static int atmel_tdes_cfb16_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_CFB |
++ TDES_FLAGS_CFB16);
++}
++
++static int atmel_tdes_cfb16_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_CFB | TDES_FLAGS_CFB16);
++}
++
++static int atmel_tdes_cfb32_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_CFB |
++ TDES_FLAGS_CFB32);
++}
++
++static int atmel_tdes_cfb32_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_CFB | TDES_FLAGS_CFB32);
++}
++
++static int atmel_tdes_ofb_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_OFB);
++}
++
++static int atmel_tdes_ofb_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_OFB);
++}
++
++static int atmel_tdes_cra_init(struct crypto_tfm *tfm)
++{
++ tfm->crt_ablkcipher.reqsize = sizeof(struct atmel_tdes_reqctx);
++
++ return 0;
++}
++
++static void atmel_tdes_cra_exit(struct crypto_tfm *tfm)
++{
++}
++
++static struct crypto_alg tdes_algs[] = {
++{
++ .cra_name = "ecb(des)",
++ .cra_driver_name = "atmel-ecb-des",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = DES_KEY_SIZE,
++ .max_keysize = DES_KEY_SIZE,
++ .setkey = atmel_des_setkey,
++ .encrypt = atmel_tdes_ecb_encrypt,
++ .decrypt = atmel_tdes_ecb_decrypt,
++ }
++},
++{
++ .cra_name = "cbc(des)",
++ .cra_driver_name = "atmel-cbc-des",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = DES_KEY_SIZE,
++ .max_keysize = DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_des_setkey,
++ .encrypt = atmel_tdes_cbc_encrypt,
++ .decrypt = atmel_tdes_cbc_decrypt,
++ }
++},
++{
++ .cra_name = "cfb(des)",
++ .cra_driver_name = "atmel-cfb-des",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = DES_KEY_SIZE,
++ .max_keysize = DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_des_setkey,
++ .encrypt = atmel_tdes_cfb_encrypt,
++ .decrypt = atmel_tdes_cfb_decrypt,
++ }
++},
++{
++ .cra_name = "cfb8(des)",
++ .cra_driver_name = "atmel-cfb8-des",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = CFB8_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = DES_KEY_SIZE,
++ .max_keysize = DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_des_setkey,
++ .encrypt = atmel_tdes_cfb8_encrypt,
++ .decrypt = atmel_tdes_cfb8_decrypt,
++ }
++},
++{
++ .cra_name = "cfb16(des)",
++ .cra_driver_name = "atmel-cfb16-des",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = CFB16_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = DES_KEY_SIZE,
++ .max_keysize = DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_des_setkey,
++ .encrypt = atmel_tdes_cfb16_encrypt,
++ .decrypt = atmel_tdes_cfb16_decrypt,
++ }
++},
++{
++ .cra_name = "cfb32(des)",
++ .cra_driver_name = "atmel-cfb32-des",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = CFB32_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = DES_KEY_SIZE,
++ .max_keysize = DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_des_setkey,
++ .encrypt = atmel_tdes_cfb32_encrypt,
++ .decrypt = atmel_tdes_cfb32_decrypt,
++ }
++},
++{
++ .cra_name = "ofb(des)",
++ .cra_driver_name = "atmel-ofb-des",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = DES_KEY_SIZE,
++ .max_keysize = DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_des_setkey,
++ .encrypt = atmel_tdes_ofb_encrypt,
++ .decrypt = atmel_tdes_ofb_decrypt,
++ }
++},
++{
++ .cra_name = "ecb(des3_ede)",
++ .cra_driver_name = "atmel-ecb-tdes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = 2 * DES_KEY_SIZE,
++ .max_keysize = 3 * DES_KEY_SIZE,
++ .setkey = atmel_tdes_setkey,
++ .encrypt = atmel_tdes_ecb_encrypt,
++ .decrypt = atmel_tdes_ecb_decrypt,
++ }
++},
++{
++ .cra_name = "cbc(des3_ede)",
++ .cra_driver_name = "atmel-cbc-tdes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = 2*DES_KEY_SIZE,
++ .max_keysize = 3*DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_tdes_setkey,
++ .encrypt = atmel_tdes_cbc_encrypt,
++ .decrypt = atmel_tdes_cbc_decrypt,
++ }
++},
++{
++ .cra_name = "cfb(des3_ede)",
++ .cra_driver_name = "atmel-cfb-tdes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = 2*DES_KEY_SIZE,
++ .max_keysize = 2*DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_tdes_setkey,
++ .encrypt = atmel_tdes_cfb_encrypt,
++ .decrypt = atmel_tdes_cfb_decrypt,
++ }
++},
++{
++ .cra_name = "cfb8(des3_ede)",
++ .cra_driver_name = "atmel-cfb8-tdes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = CFB8_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = 2*DES_KEY_SIZE,
++ .max_keysize = 2*DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_tdes_setkey,
++ .encrypt = atmel_tdes_cfb8_encrypt,
++ .decrypt = atmel_tdes_cfb8_decrypt,
++ }
++},
++{
++ .cra_name = "cfb16(des3_ede)",
++ .cra_driver_name = "atmel-cfb16-tdes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = CFB16_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = 2*DES_KEY_SIZE,
++ .max_keysize = 2*DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_tdes_setkey,
++ .encrypt = atmel_tdes_cfb16_encrypt,
++ .decrypt = atmel_tdes_cfb16_decrypt,
++ }
++},
++{
++ .cra_name = "cfb32(des3_ede)",
++ .cra_driver_name = "atmel-cfb32-tdes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = CFB32_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = 2*DES_KEY_SIZE,
++ .max_keysize = 2*DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_tdes_setkey,
++ .encrypt = atmel_tdes_cfb32_encrypt,
++ .decrypt = atmel_tdes_cfb32_decrypt,
++ }
++},
++{
++ .cra_name = "ofb(des3_ede)",
++ .cra_driver_name = "atmel-ofb-tdes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = 2*DES_KEY_SIZE,
++ .max_keysize = 3*DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_tdes_setkey,
++ .encrypt = atmel_tdes_ofb_encrypt,
++ .decrypt = atmel_tdes_ofb_decrypt,
++ }
++},
++};
++
++static void atmel_tdes_queue_task(unsigned long data)
++{
++ struct atmel_tdes_dev *dd = (struct atmel_tdes_dev *)data;
++
++ atmel_tdes_handle_queue(dd, NULL);
++}
++
++static void atmel_tdes_done_task(unsigned long data)
++{
++ struct atmel_tdes_dev *dd = (struct atmel_tdes_dev *) data;
++ int err;
++
++ err = atmel_tdes_crypt_dma_stop(dd);
++
++ err = dd->err ? : err;
++
++ if (dd->total && !err) {
++ err = atmel_tdes_crypt_dma_start(dd);
++ if (!err)
++ return;
++ }
++
++ atmel_tdes_finish_req(dd, err);
++ atmel_tdes_handle_queue(dd, NULL);
++}
++
++static irqreturn_t atmel_tdes_irq(int irq, void *dev_id)
++{
++ struct atmel_tdes_dev *tdes_dd = dev_id;
++ u32 reg;
++
++ reg = atmel_tdes_read(tdes_dd, TDES_ISR);
++ if (reg & atmel_tdes_read(tdes_dd, TDES_IMR)) {
++ atmel_tdes_write(tdes_dd, TDES_IDR, reg);
++ if (TDES_FLAGS_BUSY & tdes_dd->flags)
++ tasklet_schedule(&tdes_dd->done_task);
++ else
++ dev_warn(tdes_dd->dev, "TDES interrupt when no active requests.\n");
++ return IRQ_HANDLED;
++ }
++
++ return IRQ_NONE;
++}
++
++static void atmel_tdes_unregister_algs(struct atmel_tdes_dev *dd)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(tdes_algs); i++)
++ crypto_unregister_alg(&tdes_algs[i]);
++}
++
++static int atmel_tdes_register_algs(struct atmel_tdes_dev *dd)
++{
++ int err, i, j;
++
++ for (i = 0; i < ARRAY_SIZE(tdes_algs); i++) {
++ INIT_LIST_HEAD(&tdes_algs[i].cra_list);
++ err = crypto_register_alg(&tdes_algs[i]);
++ if (err)
++ goto err_tdes_algs;
++ }
++
++ return 0;
++
++err_tdes_algs:
++ for (j = 0; j < i; j++)
++ crypto_unregister_alg(&tdes_algs[j]);
++
++ return err;
++}
++
++static int __devinit atmel_tdes_probe(struct platform_device *pdev)
++{
++ struct atmel_tdes_dev *tdes_dd;
++ struct device *dev = &pdev->dev;
++ struct resource *tdes_res;
++ unsigned long tdes_phys_size;
++ int err;
++
++ tdes_dd = kzalloc(sizeof(struct atmel_tdes_dev), GFP_KERNEL);
++ if (tdes_dd == NULL) {
++ dev_err(dev, "unable to alloc data struct.\n");
++ err = -ENOMEM;
++ goto tdes_dd_err;
++ }
++
++ tdes_dd->dev = dev;
++
++ platform_set_drvdata(pdev, tdes_dd);
++
++ INIT_LIST_HEAD(&tdes_dd->list);
++
++ tasklet_init(&tdes_dd->done_task, atmel_tdes_done_task,
++ (unsigned long)tdes_dd);
++ tasklet_init(&tdes_dd->queue_task, atmel_tdes_queue_task,
++ (unsigned long)tdes_dd);
++
++ crypto_init_queue(&tdes_dd->queue, ATMEL_TDES_QUEUE_LENGTH);
++
++ tdes_dd->irq = -1;
++
++ /* Get the base address */
++ tdes_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!tdes_res) {
++ dev_err(dev, "no MEM resource info\n");
++ err = -ENODEV;
++ goto res_err;
++ }
++ tdes_dd->phys_base = tdes_res->start;
++ tdes_phys_size = resource_size(tdes_res);
++
++ /* Get the IRQ */
++ tdes_dd->irq = platform_get_irq(pdev, 0);
++ if (tdes_dd->irq < 0) {
++ dev_err(dev, "no IRQ resource info\n");
++ err = tdes_dd->irq;
++ goto res_err;
++ }
++
++ err = request_irq(tdes_dd->irq, atmel_tdes_irq, IRQF_SHARED,
++ "atmel-tdes", tdes_dd);
++ if (err) {
++ dev_err(dev, "unable to request tdes irq.\n");
++ goto tdes_irq_err;
++ }
++
++ /* Initializing the clock */
++ tdes_dd->iclk = clk_get(&pdev->dev, NULL);
++ if (IS_ERR(tdes_dd->iclk)) {
++ dev_err(dev, "clock intialization failed.\n");
++ err = PTR_ERR(tdes_dd->iclk);
++ goto clk_err;
++ }
++
++ tdes_dd->io_base = ioremap(tdes_dd->phys_base, tdes_phys_size);
++ if (!tdes_dd->io_base) {
++ dev_err(dev, "can't ioremap\n");
++ err = -ENOMEM;
++ goto tdes_io_err;
++ }
++
++ err = atmel_tdes_dma_init(tdes_dd);
++ if (err)
++ goto err_tdes_dma;
++
++ spin_lock(&atmel_tdes.lock);
++ list_add_tail(&tdes_dd->list, &atmel_tdes.dev_list);
++ spin_unlock(&atmel_tdes.lock);
++
++ err = atmel_tdes_register_algs(tdes_dd);
++ if (err)
++ goto err_algs;
++
++ dev_info(dev, "Atmel DES/TDES\n");
++
++ return 0;
++
++err_algs:
++ spin_lock(&atmel_tdes.lock);
++ list_del(&tdes_dd->list);
++ spin_unlock(&atmel_tdes.lock);
++ atmel_tdes_dma_cleanup(tdes_dd);
++err_tdes_dma:
++ iounmap(tdes_dd->io_base);
++tdes_io_err:
++ clk_put(tdes_dd->iclk);
++clk_err:
++ free_irq(tdes_dd->irq, tdes_dd);
++tdes_irq_err:
++res_err:
++ tasklet_kill(&tdes_dd->done_task);
++ tasklet_kill(&tdes_dd->queue_task);
++ kfree(tdes_dd);
++ tdes_dd = NULL;
++tdes_dd_err:
++ dev_err(dev, "initialization failed.\n");
++
++ return err;
++}
++
++static int __devexit atmel_tdes_remove(struct platform_device *pdev)
++{
++ static struct atmel_tdes_dev *tdes_dd;
++
++ tdes_dd = platform_get_drvdata(pdev);
++ if (!tdes_dd)
++ return -ENODEV;
++ spin_lock(&atmel_tdes.lock);
++ list_del(&tdes_dd->list);
++ spin_unlock(&atmel_tdes.lock);
++
++ atmel_tdes_unregister_algs(tdes_dd);
++
++ tasklet_kill(&tdes_dd->done_task);
++ tasklet_kill(&tdes_dd->queue_task);
++
++ atmel_tdes_dma_cleanup(tdes_dd);
++
++ iounmap(tdes_dd->io_base);
++
++ clk_put(tdes_dd->iclk);
++
++ if (tdes_dd->irq >= 0)
++ free_irq(tdes_dd->irq, tdes_dd);
++
++ kfree(tdes_dd);
++ tdes_dd = NULL;
++
++ return 0;
++}
++
++static struct platform_driver atmel_tdes_driver = {
++ .probe = atmel_tdes_probe,
++ .remove = __devexit_p(atmel_tdes_remove),
++ .driver = {
++ .name = "atmel_tdes",
++ .owner = THIS_MODULE,
++ },
++};
++
++module_platform_driver(atmel_tdes_driver);
++
++MODULE_DESCRIPTION("Atmel DES/TDES hw acceleration support.");
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Nicolas Royer - Eukréa Electromatique");
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0181-crypto-add-Atmel-SHA1-SHA256-driver.patch b/patches.at91/0181-crypto-add-Atmel-SHA1-SHA256-driver.patch
new file mode 100644
index 00000000000000..56b9a474fa4eaf
--- /dev/null
+++ b/patches.at91/0181-crypto-add-Atmel-SHA1-SHA256-driver.patch
@@ -0,0 +1,1226 @@
+From 3d0dc28cd259b675bf98fa158c9a6cb800c40683 Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:06 +0200
+Subject: crypto: add Atmel SHA1/SHA256 driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ drivers/crypto/Kconfig | 14 +
+ drivers/crypto/Makefile | 1 +
+ drivers/crypto/atmel-sha-regs.h | 46 ++
+ drivers/crypto/atmel-sha.c | 1112 +++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 1173 insertions(+)
+ create mode 100644 drivers/crypto/atmel-sha-regs.h
+ create mode 100644 drivers/crypto/atmel-sha.c
+
+diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
+index 2124898..2339add 100644
+--- a/drivers/crypto/Kconfig
++++ b/drivers/crypto/Kconfig
+@@ -329,4 +329,18 @@ config CRYPTO_DEV_ATMEL_TDES
+ To compile this driver as a module, choose M here: the module
+ will be called atmel-tdes.
+
++config CRYPTO_DEV_ATMEL_SHA
++ tristate "Support for Atmel SHA1/SHA256 hw accelerator"
++ depends on ARCH_AT91
++ select CRYPTO_SHA1
++ select CRYPTO_SHA256
++ select CRYPTO_ALGAPI
++ help
++ Some Atmel processors have SHA1/SHA256 hw accelerator.
++ Select this if you want to use the Atmel module for
++ SHA1/SHA256 algorithms.
++
++ To compile this driver as a module, choose M here: the module
++ will be called atmel-sha.
++
+ endif # CRYPTO_HW
+diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
+index 443bf4d..d355c25 100644
+--- a/drivers/crypto/Makefile
++++ b/drivers/crypto/Makefile
+@@ -16,3 +16,4 @@ obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
+ obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
+ obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o
+ obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o
++obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA) += atmel-sha.o
+diff --git a/drivers/crypto/atmel-sha-regs.h b/drivers/crypto/atmel-sha-regs.h
+new file mode 100644
+index 0000000..dc53a20
+--- /dev/null
++++ b/drivers/crypto/atmel-sha-regs.h
+@@ -0,0 +1,46 @@
++#ifndef __ATMEL_SHA_REGS_H__
++#define __ATMEL_SHA_REGS_H__
++
++#define SHA_REG_DIGEST(x) (0x80 + ((x) * 0x04))
++#define SHA_REG_DIN(x) (0x40 + ((x) * 0x04))
++
++#define SHA_CR 0x00
++#define SHA_CR_START (1 << 0)
++#define SHA_CR_FIRST (1 << 4)
++#define SHA_CR_SWRST (1 << 8)
++
++#define SHA_MR 0x04
++#define SHA_MR_MODE_MASK (0x3 << 0)
++#define SHA_MR_MODE_MANUAL 0x0
++#define SHA_MR_MODE_AUTO 0x1
++#define SHA_MR_MODE_PDC 0x2
++#define SHA_MR_DUALBUFF (1 << 3)
++#define SHA_MR_PROCDLY (1 << 4)
++#define SHA_MR_ALGO_SHA1 (0 << 8)
++#define SHA_MR_ALGO_SHA256 (1 << 8)
++
++#define SHA_IER 0x10
++#define SHA_IDR 0x14
++#define SHA_IMR 0x18
++#define SHA_ISR 0x1C
++#define SHA_INT_DATARDY (1 << 0)
++#define SHA_INT_ENDTX (1 << 1)
++#define SHA_INT_TXBUFE (1 << 2)
++#define SHA_INT_URAD (1 << 8)
++#define SHA_ISR_URAT_MASK (0x7 << 12)
++#define SHA_ISR_URAT_IDR (0x0 << 12)
++#define SHA_ISR_URAT_ODR (0x1 << 12)
++#define SHA_ISR_URAT_MR (0x2 << 12)
++#define SHA_ISR_URAT_WO (0x5 << 12)
++
++#define SHA_TPR 0x108
++#define SHA_TCR 0x10C
++#define SHA_TNPR 0x118
++#define SHA_TNCR 0x11C
++#define SHA_PTCR 0x120
++#define SHA_PTCR_TXTEN (1 << 8)
++#define SHA_PTCR_TXTDIS (1 << 9)
++#define SHA_PTSR 0x124
++#define SHA_PTSR_TXTEN (1 << 8)
++
++#endif /* __ATMEL_SHA_REGS_H__ */
+diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
+new file mode 100644
+index 0000000..f938b9d
+--- /dev/null
++++ b/drivers/crypto/atmel-sha.c
+@@ -0,0 +1,1112 @@
++/*
++ * Cryptographic API.
++ *
++ * Support for ATMEL SHA1/SHA256 HW acceleration.
++ *
++ * Copyright (c) 2012 Eukréa Electromatique - ATMEL
++ * Author: Nicolas Royer <nicolas@eukrea.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.
++ *
++ * Some ideas are from omap-sham.c drivers.
++ */
++
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/err.h>
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/hw_random.h>
++#include <linux/platform_device.h>
++
++#include <linux/device.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/clk.h>
++#include <linux/irq.h>
++#include <linux/io.h>
++#include <linux/platform_device.h>
++#include <linux/scatterlist.h>
++#include <linux/dma-mapping.h>
++#include <linux/delay.h>
++#include <linux/crypto.h>
++#include <linux/cryptohash.h>
++#include <crypto/scatterwalk.h>
++#include <crypto/algapi.h>
++#include <crypto/sha.h>
++#include <crypto/hash.h>
++#include <crypto/internal/hash.h>
++#include "atmel-sha-regs.h"
++
++/* SHA flags */
++#define SHA_FLAGS_BUSY BIT(0)
++#define SHA_FLAGS_FINAL BIT(1)
++#define SHA_FLAGS_DMA_ACTIVE BIT(2)
++#define SHA_FLAGS_OUTPUT_READY BIT(3)
++#define SHA_FLAGS_INIT BIT(4)
++#define SHA_FLAGS_CPU BIT(5)
++#define SHA_FLAGS_DMA_READY BIT(6)
++
++#define SHA_FLAGS_FINUP BIT(16)
++#define SHA_FLAGS_SG BIT(17)
++#define SHA_FLAGS_SHA1 BIT(18)
++#define SHA_FLAGS_SHA256 BIT(19)
++#define SHA_FLAGS_ERROR BIT(20)
++#define SHA_FLAGS_PAD BIT(21)
++
++#define SHA_FLAGS_DUALBUFF BIT(24)
++
++#define SHA_OP_UPDATE 1
++#define SHA_OP_FINAL 2
++
++#define SHA_BUFFER_LEN PAGE_SIZE
++
++#define ATMEL_SHA_DMA_THRESHOLD 56
++
++
++struct atmel_sha_dev;
++
++struct atmel_sha_reqctx {
++ struct atmel_sha_dev *dd;
++ unsigned long flags;
++ unsigned long op;
++
++ u8 digest[SHA256_DIGEST_SIZE] __aligned(sizeof(u32));
++ size_t digcnt;
++ size_t bufcnt;
++ size_t buflen;
++ dma_addr_t dma_addr;
++
++ /* walk state */
++ struct scatterlist *sg;
++ unsigned int offset; /* offset in current sg */
++ unsigned int total; /* total request */
++
++ u8 buffer[0] __aligned(sizeof(u32));
++};
++
++struct atmel_sha_ctx {
++ struct atmel_sha_dev *dd;
++
++ unsigned long flags;
++
++ /* fallback stuff */
++ struct crypto_shash *fallback;
++
++};
++
++#define ATMEL_SHA_QUEUE_LENGTH 1
++
++struct atmel_sha_dev {
++ struct list_head list;
++ unsigned long phys_base;
++ struct device *dev;
++ struct clk *iclk;
++ int irq;
++ void __iomem *io_base;
++
++ spinlock_t lock;
++ int err;
++ struct tasklet_struct done_task;
++
++ unsigned long flags;
++ struct crypto_queue queue;
++ struct ahash_request *req;
++};
++
++struct atmel_sha_drv {
++ struct list_head dev_list;
++ spinlock_t lock;
++};
++
++static struct atmel_sha_drv atmel_sha = {
++ .dev_list = LIST_HEAD_INIT(atmel_sha.dev_list),
++ .lock = __SPIN_LOCK_UNLOCKED(atmel_sha.lock),
++};
++
++static inline u32 atmel_sha_read(struct atmel_sha_dev *dd, u32 offset)
++{
++ return readl_relaxed(dd->io_base + offset);
++}
++
++static inline void atmel_sha_write(struct atmel_sha_dev *dd,
++ u32 offset, u32 value)
++{
++ writel_relaxed(value, dd->io_base + offset);
++}
++
++static void atmel_sha_dualbuff_test(struct atmel_sha_dev *dd)
++{
++ atmel_sha_write(dd, SHA_MR, SHA_MR_DUALBUFF);
++
++ if (atmel_sha_read(dd, SHA_MR) & SHA_MR_DUALBUFF)
++ dd->flags |= SHA_FLAGS_DUALBUFF;
++}
++
++static size_t atmel_sha_append_sg(struct atmel_sha_reqctx *ctx)
++{
++ size_t count;
++
++ while ((ctx->bufcnt < ctx->buflen) && ctx->total) {
++ count = min(ctx->sg->length - ctx->offset, ctx->total);
++ count = min(count, ctx->buflen - ctx->bufcnt);
++
++ if (count <= 0)
++ break;
++
++ scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, ctx->sg,
++ ctx->offset, count, 0);
++
++ ctx->bufcnt += count;
++ ctx->offset += count;
++ ctx->total -= count;
++
++ if (ctx->offset == ctx->sg->length) {
++ ctx->sg = sg_next(ctx->sg);
++ if (ctx->sg)
++ ctx->offset = 0;
++ else
++ ctx->total = 0;
++ }
++ }
++
++ return 0;
++}
++
++/*
++ * The purpose of this padding is to ensure that the padded message
++ * is a multiple of 512 bits. The bit "1" is appended at the end of
++ * the message followed by "padlen-1" zero bits. Then a 64 bits block
++ * equals to the message length in bits is appended.
++ *
++ * padlen is calculated as followed:
++ * - if message length < 56 bytes then padlen = 56 - message length
++ * - else padlen = 64 + 56 - message length
++ */
++static void atmel_sha_fill_padding(struct atmel_sha_reqctx *ctx, int length)
++{
++ unsigned int index, padlen;
++ u64 bits;
++ u64 size;
++
++ bits = (ctx->bufcnt + ctx->digcnt + length) << 3;
++ size = cpu_to_be64(bits);
++
++ index = ctx->bufcnt & 0x3f;
++ padlen = (index < 56) ? (56 - index) : ((64+56) - index);
++ *(ctx->buffer + ctx->bufcnt) = 0x80;
++ memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1);
++ memcpy(ctx->buffer + ctx->bufcnt + padlen, &size, 8);
++ ctx->bufcnt += padlen + 8;
++ ctx->flags |= SHA_FLAGS_PAD;
++}
++
++static int atmel_sha_init(struct ahash_request *req)
++{
++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
++ struct atmel_sha_ctx *tctx = crypto_ahash_ctx(tfm);
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++ struct atmel_sha_dev *dd = NULL;
++ struct atmel_sha_dev *tmp;
++
++ spin_lock_bh(&atmel_sha.lock);
++ if (!tctx->dd) {
++ list_for_each_entry(tmp, &atmel_sha.dev_list, list) {
++ dd = tmp;
++ break;
++ }
++ tctx->dd = dd;
++ } else {
++ dd = tctx->dd;
++ }
++
++ spin_unlock_bh(&atmel_sha.lock);
++
++ ctx->dd = dd;
++
++ ctx->flags = 0;
++
++ dev_dbg(dd->dev, "init: digest size: %d\n",
++ crypto_ahash_digestsize(tfm));
++
++ if (crypto_ahash_digestsize(tfm) == SHA1_DIGEST_SIZE)
++ ctx->flags |= SHA_FLAGS_SHA1;
++ else if (crypto_ahash_digestsize(tfm) == SHA256_DIGEST_SIZE)
++ ctx->flags |= SHA_FLAGS_SHA256;
++
++ ctx->bufcnt = 0;
++ ctx->digcnt = 0;
++ ctx->buflen = SHA_BUFFER_LEN;
++
++ return 0;
++}
++
++static void atmel_sha_write_ctrl(struct atmel_sha_dev *dd, int dma)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
++ u32 valcr = 0, valmr = SHA_MR_MODE_AUTO;
++
++ if (likely(dma)) {
++ atmel_sha_write(dd, SHA_IER, SHA_INT_TXBUFE);
++ valmr = SHA_MR_MODE_PDC;
++ if (dd->flags & SHA_FLAGS_DUALBUFF)
++ valmr = SHA_MR_DUALBUFF;
++ } else {
++ atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY);
++ }
++
++ if (ctx->flags & SHA_FLAGS_SHA256)
++ valmr |= SHA_MR_ALGO_SHA256;
++
++ /* Setting CR_FIRST only for the first iteration */
++ if (!ctx->digcnt)
++ valcr = SHA_CR_FIRST;
++
++ atmel_sha_write(dd, SHA_CR, valcr);
++ atmel_sha_write(dd, SHA_MR, valmr);
++}
++
++static int atmel_sha_xmit_cpu(struct atmel_sha_dev *dd, const u8 *buf,
++ size_t length, int final)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
++ int count, len32;
++ const u32 *buffer = (const u32 *)buf;
++
++ dev_dbg(dd->dev, "xmit_cpu: digcnt: %d, length: %d, final: %d\n",
++ ctx->digcnt, length, final);
++
++ atmel_sha_write_ctrl(dd, 0);
++
++ /* should be non-zero before next lines to disable clocks later */
++ ctx->digcnt += length;
++
++ if (final)
++ dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */
++
++ len32 = DIV_ROUND_UP(length, sizeof(u32));
++
++ dd->flags |= SHA_FLAGS_CPU;
++
++ for (count = 0; count < len32; count++)
++ atmel_sha_write(dd, SHA_REG_DIN(count), buffer[count]);
++
++ return -EINPROGRESS;
++}
++
++static int atmel_sha_xmit_pdc(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
++ size_t length1, dma_addr_t dma_addr2, size_t length2, int final)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
++ int len32;
++
++ dev_dbg(dd->dev, "xmit_pdc: digcnt: %d, length: %d, final: %d\n",
++ ctx->digcnt, length1, final);
++
++ len32 = DIV_ROUND_UP(length1, sizeof(u32));
++ atmel_sha_write(dd, SHA_PTCR, SHA_PTCR_TXTDIS);
++ atmel_sha_write(dd, SHA_TPR, dma_addr1);
++ atmel_sha_write(dd, SHA_TCR, len32);
++
++ len32 = DIV_ROUND_UP(length2, sizeof(u32));
++ atmel_sha_write(dd, SHA_TNPR, dma_addr2);
++ atmel_sha_write(dd, SHA_TNCR, len32);
++
++ atmel_sha_write_ctrl(dd, 1);
++
++ /* should be non-zero before next lines to disable clocks later */
++ ctx->digcnt += length1;
++
++ if (final)
++ dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */
++
++ dd->flags |= SHA_FLAGS_DMA_ACTIVE;
++
++ /* Start DMA transfer */
++ atmel_sha_write(dd, SHA_PTCR, SHA_PTCR_TXTEN);
++
++ return -EINPROGRESS;
++}
++
++static int atmel_sha_update_cpu(struct atmel_sha_dev *dd)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
++ int bufcnt;
++
++ atmel_sha_append_sg(ctx);
++ atmel_sha_fill_padding(ctx, 0);
++
++ bufcnt = ctx->bufcnt;
++ ctx->bufcnt = 0;
++
++ return atmel_sha_xmit_cpu(dd, ctx->buffer, bufcnt, 1);
++}
++
++static int atmel_sha_xmit_dma_map(struct atmel_sha_dev *dd,
++ struct atmel_sha_reqctx *ctx,
++ size_t length, int final)
++{
++ ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer,
++ ctx->buflen + SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
++ if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
++ dev_err(dd->dev, "dma %u bytes error\n", ctx->buflen +
++ SHA1_BLOCK_SIZE);
++ return -EINVAL;
++ }
++
++ ctx->flags &= ~SHA_FLAGS_SG;
++
++ /* next call does not fail... so no unmap in the case of error */
++ return atmel_sha_xmit_pdc(dd, ctx->dma_addr, length, 0, 0, final);
++}
++
++static int atmel_sha_update_dma_slow(struct atmel_sha_dev *dd)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
++ unsigned int final;
++ size_t count;
++
++ atmel_sha_append_sg(ctx);
++
++ final = (ctx->flags & SHA_FLAGS_FINUP) && !ctx->total;
++
++ dev_dbg(dd->dev, "slow: bufcnt: %u, digcnt: %d, final: %d\n",
++ ctx->bufcnt, ctx->digcnt, final);
++
++ if (final)
++ atmel_sha_fill_padding(ctx, 0);
++
++ if (final || (ctx->bufcnt == ctx->buflen && ctx->total)) {
++ count = ctx->bufcnt;
++ ctx->bufcnt = 0;
++ return atmel_sha_xmit_dma_map(dd, ctx, count, final);
++ }
++
++ return 0;
++}
++
++static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
++ unsigned int length, final, tail;
++ struct scatterlist *sg;
++ unsigned int count;
++
++ if (!ctx->total)
++ return 0;
++
++ if (ctx->bufcnt || ctx->offset)
++ return atmel_sha_update_dma_slow(dd);
++
++ dev_dbg(dd->dev, "fast: digcnt: %d, bufcnt: %u, total: %u\n",
++ ctx->digcnt, ctx->bufcnt, ctx->total);
++
++ sg = ctx->sg;
++
++ if (!IS_ALIGNED(sg->offset, sizeof(u32)))
++ return atmel_sha_update_dma_slow(dd);
++
++ if (!sg_is_last(sg) && !IS_ALIGNED(sg->length, SHA1_BLOCK_SIZE))
++ /* size is not SHA1_BLOCK_SIZE aligned */
++ return atmel_sha_update_dma_slow(dd);
++
++ length = min(ctx->total, sg->length);
++
++ if (sg_is_last(sg)) {
++ if (!(ctx->flags & SHA_FLAGS_FINUP)) {
++ /* not last sg must be SHA1_BLOCK_SIZE aligned */
++ tail = length & (SHA1_BLOCK_SIZE - 1);
++ length -= tail;
++ if (length == 0) {
++ /* offset where to start slow */
++ ctx->offset = length;
++ return atmel_sha_update_dma_slow(dd);
++ }
++ }
++ }
++
++ ctx->total -= length;
++ ctx->offset = length; /* offset where to start slow */
++
++ final = (ctx->flags & SHA_FLAGS_FINUP) && !ctx->total;
++
++ /* Add padding */
++ if (final) {
++ tail = length & (SHA1_BLOCK_SIZE - 1);
++ length -= tail;
++ ctx->total += tail;
++ ctx->offset = length; /* offset where to start slow */
++
++ sg = ctx->sg;
++ atmel_sha_append_sg(ctx);
++
++ atmel_sha_fill_padding(ctx, length);
++
++ ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer,
++ ctx->buflen + SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
++ if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
++ dev_err(dd->dev, "dma %u bytes error\n",
++ ctx->buflen + SHA1_BLOCK_SIZE);
++ return -EINVAL;
++ }
++
++ if (length == 0) {
++ ctx->flags &= ~SHA_FLAGS_SG;
++ count = ctx->bufcnt;
++ ctx->bufcnt = 0;
++ return atmel_sha_xmit_pdc(dd, ctx->dma_addr, count, 0,
++ 0, final);
++ } else {
++ ctx->sg = sg;
++ if (!dma_map_sg(dd->dev, ctx->sg, 1,
++ DMA_TO_DEVICE)) {
++ dev_err(dd->dev, "dma_map_sg error\n");
++ return -EINVAL;
++ }
++
++ ctx->flags |= SHA_FLAGS_SG;
++
++ count = ctx->bufcnt;
++ ctx->bufcnt = 0;
++ return atmel_sha_xmit_pdc(dd, sg_dma_address(ctx->sg),
++ length, ctx->dma_addr, count, final);
++ }
++ }
++
++ if (!dma_map_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE)) {
++ dev_err(dd->dev, "dma_map_sg error\n");
++ return -EINVAL;
++ }
++
++ ctx->flags |= SHA_FLAGS_SG;
++
++ /* next call does not fail... so no unmap in the case of error */
++ return atmel_sha_xmit_pdc(dd, sg_dma_address(ctx->sg), length, 0,
++ 0, final);
++}
++
++static int atmel_sha_update_dma_stop(struct atmel_sha_dev *dd)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
++
++ if (ctx->flags & SHA_FLAGS_SG) {
++ dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE);
++ if (ctx->sg->length == ctx->offset) {
++ ctx->sg = sg_next(ctx->sg);
++ if (ctx->sg)
++ ctx->offset = 0;
++ }
++ if (ctx->flags & SHA_FLAGS_PAD)
++ dma_unmap_single(dd->dev, ctx->dma_addr,
++ ctx->buflen + SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
++ } else {
++ dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen +
++ SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
++ }
++
++ return 0;
++}
++
++static int atmel_sha_update_req(struct atmel_sha_dev *dd)
++{
++ struct ahash_request *req = dd->req;
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++ int err;
++
++ dev_dbg(dd->dev, "update_req: total: %u, digcnt: %d, finup: %d\n",
++ ctx->total, ctx->digcnt, (ctx->flags & SHA_FLAGS_FINUP) != 0);
++
++ if (ctx->flags & SHA_FLAGS_CPU)
++ err = atmel_sha_update_cpu(dd);
++ else
++ err = atmel_sha_update_dma_start(dd);
++
++ /* wait for dma completion before can take more data */
++ dev_dbg(dd->dev, "update: err: %d, digcnt: %d\n",
++ err, ctx->digcnt);
++
++ return err;
++}
++
++static int atmel_sha_final_req(struct atmel_sha_dev *dd)
++{
++ struct ahash_request *req = dd->req;
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++ int err = 0;
++ int count;
++
++ if (ctx->bufcnt >= ATMEL_SHA_DMA_THRESHOLD) {
++ atmel_sha_fill_padding(ctx, 0);
++ count = ctx->bufcnt;
++ ctx->bufcnt = 0;
++ err = atmel_sha_xmit_dma_map(dd, ctx, count, 1);
++ }
++ /* faster to handle last block with cpu */
++ else {
++ atmel_sha_fill_padding(ctx, 0);
++ count = ctx->bufcnt;
++ ctx->bufcnt = 0;
++ err = atmel_sha_xmit_cpu(dd, ctx->buffer, count, 1);
++ }
++
++ dev_dbg(dd->dev, "final_req: err: %d\n", err);
++
++ return err;
++}
++
++static void atmel_sha_copy_hash(struct ahash_request *req)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++ u32 *hash = (u32 *)ctx->digest;
++ int i;
++
++ if (likely(ctx->flags & SHA_FLAGS_SHA1))
++ for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++)
++ hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
++ else
++ for (i = 0; i < SHA256_DIGEST_SIZE / sizeof(u32); i++)
++ hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
++}
++
++static void atmel_sha_copy_ready_hash(struct ahash_request *req)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++
++ if (!req->result)
++ return;
++
++ if (likely(ctx->flags & SHA_FLAGS_SHA1))
++ memcpy(req->result, ctx->digest, SHA1_DIGEST_SIZE);
++ else
++ memcpy(req->result, ctx->digest, SHA256_DIGEST_SIZE);
++}
++
++static int atmel_sha_finish(struct ahash_request *req)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++ struct atmel_sha_dev *dd = ctx->dd;
++ int err = 0;
++
++ if (ctx->digcnt)
++ atmel_sha_copy_ready_hash(req);
++
++ dev_dbg(dd->dev, "digcnt: %d, bufcnt: %d\n", ctx->digcnt,
++ ctx->bufcnt);
++
++ return err;
++}
++
++static void atmel_sha_finish_req(struct ahash_request *req, int err)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++ struct atmel_sha_dev *dd = ctx->dd;
++
++ if (!err) {
++ atmel_sha_copy_hash(req);
++ if (SHA_FLAGS_FINAL & dd->flags)
++ err = atmel_sha_finish(req);
++ } else {
++ ctx->flags |= SHA_FLAGS_ERROR;
++ }
++
++ /* atomic operation is not needed here */
++ dd->flags &= ~(SHA_FLAGS_BUSY | SHA_FLAGS_FINAL | SHA_FLAGS_CPU |
++ SHA_FLAGS_DMA_READY | SHA_FLAGS_OUTPUT_READY);
++
++ clk_disable_unprepare(dd->iclk);
++
++ if (req->base.complete)
++ req->base.complete(&req->base, err);
++
++ /* handle new request */
++ tasklet_schedule(&dd->done_task);
++}
++
++static int atmel_sha_hw_init(struct atmel_sha_dev *dd)
++{
++ clk_prepare_enable(dd->iclk);
++
++ if (SHA_FLAGS_INIT & dd->flags) {
++ atmel_sha_write(dd, SHA_CR, SHA_CR_SWRST);
++ atmel_sha_dualbuff_test(dd);
++ dd->flags |= SHA_FLAGS_INIT;
++ dd->err = 0;
++ }
++
++ return 0;
++}
++
++static int atmel_sha_handle_queue(struct atmel_sha_dev *dd,
++ struct ahash_request *req)
++{
++ struct crypto_async_request *async_req, *backlog;
++ struct atmel_sha_reqctx *ctx;
++ unsigned long flags;
++ int err = 0, ret = 0;
++
++ spin_lock_irqsave(&dd->lock, flags);
++ if (req)
++ ret = ahash_enqueue_request(&dd->queue, req);
++
++ if (SHA_FLAGS_BUSY & dd->flags) {
++ spin_unlock_irqrestore(&dd->lock, flags);
++ return ret;
++ }
++
++ backlog = crypto_get_backlog(&dd->queue);
++ async_req = crypto_dequeue_request(&dd->queue);
++ if (async_req)
++ dd->flags |= SHA_FLAGS_BUSY;
++
++ spin_unlock_irqrestore(&dd->lock, flags);
++
++ if (!async_req)
++ return ret;
++
++ if (backlog)
++ backlog->complete(backlog, -EINPROGRESS);
++
++ req = ahash_request_cast(async_req);
++ dd->req = req;
++ ctx = ahash_request_ctx(req);
++
++ dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n",
++ ctx->op, req->nbytes);
++
++ err = atmel_sha_hw_init(dd);
++
++ if (err)
++ goto err1;
++
++ if (ctx->op == SHA_OP_UPDATE) {
++ err = atmel_sha_update_req(dd);
++ if (err != -EINPROGRESS && (ctx->flags & SHA_FLAGS_FINUP)) {
++ /* no final() after finup() */
++ err = atmel_sha_final_req(dd);
++ }
++ } else if (ctx->op == SHA_OP_FINAL) {
++ err = atmel_sha_final_req(dd);
++ }
++
++err1:
++ if (err != -EINPROGRESS)
++ /* done_task will not finish it, so do it here */
++ atmel_sha_finish_req(req, err);
++
++ dev_dbg(dd->dev, "exit, err: %d\n", err);
++
++ return ret;
++}
++
++static int atmel_sha_enqueue(struct ahash_request *req, unsigned int op)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++ struct atmel_sha_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
++ struct atmel_sha_dev *dd = tctx->dd;
++
++ ctx->op = op;
++
++ return atmel_sha_handle_queue(dd, req);
++}
++
++static int atmel_sha_update(struct ahash_request *req)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++
++ if (!req->nbytes)
++ return 0;
++
++ ctx->total = req->nbytes;
++ ctx->sg = req->src;
++ ctx->offset = 0;
++
++ if (ctx->flags & SHA_FLAGS_FINUP) {
++ if (ctx->bufcnt + ctx->total < ATMEL_SHA_DMA_THRESHOLD)
++ /* faster to use CPU for short transfers */
++ ctx->flags |= SHA_FLAGS_CPU;
++ } else if (ctx->bufcnt + ctx->total < ctx->buflen) {
++ atmel_sha_append_sg(ctx);
++ return 0;
++ }
++ return atmel_sha_enqueue(req, SHA_OP_UPDATE);
++}
++
++static int atmel_sha_final(struct ahash_request *req)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++ struct atmel_sha_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
++ struct atmel_sha_dev *dd = tctx->dd;
++
++ int err = 0;
++
++ ctx->flags |= SHA_FLAGS_FINUP;
++
++ if (ctx->flags & SHA_FLAGS_ERROR)
++ return 0; /* uncompleted hash is not needed */
++
++ if (ctx->bufcnt) {
++ return atmel_sha_enqueue(req, SHA_OP_FINAL);
++ } else if (!(ctx->flags & SHA_FLAGS_PAD)) { /* add padding */
++ err = atmel_sha_hw_init(dd);
++ if (err)
++ goto err1;
++
++ dd->flags |= SHA_FLAGS_BUSY;
++ err = atmel_sha_final_req(dd);
++ } else {
++ /* copy ready hash (+ finalize hmac) */
++ return atmel_sha_finish(req);
++ }
++
++err1:
++ if (err != -EINPROGRESS)
++ /* done_task will not finish it, so do it here */
++ atmel_sha_finish_req(req, err);
++
++ return err;
++}
++
++static int atmel_sha_finup(struct ahash_request *req)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++ int err1, err2;
++
++ ctx->flags |= SHA_FLAGS_FINUP;
++
++ err1 = atmel_sha_update(req);
++ if (err1 == -EINPROGRESS || err1 == -EBUSY)
++ return err1;
++
++ /*
++ * final() has to be always called to cleanup resources
++ * even if udpate() failed, except EINPROGRESS
++ */
++ err2 = atmel_sha_final(req);
++
++ return err1 ?: err2;
++}
++
++static int atmel_sha_digest(struct ahash_request *req)
++{
++ return atmel_sha_init(req) ?: atmel_sha_finup(req);
++}
++
++static int atmel_sha_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base)
++{
++ struct atmel_sha_ctx *tctx = crypto_tfm_ctx(tfm);
++ const char *alg_name = crypto_tfm_alg_name(tfm);
++
++ /* Allocate a fallback and abort if it failed. */
++ tctx->fallback = crypto_alloc_shash(alg_name, 0,
++ CRYPTO_ALG_NEED_FALLBACK);
++ if (IS_ERR(tctx->fallback)) {
++ pr_err("atmel-sha: fallback driver '%s' could not be loaded.\n",
++ alg_name);
++ return PTR_ERR(tctx->fallback);
++ }
++ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
++ sizeof(struct atmel_sha_reqctx) +
++ SHA_BUFFER_LEN + SHA256_BLOCK_SIZE);
++
++ return 0;
++}
++
++static int atmel_sha_cra_init(struct crypto_tfm *tfm)
++{
++ return atmel_sha_cra_init_alg(tfm, NULL);
++}
++
++static void atmel_sha_cra_exit(struct crypto_tfm *tfm)
++{
++ struct atmel_sha_ctx *tctx = crypto_tfm_ctx(tfm);
++
++ crypto_free_shash(tctx->fallback);
++ tctx->fallback = NULL;
++}
++
++static struct ahash_alg sha_algs[] = {
++{
++ .init = atmel_sha_init,
++ .update = atmel_sha_update,
++ .final = atmel_sha_final,
++ .finup = atmel_sha_finup,
++ .digest = atmel_sha_digest,
++ .halg = {
++ .digestsize = SHA1_DIGEST_SIZE,
++ .base = {
++ .cra_name = "sha1",
++ .cra_driver_name = "atmel-sha1",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_ASYNC |
++ CRYPTO_ALG_NEED_FALLBACK,
++ .cra_blocksize = SHA1_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_sha_ctx),
++ .cra_alignmask = 0,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_sha_cra_init,
++ .cra_exit = atmel_sha_cra_exit,
++ }
++ }
++},
++{
++ .init = atmel_sha_init,
++ .update = atmel_sha_update,
++ .final = atmel_sha_final,
++ .finup = atmel_sha_finup,
++ .digest = atmel_sha_digest,
++ .halg = {
++ .digestsize = SHA256_DIGEST_SIZE,
++ .base = {
++ .cra_name = "sha256",
++ .cra_driver_name = "atmel-sha256",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_ASYNC |
++ CRYPTO_ALG_NEED_FALLBACK,
++ .cra_blocksize = SHA256_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_sha_ctx),
++ .cra_alignmask = 0,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_sha_cra_init,
++ .cra_exit = atmel_sha_cra_exit,
++ }
++ }
++},
++};
++
++static void atmel_sha_done_task(unsigned long data)
++{
++ struct atmel_sha_dev *dd = (struct atmel_sha_dev *)data;
++ int err = 0;
++
++ if (!(SHA_FLAGS_BUSY & dd->flags)) {
++ atmel_sha_handle_queue(dd, NULL);
++ return;
++ }
++
++ if (SHA_FLAGS_CPU & dd->flags) {
++ if (SHA_FLAGS_OUTPUT_READY & dd->flags) {
++ dd->flags &= ~SHA_FLAGS_OUTPUT_READY;
++ goto finish;
++ }
++ } else if (SHA_FLAGS_DMA_READY & dd->flags) {
++ if (SHA_FLAGS_DMA_ACTIVE & dd->flags) {
++ dd->flags &= ~SHA_FLAGS_DMA_ACTIVE;
++ atmel_sha_update_dma_stop(dd);
++ if (dd->err) {
++ err = dd->err;
++ goto finish;
++ }
++ }
++ if (SHA_FLAGS_OUTPUT_READY & dd->flags) {
++ /* hash or semi-hash ready */
++ dd->flags &= ~(SHA_FLAGS_DMA_READY |
++ SHA_FLAGS_OUTPUT_READY);
++ err = atmel_sha_update_dma_start(dd);
++ if (err != -EINPROGRESS)
++ goto finish;
++ }
++ }
++ return;
++
++finish:
++ /* finish curent request */
++ atmel_sha_finish_req(dd->req, err);
++}
++
++static irqreturn_t atmel_sha_irq(int irq, void *dev_id)
++{
++ struct atmel_sha_dev *sha_dd = dev_id;
++ u32 reg;
++
++ reg = atmel_sha_read(sha_dd, SHA_ISR);
++ if (reg & atmel_sha_read(sha_dd, SHA_IMR)) {
++ atmel_sha_write(sha_dd, SHA_IDR, reg);
++ if (SHA_FLAGS_BUSY & sha_dd->flags) {
++ sha_dd->flags |= SHA_FLAGS_OUTPUT_READY;
++ if (!(SHA_FLAGS_CPU & sha_dd->flags))
++ sha_dd->flags |= SHA_FLAGS_DMA_READY;
++ tasklet_schedule(&sha_dd->done_task);
++ } else {
++ dev_warn(sha_dd->dev, "SHA interrupt when no active requests.\n");
++ }
++ return IRQ_HANDLED;
++ }
++
++ return IRQ_NONE;
++}
++
++static void atmel_sha_unregister_algs(struct atmel_sha_dev *dd)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(sha_algs); i++)
++ crypto_unregister_ahash(&sha_algs[i]);
++}
++
++static int atmel_sha_register_algs(struct atmel_sha_dev *dd)
++{
++ int err, i, j;
++
++ for (i = 0; i < ARRAY_SIZE(sha_algs); i++) {
++ err = crypto_register_ahash(&sha_algs[i]);
++ if (err)
++ goto err_sha_algs;
++ }
++
++ return 0;
++
++err_sha_algs:
++ for (j = 0; j < i; j++)
++ crypto_unregister_ahash(&sha_algs[j]);
++
++ return err;
++}
++
++static int __devinit atmel_sha_probe(struct platform_device *pdev)
++{
++ struct atmel_sha_dev *sha_dd;
++ struct device *dev = &pdev->dev;
++ struct resource *sha_res;
++ unsigned long sha_phys_size;
++ int err;
++
++ sha_dd = kzalloc(sizeof(struct atmel_sha_dev), GFP_KERNEL);
++ if (sha_dd == NULL) {
++ dev_err(dev, "unable to alloc data struct.\n");
++ err = -ENOMEM;
++ goto sha_dd_err;
++ }
++
++ sha_dd->dev = dev;
++
++ platform_set_drvdata(pdev, sha_dd);
++
++ INIT_LIST_HEAD(&sha_dd->list);
++
++ tasklet_init(&sha_dd->done_task, atmel_sha_done_task,
++ (unsigned long)sha_dd);
++
++ crypto_init_queue(&sha_dd->queue, ATMEL_SHA_QUEUE_LENGTH);
++
++ sha_dd->irq = -1;
++
++ /* Get the base address */
++ sha_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!sha_res) {
++ dev_err(dev, "no MEM resource info\n");
++ err = -ENODEV;
++ goto res_err;
++ }
++ sha_dd->phys_base = sha_res->start;
++ sha_phys_size = resource_size(sha_res);
++
++ /* Get the IRQ */
++ sha_dd->irq = platform_get_irq(pdev, 0);
++ if (sha_dd->irq < 0) {
++ dev_err(dev, "no IRQ resource info\n");
++ err = sha_dd->irq;
++ goto res_err;
++ }
++
++ err = request_irq(sha_dd->irq, atmel_sha_irq, IRQF_SHARED, "atmel-sha",
++ sha_dd);
++ if (err) {
++ dev_err(dev, "unable to request sha irq.\n");
++ goto res_err;
++ }
++
++ /* Initializing the clock */
++ sha_dd->iclk = clk_get(&pdev->dev, NULL);
++ if (IS_ERR(sha_dd->iclk)) {
++ dev_err(dev, "clock intialization failed.\n");
++ err = PTR_ERR(sha_dd->iclk);
++ goto clk_err;
++ }
++
++ sha_dd->io_base = ioremap(sha_dd->phys_base, sha_phys_size);
++ if (!sha_dd->io_base) {
++ dev_err(dev, "can't ioremap\n");
++ err = -ENOMEM;
++ goto sha_io_err;
++ }
++
++ spin_lock(&atmel_sha.lock);
++ list_add_tail(&sha_dd->list, &atmel_sha.dev_list);
++ spin_unlock(&atmel_sha.lock);
++
++ err = atmel_sha_register_algs(sha_dd);
++ if (err)
++ goto err_algs;
++
++ dev_info(dev, "Atmel SHA1/SHA256\n");
++
++ return 0;
++
++err_algs:
++ spin_lock(&atmel_sha.lock);
++ list_del(&sha_dd->list);
++ spin_unlock(&atmel_sha.lock);
++ iounmap(sha_dd->io_base);
++sha_io_err:
++ clk_put(sha_dd->iclk);
++clk_err:
++ free_irq(sha_dd->irq, sha_dd);
++res_err:
++ tasklet_kill(&sha_dd->done_task);
++ kfree(sha_dd);
++ sha_dd = NULL;
++sha_dd_err:
++ dev_err(dev, "initialization failed.\n");
++
++ return err;
++}
++
++static int __devexit atmel_sha_remove(struct platform_device *pdev)
++{
++ static struct atmel_sha_dev *sha_dd;
++
++ sha_dd = platform_get_drvdata(pdev);
++ if (!sha_dd)
++ return -ENODEV;
++ spin_lock(&atmel_sha.lock);
++ list_del(&sha_dd->list);
++ spin_unlock(&atmel_sha.lock);
++
++ atmel_sha_unregister_algs(sha_dd);
++
++ tasklet_kill(&sha_dd->done_task);
++
++ iounmap(sha_dd->io_base);
++
++ clk_put(sha_dd->iclk);
++
++ if (sha_dd->irq >= 0)
++ free_irq(sha_dd->irq, sha_dd);
++
++ kfree(sha_dd);
++ sha_dd = NULL;
++
++ return 0;
++}
++
++static struct platform_driver atmel_sha_driver = {
++ .probe = atmel_sha_probe,
++ .remove = __devexit_p(atmel_sha_remove),
++ .driver = {
++ .name = "atmel_sha",
++ .owner = THIS_MODULE,
++ },
++};
++
++module_platform_driver(atmel_sha_driver);
++
++MODULE_DESCRIPTION("Atmel SHA1/SHA256 hw acceleration support.");
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Nicolas Royer - Eukréa Electromatique");
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0182-crypto-add-atmel-test-driver.patch b/patches.at91/0182-crypto-add-atmel-test-driver.patch
new file mode 100644
index 00000000000000..7080cbc8bfe663
--- /dev/null
+++ b/patches.at91/0182-crypto-add-atmel-test-driver.patch
@@ -0,0 +1,502 @@
+From 84820a1650d935f04a4a1e4b95905c7bc7b47d71 Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:07 +0200
+Subject: crypto: add atmel-test driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ drivers/crypto/Kconfig | 12 ++
+ drivers/crypto/Makefile | 1 +
+ drivers/crypto/atmel-test.c | 444 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 457 insertions(+)
+ create mode 100644 drivers/crypto/atmel-test.c
+
+diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
+index 2339add..7a356fe 100644
+--- a/drivers/crypto/Kconfig
++++ b/drivers/crypto/Kconfig
+@@ -343,4 +343,16 @@ config CRYPTO_DEV_ATMEL_SHA
+ To compile this driver as a module, choose M here: the module
+ will be called atmel-sha.
+
++config CRYPTO_DEV_ATMEL_TEST
++ tristate "TEST MODULE"
++ depends on ARCH_AT91
++ select CRYPTO_SHA1
++ select CRYPTO_SHA256
++ help
++ Some Atmel processors have SHA1/SHA256/TDES/AES hw accelerator.
++ Select this if you want to test SHA1/SHA256/TDES/AES drivers.
++
++ To compile this driver as a module, choose M here: the module
++ will be called atmel-test.
++
+ endif # CRYPTO_HW
+diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
+index d355c25..bbe005b 100644
+--- a/drivers/crypto/Makefile
++++ b/drivers/crypto/Makefile
+@@ -17,3 +17,4 @@ obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
+ obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o
+ obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o
+ obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA) += atmel-sha.o
++obj-$(CONFIG_CRYPTO_DEV_ATMEL_TEST) += atmel-test.o
+diff --git a/drivers/crypto/atmel-test.c b/drivers/crypto/atmel-test.c
+new file mode 100644
+index 0000000..4a23db5
+--- /dev/null
++++ b/drivers/crypto/atmel-test.c
+@@ -0,0 +1,444 @@
++/*
++ * Cryptographic API.
++ *
++ * ATMEL SHA1/SHA256/TDES/AES HW acceleration test.
++ *
++ * Author: Nicolas Royer - Eukréa Electromatique
++ *
++ * 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/kernel.h>
++#include <linux/init.h>
++#include <linux/crypto.h>
++#include <linux/err.h>
++#include <linux/scatterlist.h>
++#include <linux/gfp.h>
++#include <crypto/hash.h>
++
++static char *pattern64 =
++ "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
++ "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
++ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
++ "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
++ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
++ "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
++ "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
++ "\xad\x2b\x41\x7b\xe6\x6c\x37\x10";
++
++static char *key32 =
++ "\x60\x3d\xeb\x10\x15\xca\x71\xbe"
++ "\x2b\x73\xae\xf0\x85\x7d\x77\x81"
++ "\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
++ "\x2d\x98\x10\xa3\x09\x14\xdf\xf4";
++
++static char *iv16 =
++ "\x56\x2e\x17\x99\x6d\x09\x3d\x28"
++ "\xdd\xb3\xba\x69\x5a\x2e\x6f\x58";
++
++#define SHA1_MSG_LEN 20
++#define SHA256_MSG_LEN 32
++static char sha_out_buf[SHA256_MSG_LEN];
++
++#define TVMEMSIZE 4
++static char *tvmem[TVMEMSIZE];
++
++
++static void hexdump(unsigned char *buf, unsigned int len)
++{
++ print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
++ 16, 1,
++ buf, len, false);
++}
++
++struct hmac_sha_result {
++ struct completion completion;
++ int err;
++};
++
++static void hmac_sha_complete(struct crypto_async_request *req, int err)
++{
++ struct hmac_sha_result *r = req->data;
++ if (err == -EINPROGRESS)
++ return;
++ r->err = err;
++ complete(&r->completion);
++}
++
++static inline int do_one_ahash_op(struct ahash_request *req, int ret)
++{
++ if (ret == -EINPROGRESS || ret == -EBUSY) {
++ struct hmac_sha_result *tr = req->base.data;
++
++ ret = wait_for_completion_interruptible(&tr->completion);
++ if (!ret)
++ ret = tr->err;
++ INIT_COMPLETION(tr->completion);
++ }
++ return ret;
++}
++
++static int hmac_sha_update(const char *algo, char *data_in, size_t dlen,
++ char *hash_out, size_t outlen)
++{
++ int rc = 0;
++ struct crypto_ahash *tfm;
++ struct scatterlist sg[TVMEMSIZE];
++ struct ahash_request *req;
++ struct hmac_sha_result tresult;
++ int i, j;
++
++ /* Set hash output to 0 initially */
++ memset(hash_out, 0, outlen);
++
++ init_completion(&tresult.completion);
++ tfm = crypto_alloc_ahash(algo, 0, 0);
++ if (IS_ERR(tfm)) {
++ printk(KERN_ERR "crypto_alloc_ahash failed\n");
++ rc = PTR_ERR(tfm);
++ goto err_tfm;
++ }
++ req = ahash_request_alloc(tfm, GFP_KERNEL);
++ if (!req) {
++ printk(KERN_ERR "failed to allocate request\n");
++ rc = -ENOMEM;
++ goto err_req;
++ }
++ if (crypto_ahash_digestsize(tfm) > outlen) {
++ printk(KERN_ERR "tfm size > result buffer\n");
++ rc = -EINVAL;
++ goto err_req;
++ }
++ ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
++ hmac_sha_complete, &tresult);
++
++ sg_init_table(sg, TVMEMSIZE);
++
++ i = 0;
++ j = dlen;
++
++ while (j > PAGE_SIZE) {
++ sg_set_buf(sg + i, tvmem[i], PAGE_SIZE);
++ memcpy(tvmem[i], data_in + i * PAGE_SIZE, PAGE_SIZE);
++ i++;
++ j -= PAGE_SIZE;
++ }
++ sg_set_buf(sg + i, tvmem[i], j);
++ memcpy(tvmem[i], data_in + i * PAGE_SIZE, j);
++
++ crypto_ahash_clear_flags(tfm, -0);
++ ahash_request_set_crypt(req, sg, hash_out, dlen);
++ rc = crypto_ahash_init(req);
++ rc = do_one_ahash_op(req, crypto_ahash_update(req));
++ if (rc)
++ goto out;
++
++ rc = do_one_ahash_op(req, crypto_ahash_final(req));
++
++out:
++ ahash_request_free(req);
++err_req:
++ crypto_free_ahash(tfm);
++err_tfm:
++ return rc;
++}
++
++static int hmac_sha_digest(const char *algo, char *data_in, size_t dlen,
++ char *hash_out, size_t outlen)
++{
++ int rc = 0;
++ struct crypto_ahash *tfm;
++ struct scatterlist sg;
++ struct ahash_request *req;
++ struct hmac_sha_result tresult;
++
++ /* Set hash output to 0 initially */
++ memset(hash_out, 0, outlen);
++
++ init_completion(&tresult.completion);
++ tfm = crypto_alloc_ahash(algo, 0, 0);
++ if (IS_ERR(tfm)) {
++ printk(KERN_ERR "crypto_alloc_ahash failed\n");
++ rc = PTR_ERR(tfm);
++ goto err_tfm;
++ }
++ req = ahash_request_alloc(tfm, GFP_KERNEL);
++ if (!req) {
++ printk(KERN_ERR "failed to allocate request\n");
++ rc = -ENOMEM;
++ goto err_req;
++ }
++ if (crypto_ahash_digestsize(tfm) > outlen) {
++ printk(KERN_ERR "tfm size > result buffer\n");
++ rc = -EINVAL;
++ goto err_req;
++ }
++ ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
++ hmac_sha_complete, &tresult);
++
++ sg_init_one(&sg, data_in, dlen);
++
++ crypto_ahash_clear_flags(tfm, -0);
++ ahash_request_set_crypt(req, &sg, hash_out, dlen);
++ rc = do_one_ahash_op(req, crypto_ahash_digest(req));
++
++ ahash_request_free(req);
++err_req:
++ crypto_free_ahash(tfm);
++err_tfm:
++ return rc;
++}
++
++struct tcrypt_result {
++ struct completion completion;
++ int err;
++};
++
++static void tcrypt_complete(struct crypto_async_request *req, int err)
++{
++ struct tcrypt_result *res = req->data;
++
++ if (err == -EINPROGRESS)
++ return;
++
++ res->err = err;
++ complete(&res->completion);
++}
++
++static inline int do_one_acipher_op(struct ablkcipher_request *req, int ret)
++{
++ if (ret == -EINPROGRESS || ret == -EBUSY) {
++ struct tcrypt_result *tr = req->base.data;
++
++ ret = wait_for_completion_interruptible(&tr->completion);
++ if (!ret)
++ ret = tr->err;
++ INIT_COMPLETION(tr->completion);
++ }
++ return ret;
++}
++
++static int test_acipher(const char *algo, int enc, char *data_in,
++ char *data_out, size_t data_len, char *key, int keysize)
++ {
++ struct crypto_ablkcipher *tfm;
++ struct tcrypt_result tresult;
++ struct ablkcipher_request *req;
++ struct scatterlist sg[TVMEMSIZE];
++ unsigned int ret, i, j, iv_len;
++ char iv[128];
++
++ ret = -EAGAIN;
++
++ init_completion(&tresult.completion);
++
++ tfm = crypto_alloc_ablkcipher(algo, 0, 0);
++ if (IS_ERR(tfm)) {
++ printk(KERN_ERR "failed to load transform for %s: %ld\n",
++ algo, PTR_ERR(tfm));
++ return ret;
++ }
++
++ req = ablkcipher_request_alloc(tfm, GFP_KERNEL);
++ if (!req) {
++ printk(KERN_ERR "tcrypt: skcipher: Failed to allocate request for %s\n",
++ algo);
++ goto out;
++ }
++
++ ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
++ tcrypt_complete, &tresult);
++
++ crypto_ablkcipher_clear_flags(tfm, ~0);
++
++ ret = crypto_ablkcipher_setkey(tfm, key, keysize);
++ if (ret) {
++ printk(KERN_ERR "setkey() failed flags=%x\n",
++ crypto_ablkcipher_get_flags(tfm));
++ goto out_free_req;
++ }
++
++ printk(KERN_INFO "KEY:\n");
++ hexdump(key, keysize);
++
++ sg_init_table(sg, TVMEMSIZE);
++
++ i = 0;
++ j = data_len;
++
++ while (j > PAGE_SIZE) {
++ sg_set_buf(sg + i, tvmem[i], PAGE_SIZE);
++ memcpy(tvmem[i], data_in + i * PAGE_SIZE, PAGE_SIZE);
++ i++;
++ j -= PAGE_SIZE;
++ }
++ sg_set_buf(sg + i, tvmem[i], j);
++ memcpy(tvmem[i], data_in + i * PAGE_SIZE, j);
++
++ iv_len = crypto_ablkcipher_ivsize(tfm);
++ memcpy(iv, iv16, iv_len);
++
++ printk(KERN_INFO "IV:\n");
++ hexdump(iv, iv_len);
++
++ ablkcipher_request_set_crypt(req, sg, sg, data_len, iv);
++
++ printk(KERN_INFO "IN:\n");
++ hexdump(data_in, data_len);
++
++ if (enc)
++ ret = do_one_acipher_op(req, crypto_ablkcipher_encrypt(req));
++ else
++ ret = do_one_acipher_op(req, crypto_ablkcipher_decrypt(req));
++
++ if (ret)
++ printk(KERN_ERR "failed flags=%x\n",
++ crypto_ablkcipher_get_flags(tfm));
++ else {
++ i = 0;
++ j = data_len;
++ while (j > PAGE_SIZE) {
++ memcpy(data_out + i * PAGE_SIZE, tvmem[i], PAGE_SIZE);
++ i++;
++ j -= PAGE_SIZE;
++ }
++ memcpy(data_out + i * PAGE_SIZE, tvmem[i], j);
++
++ printk(KERN_INFO "OUT:\n");
++ hexdump(data_out, data_len);
++ }
++
++out_free_req:
++ ablkcipher_request_free(req);
++out:
++ crypto_free_ablkcipher(tfm);
++
++ return ret;
++}
++
++static int mode = 10;
++module_param_named(mode, mode, int,
++ S_IRUGO | S_IWUSR | S_IWGRP);
++
++static int keylen = 8;
++module_param_named(keylen, keylen, int,
++ S_IRUGO | S_IWUSR | S_IWGRP);
++
++static int dlen = 64;
++module_param_named(dlen, dlen, int,
++ S_IRUGO | S_IWUSR | S_IWGRP);
++
++char *ahash_algs[] = {"sha1", "sha256"};
++
++char *acipher_algs[] = {
++ "ecb(des)", "cbc(des)", "cfb(des)", "cfb32(des)",
++ "cfb16(des)", "cfb8(des)", "ofb(des)", "ecb(des3_ede)",
++ "cbc(des3_ede)", "cfb(des3_ede)", "cfb32(des3_ede)", "cfb16(des3_ede)",
++ "cfb8(des3_ede)", "ofb(des3_ede)", "ecb(aes)", "cbc(aes)",
++ "ofb(aes)", "cfb(aes)", "cfb64(aes)", "cfb32(aes)",
++ "cfb16(aes)", "cfb8(aes)", "ctr(aes)"};
++
++static int __init init_main(void)
++{
++ unsigned int i;
++ char *buf_in;
++ char *buf_out;
++ char *buf_res;
++
++ if ((dlen <= 0) || (dlen > TVMEMSIZE*PAGE_SIZE)) {
++ printk(KERN_ERR " 0 < dlen <= %i\n",
++ (int) (TVMEMSIZE*PAGE_SIZE));
++ return -EAGAIN;
++ }
++
++ for (i = 0; i < TVMEMSIZE; i++) {
++ tvmem[i] = (void *)__get_free_page(GFP_KERNEL);
++ if (!tvmem[i])
++ goto err_free_tv;
++ }
++
++ buf_in = kzalloc(dlen, GFP_KERNEL);
++ if (!buf_in)
++ goto err_buf_in_alloc;
++ buf_out = kzalloc(dlen, GFP_KERNEL);
++ if (!buf_out)
++ goto err_buf_out_alloc;
++ buf_res = kzalloc(dlen, GFP_KERNEL);
++ if (!buf_res)
++ goto err_buf_res_alloc;
++
++ if (dlen > 64) {
++ memcpy(buf_in, pattern64, 64);
++ memset(buf_in+64, 0xFF, dlen-64);
++ } else
++ memcpy(buf_in, pattern64, dlen);
++
++ if (mode < 10) {
++ if (mode >= ARRAY_SIZE(ahash_algs)) {
++ printk(KERN_ERR "mode must be < %d or > 10\n",
++ ARRAY_SIZE(ahash_algs));
++ goto exit;
++ }
++ printk(KERN_INFO "\n%s digest_req\n", ahash_algs[mode]);
++ hmac_sha_digest(ahash_algs[mode], buf_in, dlen, sha_out_buf,
++ mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
++ hexdump(sha_out_buf, mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
++
++ printk(KERN_INFO "\n%s update_req\n", ahash_algs[mode]);
++ hmac_sha_update(ahash_algs[mode], buf_in, dlen, sha_out_buf,
++ mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
++ hexdump(sha_out_buf, mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
++ } else {
++ mode -= 10;
++
++ if (mode >= ARRAY_SIZE(acipher_algs)) {
++ printk(KERN_ERR "mode must be < %d\n",
++ ARRAY_SIZE(acipher_algs) + 10);
++ goto exit;
++ }
++
++ printk(KERN_INFO "\n%s encrypt\n", acipher_algs[mode]);
++ if (test_acipher(acipher_algs[mode], 1, buf_in, buf_out,
++ dlen, key32, keylen))
++ goto exit;
++
++ printk(KERN_INFO "\n%s decrypt\n", acipher_algs[mode]);
++ if (test_acipher(acipher_algs[mode], 0, buf_out, buf_res,
++ dlen, key32, keylen))
++ goto exit;
++
++ if (memcmp(buf_in, buf_res, dlen))
++ printk(KERN_INFO "\n%s test failed\n\n",
++ acipher_algs[mode]);
++ else
++ printk(KERN_INFO "\n%s test OK\n\n",
++ acipher_algs[mode]);
++ }
++
++exit:
++ kfree(buf_res);
++err_buf_res_alloc:
++ kfree(buf_out);
++err_buf_out_alloc:
++ kfree(buf_in);
++err_buf_in_alloc:
++err_free_tv:
++ for (i = 0; i < TVMEMSIZE && tvmem[i]; i++)
++ free_page((unsigned long)tvmem[i]);
++
++ return -EAGAIN;
++}
++
++static void __exit cleanup_main(void)
++{
++}
++
++module_init(init_main);
++module_exit(cleanup_main);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Nicolas Royer - Eukréa Electromatique");
++MODULE_DESCRIPTION("Atmel HW crypto test");
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0183-crypto-add-new-tests-to-tcrypt.patch b/patches.at91/0183-crypto-add-new-tests-to-tcrypt.patch
new file mode 100644
index 00000000000000..d267bb0c8b6d30
--- /dev/null
+++ b/patches.at91/0183-crypto-add-new-tests-to-tcrypt.patch
@@ -0,0 +1,112 @@
+From 50f0d2ac8726776a89f503e21cbfa3a070d2c87a Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:08 +0200
+Subject: crypto: add new tests to tcrypt
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+- set sg buffers size equals to message size
+- add cfb & ofb tests for AES, DES & TDES
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ crypto/tcrypt.c | 50 +++++++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 45 insertions(+), 5 deletions(-)
+
+diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
+index 8f147bf..a9296bd 100644
+--- a/crypto/tcrypt.c
++++ b/crypto/tcrypt.c
+@@ -809,7 +809,7 @@ static void test_acipher_speed(const char *algo, int enc, unsigned int sec,
+ struct cipher_speed_template *template,
+ unsigned int tcount, u8 *keysize)
+ {
+- unsigned int ret, i, j, iv_len;
++ unsigned int ret, i, j, k, iv_len;
+ struct tcrypt_result tresult;
+ const char *key;
+ char iv[128];
+@@ -883,11 +883,23 @@ static void test_acipher_speed(const char *algo, int enc, unsigned int sec,
+ }
+
+ sg_init_table(sg, TVMEMSIZE);
+- sg_set_buf(sg, tvmem[0] + *keysize,
++
++ k = *keysize + *b_size;
++ if (k > PAGE_SIZE) {
++ sg_set_buf(sg, tvmem[0] + *keysize,
+ PAGE_SIZE - *keysize);
+- for (j = 1; j < TVMEMSIZE; j++) {
+- sg_set_buf(sg + j, tvmem[j], PAGE_SIZE);
+- memset(tvmem[j], 0xff, PAGE_SIZE);
++ k -= PAGE_SIZE;
++ j = 1;
++ while (k > PAGE_SIZE) {
++ sg_set_buf(sg + j, tvmem[j], PAGE_SIZE);
++ memset(tvmem[j], 0xff, PAGE_SIZE);
++ j++;
++ k -= PAGE_SIZE;
++ }
++ sg_set_buf(sg + j, tvmem[j], k);
++ memset(tvmem[j], 0xff, k);
++ } else {
++ sg_set_buf(sg, tvmem[0] + *keysize, *b_size);
+ }
+
+ iv_len = crypto_ablkcipher_ivsize(tfm);
+@@ -1512,6 +1524,14 @@ static int do_test(int m)
+ speed_template_16_24_32);
+ test_acipher_speed("ctr(aes)", DECRYPT, sec, NULL, 0,
+ speed_template_16_24_32);
++ test_acipher_speed("cfb(aes)", ENCRYPT, sec, NULL, 0,
++ speed_template_16_24_32);
++ test_acipher_speed("cfb(aes)", DECRYPT, sec, NULL, 0,
++ speed_template_16_24_32);
++ test_acipher_speed("ofb(aes)", ENCRYPT, sec, NULL, 0,
++ speed_template_16_24_32);
++ test_acipher_speed("ofb(aes)", DECRYPT, sec, NULL, 0,
++ speed_template_16_24_32);
+ break;
+
+ case 501:
+@@ -1527,6 +1547,18 @@ static int do_test(int m)
+ test_acipher_speed("cbc(des3_ede)", DECRYPT, sec,
+ des3_speed_template, DES3_SPEED_VECTORS,
+ speed_template_24);
++ test_acipher_speed("cfb(des3_ede)", ENCRYPT, sec,
++ des3_speed_template, DES3_SPEED_VECTORS,
++ speed_template_24);
++ test_acipher_speed("cfb(des3_ede)", DECRYPT, sec,
++ des3_speed_template, DES3_SPEED_VECTORS,
++ speed_template_24);
++ test_acipher_speed("ofb(des3_ede)", ENCRYPT, sec,
++ des3_speed_template, DES3_SPEED_VECTORS,
++ speed_template_24);
++ test_acipher_speed("ofb(des3_ede)", DECRYPT, sec,
++ des3_speed_template, DES3_SPEED_VECTORS,
++ speed_template_24);
+ break;
+
+ case 502:
+@@ -1538,6 +1570,14 @@ static int do_test(int m)
+ speed_template_8);
+ test_acipher_speed("cbc(des)", DECRYPT, sec, NULL, 0,
+ speed_template_8);
++ test_acipher_speed("cfb(des)", ENCRYPT, sec, NULL, 0,
++ speed_template_8);
++ test_acipher_speed("cfb(des)", DECRYPT, sec, NULL, 0,
++ speed_template_8);
++ test_acipher_speed("ofb(des)", ENCRYPT, sec, NULL, 0,
++ speed_template_8);
++ test_acipher_speed("ofb(des)", DECRYPT, sec, NULL, 0,
++ speed_template_8);
+ break;
+
+ case 503:
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0184-AT91SAM9G45-crypto-same-platform-data-header-for-all.patch b/patches.at91/0184-AT91SAM9G45-crypto-same-platform-data-header-for-all.patch
new file mode 100644
index 00000000000000..219273142a74c0
--- /dev/null
+++ b/patches.at91/0184-AT91SAM9G45-crypto-same-platform-data-header-for-all.patch
@@ -0,0 +1,54 @@
+From 308c14408fc521e386e512fb6d8dfafce1b59dd9 Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:09 +0200
+Subject: AT91SAM9G45: crypto: same platform data header for all crypto
+ peripherals
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ arch/arm/mach-at91/at91sam9g45_devices.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
+index 3d523f0..896088d 100644
+--- a/arch/arm/mach-at91/at91sam9g45_devices.c
++++ b/arch/arm/mach-at91/at91sam9g45_devices.c
+@@ -31,7 +31,7 @@
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at_hdmac.h>
+ #include <mach/atmel-mci.h>
+-#include <linux/platform_data/atmel-aes.h>
++#include <linux/platform_data/atmel-crypto.h>
+ #include <media/atmel-isi.h>
+
+ #include "generic.h"
+@@ -584,7 +584,7 @@ static void __init at91_add_device_tdes(void) {}
+ * -------------------------------------------------------------------- */
+
+ #if defined(CONFIG_CRYPTO_DEV_ATMEL_AES) || defined(CONFIG_CRYPTO_DEV_ATMEL_AES_MODULE)
+-static struct aes_platform_data aes_data;
++static struct crypto_platform_data aes_data;
+ static u64 aes_dmamask = DMA_BIT_MASK(32);
+
+ static struct resource aes_resources[] = {
+@@ -615,9 +615,9 @@ static struct platform_device at91sam9g45_aes_device = {
+ static void __init at91_add_device_aes(void)
+ {
+ struct at_dma_slave *atslave;
+- struct aes_dma_data *alt_atslave;
++ struct crypto_dma_data *alt_atslave;
+
+- alt_atslave = kzalloc(sizeof(struct aes_dma_data), GFP_KERNEL);
++ alt_atslave = kzalloc(sizeof(struct crypto_dma_data), GFP_KERNEL);
+
+ /* DMA TX slave channel configuration */
+ atslave = &alt_atslave->txdata;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0185-AT91SAM9G45-dts-add-crypto-peripherals.patch b/patches.at91/0185-AT91SAM9G45-dts-add-crypto-peripherals.patch
new file mode 100644
index 00000000000000..ddaee7925cdad8
--- /dev/null
+++ b/patches.at91/0185-AT91SAM9G45-dts-add-crypto-peripherals.patch
@@ -0,0 +1,65 @@
+From 5a8755b4c17d6199200486a431020afb42ad9122 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 22 Oct 2012 16:05:01 +0200
+Subject: AT91SAM9G45: dts: add crypto peripherals
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+
+Conflicts:
+ arch/arm/boot/dts/at91sam9g45.dtsi
+---
+ arch/arm/boot/dts/at91sam9g45.dtsi | 25 +++++++++++++++++++++++++
+ 1 file changed, 25 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
+index b032a8c..948dc96 100644
+--- a/arch/arm/boot/dts/at91sam9g45.dtsi
++++ b/arch/arm/boot/dts/at91sam9g45.dtsi
+@@ -106,6 +106,7 @@
+ compatible = "atmel,at91sam9g45-dma";
+ reg = <0xffffec00 0x200>;
+ interrupts = <21 4 0>;
++ #dma-cells = <1>;
+ };
+
+ pioA: gpio@fffff200 {
+@@ -243,6 +244,30 @@
+ #size-cells = <0>;
+ status = "disabled";
+ };
++
++ aes@fffc0000 {
++ compatible = "atmel,sam9g46-aes";
++ reg = <0xfffc0000 0x100>;
++ interrupts = <28 4 0>;
++ dma = <&dma 0x2000020c /* tx cfg = ATC_FIFOCFG_ENOUGHSPACE 0x20006020
++ | ATC_DST_H2SEL_HW
++ | ATC_DST_PER(AT_DMA_ID_AES_TX); */
++ &dma 0x200020b0 /* rx cfg = ATC_FIFOCFG_ENOUGHSPACE 0x20000603
++ | ATC_SRC_H2SEL_HW
++ | ATC_SRC_PER(AT_DMA_ID_AES_RX); */
++ >;
++ dma-name = "tx", "rx";
++ };
++ tdes@0xfffc4000 {
++ compatible = "atmel,sam9g46-tdes";
++ reg = <0xfffc4000 0x130>;
++ interrupts = <28 4 0>;
++ };
++ sha@0xfffc8000 {
++ compatible = "atmel,sam9g46-sha";
++ reg = <0xfffc8000 0x130>;
++ interrupts = <28 4 0>;
++ };
+ };
+
+ nand0: nand@40000000 {
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0186-AT91SAM9N12-add-crypto-peripherals.patch b/patches.at91/0186-AT91SAM9N12-add-crypto-peripherals.patch
new file mode 100644
index 00000000000000..57fb37802ddaa6
--- /dev/null
+++ b/patches.at91/0186-AT91SAM9N12-add-crypto-peripherals.patch
@@ -0,0 +1,90 @@
+From c3c525946e9afc0597632c3f0cee06be156ad9f8 Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:13 +0200
+Subject: AT91SAM9N12: add crypto peripherals
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ arch/arm/mach-at91/at91sam9n12.c | 17 +++++++++++++++++
+ arch/arm/mach-at91/include/mach/at91sam9n12.h | 2 ++
+ 2 files changed, 19 insertions(+)
+
+diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
+index ebe94bb..d09baf1 100644
+--- a/arch/arm/mach-at91/at91sam9n12.c
++++ b/arch/arm/mach-at91/at91sam9n12.c
+@@ -17,6 +17,7 @@
+ #include <mach/cpu.h>
+ #include <mach/board.h>
+
++
+ #include "soc.h"
+ #include "generic.h"
+ #include "clock.h"
+@@ -134,6 +135,17 @@ static struct clk ssc_clk = {
+ .pmc_mask = 1 << AT91SAM9N12_ID_SSC,
+ .type = CLK_TYPE_PERIPHERAL,
+ };
++static struct clk aes_clk = {
++ .name = "aes_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_AES,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk sha_clk = {
++ .name = "sha_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_SHA,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++
+
+ static struct clk *periph_clocks[] __initdata = {
+ &pioAB_clk,
+@@ -157,6 +169,8 @@ static struct clk *periph_clocks[] __initdata = {
+ &uhp_clk,
+ &udp_clk,
+ &ssc_clk,
++ &aes_clk,
++ &sha_clk,
+ };
+
+ static struct clk_lookup periph_clocks_lookups[] = {
+@@ -176,6 +190,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_ID("pioB", &pioAB_clk),
+ CLKDEV_CON_ID("pioC", &pioCD_clk),
+ CLKDEV_CON_ID("pioD", &pioCD_clk),
++ CLKDEV_CON_DEV_ID("aes_clk", "f000c000.aes", &aes_clk),
++ CLKDEV_CON_DEV_ID("sha_clk", "f0014000.sha", &sha_clk),
+ /* additional fake clock for macb_hclk */
+ CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &uhp_clk),
+ CLKDEV_CON_DEV_ID("ohci_clk", "500000.ohci", &uhp_clk),
+@@ -219,6 +235,7 @@ static void __init at91sam9n12_register_clocks(void)
+ static void __init at91sam9n12_map_io(void)
+ {
+ at91_init_sram(0, AT91SAM9N12_SRAM_BASE, AT91SAM9N12_SRAM_SIZE);
++ init_consistent_dma_size(SZ_4M);
+ }
+
+ void __init at91sam9n12_initialize(void)
+diff --git a/arch/arm/mach-at91/include/mach/at91sam9n12.h b/arch/arm/mach-at91/include/mach/at91sam9n12.h
+index d374b87..e07b0de 100644
+--- a/arch/arm/mach-at91/include/mach/at91sam9n12.h
++++ b/arch/arm/mach-at91/include/mach/at91sam9n12.h
+@@ -36,7 +36,9 @@
+ #define AT91SAM9N12_ID_UDP 23 /* USB Device High Speed */
+ #define AT91SAM9N12_ID_LCDC 25 /* LCD Controller */
+ #define AT91SAM9N12_ID_ISI 25 /* Image Sensor Interface */
++#define AT91SAM9N12_ID_SHA 27 /* SHA */
+ #define AT91SAM9N12_ID_SSC 28 /* Synchronous Serial Controller */
++#define AT91SAM9N12_ID_AES 29 /* AES */
+ #define AT91SAM9N12_ID_TRNG 30 /* TRNG */
+ #define AT91SAM9N12_ID_IRQ0 31 /* Advanced Interrupt Controller */
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0187-AT91SAM9N12-dts-add-crypto-peripherals.patch b/patches.at91/0187-AT91SAM9N12-dts-add-crypto-peripherals.patch
new file mode 100644
index 00000000000000..912398c1a600bf
--- /dev/null
+++ b/patches.at91/0187-AT91SAM9N12-dts-add-crypto-peripherals.patch
@@ -0,0 +1,64 @@
+From 212c6c62a492e7c01b036db250ad522e86303163 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 22 Oct 2012 16:05:17 +0200
+Subject: AT91SAM9N12: dts: add crypto peripherals
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+
+Conflicts:
+ arch/arm/boot/dts/at91sam9n12.dtsi
+---
+ arch/arm/boot/dts/at91sam9n12.dtsi | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
+index 0d08c4e..42b53bd 100644
+--- a/arch/arm/boot/dts/at91sam9n12.dtsi
++++ b/arch/arm/boot/dts/at91sam9n12.dtsi
+@@ -109,6 +109,7 @@
+ compatible = "atmel,at91sam9g45-dma";
+ reg = <0xffffec00 0x200>;
+ interrupts = <20 4 0>;
++ #dma-cells = <1>;
+ };
+
+ pioA: gpio@fffff400 {
+@@ -211,6 +212,29 @@
+ #size-cells = <0>;
+ status = "disabled";
+ };
++
++ aes@f000c000 {
++ compatible = "atmel,sam9g46-aes";
++ reg = <0xf000c000 0x100>;
++ interrupts = <29 4 0>;
++ dma = <&dma 0x2000060B /* tx cfg = ATC_FIFOCFG_ENOUGHSPACE */
++ /* | ATC_DST_H2SEL_HW */
++ /* | ATC_DST_PER(AT_DMA_ID_AES_TX); */
++ &dma 0x200060A0 /* rx cfg = ATC_FIFOCFG_ENOUGHSPACE */
++ /* | ATC_SRC_H2SEL_HW */
++ /* | ATC_SRC_PER(AT_DMA_ID_AES_RX); */
++ >;
++ dma-name = "tx", "rx";
++ };
++
++ sha@f0014000 {
++ compatible = "atmel,sam9g46-sha";
++ reg = <0xf0014000 0x100>;
++ interrupts = <27 4 0>;
++ dma = <&dma 0x200060C0>; /* rx cfg = ATC_FIFOCFG_ENOUGHSPACE */
++ /* | ATC_SRC_H2SEL_HW */
++ /* | ATC_SRC_PER(AT_DMA_ID_SHA_RX); */
++ };
+ };
+
+ nand0: nand@40000000 {
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0188-crypto-Atmel-AES-add-device-tree-support.patch b/patches.at91/0188-crypto-Atmel-AES-add-device-tree-support.patch
new file mode 100644
index 00000000000000..a7878b662f12fd
--- /dev/null
+++ b/patches.at91/0188-crypto-Atmel-AES-add-device-tree-support.patch
@@ -0,0 +1,1070 @@
+From 6dcba1a5e5b0cda9490f78b46b282ec3ec39f22c Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:15 +0200
+Subject: crypto: Atmel AES; add device tree support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ drivers/crypto/atmel-aes.c | 626 +++++++++++++++++++++++------
+ include/linux/platform_data/atmel-aes.h | 22 -
+ include/linux/platform_data/atmel-crypto.h | 22 +
+ 3 files changed, 524 insertions(+), 146 deletions(-)
+ delete mode 100644 include/linux/platform_data/atmel-aes.h
+ create mode 100644 include/linux/platform_data/atmel-crypto.h
+
+diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
+index 6bb20ff..035b87a 100644
+--- a/drivers/crypto/atmel-aes.c
++++ b/drivers/crypto/atmel-aes.c
+@@ -43,16 +43,19 @@
+ #include <crypto/aes.h>
+ #include <crypto/hash.h>
+ #include <crypto/internal/hash.h>
+-#include <linux/platform_data/atmel-aes.h>
++#include <linux/platform_data/atmel-crypto.h>
+ #include "atmel-aes-regs.h"
+
++#include <linux/of.h>
++#include <linux/of_device.h>
++
+ #define CFB8_BLOCK_SIZE 1
+ #define CFB16_BLOCK_SIZE 2
+ #define CFB32_BLOCK_SIZE 4
+ #define CFB64_BLOCK_SIZE 8
+
+ /* AES flags */
+-#define AES_FLAGS_MODE_MASK 0x01ff
++#define AES_FLAGS_MODE_MASK 0x03ff
+ #define AES_FLAGS_ENCRYPT BIT(0)
+ #define AES_FLAGS_CBC BIT(1)
+ #define AES_FLAGS_CFB BIT(2)
+@@ -60,21 +63,26 @@
+ #define AES_FLAGS_CFB16 BIT(4)
+ #define AES_FLAGS_CFB32 BIT(5)
+ #define AES_FLAGS_CFB64 BIT(6)
+-#define AES_FLAGS_OFB BIT(7)
+-#define AES_FLAGS_CTR BIT(8)
++#define AES_FLAGS_CFB128 BIT(7)
++#define AES_FLAGS_OFB BIT(8)
++#define AES_FLAGS_CTR BIT(9)
+
+ #define AES_FLAGS_INIT BIT(16)
+ #define AES_FLAGS_DMA BIT(17)
+ #define AES_FLAGS_BUSY BIT(18)
++#define AES_FLAGS_FAST BIT(19)
+
+-#define AES_FLAGS_DUALBUFF BIT(24)
+-
+-#define ATMEL_AES_QUEUE_LENGTH 1
+-#define ATMEL_AES_CACHE_SIZE 0
++#define ATMEL_AES_QUEUE_LENGTH 50
+
+ #define ATMEL_AES_DMA_THRESHOLD 16
+
+
++struct atmel_aes_caps {
++ bool has_dualbuff;
++ bool has_cfb64;
++ u32 max_burst_size;
++};
++
+ struct atmel_aes_dev;
+
+ struct atmel_aes_ctx {
+@@ -82,6 +90,8 @@ struct atmel_aes_ctx {
+
+ int keylen;
+ u32 key[AES_KEYSIZE_256 / sizeof(u32)];
++
++ u16 block_size;
+ };
+
+ struct atmel_aes_reqctx {
+@@ -117,20 +127,27 @@ struct atmel_aes_dev {
+
+ struct scatterlist *in_sg;
+ unsigned int nb_in_sg;
+-
++ size_t in_offset;
+ struct scatterlist *out_sg;
+ unsigned int nb_out_sg;
++ size_t out_offset;
+
+ size_t bufcnt;
++ size_t buflen;
++ size_t dma_size;
+
+- u8 buf_in[ATMEL_AES_DMA_THRESHOLD] __aligned(sizeof(u32));
+- int dma_in;
++ void *buf_in;
++ int dma_in;
++ dma_addr_t dma_addr_in;
+ struct atmel_aes_dma dma_lch_in;
+
+- u8 buf_out[ATMEL_AES_DMA_THRESHOLD] __aligned(sizeof(u32));
+- int dma_out;
++ void *buf_out;
++ int dma_out;
++ dma_addr_t dma_addr_out;
+ struct atmel_aes_dma dma_lch_out;
+
++ struct atmel_aes_caps caps;
++
+ u32 hw_version;
+ };
+
+@@ -170,6 +187,37 @@ static int atmel_aes_sg_length(struct ablkcipher_request *req,
+ return sg_nb;
+ }
+
++static int atmel_aes_sg_copy(struct scatterlist **sg, size_t *offset,
++ void *buf, size_t buflen, size_t total, int out)
++{
++ unsigned int count, off = 0;
++
++ while (buflen && total) {
++ count = min((*sg)->length - *offset, total);
++ count = min(count, buflen);
++
++ if (!count)
++ return off;
++
++ scatterwalk_map_and_copy(buf + off, *sg, *offset, count, out);
++
++ off += count;
++ buflen -= count;
++ *offset += count;
++ total -= count;
++
++ if (*offset == (*sg)->length) {
++ *sg = sg_next(*sg);
++ if (*sg)
++ *offset = 0;
++ else
++ total = 0;
++ }
++ }
++
++ return off;
++}
++
+ static inline u32 atmel_aes_read(struct atmel_aes_dev *dd, u32 offset)
+ {
+ return readl_relaxed(dd->io_base + offset);
+@@ -195,14 +243,6 @@ static void atmel_aes_write_n(struct atmel_aes_dev *dd, u32 offset,
+ atmel_aes_write(dd, offset, *value);
+ }
+
+-static void atmel_aes_dualbuff_test(struct atmel_aes_dev *dd)
+-{
+- atmel_aes_write(dd, AES_MR, AES_MR_DUALBUFF);
+-
+- if (atmel_aes_read(dd, AES_MR) & AES_MR_DUALBUFF)
+- dd->flags |= AES_FLAGS_DUALBUFF;
+-}
+-
+ static struct atmel_aes_dev *atmel_aes_find_dev(struct atmel_aes_ctx *ctx)
+ {
+ struct atmel_aes_dev *aes_dd = NULL;
+@@ -230,7 +270,6 @@ static int atmel_aes_hw_init(struct atmel_aes_dev *dd)
+
+ if (!(dd->flags & AES_FLAGS_INIT)) {
+ atmel_aes_write(dd, AES_CR, AES_CR_SWRST);
+- atmel_aes_dualbuff_test(dd);
+ dd->flags |= AES_FLAGS_INIT;
+ dd->err = 0;
+ }
+@@ -238,11 +277,19 @@ static int atmel_aes_hw_init(struct atmel_aes_dev *dd)
+ return 0;
+ }
+
++static inline unsigned int atmel_aes_get_version(struct atmel_aes_dev *dd)
++{
++ return atmel_aes_read(dd, AES_HW_VERSION) & 0x00000fff;
++}
++
+ static void atmel_aes_hw_version_init(struct atmel_aes_dev *dd)
+ {
+ atmel_aes_hw_init(dd);
+
+- dd->hw_version = atmel_aes_read(dd, AES_HW_VERSION);
++ dd->hw_version = atmel_aes_get_version(dd);
++
++ dev_info(dd->dev,
++ "version: 0x%x\n", dd->hw_version);
+
+ clk_disable_unprepare(dd->iclk);
+ }
+@@ -265,50 +312,77 @@ static void atmel_aes_dma_callback(void *data)
+ tasklet_schedule(&dd->done_task);
+ }
+
+-static int atmel_aes_crypt_dma(struct atmel_aes_dev *dd)
++static int atmel_aes_crypt_dma(struct atmel_aes_dev *dd,
++ dma_addr_t dma_addr_in, dma_addr_t dma_addr_out, int length)
+ {
++ struct scatterlist sg[2];
+ struct dma_async_tx_descriptor *in_desc, *out_desc;
+- int nb_dma_sg_in, nb_dma_sg_out;
+
+- dd->nb_in_sg = atmel_aes_sg_length(dd->req, dd->in_sg);
+- if (!dd->nb_in_sg)
+- goto exit_err;
++ dd->dma_size = length;
+
+- nb_dma_sg_in = dma_map_sg(dd->dev, dd->in_sg, dd->nb_in_sg,
+- DMA_TO_DEVICE);
+- if (!nb_dma_sg_in)
+- goto exit_err;
++ if (!(dd->flags & AES_FLAGS_FAST)) {
++ dma_sync_single_for_device(dd->dev, dma_addr_in, length,
++ DMA_TO_DEVICE);
++ }
+
+- in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, dd->in_sg,
+- nb_dma_sg_in, DMA_MEM_TO_DEV,
+- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ if (dd->flags & AES_FLAGS_CFB8) {
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_1_BYTE;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_1_BYTE;
++ } else if (dd->flags & AES_FLAGS_CFB16) {
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_2_BYTES;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_2_BYTES;
++ } else {
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ }
+
+- if (!in_desc)
+- goto unmap_in;
++ if (dd->flags & (AES_FLAGS_CFB8 | AES_FLAGS_CFB16 |
++ AES_FLAGS_CFB32 | AES_FLAGS_CFB64)) {
++ dd->dma_lch_in.dma_conf.src_maxburst = 1;
++ dd->dma_lch_in.dma_conf.dst_maxburst = 1;
++ dd->dma_lch_out.dma_conf.src_maxburst = 1;
++ dd->dma_lch_out.dma_conf.dst_maxburst = 1;
++ } else {
++ dd->dma_lch_in.dma_conf.src_maxburst = dd->caps.max_burst_size;
++ dd->dma_lch_in.dma_conf.dst_maxburst = dd->caps.max_burst_size;
++ dd->dma_lch_out.dma_conf.src_maxburst = dd->caps.max_burst_size;
++ dd->dma_lch_out.dma_conf.dst_maxburst = dd->caps.max_burst_size;
++ }
+
+- /* callback not needed */
++ dmaengine_slave_config(dd->dma_lch_in.chan, &dd->dma_lch_in.dma_conf);
++ dmaengine_slave_config(dd->dma_lch_out.chan, &dd->dma_lch_out.dma_conf);
+
+- dd->nb_out_sg = atmel_aes_sg_length(dd->req, dd->out_sg);
+- if (!dd->nb_out_sg)
+- goto unmap_in;
++ dd->flags |= AES_FLAGS_DMA;
+
+- nb_dma_sg_out = dma_map_sg(dd->dev, dd->out_sg, dd->nb_out_sg,
+- DMA_FROM_DEVICE);
+- if (!nb_dma_sg_out)
+- goto unmap_out;
++ sg_init_table(&sg[0], 1);
++ sg_dma_address(&sg[0]) = dma_addr_in;
++ sg_dma_len(&sg[0]) = length;
+
+- out_desc = dmaengine_prep_slave_sg(dd->dma_lch_out.chan, dd->out_sg,
+- nb_dma_sg_out, DMA_DEV_TO_MEM,
+- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ sg_init_table(&sg[1], 1);
++ sg_dma_address(&sg[1]) = dma_addr_out;
++ sg_dma_len(&sg[1]) = length;
+
++ in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, &sg[0],
++ 1, DMA_MEM_TO_DEV,
++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ if (!in_desc)
++ return -EINVAL;
++
++ out_desc = dmaengine_prep_slave_sg(dd->dma_lch_out.chan, &sg[1],
++ 1, DMA_DEV_TO_MEM,
++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!out_desc)
+- goto unmap_out;
++ return -EINVAL;
+
+ out_desc->callback = atmel_aes_dma_callback;
+ out_desc->callback_param = dd;
+
+- dd->total -= dd->req->nbytes;
+-
+ dmaengine_submit(out_desc);
+ dma_async_issue_pending(dd->dma_lch_out.chan);
+
+@@ -316,15 +390,6 @@ static int atmel_aes_crypt_dma(struct atmel_aes_dev *dd)
+ dma_async_issue_pending(dd->dma_lch_in.chan);
+
+ return 0;
+-
+-unmap_out:
+- dma_unmap_sg(dd->dev, dd->out_sg, dd->nb_out_sg,
+- DMA_FROM_DEVICE);
+-unmap_in:
+- dma_unmap_sg(dd->dev, dd->in_sg, dd->nb_in_sg,
+- DMA_TO_DEVICE);
+-exit_err:
+- return -EINVAL;
+ }
+
+ static int atmel_aes_crypt_cpu_start(struct atmel_aes_dev *dd)
+@@ -357,30 +422,66 @@ static int atmel_aes_crypt_cpu_start(struct atmel_aes_dev *dd)
+
+ static int atmel_aes_crypt_dma_start(struct atmel_aes_dev *dd)
+ {
+- int err;
++ int err, fast = 0, in, out;
++ size_t count;
++ dma_addr_t addr_in, addr_out;
++
++ if ((!dd->in_offset) && (!dd->out_offset)) {
++ /* check for alignment */
++ in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32)) &&
++ IS_ALIGNED(dd->in_sg->length, dd->ctx->block_size);
++ out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32)) &&
++ IS_ALIGNED(dd->out_sg->length, dd->ctx->block_size);
++ fast = in && out;
++
++ if (sg_dma_len(dd->in_sg) != sg_dma_len(dd->out_sg))
++ fast = 0;
++ }
++
++
++ if (fast) {
++ count = min(dd->total, sg_dma_len(dd->in_sg));
++ count = min(count, sg_dma_len(dd->out_sg));
++
++ err = dma_map_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
++ if (!err) {
++ dev_err(dd->dev, "dma_map_sg() error\n");
++ return -EINVAL;
++ }
++
++ err = dma_map_sg(dd->dev, dd->out_sg, 1,
++ DMA_FROM_DEVICE);
++ if (!err) {
++ dev_err(dd->dev, "dma_map_sg() error\n");
++ dma_unmap_sg(dd->dev, dd->in_sg, 1,
++ DMA_TO_DEVICE);
++ return -EINVAL;
++ }
++
++ addr_in = sg_dma_address(dd->in_sg);
++ addr_out = sg_dma_address(dd->out_sg);
++
++ dd->flags |= AES_FLAGS_FAST;
+
+- if (dd->flags & AES_FLAGS_CFB8) {
+- dd->dma_lch_in.dma_conf.dst_addr_width =
+- DMA_SLAVE_BUSWIDTH_1_BYTE;
+- dd->dma_lch_out.dma_conf.src_addr_width =
+- DMA_SLAVE_BUSWIDTH_1_BYTE;
+- } else if (dd->flags & AES_FLAGS_CFB16) {
+- dd->dma_lch_in.dma_conf.dst_addr_width =
+- DMA_SLAVE_BUSWIDTH_2_BYTES;
+- dd->dma_lch_out.dma_conf.src_addr_width =
+- DMA_SLAVE_BUSWIDTH_2_BYTES;
+ } else {
+- dd->dma_lch_in.dma_conf.dst_addr_width =
+- DMA_SLAVE_BUSWIDTH_4_BYTES;
+- dd->dma_lch_out.dma_conf.src_addr_width =
+- DMA_SLAVE_BUSWIDTH_4_BYTES;
++ /* use cache buffers */
++ count = atmel_aes_sg_copy(&dd->in_sg, &dd->in_offset,
++ dd->buf_in, dd->buflen, dd->total, 0);
++
++ addr_in = dd->dma_addr_in;
++ addr_out = dd->dma_addr_out;
++
++ dd->flags &= ~AES_FLAGS_FAST;
+ }
+
+- dmaengine_slave_config(dd->dma_lch_in.chan, &dd->dma_lch_in.dma_conf);
+- dmaengine_slave_config(dd->dma_lch_out.chan, &dd->dma_lch_out.dma_conf);
++ dd->total -= count;
+
+- dd->flags |= AES_FLAGS_DMA;
+- err = atmel_aes_crypt_dma(dd);
++ err = atmel_aes_crypt_dma(dd, addr_in, addr_out, count);
++
++ if (err && (dd->flags & AES_FLAGS_FAST)) {
++ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
++ dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_TO_DEVICE);
++ }
+
+ return err;
+ }
+@@ -415,6 +516,8 @@ static int atmel_aes_write_ctrl(struct atmel_aes_dev *dd)
+ valmr |= AES_MR_CFBS_32b;
+ else if (dd->flags & AES_FLAGS_CFB64)
+ valmr |= AES_MR_CFBS_64b;
++ else if (dd->flags & AES_FLAGS_CFB128)
++ valmr |= AES_MR_CFBS_128b;
+ } else if (dd->flags & AES_FLAGS_OFB) {
+ valmr |= AES_MR_OPMOD_OFB;
+ } else if (dd->flags & AES_FLAGS_CTR) {
+@@ -428,7 +531,7 @@ static int atmel_aes_write_ctrl(struct atmel_aes_dev *dd)
+
+ if (dd->total > ATMEL_AES_DMA_THRESHOLD) {
+ valmr |= AES_MR_SMOD_IDATAR0;
+- if (dd->flags & AES_FLAGS_DUALBUFF)
++ if (dd->caps.has_dualbuff)
+ valmr |= AES_MR_DUALBUFF;
+ } else {
+ valmr |= AES_MR_SMOD_AUTO;
+@@ -482,7 +585,9 @@ static int atmel_aes_handle_queue(struct atmel_aes_dev *dd,
+ /* assign new request to device */
+ dd->req = req;
+ dd->total = req->nbytes;
++ dd->in_offset = 0;
+ dd->in_sg = req->src;
++ dd->out_offset = 0;
+ dd->out_sg = req->dst;
+
+ rctx = ablkcipher_request_ctx(req);
+@@ -511,18 +616,86 @@ static int atmel_aes_handle_queue(struct atmel_aes_dev *dd,
+ static int atmel_aes_crypt_dma_stop(struct atmel_aes_dev *dd)
+ {
+ int err = -EINVAL;
++ size_t count;
+
+ if (dd->flags & AES_FLAGS_DMA) {
+- dma_unmap_sg(dd->dev, dd->out_sg,
+- dd->nb_out_sg, DMA_FROM_DEVICE);
+- dma_unmap_sg(dd->dev, dd->in_sg,
+- dd->nb_in_sg, DMA_TO_DEVICE);
+ err = 0;
++ if (dd->flags & AES_FLAGS_FAST) {
++ dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
++ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
++ } else {
++ dma_sync_single_for_device(dd->dev, dd->dma_addr_out,
++ dd->dma_size, DMA_FROM_DEVICE);
++
++ /* copy data */
++ count = atmel_aes_sg_copy(&dd->out_sg, &dd->out_offset,
++ dd->buf_out, dd->buflen, dd->dma_size, 1);
++ if (count != dd->dma_size) {
++ err = -EINVAL;
++ pr_err("not all data converted: %u\n", count);
++ }
++ }
++ }
++
++ return err;
++}
++
++
++static int atmel_aes_buff_init(struct atmel_aes_dev *dd)
++{
++ int err = -ENOMEM;
++
++ dd->buf_in = (void *)__get_free_pages(GFP_KERNEL, 0);
++ dd->buf_out = (void *)__get_free_pages(GFP_KERNEL, 0);
++ dd->buflen = PAGE_SIZE;
++ dd->buflen &= ~(AES_BLOCK_SIZE - 1);
++
++ if (!dd->buf_in || !dd->buf_out) {
++ dev_err(dd->dev, "unable to alloc pages.\n");
++ goto err_alloc;
+ }
+
++ /* MAP here */
++ dd->dma_addr_in = dma_map_single(dd->dev, dd->buf_in,
++ dd->buflen, DMA_TO_DEVICE);
++ if (dma_mapping_error(dd->dev, dd->dma_addr_in)) {
++ dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
++ err = -EINVAL;
++ goto err_map_in;
++ }
++
++ dd->dma_addr_out = dma_map_single(dd->dev, dd->buf_out,
++ dd->buflen, DMA_FROM_DEVICE);
++ if (dma_mapping_error(dd->dev, dd->dma_addr_out)) {
++ dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
++ err = -EINVAL;
++ goto err_map_out;
++ }
++
++ return 0;
++
++err_map_out:
++ dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen,
++ DMA_TO_DEVICE);
++err_map_in:
++ free_page((unsigned long)dd->buf_out);
++ free_page((unsigned long)dd->buf_in);
++err_alloc:
++ if (err)
++ pr_err("error: %d\n", err);
+ return err;
+ }
+
++static void atmel_aes_buff_cleanup(struct atmel_aes_dev *dd)
++{
++ dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
++ DMA_FROM_DEVICE);
++ dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen,
++ DMA_TO_DEVICE);
++ free_page((unsigned long)dd->buf_out);
++ free_page((unsigned long)dd->buf_in);
++}
++
+ static int atmel_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
+ {
+ struct atmel_aes_ctx *ctx = crypto_ablkcipher_ctx(
+@@ -530,9 +703,30 @@ static int atmel_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
+ struct atmel_aes_reqctx *rctx = ablkcipher_request_ctx(req);
+ struct atmel_aes_dev *dd;
+
+- if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) {
+- pr_err("request size is not exact amount of AES blocks\n");
+- return -EINVAL;
++ if (mode & AES_FLAGS_CFB8) {
++ if (!IS_ALIGNED(req->nbytes, CFB8_BLOCK_SIZE)) {
++ pr_err("request size is not exact amount of CFB8 blocks\n");
++ return -EINVAL;
++ }
++ ctx->block_size = CFB8_BLOCK_SIZE;
++ } else if (mode & AES_FLAGS_CFB16) {
++ if (!IS_ALIGNED(req->nbytes, CFB16_BLOCK_SIZE)) {
++ pr_err("request size is not exact amount of CFB16 blocks\n");
++ return -EINVAL;
++ }
++ ctx->block_size = CFB16_BLOCK_SIZE;
++ } else if (mode & AES_FLAGS_CFB32) {
++ if (!IS_ALIGNED(req->nbytes, CFB32_BLOCK_SIZE)) {
++ pr_err("request size is not exact amount of CFB32 blocks\n");
++ return -EINVAL;
++ }
++ ctx->block_size = CFB32_BLOCK_SIZE;
++ } else {
++ if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) {
++ pr_err("request size is not exact amount of AES blocks\n");
++ return -EINVAL;
++ }
++ ctx->block_size = AES_BLOCK_SIZE;
+ }
+
+ dd = atmel_aes_find_dev(ctx);
+@@ -556,14 +750,12 @@ static bool atmel_aes_filter(struct dma_chan *chan, void *slave)
+ }
+ }
+
+-static int atmel_aes_dma_init(struct atmel_aes_dev *dd)
++static int atmel_aes_dma_init(struct atmel_aes_dev *dd,
++ struct crypto_platform_data *pdata)
+ {
+ int err = -ENOMEM;
+- struct aes_platform_data *pdata;
+ dma_cap_mask_t mask_in, mask_out;
+
+- pdata = dd->dev->platform_data;
+-
+ if (pdata && pdata->dma_slave->txdata.dma_dev &&
+ pdata->dma_slave->rxdata.dma_dev) {
+
+@@ -573,28 +765,38 @@ static int atmel_aes_dma_init(struct atmel_aes_dev *dd)
+
+ dd->dma_lch_in.chan = dma_request_channel(mask_in,
+ atmel_aes_filter, &pdata->dma_slave->rxdata);
++
+ if (!dd->dma_lch_in.chan)
+ goto err_dma_in;
+
+ dd->dma_lch_in.dma_conf.direction = DMA_MEM_TO_DEV;
+ dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base +
+ AES_IDATAR(0);
+- dd->dma_lch_in.dma_conf.src_maxburst = 1;
+- dd->dma_lch_in.dma_conf.dst_maxburst = 1;
++ dd->dma_lch_in.dma_conf.src_maxburst = dd->caps.max_burst_size;
++ dd->dma_lch_in.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_in.dma_conf.dst_maxburst = dd->caps.max_burst_size;
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
+ dd->dma_lch_in.dma_conf.device_fc = false;
+
+ dma_cap_zero(mask_out);
+ dma_cap_set(DMA_SLAVE, mask_out);
+ dd->dma_lch_out.chan = dma_request_channel(mask_out,
+ atmel_aes_filter, &pdata->dma_slave->txdata);
++
+ if (!dd->dma_lch_out.chan)
+ goto err_dma_out;
+
+ dd->dma_lch_out.dma_conf.direction = DMA_DEV_TO_MEM;
+ dd->dma_lch_out.dma_conf.src_addr = dd->phys_base +
+ AES_ODATAR(0);
+- dd->dma_lch_out.dma_conf.src_maxburst = 1;
+- dd->dma_lch_out.dma_conf.dst_maxburst = 1;
++ dd->dma_lch_out.dma_conf.src_maxburst = dd->caps.max_burst_size;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_out.dma_conf.dst_maxburst = dd->caps.max_burst_size;
++ dd->dma_lch_out.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
+ dd->dma_lch_out.dma_conf.device_fc = false;
+
+ return 0;
+@@ -670,13 +872,13 @@ static int atmel_aes_ofb_decrypt(struct ablkcipher_request *req)
+ static int atmel_aes_cfb_encrypt(struct ablkcipher_request *req)
+ {
+ return atmel_aes_crypt(req,
+- AES_FLAGS_ENCRYPT | AES_FLAGS_CFB);
++ AES_FLAGS_ENCRYPT | AES_FLAGS_CFB | AES_FLAGS_CFB128);
+ }
+
+ static int atmel_aes_cfb_decrypt(struct ablkcipher_request *req)
+ {
+ return atmel_aes_crypt(req,
+- AES_FLAGS_CFB);
++ AES_FLAGS_CFB | AES_FLAGS_CFB128);
+ }
+
+ static int atmel_aes_cfb64_encrypt(struct ablkcipher_request *req)
+@@ -758,7 +960,7 @@ static struct crypto_alg aes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
+- .cra_alignmask = 0x0,
++ .cra_alignmask = 0xf,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_aes_cra_init,
+@@ -778,7 +980,7 @@ static struct crypto_alg aes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
+- .cra_alignmask = 0x0,
++ .cra_alignmask = 0xf,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_aes_cra_init,
+@@ -799,7 +1001,7 @@ static struct crypto_alg aes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
+- .cra_alignmask = 0x0,
++ .cra_alignmask = 0xf,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_aes_cra_init,
+@@ -820,7 +1022,7 @@ static struct crypto_alg aes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
+- .cra_alignmask = 0x0,
++ .cra_alignmask = 0xf,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_aes_cra_init,
+@@ -841,7 +1043,7 @@ static struct crypto_alg aes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = CFB32_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
+- .cra_alignmask = 0x0,
++ .cra_alignmask = 0x3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_aes_cra_init,
+@@ -862,7 +1064,7 @@ static struct crypto_alg aes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = CFB16_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
+- .cra_alignmask = 0x0,
++ .cra_alignmask = 0x1,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_aes_cra_init,
+@@ -904,7 +1106,7 @@ static struct crypto_alg aes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
+- .cra_alignmask = 0x0,
++ .cra_alignmask = 0xf,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_aes_cra_init,
+@@ -920,15 +1122,14 @@ static struct crypto_alg aes_algs[] = {
+ },
+ };
+
+-static struct crypto_alg aes_cfb64_alg[] = {
+-{
++static struct crypto_alg aes_cfb64_alg = {
+ .cra_name = "cfb64(aes)",
+ .cra_driver_name = "atmel-cfb64-aes",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = CFB64_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
+- .cra_alignmask = 0x0,
++ .cra_alignmask = 0x7,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_aes_cra_init,
+@@ -941,7 +1142,6 @@ static struct crypto_alg aes_cfb64_alg[] = {
+ .encrypt = atmel_aes_cfb64_encrypt,
+ .decrypt = atmel_aes_cfb64_decrypt,
+ }
+-},
+ };
+
+ static void atmel_aes_queue_task(unsigned long data)
+@@ -974,7 +1174,14 @@ static void atmel_aes_done_task(unsigned long data)
+ err = dd->err ? : err;
+
+ if (dd->total && !err) {
+- err = atmel_aes_crypt_dma_start(dd);
++ if (dd->flags & AES_FLAGS_FAST) {
++ dd->in_sg = sg_next(dd->in_sg);
++ dd->out_sg = sg_next(dd->out_sg);
++ if (!dd->in_sg || !dd->out_sg)
++ err = -EINVAL;
++ }
++ if (!err)
++ err = atmel_aes_crypt_dma_start(dd);
+ if (!err)
+ return; /* DMA started. Not fininishing. */
+ }
+@@ -1008,8 +1215,8 @@ static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd)
+
+ for (i = 0; i < ARRAY_SIZE(aes_algs); i++)
+ crypto_unregister_alg(&aes_algs[i]);
+- if (dd->hw_version >= 0x130)
+- crypto_unregister_alg(&aes_cfb64_alg[0]);
++ if (dd->caps.has_cfb64)
++ crypto_unregister_alg(&aes_cfb64_alg);
+ }
+
+ static int atmel_aes_register_algs(struct atmel_aes_dev *dd)
+@@ -1023,11 +1230,9 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd)
+ goto err_aes_algs;
+ }
+
+- atmel_aes_hw_version_init(dd);
+-
+- if (dd->hw_version >= 0x130) {
+- INIT_LIST_HEAD(&aes_cfb64_alg[0].cra_list);
+- err = crypto_register_alg(&aes_cfb64_alg[0]);
++ if (dd->caps.has_cfb64) {
++ INIT_LIST_HEAD(&aes_cfb64_alg.cra_list);
++ err = crypto_register_alg(&aes_cfb64_alg);
+ if (err)
+ goto err_aes_cfb64_alg;
+ }
+@@ -1043,10 +1248,158 @@ err_aes_algs:
+ return err;
+ }
+
++
++#ifdef CONFIG_OF
++static const struct of_device_id atmel_aes_dt_ids[] = {
++ { .compatible = "atmel,sam9g46-aes" },
++ { /* sentinel */ }
++};
++
++MODULE_DEVICE_TABLE(of, atmel_aes_dt_ids);
++
++static int atmel_aes_dma_of_init(struct device_node *np,
++ struct at_dma_slave *atslave, const char *name)
++{
++ struct of_phandle_args dma_spec;
++ struct device_node *dmac_np;
++ struct platform_device *dmac_pdev;
++ const __be32 *nbcells;
++ int ret;
++ int index;
++
++ index = of_property_match_string(np, "dma-name", name);
++ if (index < 0) {
++ pr_err("%s: dma-name property is required\n", np->full_name);
++ ret = -EINVAL;
++ goto err0;
++ }
++
++ ret = of_parse_phandle_with_args(np, "dma", "#dma-cells",
++ index, &dma_spec);
++ if (ret || !dma_spec.np) {
++ pr_err("%s: can't parse dma property (%d)\n",
++ np->full_name, ret);
++ goto err0;
++ }
++ dmac_np = dma_spec.np;
++
++ /* check property format */
++ nbcells = of_get_property(dmac_np, "#dma-cells", NULL);
++ if (!nbcells) {
++ pr_err("%s: #dma-cells property is required\n", np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ if (dma_spec.args_count != be32_to_cpup(nbcells)
++ || dma_spec.args_count != 1) {
++ pr_err("%s: wrong #dma-cells for %s\n",
++ np->full_name, dmac_np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ /* retreive DMA controller information */
++ dmac_pdev = of_find_device_by_node(dmac_np);
++ if (!dmac_pdev) {
++ pr_err("%s: unable to find pdev from DMA controller\n",
++ dmac_np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ /* now fill in the at_dma_slave structure */
++ atslave->dma_dev = &dmac_pdev->dev;
++ atslave->cfg = dma_spec.args[0];
++
++err1:
++ of_node_put(dma_spec.np);
++err0:
++ pr_debug("%s exited with status %d\n", __func__, ret);
++ return ret;
++}
++
++static struct crypto_platform_data __devinit*
++atmel_aes_of_init(struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ struct crypto_platform_data *pdata;
++ struct at_dma_slave *atslave;
++
++ if (!np) {
++ dev_err(&pdev->dev, "device node not found\n");
++ return ERR_PTR(-EINVAL);
++ }
++
++ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
++ if (!pdata) {
++ dev_err(&pdev->dev, "could not allocate memory for pdata\n");
++ return ERR_PTR(-ENOMEM);
++ }
++
++ pdata->dma_slave = devm_kzalloc(&pdev->dev,
++ sizeof(*(pdata->dma_slave)),
++ GFP_KERNEL);
++ if (!pdata->dma_slave) {
++ dev_err(&pdev->dev, "could not allocate memory for dma_slave\n");
++ devm_kfree(&pdev->dev, pdata);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ atslave = &pdata->dma_slave->txdata;
++ /* retrieve TX DMA configuration first */
++ if (atmel_aes_dma_of_init(np, atslave, "tx")) {
++ dev_err(&pdev->dev, "could not find TX DMA parameters\n");
++ devm_kfree(&pdev->dev, pdata->dma_slave);
++ devm_kfree(&pdev->dev, pdata);
++ return ERR_PTR(-EINVAL);
++ }
++
++ atslave = &pdata->dma_slave->rxdata;
++ /* retrieve RX DMA configuration first */
++ if (atmel_aes_dma_of_init(np, atslave, "rx")) {
++ dev_err(&pdev->dev, "could not find RX DMA parameters\n");
++ devm_kfree(&pdev->dev, pdata->dma_slave);
++ devm_kfree(&pdev->dev, pdata);
++ return ERR_PTR(-EINVAL);
++ }
++
++ return pdata;
++}
++#else /* CONFIG_OF */
++static inline struct crypto_platform_data*
++atmel_aes_of_init(struct platform_device *dev)
++{
++ return ERR_PTR(-EINVAL);
++}
++#endif
++
++static void atmel_aes_get_cap(struct atmel_aes_dev *dd)
++{
++ dd->caps.has_dualbuff = 0;
++ dd->caps.has_cfb64 = 0;
++ dd->caps.max_burst_size = 1;
++
++ /* keep only major version number */
++ switch (dd->hw_version & 0xff0) {
++ case 0x130:
++ dd->caps.has_dualbuff = 1;
++ dd->caps.has_cfb64 = 1;
++ dd->caps.max_burst_size = 4;
++ break;
++ case 0x120:
++ break;
++ default:
++ dev_warn(dd->dev,
++ "Unmanaged aes version, set minimum capabilities\n");
++ break;
++ }
++}
++
+ static int __devinit atmel_aes_probe(struct platform_device *pdev)
+ {
+ struct atmel_aes_dev *aes_dd;
+- struct aes_platform_data *pdata;
++ struct crypto_platform_data *pdata;
+ struct device *dev = &pdev->dev;
+ struct resource *aes_res;
+ unsigned long aes_phys_size;
+@@ -1054,8 +1407,11 @@ static int __devinit atmel_aes_probe(struct platform_device *pdev)
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+- err = -ENXIO;
+- goto aes_dd_err;
++ pdata = atmel_aes_of_init(pdev);
++ if (IS_ERR(pdata)) {
++ dev_err(&pdev->dev, "platform data not available\n");
++ return PTR_ERR(pdata);
++ }
+ }
+
+ aes_dd = kzalloc(sizeof(struct atmel_aes_dev), GFP_KERNEL);
+@@ -1106,7 +1462,7 @@ static int __devinit atmel_aes_probe(struct platform_device *pdev)
+ }
+
+ /* Initializing the clock */
+- aes_dd->iclk = clk_get(&pdev->dev, NULL);
++ aes_dd->iclk = clk_get(&pdev->dev, "aes_clk");
+ if (IS_ERR(aes_dd->iclk)) {
+ dev_err(dev, "clock intialization failed.\n");
+ err = PTR_ERR(aes_dd->iclk);
+@@ -1120,7 +1476,15 @@ static int __devinit atmel_aes_probe(struct platform_device *pdev)
+ goto aes_io_err;
+ }
+
+- err = atmel_aes_dma_init(aes_dd);
++ atmel_aes_hw_version_init(aes_dd);
++
++ atmel_aes_get_cap(aes_dd);
++
++ err = atmel_aes_buff_init(aes_dd);
++ if (err)
++ goto err_aes_buff;
++
++ err = atmel_aes_dma_init(aes_dd, pdata);
+ if (err)
+ goto err_aes_dma;
+
+@@ -1142,6 +1506,8 @@ err_algs:
+ spin_unlock(&atmel_aes.lock);
+ atmel_aes_dma_cleanup(aes_dd);
+ err_aes_dma:
++ atmel_aes_buff_cleanup(aes_dd);
++err_aes_buff:
+ iounmap(aes_dd->io_base);
+ aes_io_err:
+ clk_put(aes_dd->iclk);
+@@ -1191,15 +1557,27 @@ static int __devexit atmel_aes_remove(struct platform_device *pdev)
+ }
+
+ static struct platform_driver atmel_aes_driver = {
+- .probe = atmel_aes_probe,
+ .remove = __devexit_p(atmel_aes_remove),
+ .driver = {
+ .name = "atmel_aes",
+- .owner = THIS_MODULE,
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(atmel_aes_dt_ids),
+ },
+ };
+
+-module_platform_driver(atmel_aes_driver);
++static int __init atmel_aes_init(void)
++{
++ return platform_driver_probe(&atmel_aes_driver, atmel_aes_probe);
++}
++
++static void __exit atmel_aes_exit(void)
++{
++ platform_driver_unregister(&atmel_aes_driver);
++}
++
++late_initcall(atmel_aes_init); /* try to load after dma driver when built-in */
++module_exit(atmel_aes_exit);
++
+
+ MODULE_DESCRIPTION("Atmel AES hw acceleration support.");
+ MODULE_LICENSE("GPL v2");
+diff --git a/include/linux/platform_data/atmel-aes.h b/include/linux/platform_data/atmel-aes.h
+deleted file mode 100644
+index e7a1949..0000000
+--- a/include/linux/platform_data/atmel-aes.h
++++ /dev/null
+@@ -1,22 +0,0 @@
+-#ifndef __LINUX_ATMEL_AES_H
+-#define __LINUX_ATMEL_AES_H
+-
+-#include <mach/at_hdmac.h>
+-
+-/**
+- * struct aes_dma_data - DMA data for AES
+- */
+-struct aes_dma_data {
+- struct at_dma_slave txdata;
+- struct at_dma_slave rxdata;
+-};
+-
+-/**
+- * struct aes_platform_data - board-specific AES configuration
+- * @dma_slave: DMA slave interface to use in data transfers.
+- */
+-struct aes_platform_data {
+- struct aes_dma_data *dma_slave;
+-};
+-
+-#endif /* __LINUX_ATMEL_AES_H */
+diff --git a/include/linux/platform_data/atmel-crypto.h b/include/linux/platform_data/atmel-crypto.h
+new file mode 100644
+index 0000000..eddfca7
+--- /dev/null
++++ b/include/linux/platform_data/atmel-crypto.h
+@@ -0,0 +1,22 @@
++#ifndef __LINUX_ATMEL_CRYPTO_H
++#define __LINUX_ATMEL_CRYPTO_H
++
++#include <mach/at_hdmac.h>
++
++/**
++ * struct crypto_dma_data - DMA data for AES/TDES/SHA
++ */
++struct crypto_dma_data {
++ struct at_dma_slave txdata;
++ struct at_dma_slave rxdata;
++};
++
++/**
++ * struct tdes_platform_data - board-specific AES/TDES/SHA configuration
++ * @dma_slave: DMA slave interface to use in data transfers.
++ */
++struct crypto_platform_data {
++ struct crypto_dma_data *dma_slave;
++};
++
++#endif /* __LINUX_ATMEL_CRYPTO_H */
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0189-crypto-Atmel-TDES-add-device-tree-support.patch b/patches.at91/0189-crypto-Atmel-TDES-add-device-tree-support.patch
new file mode 100644
index 00000000000000..217ea3b27e17f7
--- /dev/null
+++ b/patches.at91/0189-crypto-Atmel-TDES-add-device-tree-support.patch
@@ -0,0 +1,932 @@
+From ba14d3bcc1c0a32bec0a0c1b8bb8035abef12fbc Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:16 +0200
+Subject: crypto: Atmel TDES; add device tree support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ drivers/crypto/atmel-tdes-regs.h | 2 +
+ drivers/crypto/atmel-tdes.c | 541 +++++++++++++++++++++++++++++++++++----
+ 2 files changed, 487 insertions(+), 56 deletions(-)
+
+diff --git a/drivers/crypto/atmel-tdes-regs.h b/drivers/crypto/atmel-tdes-regs.h
+index 5ac2a90..f86734d 100644
+--- a/drivers/crypto/atmel-tdes-regs.h
++++ b/drivers/crypto/atmel-tdes-regs.h
+@@ -69,6 +69,8 @@
+ #define TDES_XTEARNDR_XTEA_RNDS_MASK (0x3F << 0)
+ #define TDES_XTEARNDR_XTEA_RNDS_OFFSET 0
+
++#define TDES_HW_VERSION 0xFC
++
+ #define TDES_RPR 0x100
+ #define TDES_RCR 0x104
+ #define TDES_TPR 0x108
+diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c
+index eb2b61e..9de10bd 100644
+--- a/drivers/crypto/atmel-tdes.c
++++ b/drivers/crypto/atmel-tdes.c
+@@ -43,29 +43,37 @@
+ #include <crypto/des.h>
+ #include <crypto/hash.h>
+ #include <crypto/internal/hash.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_data/atmel-crypto.h>
+ #include "atmel-tdes-regs.h"
+
+ /* TDES flags */
+-#define TDES_FLAGS_MODE_MASK 0x007f
++#define TDES_FLAGS_MODE_MASK 0x00ff
+ #define TDES_FLAGS_ENCRYPT BIT(0)
+ #define TDES_FLAGS_CBC BIT(1)
+ #define TDES_FLAGS_CFB BIT(2)
+ #define TDES_FLAGS_CFB8 BIT(3)
+ #define TDES_FLAGS_CFB16 BIT(4)
+ #define TDES_FLAGS_CFB32 BIT(5)
+-#define TDES_FLAGS_OFB BIT(6)
++#define TDES_FLAGS_CFB64 BIT(6)
++#define TDES_FLAGS_OFB BIT(7)
+
+ #define TDES_FLAGS_INIT BIT(16)
+ #define TDES_FLAGS_FAST BIT(17)
+ #define TDES_FLAGS_BUSY BIT(18)
++#define TDES_FLAGS_DMA BIT(19)
+
+-#define ATMEL_TDES_QUEUE_LENGTH 1
++#define ATMEL_TDES_QUEUE_LENGTH 50
+
+ #define CFB8_BLOCK_SIZE 1
+ #define CFB16_BLOCK_SIZE 2
+ #define CFB32_BLOCK_SIZE 4
+-#define CFB64_BLOCK_SIZE 8
+
++struct atmel_tdes_caps {
++ bool has_dma;
++ u32 has_cfb_3keys;
++};
+
+ struct atmel_tdes_dev;
+
+@@ -75,12 +83,19 @@ struct atmel_tdes_ctx {
+ int keylen;
+ u32 key[3*DES_KEY_SIZE / sizeof(u32)];
+ unsigned long flags;
++
++ u16 block_size;
+ };
+
+ struct atmel_tdes_reqctx {
+ unsigned long mode;
+ };
+
++struct atmel_tdes_dma {
++ struct dma_chan *chan;
++ struct dma_slave_config dma_conf;
++};
++
+ struct atmel_tdes_dev {
+ struct list_head list;
+ unsigned long phys_base;
+@@ -104,8 +119,10 @@ struct atmel_tdes_dev {
+ size_t total;
+
+ struct scatterlist *in_sg;
++ unsigned int nb_in_sg;
+ size_t in_offset;
+ struct scatterlist *out_sg;
++ unsigned int nb_out_sg;
+ size_t out_offset;
+
+ size_t buflen;
+@@ -114,10 +131,16 @@ struct atmel_tdes_dev {
+ void *buf_in;
+ int dma_in;
+ dma_addr_t dma_addr_in;
++ struct atmel_tdes_dma dma_lch_in;
+
+ void *buf_out;
+ int dma_out;
+ dma_addr_t dma_addr_out;
++ struct atmel_tdes_dma dma_lch_out;
++
++ struct atmel_tdes_caps caps;
++
++ u32 hw_version;
+ };
+
+ struct atmel_tdes_drv {
+@@ -212,6 +235,31 @@ static int atmel_tdes_hw_init(struct atmel_tdes_dev *dd)
+ return 0;
+ }
+
++static inline unsigned int atmel_tdes_get_version(struct atmel_tdes_dev *dd)
++{
++ return atmel_tdes_read(dd, TDES_HW_VERSION) & 0x00000fff;
++}
++
++static void atmel_tdes_hw_version_init(struct atmel_tdes_dev *dd)
++{
++ atmel_tdes_hw_init(dd);
++
++ dd->hw_version = atmel_tdes_get_version(dd);
++
++ dev_info(dd->dev,
++ "version: 0x%x\n", dd->hw_version);
++
++ clk_disable_unprepare(dd->iclk);
++}
++
++static void atmel_tdes_dma_callback(void *data)
++{
++ struct atmel_tdes_dev *dd = data;
++
++ /* dma_lch_out - completed */
++ tasklet_schedule(&dd->done_task);
++}
++
+ static int atmel_tdes_write_ctrl(struct atmel_tdes_dev *dd)
+ {
+ int err;
+@@ -222,7 +270,9 @@ static int atmel_tdes_write_ctrl(struct atmel_tdes_dev *dd)
+ if (err)
+ return err;
+
+- atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS);
++ if (!dd->caps.has_dma)
++ atmel_tdes_write(dd, TDES_PTCR,
++ TDES_PTCR_TXTDIS | TDES_PTCR_RXTDIS);
+
+ /* MR register must be set before IV registers */
+ if (dd->ctx->keylen > (DES_KEY_SIZE << 1)) {
+@@ -246,6 +296,8 @@ static int atmel_tdes_write_ctrl(struct atmel_tdes_dev *dd)
+ valmr |= TDES_MR_CFBS_16b;
+ else if (dd->flags & TDES_FLAGS_CFB32)
+ valmr |= TDES_MR_CFBS_32b;
++ else if (dd->flags & TDES_FLAGS_CFB64)
++ valmr |= TDES_MR_CFBS_64b;
+ } else if (dd->flags & TDES_FLAGS_OFB) {
+ valmr |= TDES_MR_OPMOD_OFB;
+ }
+@@ -267,7 +319,7 @@ static int atmel_tdes_write_ctrl(struct atmel_tdes_dev *dd)
+ return 0;
+ }
+
+-static int atmel_tdes_crypt_dma_stop(struct atmel_tdes_dev *dd)
++static int atmel_tdes_crypt_pdc_stop(struct atmel_tdes_dev *dd)
+ {
+ int err = 0;
+ size_t count;
+@@ -293,7 +345,7 @@ static int atmel_tdes_crypt_dma_stop(struct atmel_tdes_dev *dd)
+ return err;
+ }
+
+-static int atmel_tdes_dma_init(struct atmel_tdes_dev *dd)
++static int atmel_tdes_buff_init(struct atmel_tdes_dev *dd)
+ {
+ int err = -ENOMEM;
+
+@@ -338,7 +390,7 @@ err_alloc:
+ return err;
+ }
+
+-static void atmel_tdes_dma_cleanup(struct atmel_tdes_dev *dd)
++static void atmel_tdes_buff_cleanup(struct atmel_tdes_dev *dd)
+ {
+ dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
+ DMA_FROM_DEVICE);
+@@ -348,7 +400,7 @@ static void atmel_tdes_dma_cleanup(struct atmel_tdes_dev *dd)
+ free_page((unsigned long)dd->buf_in);
+ }
+
+-static int atmel_tdes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
++static int atmel_tdes_crypt_pdc(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
+ dma_addr_t dma_addr_out, int length)
+ {
+ struct atmel_tdes_ctx *ctx = crypto_tfm_ctx(tfm);
+@@ -384,7 +436,76 @@ static int atmel_tdes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
+ return 0;
+ }
+
+-static int atmel_tdes_crypt_dma_start(struct atmel_tdes_dev *dd)
++static int atmel_tdes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
++ dma_addr_t dma_addr_out, int length)
++{
++ struct atmel_tdes_ctx *ctx = crypto_tfm_ctx(tfm);
++ struct atmel_tdes_dev *dd = ctx->dd;
++ struct scatterlist sg[2];
++ struct dma_async_tx_descriptor *in_desc, *out_desc;
++
++ dd->dma_size = length;
++
++ if (!(dd->flags & TDES_FLAGS_FAST)) {
++ dma_sync_single_for_device(dd->dev, dma_addr_in, length,
++ DMA_TO_DEVICE);
++ }
++
++ if (dd->flags & TDES_FLAGS_CFB8) {
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_1_BYTE;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_1_BYTE;
++ } else if (dd->flags & TDES_FLAGS_CFB16) {
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_2_BYTES;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_2_BYTES;
++ } else {
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ }
++
++ dmaengine_slave_config(dd->dma_lch_in.chan, &dd->dma_lch_in.dma_conf);
++ dmaengine_slave_config(dd->dma_lch_out.chan, &dd->dma_lch_out.dma_conf);
++
++ dd->flags |= TDES_FLAGS_DMA;
++
++ sg_init_table(&sg[0], 1);
++ sg_dma_address(&sg[0]) = dma_addr_in;
++ sg_dma_len(&sg[0]) = length;
++
++ sg_init_table(&sg[1], 1);
++ sg_dma_address(&sg[1]) = dma_addr_out;
++ sg_dma_len(&sg[1]) = length;
++
++ in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, &sg[0],
++ 1, DMA_MEM_TO_DEV,
++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ if (!in_desc)
++ return -EINVAL;
++
++ out_desc = dmaengine_prep_slave_sg(dd->dma_lch_out.chan, &sg[1],
++ 1, DMA_DEV_TO_MEM,
++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ if (!out_desc)
++ return -EINVAL;
++
++ out_desc->callback = atmel_tdes_dma_callback;
++ out_desc->callback_param = dd;
++
++ dmaengine_submit(out_desc);
++ dma_async_issue_pending(dd->dma_lch_out.chan);
++
++ dmaengine_submit(in_desc);
++ dma_async_issue_pending(dd->dma_lch_in.chan);
++
++ return 0;
++}
++
++static int atmel_tdes_crypt_start(struct atmel_tdes_dev *dd)
+ {
+ struct crypto_tfm *tfm = crypto_ablkcipher_tfm(
+ crypto_ablkcipher_reqtfm(dd->req));
+@@ -392,23 +513,23 @@ static int atmel_tdes_crypt_dma_start(struct atmel_tdes_dev *dd)
+ size_t count;
+ dma_addr_t addr_in, addr_out;
+
+- if (sg_is_last(dd->in_sg) && sg_is_last(dd->out_sg)) {
++ if ((!dd->in_offset) && (!dd->out_offset)) {
+ /* check for alignment */
+- in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32));
+- out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32));
+-
++ in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32)) &&
++ IS_ALIGNED(dd->in_sg->length, dd->ctx->block_size);
++ out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32)) &&
++ IS_ALIGNED(dd->out_sg->length, dd->ctx->block_size);
+ fast = in && out;
++
++ if (sg_dma_len(dd->in_sg) != sg_dma_len(dd->out_sg))
++ fast = 0;
+ }
+
++
+ if (fast) {
+ count = min(dd->total, sg_dma_len(dd->in_sg));
+ count = min(count, sg_dma_len(dd->out_sg));
+
+- if (count != dd->total) {
+- pr_err("request length != buffer length\n");
+- return -EINVAL;
+- }
+-
+ err = dma_map_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
+ if (!err) {
+ dev_err(dd->dev, "dma_map_sg() error\n");
+@@ -438,13 +559,16 @@ static int atmel_tdes_crypt_dma_start(struct atmel_tdes_dev *dd)
+ addr_out = dd->dma_addr_out;
+
+ dd->flags &= ~TDES_FLAGS_FAST;
+-
+ }
+
+ dd->total -= count;
+
+- err = atmel_tdes_crypt_dma(tfm, addr_in, addr_out, count);
+- if (err) {
++ if (dd->caps.has_dma)
++ err = atmel_tdes_crypt_dma(tfm, addr_in, addr_out, count);
++ else
++ err = atmel_tdes_crypt_pdc(tfm, addr_in, addr_out, count);
++
++ if (err && (dd->flags & TDES_FLAGS_FAST)) {
+ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
+ dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_TO_DEVICE);
+ }
+@@ -452,7 +576,6 @@ static int atmel_tdes_crypt_dma_start(struct atmel_tdes_dev *dd)
+ return err;
+ }
+
+-
+ static void atmel_tdes_finish_req(struct atmel_tdes_dev *dd, int err)
+ {
+ struct ablkcipher_request *req = dd->req;
+@@ -511,7 +634,7 @@ static int atmel_tdes_handle_queue(struct atmel_tdes_dev *dd,
+
+ err = atmel_tdes_write_ctrl(dd);
+ if (!err)
+- err = atmel_tdes_crypt_dma_start(dd);
++ err = atmel_tdes_crypt_start(dd);
+ if (err) {
+ /* des_task will not finish it, so do it here */
+ atmel_tdes_finish_req(dd, err);
+@@ -521,41 +644,145 @@ static int atmel_tdes_handle_queue(struct atmel_tdes_dev *dd,
+ return ret;
+ }
+
++static int atmel_tdes_crypt_dma_stop(struct atmel_tdes_dev *dd)
++{
++ int err = -EINVAL;
++ size_t count;
++
++ if (dd->flags & TDES_FLAGS_DMA) {
++ err = 0;
++ if (dd->flags & TDES_FLAGS_FAST) {
++ dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
++ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
++ } else {
++ dma_sync_single_for_device(dd->dev, dd->dma_addr_out,
++ dd->dma_size, DMA_FROM_DEVICE);
++
++ /* copy data */
++ count = atmel_tdes_sg_copy(&dd->out_sg, &dd->out_offset,
++ dd->buf_out, dd->buflen, dd->dma_size, 1);
++ if (count != dd->dma_size) {
++ err = -EINVAL;
++ pr_err("not all data converted: %u\n", count);
++ }
++ }
++ }
++ return err;
++}
+
+ static int atmel_tdes_crypt(struct ablkcipher_request *req, unsigned long mode)
+ {
+ struct atmel_tdes_ctx *ctx = crypto_ablkcipher_ctx(
+ crypto_ablkcipher_reqtfm(req));
+ struct atmel_tdes_reqctx *rctx = ablkcipher_request_ctx(req);
+- struct atmel_tdes_dev *dd;
+
+ if (mode & TDES_FLAGS_CFB8) {
+ if (!IS_ALIGNED(req->nbytes, CFB8_BLOCK_SIZE)) {
+ pr_err("request size is not exact amount of CFB8 blocks\n");
+ return -EINVAL;
+ }
++ ctx->block_size = CFB8_BLOCK_SIZE;
+ } else if (mode & TDES_FLAGS_CFB16) {
+ if (!IS_ALIGNED(req->nbytes, CFB16_BLOCK_SIZE)) {
+ pr_err("request size is not exact amount of CFB16 blocks\n");
+ return -EINVAL;
+ }
++ ctx->block_size = CFB16_BLOCK_SIZE;
+ } else if (mode & TDES_FLAGS_CFB32) {
+ if (!IS_ALIGNED(req->nbytes, CFB32_BLOCK_SIZE)) {
+ pr_err("request size is not exact amount of CFB32 blocks\n");
+ return -EINVAL;
+ }
+- } else if (!IS_ALIGNED(req->nbytes, DES_BLOCK_SIZE)) {
+- pr_err("request size is not exact amount of DES blocks\n");
+- return -EINVAL;
++ ctx->block_size = CFB32_BLOCK_SIZE;
++ } else {
++ if (!IS_ALIGNED(req->nbytes, DES_BLOCK_SIZE)) {
++ pr_err("request size is not exact amount of DES blocks\n");
++ return -EINVAL;
++ }
++ ctx->block_size = DES_BLOCK_SIZE;
+ }
+
+- dd = atmel_tdes_find_dev(ctx);
+- if (!dd)
++ rctx->mode = mode;
++
++ return atmel_tdes_handle_queue(ctx->dd, req);
++}
++
++static bool atmel_tdes_filter(struct dma_chan *chan, void *slave)
++{
++ struct at_dma_slave *sl = slave;
++
++ if (sl && sl->dma_dev == chan->device->dev) {
++ chan->private = sl;
++ return true;
++ } else {
++ return false;
++ }
++}
++
++static int atmel_tdes_dma_init(struct atmel_tdes_dev *dd,
++ struct crypto_platform_data *pdata)
++{
++ int err = -ENOMEM;
++ dma_cap_mask_t mask_in, mask_out;
++
++ if (pdata && pdata->dma_slave->txdata.dma_dev &&
++ pdata->dma_slave->rxdata.dma_dev) {
++
++ /* Try to grab 2 DMA channels */
++ dma_cap_zero(mask_in);
++ dma_cap_set(DMA_SLAVE, mask_in);
++
++ dd->dma_lch_in.chan = dma_request_channel(mask_in,
++ atmel_tdes_filter, &pdata->dma_slave->rxdata);
++
++ if (!dd->dma_lch_in.chan)
++ goto err_dma_in;
++
++ dd->dma_lch_in.dma_conf.direction = DMA_MEM_TO_DEV;
++ dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base +
++ TDES_IDATA1R;
++ dd->dma_lch_in.dma_conf.src_maxburst = 1;
++ dd->dma_lch_in.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_in.dma_conf.dst_maxburst = 1;
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_in.dma_conf.device_fc = false;
++
++ dma_cap_zero(mask_out);
++ dma_cap_set(DMA_SLAVE, mask_out);
++ dd->dma_lch_out.chan = dma_request_channel(mask_out,
++ atmel_tdes_filter, &pdata->dma_slave->txdata);
++
++ if (!dd->dma_lch_out.chan)
++ goto err_dma_out;
++
++ dd->dma_lch_out.dma_conf.direction = DMA_DEV_TO_MEM;
++ dd->dma_lch_out.dma_conf.src_addr = dd->phys_base +
++ TDES_ODATA1R;
++ dd->dma_lch_out.dma_conf.src_maxburst = 1;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_out.dma_conf.dst_maxburst = 1;
++ dd->dma_lch_out.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_out.dma_conf.device_fc = false;
++
++ return 0;
++ } else {
+ return -ENODEV;
++ }
+
+- rctx->mode = mode;
++err_dma_out:
++ dma_release_channel(dd->dma_lch_in.chan);
++err_dma_in:
++ return err;
++}
+
+- return atmel_tdes_handle_queue(dd, req);
++static void atmel_tdes_dma_cleanup(struct atmel_tdes_dev *dd)
++{
++ dma_release_channel(dd->dma_lch_in.chan);
++ dma_release_channel(dd->dma_lch_out.chan);
+ }
+
+ static int atmel_des_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
+@@ -595,7 +822,8 @@ static int atmel_tdes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
+ /*
+ * HW bug in cfb 3-keys mode.
+ */
+- if (strstr(alg_name, "cfb") && (keylen != 2*DES_KEY_SIZE)) {
++ if (!ctx->dd->caps.has_cfb_3keys && strstr(alg_name, "cfb")
++ && (keylen != 2*DES_KEY_SIZE)) {
+ crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+ } else if ((keylen != 2*DES_KEY_SIZE) && (keylen != 3*DES_KEY_SIZE)) {
+@@ -683,8 +911,15 @@ static int atmel_tdes_ofb_decrypt(struct ablkcipher_request *req)
+
+ static int atmel_tdes_cra_init(struct crypto_tfm *tfm)
+ {
++ struct atmel_tdes_ctx *ctx = crypto_tfm_ctx(tfm);
++ struct atmel_tdes_dev *dd;
++
+ tfm->crt_ablkcipher.reqsize = sizeof(struct atmel_tdes_reqctx);
+
++ dd = atmel_tdes_find_dev(ctx);
++ if (!dd)
++ return -ENODEV;
++
+ return 0;
+ }
+
+@@ -700,7 +935,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x7,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -720,7 +955,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x7,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -741,7 +976,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x7,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -783,7 +1018,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = CFB16_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x1,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -804,7 +1039,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = CFB32_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -825,7 +1060,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x7,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -846,7 +1081,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x7,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -866,7 +1101,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x7,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -887,7 +1122,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x7,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -929,7 +1164,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = CFB16_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x1,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -950,7 +1185,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = CFB32_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -971,7 +1206,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x7,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -999,14 +1234,24 @@ static void atmel_tdes_done_task(unsigned long data)
+ struct atmel_tdes_dev *dd = (struct atmel_tdes_dev *) data;
+ int err;
+
+- err = atmel_tdes_crypt_dma_stop(dd);
++ if (!(dd->flags & TDES_FLAGS_DMA))
++ err = atmel_tdes_crypt_pdc_stop(dd);
++ else
++ err = atmel_tdes_crypt_dma_stop(dd);
+
+ err = dd->err ? : err;
+
+ if (dd->total && !err) {
+- err = atmel_tdes_crypt_dma_start(dd);
++ if (dd->flags & TDES_FLAGS_FAST) {
++ dd->in_sg = sg_next(dd->in_sg);
++ dd->out_sg = sg_next(dd->out_sg);
++ if (!dd->in_sg || !dd->out_sg)
++ err = -EINVAL;
++ }
++ if (!err)
++ err = atmel_tdes_crypt_start(dd);
+ if (!err)
+- return;
++ return; /* DMA started. Not fininishing. */
+ }
+
+ atmel_tdes_finish_req(dd, err);
+@@ -1059,9 +1304,157 @@ err_tdes_algs:
+ return err;
+ }
+
++#ifdef CONFIG_OF
++static const struct of_device_id atmel_tdes_dt_ids[] = {
++ { .compatible = "atmel,sam9g46-tdes" },
++ { /* sentinel */ }
++};
++
++MODULE_DEVICE_TABLE(of, atmel_tdes_dt_ids);
++
++static int atmel_tdes_dma_of_init(struct device_node *np,
++ struct at_dma_slave *atslave, const char *name)
++{
++ struct of_phandle_args dma_spec;
++ struct device_node *dmac_np;
++ struct platform_device *dmac_pdev;
++ const __be32 *nbcells;
++ int ret;
++ int index;
++
++ index = of_property_match_string(np, "dma-name", name);
++ if (index < 0) {
++ pr_err("%s: dma-name property is required\n", np->full_name);
++ ret = -EINVAL;
++ goto err0;
++ }
++
++ ret = of_parse_phandle_with_args(np, "dma", "#dma-cells",
++ index, &dma_spec);
++ if (ret || !dma_spec.np) {
++ pr_err("%s: can't parse dma property (%d)\n",
++ np->full_name, ret);
++ goto err0;
++ }
++ dmac_np = dma_spec.np;
++
++ /* check property format */
++ nbcells = of_get_property(dmac_np, "#dma-cells", NULL);
++ if (!nbcells) {
++ pr_err("%s: #dma-cells property is required\n", np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ if (dma_spec.args_count != be32_to_cpup(nbcells)
++ || dma_spec.args_count != 1) {
++ pr_err("%s: wrong #dma-cells for %s\n",
++ np->full_name, dmac_np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ /* retreive DMA controller information */
++ dmac_pdev = of_find_device_by_node(dmac_np);
++ if (!dmac_pdev) {
++ pr_err("%s: unable to find pdev from DMA controller\n",
++ dmac_np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ /* now fill in the at_dma_slave structure */
++ atslave->dma_dev = &dmac_pdev->dev;
++ atslave->cfg = dma_spec.args[0];
++
++err1:
++ of_node_put(dma_spec.np);
++err0:
++ pr_debug("%s exited with status %d\n", __func__, ret);
++ return ret;
++}
++
++
++static struct crypto_platform_data __devinit*
++atmel_tdes_of_init(struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ struct crypto_platform_data *pdata;
++ struct at_dma_slave *atslave;
++
++ if (!np) {
++ dev_err(&pdev->dev, "device node not found\n");
++ return ERR_PTR(-EINVAL);
++ }
++
++ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
++ if (!pdata) {
++ dev_err(&pdev->dev, "could not allocate memory for pdata\n");
++ return ERR_PTR(-ENOMEM);
++ }
++
++ pdata->dma_slave = devm_kzalloc(&pdev->dev,
++ sizeof(*(pdata->dma_slave)),
++ GFP_KERNEL);
++ if (!pdata->dma_slave) {
++ dev_err(&pdev->dev, "could not allocate memory for dma_slave\n");
++ devm_kfree(&pdev->dev, pdata);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ atslave = &pdata->dma_slave->txdata;
++ /* retrieve TX DMA configuration first */
++ if (atmel_tdes_dma_of_init(np, atslave, "tx")) {
++ dev_err(&pdev->dev, "could not find TX DMA parameters\n");
++ devm_kfree(&pdev->dev, pdata->dma_slave);
++ devm_kfree(&pdev->dev, pdata);
++ return ERR_PTR(-EINVAL);
++ }
++
++ atslave = &pdata->dma_slave->rxdata;
++ /* retrieve RX DMA configuration first */
++ if (atmel_tdes_dma_of_init(np, atslave, "rx")) {
++ dev_err(&pdev->dev, "could not find RX DMA parameters\n");
++ devm_kfree(&pdev->dev, pdata->dma_slave);
++ devm_kfree(&pdev->dev, pdata);
++ return ERR_PTR(-EINVAL);
++ }
++
++ return pdata;
++}
++#else /* CONFIG_OF */
++static inline struct crypto_platform_data*
++atmel_tdes_of_init(struct platform_device *dev)
++{
++ return ERR_PTR(-EINVAL);
++}
++#endif
++
++static void atmel_tdes_get_cap(struct atmel_tdes_dev *dd)
++{
++
++ dd->caps.has_dma = 0;
++ dd->caps.has_cfb_3keys = 0;
++
++ /* keep only major version number */
++ switch (dd->hw_version & 0xf00) {
++ case 0x700:
++ dd->caps.has_dma = 1;
++ dd->caps.has_cfb_3keys = 1;
++ break;
++ case 0x600:
++ break;
++ default:
++ dev_warn(dd->dev,
++ "Unmanaged tdes version, set minimum capabilities\n");
++ break;
++ }
++}
++
+ static int __devinit atmel_tdes_probe(struct platform_device *pdev)
+ {
+ struct atmel_tdes_dev *tdes_dd;
++ struct crypto_platform_data *pdata;
+ struct device *dev = &pdev->dev;
+ struct resource *tdes_res;
+ unsigned long tdes_phys_size;
+@@ -1115,7 +1508,7 @@ static int __devinit atmel_tdes_probe(struct platform_device *pdev)
+ }
+
+ /* Initializing the clock */
+- tdes_dd->iclk = clk_get(&pdev->dev, NULL);
++ tdes_dd->iclk = clk_get(&pdev->dev, "tdes_clk");
+ if (IS_ERR(tdes_dd->iclk)) {
+ dev_err(dev, "clock intialization failed.\n");
+ err = PTR_ERR(tdes_dd->iclk);
+@@ -1129,9 +1522,27 @@ static int __devinit atmel_tdes_probe(struct platform_device *pdev)
+ goto tdes_io_err;
+ }
+
+- err = atmel_tdes_dma_init(tdes_dd);
++ atmel_tdes_hw_version_init(tdes_dd);
++
++ atmel_tdes_get_cap(tdes_dd);
++
++ err = atmel_tdes_buff_init(tdes_dd);
+ if (err)
+- goto err_tdes_dma;
++ goto err_tdes_buff;
++
++ if (tdes_dd->caps.has_dma) {
++ pdata = pdev->dev.platform_data;
++ if (!pdata) {
++ pdata = atmel_tdes_of_init(pdev);
++ if (IS_ERR(pdata)) {
++ dev_err(&pdev->dev, "platform data not available\n");
++ goto err_pdata;
++ }
++ }
++ err = atmel_tdes_dma_init(tdes_dd, pdata);
++ if (err)
++ goto err_tdes_dma;
++ }
+
+ spin_lock(&atmel_tdes.lock);
+ list_add_tail(&tdes_dd->list, &atmel_tdes.dev_list);
+@@ -1149,8 +1560,12 @@ err_algs:
+ spin_lock(&atmel_tdes.lock);
+ list_del(&tdes_dd->list);
+ spin_unlock(&atmel_tdes.lock);
+- atmel_tdes_dma_cleanup(tdes_dd);
++ if (tdes_dd->caps.has_dma)
++ atmel_tdes_dma_cleanup(tdes_dd);
+ err_tdes_dma:
++err_pdata:
++ atmel_tdes_buff_cleanup(tdes_dd);
++err_tdes_buff:
+ iounmap(tdes_dd->io_base);
+ tdes_io_err:
+ clk_put(tdes_dd->iclk);
+@@ -1184,7 +1599,10 @@ static int __devexit atmel_tdes_remove(struct platform_device *pdev)
+ tasklet_kill(&tdes_dd->done_task);
+ tasklet_kill(&tdes_dd->queue_task);
+
+- atmel_tdes_dma_cleanup(tdes_dd);
++ if (tdes_dd->caps.has_dma)
++ atmel_tdes_dma_cleanup(tdes_dd);
++
++ atmel_tdes_buff_cleanup(tdes_dd);
+
+ iounmap(tdes_dd->io_base);
+
+@@ -1200,15 +1618,26 @@ static int __devexit atmel_tdes_remove(struct platform_device *pdev)
+ }
+
+ static struct platform_driver atmel_tdes_driver = {
+- .probe = atmel_tdes_probe,
+ .remove = __devexit_p(atmel_tdes_remove),
+ .driver = {
+ .name = "atmel_tdes",
+- .owner = THIS_MODULE,
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(atmel_tdes_dt_ids),
+ },
+ };
+
+-module_platform_driver(atmel_tdes_driver);
++static int __init atmel_tdes_init(void)
++{
++ return platform_driver_probe(&atmel_tdes_driver, atmel_tdes_probe);
++}
++
++static void __exit atmel_tdes_exit(void)
++{
++ platform_driver_unregister(&atmel_tdes_driver);
++}
++
++late_initcall(atmel_tdes_init); /* try to load after dma driver when built-in */
++module_exit(atmel_tdes_exit);
+
+ MODULE_DESCRIPTION("Atmel DES/TDES hw acceleration support.");
+ MODULE_LICENSE("GPL v2");
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0190-crypto-Atmel-SHA-add-device-tree-support.patch b/patches.at91/0190-crypto-Atmel-SHA-add-device-tree-support.patch
new file mode 100644
index 00000000000000..d1db361f3bfaf8
--- /dev/null
+++ b/patches.at91/0190-crypto-Atmel-SHA-add-device-tree-support.patch
@@ -0,0 +1,1123 @@
+From 8d47f5d2568287ff9d0cddc524939d9cb1f6db72 Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:17 +0200
+Subject: crypto: Atmel SHA; add device tree support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ drivers/crypto/atmel-sha-regs.h | 7 +-
+ drivers/crypto/atmel-sha.c | 698 ++++++++++++++++++++++++++++++++++------
+ 2 files changed, 608 insertions(+), 97 deletions(-)
+
+diff --git a/drivers/crypto/atmel-sha-regs.h b/drivers/crypto/atmel-sha-regs.h
+index dc53a20..83b2d74 100644
+--- a/drivers/crypto/atmel-sha-regs.h
++++ b/drivers/crypto/atmel-sha-regs.h
+@@ -14,10 +14,13 @@
+ #define SHA_MR_MODE_MANUAL 0x0
+ #define SHA_MR_MODE_AUTO 0x1
+ #define SHA_MR_MODE_PDC 0x2
+-#define SHA_MR_DUALBUFF (1 << 3)
+ #define SHA_MR_PROCDLY (1 << 4)
+ #define SHA_MR_ALGO_SHA1 (0 << 8)
+ #define SHA_MR_ALGO_SHA256 (1 << 8)
++#define SHA_MR_ALGO_SHA384 (2 << 8)
++#define SHA_MR_ALGO_SHA512 (3 << 8)
++#define SHA_MR_ALGO_SHA224 (4 << 8)
++#define SHA_MR_DUALBUFF (1 << 16)
+
+ #define SHA_IER 0x10
+ #define SHA_IDR 0x14
+@@ -33,6 +36,8 @@
+ #define SHA_ISR_URAT_MR (0x2 << 12)
+ #define SHA_ISR_URAT_WO (0x5 << 12)
+
++#define SHA_HW_VERSION 0xFC
++
+ #define SHA_TPR 0x108
+ #define SHA_TCR 0x10C
+ #define SHA_TNPR 0x118
+diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
+index f938b9d..f66f1c8 100644
+--- a/drivers/crypto/atmel-sha.c
++++ b/drivers/crypto/atmel-sha.c
+@@ -43,6 +43,9 @@
+ #include <crypto/sha.h>
+ #include <crypto/hash.h>
+ #include <crypto/internal/hash.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_data/atmel-crypto.h>
+ #include "atmel-sha-regs.h"
+
+ /* SHA flags */
+@@ -57,11 +60,12 @@
+ #define SHA_FLAGS_FINUP BIT(16)
+ #define SHA_FLAGS_SG BIT(17)
+ #define SHA_FLAGS_SHA1 BIT(18)
+-#define SHA_FLAGS_SHA256 BIT(19)
+-#define SHA_FLAGS_ERROR BIT(20)
+-#define SHA_FLAGS_PAD BIT(21)
+-
+-#define SHA_FLAGS_DUALBUFF BIT(24)
++#define SHA_FLAGS_SHA224 BIT(19)
++#define SHA_FLAGS_SHA256 BIT(20)
++#define SHA_FLAGS_SHA384 BIT(21)
++#define SHA_FLAGS_SHA512 BIT(22)
++#define SHA_FLAGS_ERROR BIT(23)
++#define SHA_FLAGS_PAD BIT(24)
+
+ #define SHA_OP_UPDATE 1
+ #define SHA_OP_FINAL 2
+@@ -70,6 +74,12 @@
+
+ #define ATMEL_SHA_DMA_THRESHOLD 56
+
++struct atmel_sha_caps {
++ bool has_dma;
++ bool has_dualbuff;
++ bool has_sha224;
++ bool has_sha_384_512;
++};
+
+ struct atmel_sha_dev;
+
+@@ -78,8 +88,8 @@ struct atmel_sha_reqctx {
+ unsigned long flags;
+ unsigned long op;
+
+- u8 digest[SHA256_DIGEST_SIZE] __aligned(sizeof(u32));
+- size_t digcnt;
++ u8 digest[SHA512_DIGEST_SIZE] __aligned(sizeof(u32));
++ u64 digcnt[2];
+ size_t bufcnt;
+ size_t buflen;
+ dma_addr_t dma_addr;
+@@ -89,6 +99,8 @@ struct atmel_sha_reqctx {
+ unsigned int offset; /* offset in current sg */
+ unsigned int total; /* total request */
+
++ size_t block_size;
++
+ u8 buffer[0] __aligned(sizeof(u32));
+ };
+
+@@ -102,7 +114,12 @@ struct atmel_sha_ctx {
+
+ };
+
+-#define ATMEL_SHA_QUEUE_LENGTH 1
++#define ATMEL_SHA_QUEUE_LENGTH 50
++
++struct atmel_sha_dma {
++ struct dma_chan *chan;
++ struct dma_slave_config dma_conf;
++};
+
+ struct atmel_sha_dev {
+ struct list_head list;
+@@ -119,6 +136,12 @@ struct atmel_sha_dev {
+ unsigned long flags;
+ struct crypto_queue queue;
+ struct ahash_request *req;
++
++ struct atmel_sha_dma dma_lch_in;
++
++ struct atmel_sha_caps caps;
++
++ u32 hw_version;
+ };
+
+ struct atmel_sha_drv {
+@@ -142,14 +165,6 @@ static inline void atmel_sha_write(struct atmel_sha_dev *dd,
+ writel_relaxed(value, dd->io_base + offset);
+ }
+
+-static void atmel_sha_dualbuff_test(struct atmel_sha_dev *dd)
+-{
+- atmel_sha_write(dd, SHA_MR, SHA_MR_DUALBUFF);
+-
+- if (atmel_sha_read(dd, SHA_MR) & SHA_MR_DUALBUFF)
+- dd->flags |= SHA_FLAGS_DUALBUFF;
+-}
+-
+ static size_t atmel_sha_append_sg(struct atmel_sha_reqctx *ctx)
+ {
+ size_t count;
+@@ -193,19 +208,40 @@ static size_t atmel_sha_append_sg(struct atmel_sha_reqctx *ctx)
+ static void atmel_sha_fill_padding(struct atmel_sha_reqctx *ctx, int length)
+ {
+ unsigned int index, padlen;
+- u64 bits;
+- u64 size;
+-
+- bits = (ctx->bufcnt + ctx->digcnt + length) << 3;
+- size = cpu_to_be64(bits);
+-
+- index = ctx->bufcnt & 0x3f;
+- padlen = (index < 56) ? (56 - index) : ((64+56) - index);
+- *(ctx->buffer + ctx->bufcnt) = 0x80;
+- memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1);
+- memcpy(ctx->buffer + ctx->bufcnt + padlen, &size, 8);
+- ctx->bufcnt += padlen + 8;
+- ctx->flags |= SHA_FLAGS_PAD;
++ u64 bits[2];
++ u64 size[2];
++
++ size[0] = ctx->digcnt[0];
++ size[1] = ctx->digcnt[1];
++
++ size[0] += ctx->bufcnt;
++ if (size[0] < ctx->bufcnt)
++ size[1]++;
++
++ size[0] += length;
++ if (size[0] < length)
++ size[1]++;
++
++ bits[1] = cpu_to_be64(size[0] << 3);
++ bits[0] = cpu_to_be64(size[1] << 3 | size[0] >> 61);
++
++ if (ctx->flags & (SHA_FLAGS_SHA384 | SHA_FLAGS_SHA512)) {
++ index = ctx->bufcnt & 0x7f;
++ padlen = (index < 112) ? (112 - index) : ((128+112) - index);
++ *(ctx->buffer + ctx->bufcnt) = 0x80;
++ memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1);
++ memcpy(ctx->buffer + ctx->bufcnt + padlen, bits, 16);
++ ctx->bufcnt += padlen + 16;
++ ctx->flags |= SHA_FLAGS_PAD;
++ } else {
++ index = ctx->bufcnt & 0x3f;
++ padlen = (index < 56) ? (56 - index) : ((64+56) - index);
++ *(ctx->buffer + ctx->bufcnt) = 0x80;
++ memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1);
++ memcpy(ctx->buffer + ctx->bufcnt + padlen, &bits[1], 8);
++ ctx->bufcnt += padlen + 8;
++ ctx->flags |= SHA_FLAGS_PAD;
++ }
+ }
+
+ static int atmel_sha_init(struct ahash_request *req)
+@@ -236,13 +272,35 @@ static int atmel_sha_init(struct ahash_request *req)
+ dev_dbg(dd->dev, "init: digest size: %d\n",
+ crypto_ahash_digestsize(tfm));
+
+- if (crypto_ahash_digestsize(tfm) == SHA1_DIGEST_SIZE)
++ switch (crypto_ahash_digestsize(tfm)) {
++ case SHA1_DIGEST_SIZE:
+ ctx->flags |= SHA_FLAGS_SHA1;
+- else if (crypto_ahash_digestsize(tfm) == SHA256_DIGEST_SIZE)
++ ctx->block_size = SHA1_BLOCK_SIZE;
++ break;
++ case SHA224_DIGEST_SIZE:
++ ctx->flags |= SHA_FLAGS_SHA224;
++ ctx->block_size = SHA224_BLOCK_SIZE;
++ break;
++ case SHA256_DIGEST_SIZE:
+ ctx->flags |= SHA_FLAGS_SHA256;
++ ctx->block_size = SHA256_BLOCK_SIZE;
++ break;
++ case SHA384_DIGEST_SIZE:
++ ctx->flags |= SHA_FLAGS_SHA384;
++ ctx->block_size = SHA384_BLOCK_SIZE;
++ break;
++ case SHA512_DIGEST_SIZE:
++ ctx->flags |= SHA_FLAGS_SHA512;
++ ctx->block_size = SHA512_BLOCK_SIZE;
++ break;
++ default:
++ return -EINVAL;
++ break;
++ }
+
+ ctx->bufcnt = 0;
+- ctx->digcnt = 0;
++ ctx->digcnt[0] = 0;
++ ctx->digcnt[1] = 0;
+ ctx->buflen = SHA_BUFFER_LEN;
+
+ return 0;
+@@ -254,19 +312,28 @@ static void atmel_sha_write_ctrl(struct atmel_sha_dev *dd, int dma)
+ u32 valcr = 0, valmr = SHA_MR_MODE_AUTO;
+
+ if (likely(dma)) {
+- atmel_sha_write(dd, SHA_IER, SHA_INT_TXBUFE);
++ if (!dd->caps.has_dma)
++ atmel_sha_write(dd, SHA_IER, SHA_INT_TXBUFE);
+ valmr = SHA_MR_MODE_PDC;
+- if (dd->flags & SHA_FLAGS_DUALBUFF)
+- valmr = SHA_MR_DUALBUFF;
++ if (dd->caps.has_dualbuff)
++ valmr |= SHA_MR_DUALBUFF;
+ } else {
+ atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY);
+ }
+
+- if (ctx->flags & SHA_FLAGS_SHA256)
++ if (ctx->flags & SHA_FLAGS_SHA1)
++ valmr |= SHA_MR_ALGO_SHA1;
++ else if (ctx->flags & SHA_FLAGS_SHA224)
++ valmr |= SHA_MR_ALGO_SHA224;
++ else if (ctx->flags & SHA_FLAGS_SHA256)
+ valmr |= SHA_MR_ALGO_SHA256;
++ else if (ctx->flags & SHA_FLAGS_SHA384)
++ valmr |= SHA_MR_ALGO_SHA384;
++ else if (ctx->flags & SHA_FLAGS_SHA512)
++ valmr |= SHA_MR_ALGO_SHA512;
+
+ /* Setting CR_FIRST only for the first iteration */
+- if (!ctx->digcnt)
++ if (!(ctx->digcnt[0] || ctx->digcnt[1]))
+ valcr = SHA_CR_FIRST;
+
+ atmel_sha_write(dd, SHA_CR, valcr);
+@@ -280,13 +347,15 @@ static int atmel_sha_xmit_cpu(struct atmel_sha_dev *dd, const u8 *buf,
+ int count, len32;
+ const u32 *buffer = (const u32 *)buf;
+
+- dev_dbg(dd->dev, "xmit_cpu: digcnt: %d, length: %d, final: %d\n",
+- ctx->digcnt, length, final);
++ dev_dbg(dd->dev, "xmit_cpu: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n",
++ ctx->digcnt[1], ctx->digcnt[0], length, final);
+
+ atmel_sha_write_ctrl(dd, 0);
+
+ /* should be non-zero before next lines to disable clocks later */
+- ctx->digcnt += length;
++ ctx->digcnt[0] += length;
++ if (ctx->digcnt[0] < length)
++ ctx->digcnt[1]++;
+
+ if (final)
+ dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */
+@@ -307,8 +376,8 @@ static int atmel_sha_xmit_pdc(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
+ int len32;
+
+- dev_dbg(dd->dev, "xmit_pdc: digcnt: %d, length: %d, final: %d\n",
+- ctx->digcnt, length1, final);
++ dev_dbg(dd->dev, "xmit_pdc: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n",
++ ctx->digcnt[1], ctx->digcnt[0], length1, final);
+
+ len32 = DIV_ROUND_UP(length1, sizeof(u32));
+ atmel_sha_write(dd, SHA_PTCR, SHA_PTCR_TXTDIS);
+@@ -322,7 +391,9 @@ static int atmel_sha_xmit_pdc(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
+ atmel_sha_write_ctrl(dd, 1);
+
+ /* should be non-zero before next lines to disable clocks later */
+- ctx->digcnt += length1;
++ ctx->digcnt[0] += length1;
++ if (ctx->digcnt[0] < length1)
++ ctx->digcnt[1]++;
+
+ if (final)
+ dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */
+@@ -335,6 +406,86 @@ static int atmel_sha_xmit_pdc(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
+ return -EINPROGRESS;
+ }
+
++static void atmel_sha_dma_callback(void *data)
++{
++ struct atmel_sha_dev *dd = data;
++
++ /* dma_lch_in - completed - wait DATRDY */
++ atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY);
++}
++
++static int atmel_sha_xmit_dma(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
++ size_t length1, dma_addr_t dma_addr2, size_t length2, int final)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
++ struct dma_async_tx_descriptor *in_desc;
++ struct scatterlist sg[2];
++
++ dev_dbg(dd->dev, "xmit_dma: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n",
++ ctx->digcnt[1], ctx->digcnt[0], length1, final);
++
++ if (ctx->flags & (SHA_FLAGS_SHA1 | SHA_FLAGS_SHA224 |
++ SHA_FLAGS_SHA256)) {
++ dd->dma_lch_in.dma_conf.src_maxburst = 16;
++ dd->dma_lch_in.dma_conf.dst_maxburst = 16;
++ } else {
++ dd->dma_lch_in.dma_conf.src_maxburst = 32;
++ dd->dma_lch_in.dma_conf.dst_maxburst = 32;
++ }
++
++ dmaengine_slave_config(dd->dma_lch_in.chan, &dd->dma_lch_in.dma_conf);
++
++ if (length2) {
++ sg_init_table(sg, 2);
++ sg_dma_address(&sg[0]) = dma_addr1;
++ sg_dma_len(&sg[0]) = length1;
++ sg_dma_address(&sg[1]) = dma_addr2;
++ sg_dma_len(&sg[1]) = length2;
++ in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, sg, 2,
++ DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ } else {
++ sg_init_table(sg, 1);
++ sg_dma_address(&sg[0]) = dma_addr1;
++ sg_dma_len(&sg[0]) = length1;
++ in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, sg, 1,
++ DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ }
++ if (!in_desc)
++ return -EINVAL;
++
++ in_desc->callback = atmel_sha_dma_callback;
++ in_desc->callback_param = dd;
++
++ atmel_sha_write_ctrl(dd, 1);
++
++ /* should be non-zero before next lines to disable clocks later */
++ ctx->digcnt[0] += length1;
++ if (ctx->digcnt[0] < length1)
++ ctx->digcnt[1]++;
++
++ if (final)
++ dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */
++
++ dd->flags |= SHA_FLAGS_DMA_ACTIVE;
++
++ /* Start DMA transfer */
++ dmaengine_submit(in_desc);
++ dma_async_issue_pending(dd->dma_lch_in.chan);
++
++ return -EINPROGRESS;
++}
++
++static int atmel_sha_xmit_start(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
++ size_t length1, dma_addr_t dma_addr2, size_t length2, int final)
++{
++ if (dd->caps.has_dma)
++ return atmel_sha_xmit_dma(dd, dma_addr1, length1,
++ dma_addr2, length2, final);
++ else
++ return atmel_sha_xmit_pdc(dd, dma_addr1, length1,
++ dma_addr2, length2, final);
++}
++
+ static int atmel_sha_update_cpu(struct atmel_sha_dev *dd)
+ {
+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
+@@ -342,7 +493,6 @@ static int atmel_sha_update_cpu(struct atmel_sha_dev *dd)
+
+ atmel_sha_append_sg(ctx);
+ atmel_sha_fill_padding(ctx, 0);
+-
+ bufcnt = ctx->bufcnt;
+ ctx->bufcnt = 0;
+
+@@ -354,17 +504,17 @@ static int atmel_sha_xmit_dma_map(struct atmel_sha_dev *dd,
+ size_t length, int final)
+ {
+ ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer,
+- ctx->buflen + SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
++ ctx->buflen + ctx->block_size, DMA_TO_DEVICE);
+ if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
+ dev_err(dd->dev, "dma %u bytes error\n", ctx->buflen +
+- SHA1_BLOCK_SIZE);
++ ctx->block_size);
+ return -EINVAL;
+ }
+
+ ctx->flags &= ~SHA_FLAGS_SG;
+
+ /* next call does not fail... so no unmap in the case of error */
+- return atmel_sha_xmit_pdc(dd, ctx->dma_addr, length, 0, 0, final);
++ return atmel_sha_xmit_start(dd, ctx->dma_addr, length, 0, 0, final);
+ }
+
+ static int atmel_sha_update_dma_slow(struct atmel_sha_dev *dd)
+@@ -377,8 +527,8 @@ static int atmel_sha_update_dma_slow(struct atmel_sha_dev *dd)
+
+ final = (ctx->flags & SHA_FLAGS_FINUP) && !ctx->total;
+
+- dev_dbg(dd->dev, "slow: bufcnt: %u, digcnt: %d, final: %d\n",
+- ctx->bufcnt, ctx->digcnt, final);
++ dev_dbg(dd->dev, "slow: bufcnt: %u, digcnt: 0x%llx 0x%llx, final: %d\n",
++ ctx->bufcnt, ctx->digcnt[1], ctx->digcnt[0], final);
+
+ if (final)
+ atmel_sha_fill_padding(ctx, 0);
+@@ -405,30 +555,25 @@ static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
+ if (ctx->bufcnt || ctx->offset)
+ return atmel_sha_update_dma_slow(dd);
+
+- dev_dbg(dd->dev, "fast: digcnt: %d, bufcnt: %u, total: %u\n",
+- ctx->digcnt, ctx->bufcnt, ctx->total);
++ dev_dbg(dd->dev, "fast: digcnt: 0x%llx 0x%llx, bufcnt: %u, total: %u\n",
++ ctx->digcnt[1], ctx->digcnt[0], ctx->bufcnt, ctx->total);
+
+ sg = ctx->sg;
+
+ if (!IS_ALIGNED(sg->offset, sizeof(u32)))
+ return atmel_sha_update_dma_slow(dd);
+
+- if (!sg_is_last(sg) && !IS_ALIGNED(sg->length, SHA1_BLOCK_SIZE))
+- /* size is not SHA1_BLOCK_SIZE aligned */
++ if (!sg_is_last(sg) && !IS_ALIGNED(sg->length, ctx->block_size))
++ /* size is not ctx->block_size aligned */
+ return atmel_sha_update_dma_slow(dd);
+
+ length = min(ctx->total, sg->length);
+
+ if (sg_is_last(sg)) {
+ if (!(ctx->flags & SHA_FLAGS_FINUP)) {
+- /* not last sg must be SHA1_BLOCK_SIZE aligned */
+- tail = length & (SHA1_BLOCK_SIZE - 1);
++ /* not last sg must be ctx->block_size aligned */
++ tail = length & (ctx->block_size - 1);
+ length -= tail;
+- if (length == 0) {
+- /* offset where to start slow */
+- ctx->offset = length;
+- return atmel_sha_update_dma_slow(dd);
+- }
+ }
+ }
+
+@@ -439,7 +584,7 @@ static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
+
+ /* Add padding */
+ if (final) {
+- tail = length & (SHA1_BLOCK_SIZE - 1);
++ tail = length & (ctx->block_size - 1);
+ length -= tail;
+ ctx->total += tail;
+ ctx->offset = length; /* offset where to start slow */
+@@ -450,10 +595,10 @@ static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
+ atmel_sha_fill_padding(ctx, length);
+
+ ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer,
+- ctx->buflen + SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
++ ctx->buflen + ctx->block_size, DMA_TO_DEVICE);
+ if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
+ dev_err(dd->dev, "dma %u bytes error\n",
+- ctx->buflen + SHA1_BLOCK_SIZE);
++ ctx->buflen + ctx->block_size);
+ return -EINVAL;
+ }
+
+@@ -461,7 +606,7 @@ static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
+ ctx->flags &= ~SHA_FLAGS_SG;
+ count = ctx->bufcnt;
+ ctx->bufcnt = 0;
+- return atmel_sha_xmit_pdc(dd, ctx->dma_addr, count, 0,
++ return atmel_sha_xmit_start(dd, ctx->dma_addr, count, 0,
+ 0, final);
+ } else {
+ ctx->sg = sg;
+@@ -475,7 +620,7 @@ static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
+
+ count = ctx->bufcnt;
+ ctx->bufcnt = 0;
+- return atmel_sha_xmit_pdc(dd, sg_dma_address(ctx->sg),
++ return atmel_sha_xmit_start(dd, sg_dma_address(ctx->sg),
+ length, ctx->dma_addr, count, final);
+ }
+ }
+@@ -488,7 +633,7 @@ static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
+ ctx->flags |= SHA_FLAGS_SG;
+
+ /* next call does not fail... so no unmap in the case of error */
+- return atmel_sha_xmit_pdc(dd, sg_dma_address(ctx->sg), length, 0,
++ return atmel_sha_xmit_start(dd, sg_dma_address(ctx->sg), length, 0,
+ 0, final);
+ }
+
+@@ -503,12 +648,13 @@ static int atmel_sha_update_dma_stop(struct atmel_sha_dev *dd)
+ if (ctx->sg)
+ ctx->offset = 0;
+ }
+- if (ctx->flags & SHA_FLAGS_PAD)
++ if (ctx->flags & SHA_FLAGS_PAD) {
+ dma_unmap_single(dd->dev, ctx->dma_addr,
+- ctx->buflen + SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
++ ctx->buflen + ctx->block_size, DMA_TO_DEVICE);
++ }
+ } else {
+ dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen +
+- SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
++ ctx->block_size, DMA_TO_DEVICE);
+ }
+
+ return 0;
+@@ -520,8 +666,8 @@ static int atmel_sha_update_req(struct atmel_sha_dev *dd)
+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
+ int err;
+
+- dev_dbg(dd->dev, "update_req: total: %u, digcnt: %d, finup: %d\n",
+- ctx->total, ctx->digcnt, (ctx->flags & SHA_FLAGS_FINUP) != 0);
++ dev_dbg(dd->dev, "update_req: total: %u, digcnt: 0x%llx 0x%llx\n",
++ ctx->total, ctx->digcnt[1], ctx->digcnt[0]);
+
+ if (ctx->flags & SHA_FLAGS_CPU)
+ err = atmel_sha_update_cpu(dd);
+@@ -529,8 +675,8 @@ static int atmel_sha_update_req(struct atmel_sha_dev *dd)
+ err = atmel_sha_update_dma_start(dd);
+
+ /* wait for dma completion before can take more data */
+- dev_dbg(dd->dev, "update: err: %d, digcnt: %d\n",
+- err, ctx->digcnt);
++ dev_dbg(dd->dev, "update: err: %d, digcnt: 0x%llx 0%llx\n",
++ err, ctx->digcnt[1], ctx->digcnt[0]);
+
+ return err;
+ }
+@@ -567,12 +713,21 @@ static void atmel_sha_copy_hash(struct ahash_request *req)
+ u32 *hash = (u32 *)ctx->digest;
+ int i;
+
+- if (likely(ctx->flags & SHA_FLAGS_SHA1))
++ if (ctx->flags & SHA_FLAGS_SHA1)
+ for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++)
+ hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
+- else
++ else if (ctx->flags & SHA_FLAGS_SHA224)
++ for (i = 0; i < SHA224_DIGEST_SIZE / sizeof(u32); i++)
++ hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
++ else if (ctx->flags & SHA_FLAGS_SHA256)
+ for (i = 0; i < SHA256_DIGEST_SIZE / sizeof(u32); i++)
+ hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
++ else if (ctx->flags & SHA_FLAGS_SHA384)
++ for (i = 0; i < SHA384_DIGEST_SIZE / sizeof(u32); i++)
++ hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
++ else
++ for (i = 0; i < SHA512_DIGEST_SIZE / sizeof(u32); i++)
++ hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
+ }
+
+ static void atmel_sha_copy_ready_hash(struct ahash_request *req)
+@@ -582,10 +737,16 @@ static void atmel_sha_copy_ready_hash(struct ahash_request *req)
+ if (!req->result)
+ return;
+
+- if (likely(ctx->flags & SHA_FLAGS_SHA1))
++ if (ctx->flags & SHA_FLAGS_SHA1)
+ memcpy(req->result, ctx->digest, SHA1_DIGEST_SIZE);
+- else
++ else if (ctx->flags & SHA_FLAGS_SHA224)
++ memcpy(req->result, ctx->digest, SHA224_DIGEST_SIZE);
++ else if (ctx->flags & SHA_FLAGS_SHA256)
+ memcpy(req->result, ctx->digest, SHA256_DIGEST_SIZE);
++ else if (ctx->flags & SHA_FLAGS_SHA384)
++ memcpy(req->result, ctx->digest, SHA384_DIGEST_SIZE);
++ else
++ memcpy(req->result, ctx->digest, SHA512_DIGEST_SIZE);
+ }
+
+ static int atmel_sha_finish(struct ahash_request *req)
+@@ -594,11 +755,11 @@ static int atmel_sha_finish(struct ahash_request *req)
+ struct atmel_sha_dev *dd = ctx->dd;
+ int err = 0;
+
+- if (ctx->digcnt)
++ if (ctx->digcnt[0] || ctx->digcnt[1])
+ atmel_sha_copy_ready_hash(req);
+
+- dev_dbg(dd->dev, "digcnt: %d, bufcnt: %d\n", ctx->digcnt,
+- ctx->bufcnt);
++ dev_dbg(dd->dev, "digcnt: 0x%llx 0x%llx, bufcnt: %d\n", ctx->digcnt[1],
++ ctx->digcnt[0], ctx->bufcnt);
+
+ return err;
+ }
+@@ -633,9 +794,8 @@ static int atmel_sha_hw_init(struct atmel_sha_dev *dd)
+ {
+ clk_prepare_enable(dd->iclk);
+
+- if (SHA_FLAGS_INIT & dd->flags) {
++ if (!(SHA_FLAGS_INIT & dd->flags)) {
+ atmel_sha_write(dd, SHA_CR, SHA_CR_SWRST);
+- atmel_sha_dualbuff_test(dd);
+ dd->flags |= SHA_FLAGS_INIT;
+ dd->err = 0;
+ }
+@@ -643,6 +803,23 @@ static int atmel_sha_hw_init(struct atmel_sha_dev *dd)
+ return 0;
+ }
+
++static inline unsigned int atmel_sha_get_version(struct atmel_sha_dev *dd)
++{
++ return atmel_sha_read(dd, SHA_HW_VERSION) & 0x00000fff;
++}
++
++static void atmel_sha_hw_version_init(struct atmel_sha_dev *dd)
++{
++ atmel_sha_hw_init(dd);
++
++ dd->hw_version = atmel_sha_get_version(dd);
++
++ dev_info(dd->dev,
++ "version: 0x%x\n", dd->hw_version);
++
++ clk_disable_unprepare(dd->iclk);
++}
++
+ static int atmel_sha_handle_queue(struct atmel_sha_dev *dd,
+ struct ahash_request *req)
+ {
+@@ -687,10 +864,9 @@ static int atmel_sha_handle_queue(struct atmel_sha_dev *dd,
+
+ if (ctx->op == SHA_OP_UPDATE) {
+ err = atmel_sha_update_req(dd);
+- if (err != -EINPROGRESS && (ctx->flags & SHA_FLAGS_FINUP)) {
++ if (err != -EINPROGRESS && (ctx->flags & SHA_FLAGS_FINUP))
+ /* no final() after finup() */
+ err = atmel_sha_final_req(dd);
+- }
+ } else if (ctx->op == SHA_OP_FINAL) {
+ err = atmel_sha_final_req(dd);
+ }
+@@ -813,7 +989,7 @@ static int atmel_sha_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base)
+ }
+ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+ sizeof(struct atmel_sha_reqctx) +
+- SHA_BUFFER_LEN + SHA256_BLOCK_SIZE);
++ SHA_BUFFER_LEN + SHA512_BLOCK_SIZE);
+
+ return 0;
+ }
+@@ -831,7 +1007,7 @@ static void atmel_sha_cra_exit(struct crypto_tfm *tfm)
+ tctx->fallback = NULL;
+ }
+
+-static struct ahash_alg sha_algs[] = {
++static struct ahash_alg sha_1_256_algs[] = {
+ {
+ .init = atmel_sha_init,
+ .update = atmel_sha_update,
+@@ -880,6 +1056,79 @@ static struct ahash_alg sha_algs[] = {
+ },
+ };
+
++static struct ahash_alg sha_224_alg = {
++ .init = atmel_sha_init,
++ .update = atmel_sha_update,
++ .final = atmel_sha_final,
++ .finup = atmel_sha_finup,
++ .digest = atmel_sha_digest,
++ .halg = {
++ .digestsize = SHA224_DIGEST_SIZE,
++ .base = {
++ .cra_name = "sha224",
++ .cra_driver_name = "atmel-sha224",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_ASYNC |
++ CRYPTO_ALG_NEED_FALLBACK,
++ .cra_blocksize = SHA224_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_sha_ctx),
++ .cra_alignmask = 0,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_sha_cra_init,
++ .cra_exit = atmel_sha_cra_exit,
++ }
++ }
++};
++
++static struct ahash_alg sha_384_512_algs[] = {
++{
++ .init = atmel_sha_init,
++ .update = atmel_sha_update,
++ .final = atmel_sha_final,
++ .finup = atmel_sha_finup,
++ .digest = atmel_sha_digest,
++ .halg = {
++ .digestsize = SHA384_DIGEST_SIZE,
++ .base = {
++ .cra_name = "sha384",
++ .cra_driver_name = "atmel-sha384",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_ASYNC |
++ CRYPTO_ALG_NEED_FALLBACK,
++ .cra_blocksize = SHA384_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_sha_ctx),
++ .cra_alignmask = 0x3,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_sha_cra_init,
++ .cra_exit = atmel_sha_cra_exit,
++ }
++ }
++},
++{
++ .init = atmel_sha_init,
++ .update = atmel_sha_update,
++ .final = atmel_sha_final,
++ .finup = atmel_sha_finup,
++ .digest = atmel_sha_digest,
++ .halg = {
++ .digestsize = SHA512_DIGEST_SIZE,
++ .base = {
++ .cra_name = "sha512",
++ .cra_driver_name = "atmel-sha512",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_ASYNC |
++ CRYPTO_ALG_NEED_FALLBACK,
++ .cra_blocksize = SHA512_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_sha_ctx),
++ .cra_alignmask = 0x3,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_sha_cra_init,
++ .cra_exit = atmel_sha_cra_exit,
++ }
++ }
++},
++};
++
+ static void atmel_sha_done_task(unsigned long data)
+ {
+ struct atmel_sha_dev *dd = (struct atmel_sha_dev *)data;
+@@ -946,32 +1195,251 @@ static void atmel_sha_unregister_algs(struct atmel_sha_dev *dd)
+ {
+ int i;
+
+- for (i = 0; i < ARRAY_SIZE(sha_algs); i++)
+- crypto_unregister_ahash(&sha_algs[i]);
++ for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++)
++ crypto_unregister_ahash(&sha_1_256_algs[i]);
++
++ if (dd->caps.has_sha224)
++ crypto_unregister_ahash(&sha_224_alg);
++
++ if (dd->caps.has_sha_384_512) {
++ for (i = 0; i < ARRAY_SIZE(sha_384_512_algs); i++)
++ crypto_unregister_ahash(&sha_384_512_algs[i]);
++ }
+ }
+
+ static int atmel_sha_register_algs(struct atmel_sha_dev *dd)
+ {
+ int err, i, j;
+
+- for (i = 0; i < ARRAY_SIZE(sha_algs); i++) {
+- err = crypto_register_ahash(&sha_algs[i]);
++ for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++) {
++ err = crypto_register_ahash(&sha_1_256_algs[i]);
+ if (err)
+- goto err_sha_algs;
++ goto err_sha_1_256_algs;
++ }
++
++ if (dd->caps.has_sha224) {
++ err = crypto_register_ahash(&sha_224_alg);
++ if (err)
++ goto err_sha_224_algs;
++ }
++
++ if (dd->caps.has_sha_384_512) {
++ for (i = 0; i < ARRAY_SIZE(sha_384_512_algs); i++) {
++ err = crypto_register_ahash(&sha_384_512_algs[i]);
++ if (err)
++ goto err_sha_384_512_algs;
++ }
+ }
+
+ return 0;
+
+-err_sha_algs:
++err_sha_384_512_algs:
++ for (j = 0; j < i; j++)
++ crypto_unregister_ahash(&sha_384_512_algs[j]);
++ crypto_unregister_ahash(&sha_224_alg);
++err_sha_224_algs:
++ i = ARRAY_SIZE(sha_1_256_algs);
++err_sha_1_256_algs:
+ for (j = 0; j < i; j++)
+- crypto_unregister_ahash(&sha_algs[j]);
++ crypto_unregister_ahash(&sha_1_256_algs[j]);
+
+ return err;
+ }
+
++static bool atmel_sha_filter(struct dma_chan *chan, void *slave)
++{
++ struct at_dma_slave *sl = slave;
++
++ if (sl && sl->dma_dev == chan->device->dev) {
++ chan->private = sl;
++ return true;
++ } else {
++ return false;
++ }
++}
++
++static int atmel_sha_dma_init(struct atmel_sha_dev *dd,
++ struct crypto_platform_data *pdata)
++{
++ int err = -ENOMEM;
++ dma_cap_mask_t mask_in;
++
++ if (pdata && pdata->dma_slave->rxdata.dma_dev) {
++ /* Try to grab DMA channel */
++ dma_cap_zero(mask_in);
++ dma_cap_set(DMA_SLAVE, mask_in);
++
++ dd->dma_lch_in.chan = dma_request_channel(mask_in,
++ atmel_sha_filter, &pdata->dma_slave->rxdata);
++
++ if (!dd->dma_lch_in.chan)
++ return err;
++
++ dd->dma_lch_in.dma_conf.direction = DMA_MEM_TO_DEV;
++ dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base +
++ SHA_REG_DIN(0);
++ dd->dma_lch_in.dma_conf.src_maxburst = 1;
++ dd->dma_lch_in.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_in.dma_conf.dst_maxburst = 1;
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_in.dma_conf.device_fc = false;
++
++ return 0;
++ }
++
++ return -ENODEV;
++}
++
++static void atmel_sha_dma_cleanup(struct atmel_sha_dev *dd)
++{
++ dma_release_channel(dd->dma_lch_in.chan);
++}
++
++
++#ifdef CONFIG_OF
++static const struct of_device_id atmel_sha_dt_ids[] = {
++ { .compatible = "atmel,sam9g46-sha" },
++ { /* sentinel */ }
++};
++
++MODULE_DEVICE_TABLE(of, atmel_sha_dt_ids);
++
++static int atmel_sha_dma_of_init(struct device_node *np,
++ struct at_dma_slave *atslave)
++{
++ struct of_phandle_args dma_spec;
++ struct device_node *dmac_np;
++ struct platform_device *dmac_pdev;
++ const __be32 *nbcells;
++ int ret;
++
++ ret = of_parse_phandle_with_args(np, "dma", "#dma-cells", 0, &dma_spec);
++ if (ret || !dma_spec.np) {
++ pr_err("%s: can't parse dma property (%d)\n",
++ np->full_name, ret);
++ goto err0;
++ }
++ dmac_np = dma_spec.np;
++
++ /* check property format */
++ nbcells = of_get_property(dmac_np, "#dma-cells", NULL);
++ if (!nbcells) {
++ pr_err("%s: #dma-cells property is required\n", np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ if (dma_spec.args_count != be32_to_cpup(nbcells)
++ || dma_spec.args_count != 1) {
++ pr_err("%s: wrong #dma-cells for %s\n",
++ np->full_name, dmac_np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ /* retreive DMA controller information */
++ dmac_pdev = of_find_device_by_node(dmac_np);
++ if (!dmac_pdev) {
++ pr_err("%s: unable to find pdev from DMA controller\n",
++ dmac_np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ /* now fill in the at_dma_slave structure */
++ atslave->dma_dev = &dmac_pdev->dev;
++ atslave->cfg = dma_spec.args[0];
++
++err1:
++ of_node_put(dma_spec.np);
++err0:
++ pr_debug("%s exited with status %d\n", __func__, ret);
++ return ret;
++}
++
++
++static struct crypto_platform_data __devinit*
++atmel_sha_of_init(struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ struct crypto_platform_data *pdata;
++ struct at_dma_slave *atslave;
++
++ if (!np) {
++ dev_err(&pdev->dev, "device node not found\n");
++ return ERR_PTR(-EINVAL);
++ }
++
++ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
++ if (!pdata) {
++ dev_err(&pdev->dev, "could not allocate memory for pdata\n");
++ return ERR_PTR(-ENOMEM);
++ }
++
++ pdata->dma_slave = devm_kzalloc(&pdev->dev,
++ sizeof(*(pdata->dma_slave)),
++ GFP_KERNEL);
++ if (!pdata->dma_slave) {
++ dev_err(&pdev->dev, "could not allocate memory for dma_slave\n");
++ devm_kfree(&pdev->dev, pdata);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ atslave = &pdata->dma_slave->rxdata;
++ /* retrieve RX DMA configuration first */
++ if (atmel_sha_dma_of_init(np, atslave)) {
++ dev_err(&pdev->dev, "could not find RX DMA parameters\n");
++ devm_kfree(&pdev->dev, pdata->dma_slave);
++ devm_kfree(&pdev->dev, pdata);
++ return ERR_PTR(-EINVAL);
++ }
++
++ return pdata;
++}
++#else /* CONFIG_OF */
++static inline struct crypto_platform_data*
++atmel_sha_of_init(struct platform_device *dev)
++{
++ return ERR_PTR(-EINVAL);
++}
++#endif
++
++static void atmel_sha_get_cap(struct atmel_sha_dev *dd)
++{
++
++ dd->caps.has_dma = 0;
++ dd->caps.has_dualbuff = 0;
++ dd->caps.has_sha224 = 0;
++ dd->caps.has_sha_384_512 = 0;
++
++ /* keep only major version number */
++ switch (dd->hw_version & 0xff0) {
++ case 0x410:
++ dd->caps.has_dma = 1;
++ dd->caps.has_dualbuff = 1;
++ dd->caps.has_sha224 = 1;
++ dd->caps.has_sha_384_512 = 1;
++ break;
++ case 0x400:
++ dd->caps.has_dma = 1;
++ dd->caps.has_dualbuff = 1;
++ dd->caps.has_sha224 = 1;
++ break;
++ case 0x320:
++ break;
++ default:
++ dev_warn(dd->dev,
++ "Unmanaged sha version, set minimum capabilities\n");
++ break;
++ }
++}
++
+ static int __devinit atmel_sha_probe(struct platform_device *pdev)
+ {
+ struct atmel_sha_dev *sha_dd;
++ struct crypto_platform_data *pdata;
+ struct device *dev = &pdev->dev;
+ struct resource *sha_res;
+ unsigned long sha_phys_size;
+@@ -1023,7 +1491,7 @@ static int __devinit atmel_sha_probe(struct platform_device *pdev)
+ }
+
+ /* Initializing the clock */
+- sha_dd->iclk = clk_get(&pdev->dev, NULL);
++ sha_dd->iclk = clk_get(&pdev->dev, "sha_clk");
+ if (IS_ERR(sha_dd->iclk)) {
+ dev_err(dev, "clock intialization failed.\n");
+ err = PTR_ERR(sha_dd->iclk);
+@@ -1037,6 +1505,24 @@ static int __devinit atmel_sha_probe(struct platform_device *pdev)
+ goto sha_io_err;
+ }
+
++ atmel_sha_hw_version_init(sha_dd);
++
++ atmel_sha_get_cap(sha_dd);
++
++ if (sha_dd->caps.has_dma) {
++ pdata = pdev->dev.platform_data;
++ if (!pdata) {
++ pdata = atmel_sha_of_init(pdev);
++ if (IS_ERR(pdata)) {
++ dev_err(&pdev->dev, "platform data not available\n");
++ goto err_pdata;
++ }
++ }
++ err = atmel_sha_dma_init(sha_dd, pdata);
++ if (err)
++ goto err_sha_dma;
++ }
++
+ spin_lock(&atmel_sha.lock);
+ list_add_tail(&sha_dd->list, &atmel_sha.dev_list);
+ spin_unlock(&atmel_sha.lock);
+@@ -1053,6 +1539,10 @@ err_algs:
+ spin_lock(&atmel_sha.lock);
+ list_del(&sha_dd->list);
+ spin_unlock(&atmel_sha.lock);
++ if (sha_dd->caps.has_dma)
++ atmel_sha_dma_cleanup(sha_dd);
++err_sha_dma:
++err_pdata:
+ iounmap(sha_dd->io_base);
+ sha_io_err:
+ clk_put(sha_dd->iclk);
+@@ -1083,6 +1573,9 @@ static int __devexit atmel_sha_remove(struct platform_device *pdev)
+
+ tasklet_kill(&sha_dd->done_task);
+
++ if (sha_dd->caps.has_dma)
++ atmel_sha_dma_cleanup(sha_dd);
++
+ iounmap(sha_dd->io_base);
+
+ clk_put(sha_dd->iclk);
+@@ -1097,15 +1590,28 @@ static int __devexit atmel_sha_remove(struct platform_device *pdev)
+ }
+
+ static struct platform_driver atmel_sha_driver = {
+- .probe = atmel_sha_probe,
+ .remove = __devexit_p(atmel_sha_remove),
+ .driver = {
+ .name = "atmel_sha",
++ .of_match_table = of_match_ptr(atmel_sha_dt_ids),
+ .owner = THIS_MODULE,
+ },
+ };
+
+-module_platform_driver(atmel_sha_driver);
++static int __init atmel_sha_drv_init(void)
++{
++ return platform_driver_probe(&atmel_sha_driver, atmel_sha_probe);
++}
++
++static void __exit atmel_sha_drv_exit(void)
++{
++ platform_driver_unregister(&atmel_sha_driver);
++}
++
++/* try to load after dma driver when built-in */
++late_initcall(atmel_sha_drv_init);
++module_exit(atmel_sha_drv_exit);
++
+
+ MODULE_DESCRIPTION("Atmel SHA1/SHA256 hw acceleration support.");
+ MODULE_LICENSE("GPL v2");
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0191-crypto-Atmel-Test-add-SHA224-SHA384-and-SHA512-suppo.patch b/patches.at91/0191-crypto-Atmel-Test-add-SHA224-SHA384-and-SHA512-suppo.patch
new file mode 100644
index 00000000000000..2184541b65f28d
--- /dev/null
+++ b/patches.at91/0191-crypto-Atmel-Test-add-SHA224-SHA384-and-SHA512-suppo.patch
@@ -0,0 +1,81 @@
+From 352ab878f8ee1afe1f15dc14bb8c9ced486f5316 Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:18 +0200
+Subject: crypto: Atmel Test; add SHA224, SHA384 and SHA512 support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ drivers/crypto/atmel-test.c | 25 +++++++++++++++++++------
+ 1 file changed, 19 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/crypto/atmel-test.c b/drivers/crypto/atmel-test.c
+index 4a23db5..d9eb80d 100644
+--- a/drivers/crypto/atmel-test.c
++++ b/drivers/crypto/atmel-test.c
+@@ -41,7 +41,11 @@ static char *iv16 =
+
+ #define SHA1_MSG_LEN 20
+ #define SHA256_MSG_LEN 32
+-static char sha_out_buf[SHA256_MSG_LEN];
++#define SHA224_MSG_LEN 28
++#define SHA384_MSG_LEN 48
++#define SHA512_MSG_LEN 64
++
++static char sha_out_buf[SHA512_MSG_LEN];
+
+ #define TVMEMSIZE 4
+ static char *tvmem[TVMEMSIZE];
+@@ -331,7 +335,7 @@ static int dlen = 64;
+ module_param_named(dlen, dlen, int,
+ S_IRUGO | S_IWUSR | S_IWGRP);
+
+-char *ahash_algs[] = {"sha1", "sha256"};
++char *ahash_algs[] = {"sha1", "sha256", "sha224", "sha384", "sha512"};
+
+ char *acipher_algs[] = {
+ "ecb(des)", "cbc(des)", "cfb(des)", "cfb32(des)",
+@@ -347,6 +351,7 @@ static int __init init_main(void)
+ char *buf_in;
+ char *buf_out;
+ char *buf_res;
++ size_t outlen;
+
+ if ((dlen <= 0) || (dlen > TVMEMSIZE*PAGE_SIZE)) {
+ printk(KERN_ERR " 0 < dlen <= %i\n",
+@@ -382,15 +387,23 @@ static int __init init_main(void)
+ ARRAY_SIZE(ahash_algs));
+ goto exit;
+ }
++ switch (mode) {
++ case 0:outlen = SHA1_MSG_LEN; break;
++ case 1:outlen = SHA256_MSG_LEN; break;
++ case 2:outlen = SHA224_MSG_LEN; break;
++ case 3:outlen = SHA384_MSG_LEN; break;
++ case 4:outlen = SHA512_MSG_LEN; break;
++ }
++
+ printk(KERN_INFO "\n%s digest_req\n", ahash_algs[mode]);
+ hmac_sha_digest(ahash_algs[mode], buf_in, dlen, sha_out_buf,
+- mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
+- hexdump(sha_out_buf, mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
++ outlen);
++ hexdump(sha_out_buf, outlen);
+
+ printk(KERN_INFO "\n%s update_req\n", ahash_algs[mode]);
+ hmac_sha_update(ahash_algs[mode], buf_in, dlen, sha_out_buf,
+- mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
+- hexdump(sha_out_buf, mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
++ outlen);
++ hexdump(sha_out_buf, outlen);
+ } else {
+ mode -= 10;
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0192-pinctrl-core-device-tree-mapping-table-parsing-suppo.patch b/patches.at91/0192-pinctrl-core-device-tree-mapping-table-parsing-suppo.patch
new file mode 100644
index 00000000000000..e6c070d8a77dcb
--- /dev/null
+++ b/patches.at91/0192-pinctrl-core-device-tree-mapping-table-parsing-suppo.patch
@@ -0,0 +1,537 @@
+From f67e075c4847120d480cd6347da04359f4fd7f8c Mon Sep 17 00:00:00 2001
+From: Stephen Warren <swarren@wwwdotorg.org>
+Date: Fri, 23 Mar 2012 10:29:46 -0600
+Subject: pinctrl: core device tree mapping table parsing support
+
+During pinctrl_get(), if the client device has a device tree node, look
+for the common pinctrl properties there. If found, parse the referenced
+device tree nodes, with the help of the pinctrl drivers, and generate
+mapping table entries from them.
+
+During pinctrl_put(), free any results of device tree parsing.
+
+Acked-by: Dong Aisheng <dong.aisheng@linaro.org>
+Signed-off-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/Makefile | 1 +
+ drivers/pinctrl/core.c | 72 +++++++++---
+ drivers/pinctrl/core.h | 11 +-
+ drivers/pinctrl/devicetree.c | 249 ++++++++++++++++++++++++++++++++++++++++
+ drivers/pinctrl/devicetree.h | 35 ++++++
+ include/linux/pinctrl/pinctrl.h | 7 ++
+ 6 files changed, 357 insertions(+), 18 deletions(-)
+ create mode 100644 drivers/pinctrl/devicetree.c
+ create mode 100644 drivers/pinctrl/devicetree.h
+
+diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
+index 6d4150b..049c9fb 100644
+--- a/drivers/pinctrl/Makefile
++++ b/drivers/pinctrl/Makefile
+@@ -5,6 +5,7 @@ ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG
+ obj-$(CONFIG_PINCTRL) += core.o
+ obj-$(CONFIG_PINMUX) += pinmux.o
+ obj-$(CONFIG_PINCONF) += pinconf.o
++obj-$(CONFIG_OF) += devicetree.o
+ obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
+ obj-$(CONFIG_PINCTRL_PXA3xx) += pinctrl-pxa3xx.o
+ obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index df6296c..832f71d 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -26,6 +26,7 @@
+ #include <linux/pinctrl/pinctrl.h>
+ #include <linux/pinctrl/machine.h>
+ #include "core.h"
++#include "devicetree.h"
+ #include "pinmux.h"
+ #include "pinconf.h"
+
+@@ -45,7 +46,7 @@ struct pinctrl_maps {
+ DEFINE_MUTEX(pinctrl_mutex);
+
+ /* Global list of pin control devices (struct pinctrl_dev) */
+-static LIST_HEAD(pinctrldev_list);
++LIST_HEAD(pinctrldev_list);
+
+ /* List of pin controller handles (struct pinctrl) */
+ static LIST_HEAD(pinctrl_list);
+@@ -579,6 +580,13 @@ static struct pinctrl *create_pinctrl(struct device *dev)
+ }
+ p->dev = dev;
+ INIT_LIST_HEAD(&p->states);
++ INIT_LIST_HEAD(&p->dt_maps);
++
++ ret = pinctrl_dt_to_map(p);
++ if (ret < 0) {
++ kfree(p);
++ return ERR_PTR(ret);
++ }
+
+ devname = dev_name(dev);
+
+@@ -662,6 +670,8 @@ static void pinctrl_put_locked(struct pinctrl *p, bool inlist)
+ kfree(state);
+ }
+
++ pinctrl_dt_free_maps(p);
++
+ if (inlist)
+ list_del(&p->node);
+ kfree(p);
+@@ -787,15 +797,8 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
+ }
+ EXPORT_SYMBOL_GPL(pinctrl_select_state);
+
+-/**
+- * pinctrl_register_mappings() - register a set of pin controller mappings
+- * @maps: the pincontrol mappings table to register. This should probably be
+- * marked with __initdata so it can be discarded after boot. This
+- * function will perform a shallow copy for the mapping entries.
+- * @num_maps: the number of maps in the mapping table
+- */
+-int pinctrl_register_mappings(struct pinctrl_map const *maps,
+- unsigned num_maps)
++int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
++ bool dup, bool locked)
+ {
+ int i, ret;
+ struct pinctrl_maps *maps_node;
+@@ -851,20 +854,52 @@ int pinctrl_register_mappings(struct pinctrl_map const *maps,
+ }
+
+ maps_node->num_maps = num_maps;
+- maps_node->maps = kmemdup(maps, sizeof(*maps) * num_maps, GFP_KERNEL);
+- if (!maps_node->maps) {
+- pr_err("failed to duplicate mapping table\n");
+- kfree(maps_node);
+- return -ENOMEM;
++ if (dup) {
++ maps_node->maps = kmemdup(maps, sizeof(*maps) * num_maps,
++ GFP_KERNEL);
++ if (!maps_node->maps) {
++ pr_err("failed to duplicate mapping table\n");
++ kfree(maps_node);
++ return -ENOMEM;
++ }
++ } else {
++ maps_node->maps = maps;
+ }
+
+- mutex_lock(&pinctrl_mutex);
++ if (!locked)
++ mutex_lock(&pinctrl_mutex);
+ list_add_tail(&maps_node->node, &pinctrl_maps);
+- mutex_unlock(&pinctrl_mutex);
++ if (!locked)
++ mutex_unlock(&pinctrl_mutex);
+
+ return 0;
+ }
+
++/**
++ * pinctrl_register_mappings() - register a set of pin controller mappings
++ * @maps: the pincontrol mappings table to register. This should probably be
++ * marked with __initdata so it can be discarded after boot. This
++ * function will perform a shallow copy for the mapping entries.
++ * @num_maps: the number of maps in the mapping table
++ */
++int pinctrl_register_mappings(struct pinctrl_map const *maps,
++ unsigned num_maps)
++{
++ return pinctrl_register_map(maps, num_maps, true, false);
++}
++
++void pinctrl_unregister_map(struct pinctrl_map const *map)
++{
++ struct pinctrl_maps *maps_node;
++
++ list_for_each_entry(maps_node, &pinctrl_maps, node) {
++ if (maps_node->maps == map) {
++ list_del(&maps_node->node);
++ return;
++ }
++ }
++}
++
+ #ifdef CONFIG_DEBUG_FS
+
+ static int pinctrl_pins_show(struct seq_file *s, void *what)
+@@ -1231,6 +1266,9 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev)
+ !ops->get_group_pins)
+ return -EINVAL;
+
++ if (ops->dt_node_to_map && !ops->dt_free_map)
++ return -EINVAL;
++
+ return 0;
+ }
+
+diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
+index 17ecf65..98ae808 100644
+--- a/drivers/pinctrl/core.h
++++ b/drivers/pinctrl/core.h
+@@ -52,12 +52,15 @@ struct pinctrl_dev {
+ * @dev: the device using this pin control handle
+ * @states: a list of states for this device
+ * @state: the current state
++ * @dt_maps: the mapping table chunks dynamically parsed from device tree for
++ * this device, if any
+ */
+ struct pinctrl {
+ struct list_head node;
+ struct device *dev;
+ struct list_head states;
+ struct pinctrl_state *state;
++ struct list_head dt_maps;
+ };
+
+ /**
+@@ -100,7 +103,8 @@ struct pinctrl_setting_configs {
+ * struct pinctrl_setting - an individual mux or config setting
+ * @node: list node for struct pinctrl_settings's @settings field
+ * @type: the type of setting
+- * @pctldev: pin control device handling to be programmed
++ * @pctldev: pin control device handling to be programmed. Not used for
++ * PIN_MAP_TYPE_DUMMY_STATE.
+ * @data: Data specific to the setting type
+ */
+ struct pinctrl_setting {
+@@ -153,4 +157,9 @@ static inline struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev,
+ return radix_tree_lookup(&pctldev->pin_desc_tree, pin);
+ }
+
++int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
++ bool dup, bool locked);
++void pinctrl_unregister_map(struct pinctrl_map const *map);
++
+ extern struct mutex pinctrl_mutex;
++extern struct list_head pinctrldev_list;
+diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
+new file mode 100644
+index 0000000..5ef2feb
+--- /dev/null
++++ b/drivers/pinctrl/devicetree.c
+@@ -0,0 +1,249 @@
++/*
++ * Device tree integration for the pin control subsystem
++ *
++ * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/device.h>
++#include <linux/of.h>
++#include <linux/pinctrl/pinctrl.h>
++#include <linux/slab.h>
++
++#include "core.h"
++#include "devicetree.h"
++
++/**
++ * struct pinctrl_dt_map - mapping table chunk parsed from device tree
++ * @node: list node for struct pinctrl's @dt_maps field
++ * @pctldev: the pin controller that allocated this struct, and will free it
++ * @maps: the mapping table entries
++ */
++struct pinctrl_dt_map {
++ struct list_head node;
++ struct pinctrl_dev *pctldev;
++ struct pinctrl_map *map;
++ unsigned num_maps;
++};
++
++static void dt_free_map(struct pinctrl_dev *pctldev,
++ struct pinctrl_map *map, unsigned num_maps)
++{
++ if (pctldev) {
++ struct pinctrl_ops *ops = pctldev->desc->pctlops;
++ ops->dt_free_map(pctldev, map, num_maps);
++ } else {
++ /* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */
++ kfree(map);
++ }
++}
++
++void pinctrl_dt_free_maps(struct pinctrl *p)
++{
++ struct pinctrl_dt_map *dt_map, *n1;
++
++ list_for_each_entry_safe(dt_map, n1, &p->dt_maps, node) {
++ pinctrl_unregister_map(dt_map->map);
++ list_del(&dt_map->node);
++ dt_free_map(dt_map->pctldev, dt_map->map,
++ dt_map->num_maps);
++ kfree(dt_map);
++ }
++
++ of_node_put(p->dev->of_node);
++}
++
++static int dt_remember_or_free_map(struct pinctrl *p, const char *statename,
++ struct pinctrl_dev *pctldev,
++ struct pinctrl_map *map, unsigned num_maps)
++{
++ int i;
++ struct pinctrl_dt_map *dt_map;
++
++ /* Initialize common mapping table entry fields */
++ for (i = 0; i < num_maps; i++) {
++ map[i].dev_name = dev_name(p->dev);
++ map[i].name = statename;
++ if (pctldev)
++ map[i].ctrl_dev_name = dev_name(pctldev->dev);
++ }
++
++ /* Remember the converted mapping table entries */
++ dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL);
++ if (!dt_map) {
++ dev_err(p->dev, "failed to alloc struct pinctrl_dt_map\n");
++ dt_free_map(pctldev, map, num_maps);
++ return -ENOMEM;
++ }
++
++ dt_map->pctldev = pctldev;
++ dt_map->map = map;
++ dt_map->num_maps = num_maps;
++ list_add_tail(&dt_map->node, &p->dt_maps);
++
++ return pinctrl_register_map(map, num_maps, false, true);
++}
++
++static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np)
++{
++ struct pinctrl_dev *pctldev;
++
++ list_for_each_entry(pctldev, &pinctrldev_list, node)
++ if (pctldev->dev->of_node == np)
++ return pctldev;
++
++ return NULL;
++}
++
++static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
++ struct device_node *np_config)
++{
++ struct device_node *np_pctldev;
++ struct pinctrl_dev *pctldev;
++ struct pinctrl_ops *ops;
++ int ret;
++ struct pinctrl_map *map;
++ unsigned num_maps;
++
++ /* Find the pin controller containing np_config */
++ np_pctldev = of_node_get(np_config);
++ for (;;) {
++ np_pctldev = of_get_next_parent(np_pctldev);
++ if (!np_pctldev || of_node_is_root(np_pctldev)) {
++ dev_err(p->dev, "could not find pctldev for node %s\n",
++ np_config->full_name);
++ of_node_put(np_pctldev);
++ /* FIXME: This should trigger deferrered probe */
++ return -ENODEV;
++ }
++ pctldev = find_pinctrl_by_of_node(np_pctldev);
++ if (pctldev)
++ break;
++ }
++ of_node_put(np_pctldev);
++
++ /*
++ * Call pinctrl driver to parse device tree node, and
++ * generate mapping table entries
++ */
++ ops = pctldev->desc->pctlops;
++ if (!ops->dt_node_to_map) {
++ dev_err(p->dev, "pctldev %s doesn't support DT\n",
++ dev_name(pctldev->dev));
++ return -ENODEV;
++ }
++ ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps);
++ if (ret < 0)
++ return ret;
++
++ /* Stash the mapping table chunk away for later use */
++ return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);
++}
++
++static int dt_remember_dummy_state(struct pinctrl *p, const char *statename)
++{
++ struct pinctrl_map *map;
++
++ map = kzalloc(sizeof(*map), GFP_KERNEL);
++ if (!map) {
++ dev_err(p->dev, "failed to alloc struct pinctrl_map\n");
++ return -ENOMEM;
++ }
++
++ /* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */
++ map->type = PIN_MAP_TYPE_DUMMY_STATE;
++
++ return dt_remember_or_free_map(p, statename, NULL, map, 1);
++}
++
++int pinctrl_dt_to_map(struct pinctrl *p)
++{
++ struct device_node *np = p->dev->of_node;
++ int state, ret;
++ char *propname;
++ struct property *prop;
++ const char *statename;
++ const __be32 *list;
++ int size, config;
++ phandle phandle;
++ struct device_node *np_config;
++
++ /* CONFIG_OF enabled, p->dev not instantiated from DT */
++ if (!np) {
++ dev_dbg(p->dev, "no of_node; not parsing pinctrl DT\n");
++ return 0;
++ }
++
++ /* We may store pointers to property names within the node */
++ of_node_get(np);
++
++ /* For each defined state ID */
++ for (state = 0; ; state++) {
++ /* Retrieve the pinctrl-* property */
++ propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);
++ prop = of_find_property(np, propname, &size);
++ kfree(propname);
++ if (!prop)
++ break;
++ list = prop->value;
++ size /= sizeof(*list);
++
++ /* Determine whether pinctrl-names property names the state */
++ ret = of_property_read_string_index(np, "pinctrl-names",
++ state, &statename);
++ /*
++ * If not, statename is just the integer state ID. But rather
++ * than dynamically allocate it and have to free it later,
++ * just point part way into the property name for the string.
++ */
++ if (ret < 0) {
++ /* strlen("pinctrl-") == 8 */
++ statename = prop->name + 8;
++ }
++
++ /* For every referenced pin configuration node in it */
++ for (config = 0; config < size; config++) {
++ phandle = be32_to_cpup(list++);
++
++ /* Look up the pin configuration node */
++ np_config = of_find_node_by_phandle(phandle);
++ if (!np_config) {
++ dev_err(p->dev,
++ "prop %s index %i invalid phandle\n",
++ prop->name, config);
++ ret = -EINVAL;
++ goto err;
++ }
++
++ /* Parse the node */
++ ret = dt_to_map_one_config(p, statename, np_config);
++ of_node_put(np_config);
++ if (ret < 0)
++ goto err;
++ }
++
++ /* No entries in DT? Generate a dummy state table entry */
++ if (!size) {
++ ret = dt_remember_dummy_state(p, statename);
++ if (ret < 0)
++ goto err;
++ }
++ }
++
++ return 0;
++
++err:
++ pinctrl_dt_free_maps(p);
++ return ret;
++}
+diff --git a/drivers/pinctrl/devicetree.h b/drivers/pinctrl/devicetree.h
+new file mode 100644
+index 0000000..760bc49
+--- /dev/null
++++ b/drivers/pinctrl/devicetree.h
+@@ -0,0 +1,35 @@
++/*
++ * Internal interface to pinctrl device tree integration
++ *
++ * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifdef CONFIG_OF
++
++void pinctrl_dt_free_maps(struct pinctrl *p);
++int pinctrl_dt_to_map(struct pinctrl *p);
++
++#else
++
++static inline int pinctrl_dt_to_map(struct pinctrl *p)
++{
++ return 0;
++}
++
++static inline void pinctrl_dt_free_maps(struct pinctrl *p)
++{
++}
++
++#endif
+diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
+index 4e9f078..aa92cde 100644
+--- a/include/linux/pinctrl/pinctrl.h
++++ b/include/linux/pinctrl/pinctrl.h
+@@ -21,9 +21,11 @@
+
+ struct device;
+ struct pinctrl_dev;
++struct pinctrl_map;
+ struct pinmux_ops;
+ struct pinconf_ops;
+ struct gpio_chip;
++struct device_node;
+
+ /**
+ * struct pinctrl_pin_desc - boards/machines provide information on their
+@@ -83,6 +85,11 @@ struct pinctrl_ops {
+ unsigned *num_pins);
+ void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s,
+ unsigned offset);
++ int (*dt_node_to_map) (struct pinctrl_dev *pctldev,
++ struct device_node *np_config,
++ struct pinctrl_map **map, unsigned *num_maps);
++ void (*dt_free_map) (struct pinctrl_dev *pctldev,
++ struct pinctrl_map *map, unsigned num_maps);
+ };
+
+ /**
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0193-pinctrl-fix-build-when-CONFIG_OF-CONFIG_PINCTRL.patch b/patches.at91/0193-pinctrl-fix-build-when-CONFIG_OF-CONFIG_PINCTRL.patch
new file mode 100644
index 00000000000000..2a91bb276917fc
--- /dev/null
+++ b/patches.at91/0193-pinctrl-fix-build-when-CONFIG_OF-CONFIG_PINCTRL.patch
@@ -0,0 +1,35 @@
+From 71404155915a36c279030254266350255058b89a Mon Sep 17 00:00:00 2001
+From: Stephen Warren <swarren@nvidia.com>
+Date: Tue, 3 Apr 2012 21:53:56 -0600
+Subject: pinctrl: fix build when CONFIG_OF && !CONFIG_PINCTRL
+
+pinctrl/devicetree.c won't compile when !CONFIG_PINCTRL, since the
+pinctrl headers don't declare some types when !PINCTRL. Make sure
+pinctrl/Makefile only attempts to compile devicetree.c when OF &&
+PINCTRL.
+
+Acked-by: Dong Aisheng <dong.aisheng@linaro.org>
+Signed-off-by: Stephen Warren <swarren@nvidia.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/Makefile | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
+index 049c9fb..8e3c95a 100644
+--- a/drivers/pinctrl/Makefile
++++ b/drivers/pinctrl/Makefile
+@@ -5,7 +5,9 @@ ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG
+ obj-$(CONFIG_PINCTRL) += core.o
+ obj-$(CONFIG_PINMUX) += pinmux.o
+ obj-$(CONFIG_PINCONF) += pinconf.o
+-obj-$(CONFIG_OF) += devicetree.o
++ifeq ($(CONFIG_OF),y)
++obj-$(CONFIG_PINCTRL) += devicetree.o
++endif
+ obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
+ obj-$(CONFIG_PINCTRL_PXA3xx) += pinctrl-pxa3xx.o
+ obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0194-pinctrl-fix-dangling-comment.patch b/patches.at91/0194-pinctrl-fix-dangling-comment.patch
new file mode 100644
index 00000000000000..af511327d20267
--- /dev/null
+++ b/patches.at91/0194-pinctrl-fix-dangling-comment.patch
@@ -0,0 +1,29 @@
+From 51c38f7a1e3171e80e2c4c3db1bf6276a2711298 Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Tue, 24 Apr 2012 15:20:02 +0200
+Subject: pinctrl: fix dangling comment
+
+This comment was referring to an older PINMUX define, it should
+be PINCTRL now.
+
+Reported-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Dong Aisheng <dong.aisheng@linaro.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ include/linux/pinctrl/machine.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/linux/pinctrl/machine.h b/include/linux/pinctrl/machine.h
+index e4d1de7..9c4a198 100644
+--- a/include/linux/pinctrl/machine.h
++++ b/include/linux/pinctrl/machine.h
+@@ -163,5 +163,5 @@ static inline int pinctrl_register_mappings(struct pinctrl_map const *map,
+ return 0;
+ }
+
+-#endif /* !CONFIG_PINMUX */
++#endif /* !CONFIG_PINCTRL */
+ #endif
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0195-pinctrl-implement-devm_pinctrl_get-put.patch b/patches.at91/0195-pinctrl-implement-devm_pinctrl_get-put.patch
new file mode 100644
index 00000000000000..fab78ce91b335c
--- /dev/null
+++ b/patches.at91/0195-pinctrl-implement-devm_pinctrl_get-put.patch
@@ -0,0 +1,308 @@
+From 51da4591803af89917c5ef0f8b1e36b2f1398883 Mon Sep 17 00:00:00 2001
+From: Stephen Warren <swarren@nvidia.com>
+Date: Mon, 16 Apr 2012 10:51:00 -0600
+Subject: pinctrl: implement devm_pinctrl_get()/put()
+
+These functions allow the driver core to automatically clean up any
+allocations made by drivers, thus leading to simplified drivers.
+
+Signed-off-by: Stephen Warren <swarren@nvidia.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ Documentation/driver-model/devres.txt | 4 +++
+ Documentation/pinctrl.txt | 48 ++++++++++++++++++------------
+ drivers/pinctrl/core.c | 56 +++++++++++++++++++++++++++++++++++
+ include/linux/pinctrl/consumer.h | 44 +++++++++++++++++++++++++++
+ 4 files changed, 133 insertions(+), 19 deletions(-)
+
+diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
+index 2a596a4..ef4fa7b 100644
+--- a/Documentation/driver-model/devres.txt
++++ b/Documentation/driver-model/devres.txt
+@@ -276,3 +276,7 @@ REGULATOR
+ devm_regulator_get()
+ devm_regulator_put()
+ devm_regulator_bulk_get()
++
++PINCTRL
++ devm_pinctrl_get()
++ devm_pinctrl_put()
+diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt
+index d97bccf..fa829f1 100644
+--- a/Documentation/pinctrl.txt
++++ b/Documentation/pinctrl.txt
+@@ -952,13 +952,13 @@ case), we define a mapping like this:
+ The result of grabbing this mapping from the device with something like
+ this (see next paragraph):
+
+- p = pinctrl_get(dev);
++ p = devm_pinctrl_get(dev);
+ s = pinctrl_lookup_state(p, "8bit");
+ ret = pinctrl_select_state(p, s);
+
+ or more simply:
+
+- p = pinctrl_get_select(dev, "8bit");
++ p = devm_pinctrl_get_select(dev, "8bit");
+
+ Will be that you activate all the three bottom records in the mapping at
+ once. Since they share the same name, pin controller device, function and
+@@ -992,7 +992,7 @@ foo_probe()
+ /* Allocate a state holder named "foo" etc */
+ struct foo_state *foo = ...;
+
+- foo->p = pinctrl_get(&device);
++ foo->p = devm_pinctrl_get(&device);
+ if (IS_ERR(foo->p)) {
+ /* FIXME: clean up "foo" here */
+ return PTR_ERR(foo->p);
+@@ -1000,24 +1000,17 @@ foo_probe()
+
+ foo->s = pinctrl_lookup_state(foo->p, PINCTRL_STATE_DEFAULT);
+ if (IS_ERR(foo->s)) {
+- pinctrl_put(foo->p);
+ /* FIXME: clean up "foo" here */
+ return PTR_ERR(s);
+ }
+
+ ret = pinctrl_select_state(foo->s);
+ if (ret < 0) {
+- pinctrl_put(foo->p);
+ /* FIXME: clean up "foo" here */
+ return ret;
+ }
+ }
+
+-foo_remove()
+-{
+- pinctrl_put(state->p);
+-}
+-
+ This get/lookup/select/put sequence can just as well be handled by bus drivers
+ if you don't want each and every driver to handle it and you know the
+ arrangement on your bus.
+@@ -1029,6 +1022,11 @@ The semantics of the pinctrl APIs are:
+ kernel memory to hold the pinmux state. All mapping table parsing or similar
+ slow operations take place within this API.
+
++- devm_pinctrl_get() is a variant of pinctrl_get() that causes pinctrl_put()
++ to be called automatically on the retrieved pointer when the associated
++ device is removed. It is recommended to use this function over plain
++ pinctrl_get().
++
+ - pinctrl_lookup_state() is called in process context to obtain a handle to a
+ specific state for a the client device. This operation may be slow too.
+
+@@ -1041,14 +1039,25 @@ The semantics of the pinctrl APIs are:
+
+ - pinctrl_put() frees all information associated with a pinctrl handle.
+
++- devm_pinctrl_put() is a variant of pinctrl_put() that may be used to
++ explicitly destroy a pinctrl object returned by devm_pinctrl_get().
++ However, use of this function will be rare, due to the automatic cleanup
++ that will occur even without calling it.
++
++ pinctrl_get() must be paired with a plain pinctrl_put().
++ pinctrl_get() may not be paired with devm_pinctrl_put().
++ devm_pinctrl_get() can optionally be paired with devm_pinctrl_put().
++ devm_pinctrl_get() may not be paired with plain pinctrl_put().
++
+ Usually the pin control core handled the get/put pair and call out to the
+ device drivers bookkeeping operations, like checking available functions and
+ the associated pins, whereas the enable/disable pass on to the pin controller
+ driver which takes care of activating and/or deactivating the mux setting by
+ quickly poking some registers.
+
+-The pins are allocated for your device when you issue the pinctrl_get() call,
+-after this you should be able to see this in the debugfs listing of all pins.
++The pins are allocated for your device when you issue the devm_pinctrl_get()
++call, after this you should be able to see this in the debugfs listing of all
++pins.
+
+
+ System pin control hogging
+@@ -1094,13 +1103,13 @@ it, disables and releases it, and muxes it in on the pins defined by group B:
+
+ #include <linux/pinctrl/consumer.h>
+
+-foo_switch()
+-{
+- struct pinctrl *p;
+- struct pinctrl_state *s1, *s2;
++struct pinctrl *p;
++struct pinctrl_state *s1, *s2;
+
++foo_probe()
++{
+ /* Setup */
+- p = pinctrl_get(&device);
++ p = devm_pinctrl_get(&device);
+ if (IS_ERR(p))
+ ...
+
+@@ -1111,7 +1120,10 @@ foo_switch()
+ s2 = pinctrl_lookup_state(foo->p, "pos-B");
+ if (IS_ERR(s2))
+ ...
++}
+
++foo_switch()
++{
+ /* Enable on position A */
+ ret = pinctrl_select_state(s1);
+ if (ret < 0)
+@@ -1125,8 +1137,6 @@ foo_switch()
+ ...
+
+ ...
+-
+- pinctrl_put(p);
+ }
+
+ The above has to be done from process context.
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index 832f71d..f4544f4 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -23,6 +23,7 @@
+ #include <linux/sysfs.h>
+ #include <linux/debugfs.h>
+ #include <linux/seq_file.h>
++#include <linux/pinctrl/consumer.h>
+ #include <linux/pinctrl/pinctrl.h>
+ #include <linux/pinctrl/machine.h>
+ #include "core.h"
+@@ -797,6 +798,61 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
+ }
+ EXPORT_SYMBOL_GPL(pinctrl_select_state);
+
++static void devm_pinctrl_release(struct device *dev, void *res)
++{
++ pinctrl_put(*(struct pinctrl **)res);
++}
++
++/**
++ * struct devm_pinctrl_get() - Resource managed pinctrl_get()
++ * @dev: the device to obtain the handle for
++ *
++ * If there is a need to explicitly destroy the returned struct pinctrl,
++ * devm_pinctrl_put() should be used, rather than plain pinctrl_put().
++ */
++struct pinctrl *devm_pinctrl_get(struct device *dev)
++{
++ struct pinctrl **ptr, *p;
++
++ ptr = devres_alloc(devm_pinctrl_release, sizeof(*ptr), GFP_KERNEL);
++ if (!ptr)
++ return ERR_PTR(-ENOMEM);
++
++ p = pinctrl_get(dev);
++ if (!IS_ERR(p)) {
++ *ptr = p;
++ devres_add(dev, ptr);
++ } else {
++ devres_free(ptr);
++ }
++
++ return p;
++}
++EXPORT_SYMBOL_GPL(devm_pinctrl_get);
++
++static int devm_pinctrl_match(struct device *dev, void *res, void *data)
++{
++ struct pinctrl **p = res;
++
++ return *p == data;
++}
++
++/**
++ * devm_pinctrl_put() - Resource managed pinctrl_put()
++ * @p: the pinctrl handle to release
++ *
++ * Deallocate a struct pinctrl obtained via devm_pinctrl_get(). Normally
++ * this function will not need to be called and the resource management
++ * code will ensure that the resource is freed.
++ */
++void devm_pinctrl_put(struct pinctrl *p)
++{
++ WARN_ON(devres_destroy(p->dev, devm_pinctrl_release,
++ devm_pinctrl_match, p));
++ pinctrl_put(p);
++}
++EXPORT_SYMBOL_GPL(devm_pinctrl_put);
++
+ int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
+ bool dup, bool locked)
+ {
+diff --git a/include/linux/pinctrl/consumer.h b/include/linux/pinctrl/consumer.h
+index 191e726..6dd96fb 100644
+--- a/include/linux/pinctrl/consumer.h
++++ b/include/linux/pinctrl/consumer.h
+@@ -36,6 +36,9 @@ extern struct pinctrl_state * __must_check pinctrl_lookup_state(
+ const char *name);
+ extern int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s);
+
++extern struct pinctrl * __must_check devm_pinctrl_get(struct device *dev);
++extern void devm_pinctrl_put(struct pinctrl *p);
++
+ #else /* !CONFIG_PINCTRL */
+
+ static inline int pinctrl_request_gpio(unsigned gpio)
+@@ -79,6 +82,15 @@ static inline int pinctrl_select_state(struct pinctrl *p,
+ return 0;
+ }
+
++static inline struct pinctrl * __must_check devm_pinctrl_get(struct device *dev)
++{
++ return NULL;
++}
++
++static inline void devm_pinctrl_put(struct pinctrl *p)
++{
++}
++
+ #endif /* CONFIG_PINCTRL */
+
+ static inline struct pinctrl * __must_check pinctrl_get_select(
+@@ -113,6 +125,38 @@ static inline struct pinctrl * __must_check pinctrl_get_select_default(
+ return pinctrl_get_select(dev, PINCTRL_STATE_DEFAULT);
+ }
+
++static inline struct pinctrl * __must_check devm_pinctrl_get_select(
++ struct device *dev, const char *name)
++{
++ struct pinctrl *p;
++ struct pinctrl_state *s;
++ int ret;
++
++ p = devm_pinctrl_get(dev);
++ if (IS_ERR(p))
++ return p;
++
++ s = pinctrl_lookup_state(p, name);
++ if (IS_ERR(s)) {
++ devm_pinctrl_put(p);
++ return ERR_PTR(PTR_ERR(s));
++ }
++
++ ret = pinctrl_select_state(p, s);
++ if (ret < 0) {
++ devm_pinctrl_put(p);
++ return ERR_PTR(ret);
++ }
++
++ return p;
++}
++
++static inline struct pinctrl * __must_check devm_pinctrl_get_select_default(
++ struct device *dev)
++{
++ return devm_pinctrl_get_select(dev, PINCTRL_STATE_DEFAULT);
++}
++
+ #ifdef CONFIG_PINCONF
+
+ extern int pin_config_get(const char *dev_name, const char *name,
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0196-pinctrl-add-pinctrl_provide_dummies-interface-for-pl.patch b/patches.at91/0196-pinctrl-add-pinctrl_provide_dummies-interface-for-pl.patch
new file mode 100644
index 00000000000000..e3fcb3b56a10b2
--- /dev/null
+++ b/patches.at91/0196-pinctrl-add-pinctrl_provide_dummies-interface-for-pl.patch
@@ -0,0 +1,115 @@
+From 489c95dd039fae25e560ef219754a3ce4f9fd501 Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <dong.aisheng@linaro.org>
+Date: Thu, 26 Apr 2012 16:15:50 +0800
+Subject: pinctrl: add pinctrl_provide_dummies interface for platforms to use
+
+Add a interface pinctrl_provide_dummies for platform to indicate
+whether it needs use pinctrl dummy state.
+
+ChangeLog v3->v4:
+* remove dummy gpio support in pinctrl subsystem.
+ Let gpio driver decide whether it wants to use pinctrl gpio mux
+ function.
+ChangeLog v2->v3:
+* Also changed the missed pinctrl gpio APIs in v1.
+ChangeLog v1->v2:
+* Based on sascha's suggestion, drop using kconfig since it will hide
+ pinctrl errors on all other boards.
+ See: https://lkml.org/lkml/2012/4/18/282
+ It seemed both Linus and Stephen agreed with this way, so i'm ok
+ with it too.
+* Add dummy gpio support.
+ pinctrl gpio in the same situation as state.
+* Patch name changed.
+ Original is pinctrl: handle dummy state in core.
+* Split removing old dt dummy interface into a separate patch
+
+Cc: Linus Walleij <linus.walleij@linaro.org>
+Cc: Sascha Hauer <s.hauer@pengutronix.de>
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/core.c | 29 +++++++++++++++++++++++++++--
+ include/linux/pinctrl/machine.h | 5 ++++-
+ 2 files changed, 31 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index f4544f4..2b6363c5 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -43,6 +43,8 @@ struct pinctrl_maps {
+ unsigned num_maps;
+ };
+
++static bool pinctrl_dummy_state;
++
+ /* Mutex taken by all entry points */
+ DEFINE_MUTEX(pinctrl_mutex);
+
+@@ -61,6 +63,19 @@ static LIST_HEAD(pinctrl_maps);
+ _i_ < _maps_node_->num_maps; \
+ i++, _map_ = &_maps_node_->maps[_i_])
+
++/**
++ * pinctrl_provide_dummies() - indicate if pinctrl provides dummy state support
++ *
++ * Usually this function is called by platforms without pinctrl driver support
++ * but run with some shared drivers using pinctrl APIs.
++ * After calling this function, the pinctrl core will return successfully
++ * with creating a dummy state for the driver to keep going smoothly.
++ */
++void pinctrl_provide_dummies(void)
++{
++ pinctrl_dummy_state = true;
++}
++
+ const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev)
+ {
+ /* We're not allowed to register devices without name */
+@@ -696,8 +711,18 @@ static struct pinctrl_state *pinctrl_lookup_state_locked(struct pinctrl *p,
+ struct pinctrl_state *state;
+
+ state = find_state(p, name);
+- if (!state)
+- return ERR_PTR(-ENODEV);
++ if (!state) {
++ if (pinctrl_dummy_state) {
++ /* create dummy state */
++ dev_dbg(p->dev, "using pinctrl dummy state (%s)\n",
++ name);
++ state = create_state(p, name);
++ if (IS_ERR(state))
++ return state;
++ } else {
++ return ERR_PTR(-ENODEV);
++ }
++ }
+
+ return state;
+ }
+diff --git a/include/linux/pinctrl/machine.h b/include/linux/pinctrl/machine.h
+index 9c4a198..7d22ab0 100644
+--- a/include/linux/pinctrl/machine.h
++++ b/include/linux/pinctrl/machine.h
+@@ -154,7 +154,7 @@ struct pinctrl_map {
+
+ extern int pinctrl_register_mappings(struct pinctrl_map const *map,
+ unsigned num_maps);
+-
++extern void pinctrl_provide_dummies(void);
+ #else
+
+ static inline int pinctrl_register_mappings(struct pinctrl_map const *map,
+@@ -163,5 +163,8 @@ static inline int pinctrl_register_mappings(struct pinctrl_map const *map,
+ return 0;
+ }
+
++static inline void pinctrl_provide_dummies(void)
++{
++}
+ #endif /* !CONFIG_PINCTRL */
+ #endif
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0197-pinctrl-remove-pinctrl_remove_gpio_range.patch b/patches.at91/0197-pinctrl-remove-pinctrl_remove_gpio_range.patch
new file mode 100644
index 00000000000000..fc5a9090200fd6
--- /dev/null
+++ b/patches.at91/0197-pinctrl-remove-pinctrl_remove_gpio_range.patch
@@ -0,0 +1,103 @@
+From 1332062fec70ff4fc2f3dd9360911a59ba78bcaf Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <dong.aisheng@linaro.org>
+Date: Wed, 23 May 2012 21:22:40 +0800
+Subject: pinctrl: remove pinctrl_remove_gpio_range
+
+The gpio ranges will be automatically removed when the pinctrl
+driver is unregistered.
+
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/core.c | 19 +++++--------------
+ drivers/pinctrl/pinctrl-tegra.c | 1 -
+ drivers/pinctrl/pinctrl-u300.c | 2 --
+ include/linux/pinctrl/pinctrl.h | 2 --
+ 4 files changed, 5 insertions(+), 19 deletions(-)
+
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index 2b6363c5..7b3fc93 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -313,20 +313,6 @@ void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
+ EXPORT_SYMBOL_GPL(pinctrl_add_gpio_range);
+
+ /**
+- * pinctrl_remove_gpio_range() - remove a range of GPIOs fro a pin controller
+- * @pctldev: pin controller device to remove the range from
+- * @range: the GPIO range to remove
+- */
+-void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
+- struct pinctrl_gpio_range *range)
+-{
+- mutex_lock(&pinctrl_mutex);
+- list_del(&range->node);
+- mutex_unlock(&pinctrl_mutex);
+-}
+-EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range);
+-
+-/**
+ * pinctrl_get_group_selector() - returns the group selector for a group
+ * @pctldev: the pin controller handling the group
+ * @pin_group: the pin group to look up
+@@ -1456,6 +1442,7 @@ EXPORT_SYMBOL_GPL(pinctrl_register);
+ */
+ void pinctrl_unregister(struct pinctrl_dev *pctldev)
+ {
++ struct pinctrl_gpio_range *range, *n;
+ if (pctldev == NULL)
+ return;
+
+@@ -1471,6 +1458,10 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev)
+ /* Destroy descriptor tree */
+ pinctrl_free_pindescs(pctldev, pctldev->desc->pins,
+ pctldev->desc->npins);
++ /* remove gpio ranges map */
++ list_for_each_entry_safe(range, n, &pctldev->gpio_ranges, node)
++ list_del(&range->node);
++
+ kfree(pctldev);
+
+ mutex_unlock(&pinctrl_mutex);
+diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
+index 9b32968..0b3c02f 100644
+--- a/drivers/pinctrl/pinctrl-tegra.c
++++ b/drivers/pinctrl/pinctrl-tegra.c
+@@ -525,7 +525,6 @@ static int __devexit tegra_pinctrl_remove(struct platform_device *pdev)
+ {
+ struct tegra_pmx *pmx = platform_get_drvdata(pdev);
+
+- pinctrl_remove_gpio_range(pmx->pctl, &tegra_pinctrl_gpio_range);
+ pinctrl_unregister(pmx->pctl);
+
+ return 0;
+diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c
+index 26eb8cc..9ff6207 100644
+--- a/drivers/pinctrl/pinctrl-u300.c
++++ b/drivers/pinctrl/pinctrl-u300.c
+@@ -1185,8 +1185,6 @@ static int __devexit u300_pmx_remove(struct platform_device *pdev)
+ struct u300_pmx *upmx = platform_get_drvdata(pdev);
+ int i;
+
+- for (i = 0; i < ARRAY_SIZE(u300_gpio_ranges); i++)
+- pinctrl_remove_gpio_range(upmx->pctl, &u300_gpio_ranges[i]);
+ pinctrl_unregister(upmx->pctl);
+ iounmap(upmx->virtbase);
+ release_mem_region(upmx->phybase, upmx->physize);
+diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
+index aa92cde..6e30132 100644
+--- a/include/linux/pinctrl/pinctrl.h
++++ b/include/linux/pinctrl/pinctrl.h
+@@ -124,8 +124,6 @@ extern void pinctrl_unregister(struct pinctrl_dev *pctldev);
+ extern bool pin_is_valid(struct pinctrl_dev *pctldev, int pin);
+ extern void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range);
+-extern void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
+- struct pinctrl_gpio_range *range);
+ extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev);
+ extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev);
+ #else
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0198-pinctrl-add-pinctrl_add_gpio_ranges-function.patch b/patches.at91/0198-pinctrl-add-pinctrl_add_gpio_ranges-function.patch
new file mode 100644
index 00000000000000..ab6bf0ed17326a
--- /dev/null
+++ b/patches.at91/0198-pinctrl-add-pinctrl_add_gpio_ranges-function.patch
@@ -0,0 +1,55 @@
+From d52a7f1a57f4ffda01f648c2ae986ab52edaa517 Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <dong.aisheng@linaro.org>
+Date: Wed, 23 May 2012 21:22:41 +0800
+Subject: pinctrl: add pinctrl_add_gpio_ranges function
+
+Often GPIO ranges are added in batch, so create a special
+function for that.
+
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/core.c | 11 +++++++++++
+ include/linux/pinctrl/pinctrl.h | 3 +++
+ 2 files changed, 14 insertions(+)
+
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index 7b3fc93..fa8a440 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -312,6 +312,17 @@ void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
+ }
+ EXPORT_SYMBOL_GPL(pinctrl_add_gpio_range);
+
++void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev,
++ struct pinctrl_gpio_range *ranges,
++ unsigned nranges)
++{
++ int i;
++
++ for (i = 0; i < nranges; i++)
++ pinctrl_add_gpio_range(pctldev, &ranges[i]);
++}
++EXPORT_SYMBOL_GPL(pinctrl_add_gpio_ranges);
++
+ /**
+ * pinctrl_get_group_selector() - returns the group selector for a group
+ * @pctldev: the pin controller handling the group
+diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
+index 6e30132..e162710 100644
+--- a/include/linux/pinctrl/pinctrl.h
++++ b/include/linux/pinctrl/pinctrl.h
+@@ -124,6 +124,9 @@ extern void pinctrl_unregister(struct pinctrl_dev *pctldev);
+ extern bool pin_is_valid(struct pinctrl_dev *pctldev, int pin);
+ extern void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range);
++extern void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev,
++ struct pinctrl_gpio_range *ranges,
++ unsigned nranges);
+ extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev);
+ extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev);
+ #else
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0199-pinctrl-support-gpio-request-deferred-probing.patch b/patches.at91/0199-pinctrl-support-gpio-request-deferred-probing.patch
new file mode 100644
index 00000000000000..1776c362f2a99b
--- /dev/null
+++ b/patches.at91/0199-pinctrl-support-gpio-request-deferred-probing.patch
@@ -0,0 +1,51 @@
+From d834e7a76cf4e427904024a9b5b32f80a8f085a6 Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <dong.aisheng@linaro.org>
+Date: Wed, 25 Apr 2012 19:38:13 +0800
+Subject: pinctrl: support gpio request deferred probing
+
+As pinctrl handles, it may be possible the pinctrl gpio ranges
+are still not got registered when user call pinctrl_gpio_request.
+Thus, add defer support for it too.
+
+Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/core.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index fa8a440..c9c74dc 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -272,7 +272,8 @@ pinctrl_match_gpio_range(struct pinctrl_dev *pctldev, unsigned gpio)
+ *
+ * Find the pin controller handling a certain GPIO pin from the pinspace of
+ * the GPIO subsystem, return the device and the matching GPIO range. Returns
+- * negative if the GPIO range could not be found in any device.
++ * -EPROBE_DEFER if the GPIO range could not be found in any device since it
++ * may still have not been registered.
+ */
+ static int pinctrl_get_device_gpio_range(unsigned gpio,
+ struct pinctrl_dev **outdev,
+@@ -292,7 +293,7 @@ static int pinctrl_get_device_gpio_range(unsigned gpio,
+ }
+ }
+
+- return -EINVAL;
++ return -EPROBE_DEFER;
+ }
+
+ /**
+@@ -374,7 +375,7 @@ int pinctrl_request_gpio(unsigned gpio)
+ ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
+ if (ret) {
+ mutex_unlock(&pinctrl_mutex);
+- return -EINVAL;
++ return ret;
+ }
+
+ /* Convert to the pin controllers number space */
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0200-pinctrl-propagate-map-validation-errors.patch b/patches.at91/0200-pinctrl-propagate-map-validation-errors.patch
new file mode 100644
index 00000000000000..5d7c39c308249e
--- /dev/null
+++ b/patches.at91/0200-pinctrl-propagate-map-validation-errors.patch
@@ -0,0 +1,38 @@
+From 1f8eba396ef610c82faaf227a8b76e98cdf90afd Mon Sep 17 00:00:00 2001
+From: Stephen Warren <swarren@nvidia.com>
+Date: Wed, 25 Apr 2012 10:32:16 -0600
+Subject: pinctrl: propagate map validation errors
+
+pinctrl_register_map() was returning early if pinmux_validate_map() or
+pinconf_validate_map() failed, but was not actually returning the error
+code.
+
+Signed-off-by: Stephen Warren <swarren@nvidia.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/core.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index c9c74dc..6ae3a33 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -911,13 +911,13 @@ int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
+ case PIN_MAP_TYPE_MUX_GROUP:
+ ret = pinmux_validate_map(&maps[i], i);
+ if (ret < 0)
+- return 0;
++ return ret;
+ break;
+ case PIN_MAP_TYPE_CONFIGS_PIN:
+ case PIN_MAP_TYPE_CONFIGS_GROUP:
+ ret = pinconf_validate_map(&maps[i], i);
+ if (ret < 0)
+- return 0;
++ return ret;
+ break;
+ default:
+ pr_err("failed to register map %s (%d): invalid type given\n",
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0201-pinctrl-mark-non-EXPERIMENTAL.patch b/patches.at91/0201-pinctrl-mark-non-EXPERIMENTAL.patch
new file mode 100644
index 00000000000000..f30229d20be909
--- /dev/null
+++ b/patches.at91/0201-pinctrl-mark-non-EXPERIMENTAL.patch
@@ -0,0 +1,30 @@
+From ac7194c8e5bc5956a26b7460b7e58b22504a375d Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Thu, 12 Apr 2012 19:48:42 +0200
+Subject: pinctrl: mark non-EXPERIMENTAL
+
+With the finalization of the external driver API and the device
+tree support, this subsystem is now mature and can be promoted to
+non-experimental status.
+
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/Kconfig | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
+index abfb964..f73a5ea 100644
+--- a/drivers/pinctrl/Kconfig
++++ b/drivers/pinctrl/Kconfig
+@@ -4,7 +4,6 @@
+
+ config PINCTRL
+ bool
+- depends on EXPERIMENTAL
+
+ if PINCTRL
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0202-pinctrl-implement-pinctrl-deferred-probing.patch b/patches.at91/0202-pinctrl-implement-pinctrl-deferred-probing.patch
new file mode 100644
index 00000000000000..a97355b89ac48e
--- /dev/null
+++ b/patches.at91/0202-pinctrl-implement-pinctrl-deferred-probing.patch
@@ -0,0 +1,82 @@
+From c74f8821901c3338e120844cbff9bf0676243451 Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Tue, 10 Apr 2012 10:00:38 +0200
+Subject: pinctrl: implement pinctrl deferred probing
+
+If drivers try to obtain pinctrl handles for a pin controller that
+has not yet registered to the subsystem, we need to be able to
+back out and retry with deferred probing. So let's return
+-EPROBE_DEFER whenever this location fails. Also downgrade the
+errors to info, maybe we will even set them to debug once the
+deferred probing is commonplace.
+
+Cc: Arnd Bergmann <arnd@arndb.de>
+Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ Documentation/pinctrl.txt | 5 +++++
+ drivers/pinctrl/core.c | 9 ++++++---
+ drivers/pinctrl/devicetree.c | 6 +++---
+ 3 files changed, 14 insertions(+), 6 deletions(-)
+
+diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt
+index fa829f1..b85f0bd 100644
+--- a/Documentation/pinctrl.txt
++++ b/Documentation/pinctrl.txt
+@@ -1059,6 +1059,11 @@ The pins are allocated for your device when you issue the devm_pinctrl_get()
+ call, after this you should be able to see this in the debugfs listing of all
+ pins.
+
++NOTE: the pinctrl system will return -EPROBE_DEFER if it cannot find the
++requested pinctrl handles, for example if the pinctrl driver has not yet
++registered. Thus make sure that the error path in your driver gracefully
++cleans up and is ready to retry the probing later in the startup process.
++
+
+ System pin control hogging
+ ==========================
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index 6ae3a33..ff78028 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -531,11 +531,14 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
+
+ setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
+ if (setting->pctldev == NULL) {
+- dev_err(p->dev, "unknown pinctrl device %s in map entry",
++ dev_info(p->dev, "unknown pinctrl device %s in map entry, deferring probe",
+ map->ctrl_dev_name);
+ kfree(setting);
+- /* Eventually, this should trigger deferred probe */
+- return -ENODEV;
++ /*
++ * OK let us guess that the driver is not there yet, and
++ * let's defer obtaining this pinctrl handle to later...
++ */
++ return -EPROBE_DEFER;
+ }
+
+ switch (map->type) {
+diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
+index 5ef2feb..fcb1de4 100644
+--- a/drivers/pinctrl/devicetree.c
++++ b/drivers/pinctrl/devicetree.c
+@@ -121,11 +121,11 @@ static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
+ for (;;) {
+ np_pctldev = of_get_next_parent(np_pctldev);
+ if (!np_pctldev || of_node_is_root(np_pctldev)) {
+- dev_err(p->dev, "could not find pctldev for node %s\n",
++ dev_info(p->dev, "could not find pctldev for node %s, deferring probe\n",
+ np_config->full_name);
+ of_node_put(np_pctldev);
+- /* FIXME: This should trigger deferrered probe */
+- return -ENODEV;
++ /* OK let's just assume this will appear later then */
++ return -EPROBE_DEFER;
+ }
+ pctldev = find_pinctrl_by_of_node(np_pctldev);
+ if (pctldev)
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0203-pinctrl-replace-list_-with-get_-_count.patch b/patches.at91/0203-pinctrl-replace-list_-with-get_-_count.patch
new file mode 100644
index 00000000000000..beed95932c6ad9
--- /dev/null
+++ b/patches.at91/0203-pinctrl-replace-list_-with-get_-_count.patch
@@ -0,0 +1,634 @@
+From 0fb545a399810ecbb6b81899a36c95671bc5dfc6 Mon Sep 17 00:00:00 2001
+From: Viresh Kumar <viresh.kumar@st.com>
+Date: Fri, 30 Mar 2012 11:25:40 +0530
+Subject: pinctrl: replace list_*() with get_*_count()
+
+Most of the SoC drivers implement list_groups() and list_functions()
+routines for pinctrl and pinmux. These routines continue returning
+zero until the selector argument is greater than total count of
+available groups or functions.
+
+This patch replaces these list_*() routines with get_*_count()
+routines, which returns the number of available selection for SoC
+driver. pinctrl layer will use this value to check the range it can
+choose.
+
+This patch fixes all user drivers for this change. There are other
+routines in user drivers, which have checks to check validity of
+selector passed to them. It is also no more required and hence
+removed.
+
+Documentation updated as well.
+
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Viresh Kumar <viresh.kumar@st.com>
+[Folded in fix and fixed a minor merge artifact manually]
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ Documentation/pinctrl.txt | 37 +++++++++++++++----------------------
+ drivers/pinctrl/core.c | 10 ++++++----
+ drivers/pinctrl/pinconf.c | 3 ++-
+ drivers/pinctrl/pinctrl-pxa3xx.c | 24 ++++++++++--------------
+ drivers/pinctrl/pinctrl-sirf.c | 20 ++++++--------------
+ drivers/pinctrl/pinctrl-tegra.c | 40 ++++++----------------------------------
+ drivers/pinctrl/pinctrl-u300.c | 20 ++++++--------------
+ drivers/pinctrl/pinmux.c | 11 +++++++----
+ include/linux/pinctrl/pinctrl.h | 6 ++----
+ include/linux/pinctrl/pinmux.h | 7 +++----
+ 10 files changed, 63 insertions(+), 115 deletions(-)
+
+diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt
+index b85f0bd..f5add79 100644
+--- a/Documentation/pinctrl.txt
++++ b/Documentation/pinctrl.txt
+@@ -152,11 +152,9 @@ static const struct foo_group foo_groups[] = {
+ };
+
+
+-static int foo_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
++static int foo_get_groups_count(struct pinctrl_dev *pctldev)
+ {
+- if (selector >= ARRAY_SIZE(foo_groups))
+- return -EINVAL;
+- return 0;
++ return ARRAY_SIZE(foo_groups);
+ }
+
+ static const char *foo_get_group_name(struct pinctrl_dev *pctldev,
+@@ -175,7 +173,7 @@ static int foo_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+ }
+
+ static struct pinctrl_ops foo_pctrl_ops = {
+- .list_groups = foo_list_groups,
++ .get_groups_count = foo_get_groups_count,
+ .get_group_name = foo_get_group_name,
+ .get_group_pins = foo_get_group_pins,
+ };
+@@ -186,13 +184,12 @@ static struct pinctrl_desc foo_desc = {
+ .pctlops = &foo_pctrl_ops,
+ };
+
+-The pin control subsystem will call the .list_groups() function repeatedly
+-beginning on 0 until it returns non-zero to determine legal selectors, then
+-it will call the other functions to retrieve the name and pins of the group.
+-Maintaining the data structure of the groups is up to the driver, this is
+-just a simple example - in practice you may need more entries in your group
+-structure, for example specific register ranges associated with each group
+-and so on.
++The pin control subsystem will call the .get_groups_count() function to
++determine total number of legal selectors, then it will call the other functions
++to retrieve the name and pins of the group. Maintaining the data structure of
++the groups is up to the driver, this is just a simple example - in practice you
++may need more entries in your group structure, for example specific register
++ranges associated with each group and so on.
+
+
+ Pin configuration
+@@ -606,11 +603,9 @@ static const struct foo_group foo_groups[] = {
+ };
+
+
+-static int foo_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
++static int foo_get_groups_count(struct pinctrl_dev *pctldev)
+ {
+- if (selector >= ARRAY_SIZE(foo_groups))
+- return -EINVAL;
+- return 0;
++ return ARRAY_SIZE(foo_groups);
+ }
+
+ static const char *foo_get_group_name(struct pinctrl_dev *pctldev,
+@@ -629,7 +624,7 @@ static int foo_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+ }
+
+ static struct pinctrl_ops foo_pctrl_ops = {
+- .list_groups = foo_list_groups,
++ .get_groups_count = foo_get_groups_count,
+ .get_group_name = foo_get_group_name,
+ .get_group_pins = foo_get_group_pins,
+ };
+@@ -663,11 +658,9 @@ static const struct foo_pmx_func foo_functions[] = {
+ },
+ };
+
+-int foo_list_funcs(struct pinctrl_dev *pctldev, unsigned selector)
++int foo_get_functions_count(struct pinctrl_dev *pctldev)
+ {
+- if (selector >= ARRAY_SIZE(foo_functions))
+- return -EINVAL;
+- return 0;
++ return ARRAY_SIZE(foo_functions);
+ }
+
+ const char *foo_get_fname(struct pinctrl_dev *pctldev, unsigned selector)
+@@ -703,7 +696,7 @@ void foo_disable(struct pinctrl_dev *pctldev, unsigned selector,
+ }
+
+ struct pinmux_ops foo_pmxops = {
+- .list_functions = foo_list_funcs,
++ .get_functions_count = foo_get_functions_count,
+ .get_function_name = foo_get_fname,
+ .get_function_groups = foo_get_groups,
+ .enable = foo_enable,
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index ff78028..c70ae2d 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -333,9 +333,10 @@ int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
+ const char *pin_group)
+ {
+ const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
++ unsigned ngroups = pctlops->get_groups_count(pctldev);
+ unsigned group_selector = 0;
+
+- while (pctlops->list_groups(pctldev, group_selector) >= 0) {
++ while (group_selector < ngroups) {
+ const char *gname = pctlops->get_group_name(pctldev,
+ group_selector);
+ if (!strcmp(gname, pin_group)) {
+@@ -1023,12 +1024,13 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
+ {
+ struct pinctrl_dev *pctldev = s->private;
+ const struct pinctrl_ops *ops = pctldev->desc->pctlops;
+- unsigned selector = 0;
++ unsigned ngroups, selector = 0;
+
++ ngroups = ops->get_groups_count(pctldev);
+ mutex_lock(&pinctrl_mutex);
+
+ seq_puts(s, "registered pin groups:\n");
+- while (ops->list_groups(pctldev, selector) >= 0) {
++ while (selector < ngroups) {
+ const unsigned *pins;
+ unsigned num_pins;
+ const char *gname = ops->get_group_name(pctldev, selector);
+@@ -1343,7 +1345,7 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev)
+ const struct pinctrl_ops *ops = pctldev->desc->pctlops;
+
+ if (!ops ||
+- !ops->list_groups ||
++ !ops->get_groups_count ||
+ !ops->get_group_name ||
+ !ops->get_group_pins)
+ return -EINVAL;
+diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c
+index 7321e86..eb3a14f4 100644
+--- a/drivers/pinctrl/pinconf.c
++++ b/drivers/pinctrl/pinconf.c
+@@ -495,6 +495,7 @@ static int pinconf_groups_show(struct seq_file *s, void *what)
+ struct pinctrl_dev *pctldev = s->private;
+ const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
+ const struct pinconf_ops *ops = pctldev->desc->confops;
++ unsigned ngroups = pctlops->get_groups_count(pctldev);
+ unsigned selector = 0;
+
+ if (!ops || !ops->pin_config_group_get)
+@@ -505,7 +506,7 @@ static int pinconf_groups_show(struct seq_file *s, void *what)
+
+ mutex_lock(&pinctrl_mutex);
+
+- while (pctlops->list_groups(pctldev, selector) >= 0) {
++ while (selector < ngroups) {
+ const char *gname = pctlops->get_group_name(pctldev, selector);
+
+ seq_printf(s, "%u (%s):", selector, gname);
+diff --git a/drivers/pinctrl/pinctrl-pxa3xx.c b/drivers/pinctrl/pinctrl-pxa3xx.c
+index 079dce0..7644e42 100644
+--- a/drivers/pinctrl/pinctrl-pxa3xx.c
++++ b/drivers/pinctrl/pinctrl-pxa3xx.c
+@@ -25,20 +25,18 @@ static struct pinctrl_gpio_range pxa3xx_pinctrl_gpio_range = {
+ .pin_base = 0,
+ };
+
+-static int pxa3xx_list_groups(struct pinctrl_dev *pctrldev, unsigned selector)
++static int pxa3xx_get_groups_count(struct pinctrl_dev *pctrldev)
+ {
+ struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+- if (selector >= info->num_grps)
+- return -EINVAL;
+- return 0;
++
++ return info->num_grps;
+ }
+
+ static const char *pxa3xx_get_group_name(struct pinctrl_dev *pctrldev,
+ unsigned selector)
+ {
+ struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+- if (selector >= info->num_grps)
+- return NULL;
++
+ return info->grps[selector].name;
+ }
+
+@@ -48,25 +46,23 @@ static int pxa3xx_get_group_pins(struct pinctrl_dev *pctrldev,
+ unsigned *num_pins)
+ {
+ struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+- if (selector >= info->num_grps)
+- return -EINVAL;
++
+ *pins = info->grps[selector].pins;
+ *num_pins = info->grps[selector].npins;
+ return 0;
+ }
+
+ static struct pinctrl_ops pxa3xx_pctrl_ops = {
+- .list_groups = pxa3xx_list_groups,
++ .get_groups_count = pxa3xx_get_groups_count,
+ .get_group_name = pxa3xx_get_group_name,
+ .get_group_pins = pxa3xx_get_group_pins,
+ };
+
+-static int pxa3xx_pmx_list_func(struct pinctrl_dev *pctrldev, unsigned func)
++static int pxa3xx_pmx_get_funcs_count(struct pinctrl_dev *pctrldev)
+ {
+ struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+- if (func >= info->num_funcs)
+- return -EINVAL;
+- return 0;
++
++ return info->num_funcs;
+ }
+
+ static const char *pxa3xx_pmx_get_func_name(struct pinctrl_dev *pctrldev,
+@@ -170,7 +166,7 @@ static int pxa3xx_pmx_request_gpio(struct pinctrl_dev *pctrldev,
+ }
+
+ static struct pinmux_ops pxa3xx_pmx_ops = {
+- .list_functions = pxa3xx_pmx_list_func,
++ .get_functions_count = pxa3xx_pmx_get_funcs_count,
+ .get_function_name = pxa3xx_pmx_get_func_name,
+ .get_function_groups = pxa3xx_pmx_get_groups,
+ .enable = pxa3xx_pmx_enable,
+diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c
+index 6b3534c..ba15b1a 100644
+--- a/drivers/pinctrl/pinctrl-sirf.c
++++ b/drivers/pinctrl/pinctrl-sirf.c
+@@ -853,18 +853,14 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = {
+ SIRFSOC_PIN_GROUP("gpsgrp", gps_pins),
+ };
+
+-static int sirfsoc_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
++static int sirfsoc_get_groups_count(struct pinctrl_dev *pctldev)
+ {
+- if (selector >= ARRAY_SIZE(sirfsoc_pin_groups))
+- return -EINVAL;
+- return 0;
++ return ARRAY_SIZE(sirfsoc_pin_groups);
+ }
+
+ static const char *sirfsoc_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+ {
+- if (selector >= ARRAY_SIZE(sirfsoc_pin_groups))
+- return NULL;
+ return sirfsoc_pin_groups[selector].name;
+ }
+
+@@ -872,8 +868,6 @@ static int sirfsoc_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector
+ const unsigned **pins,
+ unsigned *num_pins)
+ {
+- if (selector >= ARRAY_SIZE(sirfsoc_pin_groups))
+- return -EINVAL;
+ *pins = sirfsoc_pin_groups[selector].pins;
+ *num_pins = sirfsoc_pin_groups[selector].num_pins;
+ return 0;
+@@ -886,7 +880,7 @@ static void sirfsoc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s
+ }
+
+ static struct pinctrl_ops sirfsoc_pctrl_ops = {
+- .list_groups = sirfsoc_list_groups,
++ .get_groups_count = sirfsoc_get_groups_count,
+ .get_group_name = sirfsoc_get_group_name,
+ .get_group_pins = sirfsoc_get_group_pins,
+ .pin_dbg_show = sirfsoc_pin_dbg_show,
+@@ -1033,11 +1027,9 @@ static void sirfsoc_pinmux_disable(struct pinctrl_dev *pmxdev, unsigned selector
+ sirfsoc_pinmux_endisable(spmx, selector, false);
+ }
+
+-static int sirfsoc_pinmux_list_funcs(struct pinctrl_dev *pmxdev, unsigned selector)
++static int sirfsoc_pinmux_get_funcs_count(struct pinctrl_dev *pmxdev)
+ {
+- if (selector >= ARRAY_SIZE(sirfsoc_pmx_functions))
+- return -EINVAL;
+- return 0;
++ return ARRAY_SIZE(sirfsoc_pmx_functions);
+ }
+
+ static const char *sirfsoc_pinmux_get_func_name(struct pinctrl_dev *pctldev,
+@@ -1074,9 +1066,9 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev,
+ }
+
+ static struct pinmux_ops sirfsoc_pinmux_ops = {
+- .list_functions = sirfsoc_pinmux_list_funcs,
+ .enable = sirfsoc_pinmux_enable,
+ .disable = sirfsoc_pinmux_disable,
++ .get_functions_count = sirfsoc_pinmux_get_funcs_count,
+ .get_function_name = sirfsoc_pinmux_get_func_name,
+ .get_function_groups = sirfsoc_pinmux_get_groups,
+ .gpio_request_enable = sirfsoc_pinmux_request_gpio,
+diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
+index 0b3c02f..c4c47c5 100644
+--- a/drivers/pinctrl/pinctrl-tegra.c
++++ b/drivers/pinctrl/pinctrl-tegra.c
+@@ -53,15 +53,11 @@ static inline void pmx_writel(struct tegra_pmx *pmx, u32 val, u32 bank, u32 reg)
+ writel(val, pmx->regs[bank] + reg);
+ }
+
+-static int tegra_pinctrl_list_groups(struct pinctrl_dev *pctldev,
+- unsigned group)
++static int tegra_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+ {
+ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+- if (group >= pmx->soc->ngroups)
+- return -EINVAL;
+-
+- return 0;
++ return pmx->soc->ngroups;
+ }
+
+ static const char *tegra_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+@@ -69,9 +65,6 @@ static const char *tegra_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+ {
+ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+- if (group >= pmx->soc->ngroups)
+- return NULL;
+-
+ return pmx->soc->groups[group].name;
+ }
+
+@@ -82,9 +75,6 @@ static int tegra_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+ {
+ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+- if (group >= pmx->soc->ngroups)
+- return -EINVAL;
+-
+ *pins = pmx->soc->groups[group].pins;
+ *num_pins = pmx->soc->groups[group].npins;
+
+@@ -99,21 +89,17 @@ static void tegra_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
+ }
+
+ static struct pinctrl_ops tegra_pinctrl_ops = {
+- .list_groups = tegra_pinctrl_list_groups,
++ .get_groups_count = tegra_pinctrl_get_groups_count,
+ .get_group_name = tegra_pinctrl_get_group_name,
+ .get_group_pins = tegra_pinctrl_get_group_pins,
+ .pin_dbg_show = tegra_pinctrl_pin_dbg_show,
+ };
+
+-static int tegra_pinctrl_list_funcs(struct pinctrl_dev *pctldev,
+- unsigned function)
++static int tegra_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
+ {
+ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+- if (function >= pmx->soc->nfunctions)
+- return -EINVAL;
+-
+- return 0;
++ return pmx->soc->nfunctions;
+ }
+
+ static const char *tegra_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
+@@ -121,9 +107,6 @@ static const char *tegra_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
+ {
+ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+- if (function >= pmx->soc->nfunctions)
+- return NULL;
+-
+ return pmx->soc->functions[function].name;
+ }
+
+@@ -134,9 +117,6 @@ static int tegra_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
+ {
+ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+- if (function >= pmx->soc->nfunctions)
+- return -EINVAL;
+-
+ *groups = pmx->soc->functions[function].groups;
+ *num_groups = pmx->soc->functions[function].ngroups;
+
+@@ -151,8 +131,6 @@ static int tegra_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function,
+ int i;
+ u32 val;
+
+- if (group >= pmx->soc->ngroups)
+- return -EINVAL;
+ g = &pmx->soc->groups[group];
+
+ if (g->mux_reg < 0)
+@@ -180,8 +158,6 @@ static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev,
+ const struct tegra_pingroup *g;
+ u32 val;
+
+- if (group >= pmx->soc->ngroups)
+- return;
+ g = &pmx->soc->groups[group];
+
+ if (g->mux_reg < 0)
+@@ -194,7 +170,7 @@ static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev,
+ }
+
+ static struct pinmux_ops tegra_pinmux_ops = {
+- .list_functions = tegra_pinctrl_list_funcs,
++ .get_functions_count = tegra_pinctrl_get_funcs_count,
+ .get_function_name = tegra_pinctrl_get_func_name,
+ .get_function_groups = tegra_pinctrl_get_func_groups,
+ .enable = tegra_pinctrl_enable,
+@@ -324,8 +300,6 @@ static int tegra_pinconf_group_get(struct pinctrl_dev *pctldev,
+ s16 reg;
+ u32 val, mask;
+
+- if (group >= pmx->soc->ngroups)
+- return -EINVAL;
+ g = &pmx->soc->groups[group];
+
+ ret = tegra_pinconf_reg(pmx, g, param, &bank, &reg, &bit, &width);
+@@ -353,8 +327,6 @@ static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev,
+ s16 reg;
+ u32 val, mask;
+
+- if (group >= pmx->soc->ngroups)
+- return -EINVAL;
+ g = &pmx->soc->groups[group];
+
+ ret = tegra_pinconf_reg(pmx, g, param, &bank, &reg, &bit, &width);
+diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c
+index 9ff6207..10de43c 100644
+--- a/drivers/pinctrl/pinctrl-u300.c
++++ b/drivers/pinctrl/pinctrl-u300.c
+@@ -836,18 +836,14 @@ static const struct u300_pin_group u300_pin_groups[] = {
+ },
+ };
+
+-static int u300_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
++static int u300_get_groups_count(struct pinctrl_dev *pctldev)
+ {
+- if (selector >= ARRAY_SIZE(u300_pin_groups))
+- return -EINVAL;
+- return 0;
++ return ARRAY_SIZE(u300_pin_groups);
+ }
+
+ static const char *u300_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+ {
+- if (selector >= ARRAY_SIZE(u300_pin_groups))
+- return NULL;
+ return u300_pin_groups[selector].name;
+ }
+
+@@ -855,8 +851,6 @@ static int u300_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+ const unsigned **pins,
+ unsigned *num_pins)
+ {
+- if (selector >= ARRAY_SIZE(u300_pin_groups))
+- return -EINVAL;
+ *pins = u300_pin_groups[selector].pins;
+ *num_pins = u300_pin_groups[selector].num_pins;
+ return 0;
+@@ -869,7 +863,7 @@ static void u300_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+ }
+
+ static struct pinctrl_ops u300_pctrl_ops = {
+- .list_groups = u300_list_groups,
++ .get_groups_count = u300_get_groups_count,
+ .get_group_name = u300_get_group_name,
+ .get_group_pins = u300_get_group_pins,
+ .pin_dbg_show = u300_pin_dbg_show,
+@@ -991,11 +985,9 @@ static void u300_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector,
+ u300_pmx_endisable(upmx, selector, false);
+ }
+
+-static int u300_pmx_list_funcs(struct pinctrl_dev *pctldev, unsigned selector)
++static int u300_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
+ {
+- if (selector >= ARRAY_SIZE(u300_pmx_functions))
+- return -EINVAL;
+- return 0;
++ return ARRAY_SIZE(u300_pmx_functions);
+ }
+
+ static const char *u300_pmx_get_func_name(struct pinctrl_dev *pctldev,
+@@ -1014,7 +1006,7 @@ static int u300_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
+ }
+
+ static struct pinmux_ops u300_pmx_ops = {
+- .list_functions = u300_pmx_list_funcs,
++ .get_functions_count = u300_pmx_get_funcs_count,
+ .get_function_name = u300_pmx_get_func_name,
+ .get_function_groups = u300_pmx_get_groups,
+ .enable = u300_pmx_enable,
+diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
+index 4e62783..375b214 100644
+--- a/drivers/pinctrl/pinmux.c
++++ b/drivers/pinctrl/pinmux.c
+@@ -33,10 +33,11 @@
+ int pinmux_check_ops(struct pinctrl_dev *pctldev)
+ {
+ const struct pinmux_ops *ops = pctldev->desc->pmxops;
++ unsigned nfuncs = ops->get_functions_count(pctldev);
+ unsigned selector = 0;
+
+ /* Check that we implement required operations */
+- if (!ops->list_functions ||
++ if (!ops->get_functions_count ||
+ !ops->get_function_name ||
+ !ops->get_function_groups ||
+ !ops->enable ||
+@@ -44,7 +45,7 @@ int pinmux_check_ops(struct pinctrl_dev *pctldev)
+ return -EINVAL;
+
+ /* Check that all functions registered have names */
+- while (ops->list_functions(pctldev, selector) >= 0) {
++ while (selector < nfuncs) {
+ const char *fname = ops->get_function_name(pctldev,
+ selector);
+ if (!fname) {
+@@ -287,10 +288,11 @@ static int pinmux_func_name_to_selector(struct pinctrl_dev *pctldev,
+ const char *function)
+ {
+ const struct pinmux_ops *ops = pctldev->desc->pmxops;
++ unsigned nfuncs = ops->get_functions_count(pctldev);
+ unsigned selector = 0;
+
+ /* See if this pctldev has this function */
+- while (ops->list_functions(pctldev, selector) >= 0) {
++ while (selector < nfuncs) {
+ const char *fname = ops->get_function_name(pctldev,
+ selector);
+
+@@ -477,11 +479,12 @@ static int pinmux_functions_show(struct seq_file *s, void *what)
+ {
+ struct pinctrl_dev *pctldev = s->private;
+ const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
++ unsigned nfuncs = pmxops->get_functions_count(pctldev);
+ unsigned func_selector = 0;
+
+ mutex_lock(&pinctrl_mutex);
+
+- while (pmxops->list_functions(pctldev, func_selector) >= 0) {
++ while (func_selector < nfuncs) {
+ const char *func = pmxops->get_function_name(pctldev,
+ func_selector);
+ const char * const *groups;
+diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
+index e162710..ba08516 100644
+--- a/include/linux/pinctrl/pinctrl.h
++++ b/include/linux/pinctrl/pinctrl.h
+@@ -66,9 +66,7 @@ struct pinctrl_gpio_range {
+ /**
+ * struct pinctrl_ops - global pin control operations, to be implemented by
+ * pin controller drivers.
+- * @list_groups: list the number of selectable named groups available
+- * in this pinmux driver, the core will begin on 0 and call this
+- * repeatedly as long as it returns >= 0 to enumerate the groups
++ * @get_groups_count: Returns the count of total number of groups registered.
+ * @get_group_name: return the group name of the pin group
+ * @get_group_pins: return an array of pins corresponding to a certain
+ * group selector @pins, and the size of the array in @num_pins
+@@ -76,7 +74,7 @@ struct pinctrl_gpio_range {
+ * info for a certain pin in debugfs
+ */
+ struct pinctrl_ops {
+- int (*list_groups) (struct pinctrl_dev *pctldev, unsigned selector);
++ int (*get_groups_count) (struct pinctrl_dev *pctldev);
+ const char *(*get_group_name) (struct pinctrl_dev *pctldev,
+ unsigned selector);
+ int (*get_group_pins) (struct pinctrl_dev *pctldev,
+diff --git a/include/linux/pinctrl/pinmux.h b/include/linux/pinctrl/pinmux.h
+index 47e9237..dd7bef6 100644
+--- a/include/linux/pinctrl/pinmux.h
++++ b/include/linux/pinctrl/pinmux.h
+@@ -29,9 +29,8 @@ struct pinctrl_dev;
+ * is allowed to answer "no" by returning a negative error code
+ * @free: the reverse function of the request() callback, frees a pin after
+ * being requested
+- * @list_functions: list the number of selectable named functions available
+- * in this pinmux driver, the core will begin on 0 and call this
+- * repeatedly as long as it returns >= 0 to enumerate mux settings
++ * @get_functions_count: returns number of selectable named functions available
++ * in this pinmux driver
+ * @get_function_name: return the function name of the muxing selector,
+ * called by the core to figure out which mux setting it shall map a
+ * certain device to
+@@ -62,7 +61,7 @@ struct pinctrl_dev;
+ struct pinmux_ops {
+ int (*request) (struct pinctrl_dev *pctldev, unsigned offset);
+ int (*free) (struct pinctrl_dev *pctldev, unsigned offset);
+- int (*list_functions) (struct pinctrl_dev *pctldev, unsigned selector);
++ int (*get_functions_count) (struct pinctrl_dev *pctldev);
+ const char *(*get_function_name) (struct pinctrl_dev *pctldev,
+ unsigned selector);
+ int (*get_function_groups) (struct pinctrl_dev *pctldev,
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0204-pinctrl-show-pin-name-when-request-pins.patch b/patches.at91/0204-pinctrl-show-pin-name-when-request-pins.patch
new file mode 100644
index 00000000000000..d5517298ba2e87
--- /dev/null
+++ b/patches.at91/0204-pinctrl-show-pin-name-when-request-pins.patch
@@ -0,0 +1,40 @@
+From 347e1c7f02beed8503937c53ecb23007970668ac Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <dong.aisheng@linaro.org>
+Date: Tue, 17 Apr 2012 15:00:45 +0800
+Subject: pinctrl: show pin name when request pins
+
+Pin name is more useful to users.
+
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/pinmux.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
+index 375b214..d6f6823 100644
+--- a/drivers/pinctrl/pinmux.c
++++ b/drivers/pinctrl/pinmux.c
+@@ -86,8 +86,6 @@ static int pin_request(struct pinctrl_dev *pctldev,
+ const struct pinmux_ops *ops = pctldev->desc->pmxops;
+ int status = -EINVAL;
+
+- dev_dbg(pctldev->dev, "request pin %d for %s\n", pin, owner);
+-
+ desc = pin_desc_get(pctldev, pin);
+ if (desc == NULL) {
+ dev_err(pctldev->dev,
+@@ -95,6 +93,9 @@ static int pin_request(struct pinctrl_dev *pctldev,
+ goto out;
+ }
+
++ dev_dbg(pctldev->dev, "request pin %d (%s) for %s\n",
++ pin, desc->name, owner);
++
+ if (gpio_range) {
+ /* There's no need to support multiple GPIO requests */
+ if (desc->gpio_owner) {
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0205-pinctrl-show-pin-name-for-pingroups-in-sysfs.patch b/patches.at91/0205-pinctrl-show-pin-name-for-pingroups-in-sysfs.patch
new file mode 100644
index 00000000000000..dbf7a4cbe7812a
--- /dev/null
+++ b/patches.at91/0205-pinctrl-show-pin-name-for-pingroups-in-sysfs.patch
@@ -0,0 +1,106 @@
+From 7e6ef22d45a1c112647e4a671442647f938602a4 Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <dong.aisheng@linaro.org>
+Date: Tue, 17 Apr 2012 15:00:46 +0800
+Subject: pinctrl: show pin name for pingroups in sysfs
+
+Pin name is more useful to users.
+
+After change, when cat pingroups in sysfs, it becomes:
+root@freescale /sys/kernel/debug/pinctrl/20e0000.iomuxc$ cat pingroups
+registered pin groups:
+group: uart4grp-1
+pin 219 (MX6Q_PAD_KEY_ROW0)
+pin 218 (MX6Q_PAD_KEY_COL0)
+
+group: usdhc4grp-1
+pin 305 (MX6Q_PAD_SD4_CMD)
+pin 306 (MX6Q_PAD_SD4_CLK)
+pin 315 (MX6Q_PAD_SD4_DAT0)
+pin 316 (MX6Q_PAD_SD4_DAT1)
+pin 317 (MX6Q_PAD_SD4_DAT2)
+pin 318 (MX6Q_PAD_SD4_DAT3)
+pin 319 (MX6Q_PAD_SD4_DAT4)
+pin 320 (MX6Q_PAD_SD4_DAT5)
+pin 321 (MX6Q_PAD_SD4_DAT6)
+pin 322 (MX6Q_PAD_SD4_DAT7)
+
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/core.c | 32 ++++++++++++++++++++++++++++----
+ drivers/pinctrl/core.h | 1 +
+ 2 files changed, 29 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index c70ae2d..5f8a7d2 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -141,6 +141,25 @@ int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name)
+ }
+
+ /**
++ * pin_get_name_from_id() - look up a pin name from a pin id
++ * @pctldev: the pin control device to lookup the pin on
++ * @name: the name of the pin to look up
++ */
++const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin)
++{
++ const struct pin_desc *desc;
++
++ desc = pin_desc_get(pctldev, pin);
++ if (desc == NULL) {
++ dev_err(pctldev->dev, "failed to get pin(%d) name\n",
++ pin);
++ return NULL;
++ }
++
++ return desc->name;
++}
++
++/**
+ * pin_is_valid() - check if pin exists on controller
+ * @pctldev: the pin control device to check the pin on
+ * @pin: pin to check, use the local pin controller index number
+@@ -1034,6 +1053,7 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
+ const unsigned *pins;
+ unsigned num_pins;
+ const char *gname = ops->get_group_name(pctldev, selector);
++ const char *pname;
+ int ret;
+ int i;
+
+@@ -1043,10 +1063,14 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
+ seq_printf(s, "%s [ERROR GETTING PINS]\n",
+ gname);
+ else {
+- seq_printf(s, "group: %s, pins = [ ", gname);
+- for (i = 0; i < num_pins; i++)
+- seq_printf(s, "%d ", pins[i]);
+- seq_puts(s, "]\n");
++ seq_printf(s, "group: %s\n", gname);
++ for (i = 0; i < num_pins; i++) {
++ pname = pin_get_name(pctldev, pins[i]);
++ if (WARN_ON(!pname))
++ return -EINVAL;
++ seq_printf(s, "pin %d (%s)\n", pins[i], pname);
++ }
++ seq_puts(s, "\n");
+ }
+ selector++;
+ }
+diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
+index 98ae808..1f40ff6 100644
+--- a/drivers/pinctrl/core.h
++++ b/drivers/pinctrl/core.h
+@@ -148,6 +148,7 @@ struct pin_desc {
+
+ struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name);
+ int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name);
++const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin);
+ int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
+ const char *pin_group);
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0206-dt-add-of_get_child_count-helper-function.patch b/patches.at91/0206-dt-add-of_get_child_count-helper-function.patch
new file mode 100644
index 00000000000000..a388df0d017af8
--- /dev/null
+++ b/patches.at91/0206-dt-add-of_get_child_count-helper-function.patch
@@ -0,0 +1,49 @@
+From bbc91a68271eb2285968c7f68f8325d781d1e3b0 Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <dong.aisheng@linaro.org>
+Date: Fri, 27 Apr 2012 11:36:20 +0800
+Subject: dt: add of_get_child_count helper function
+
+Currently most code to get child count in kernel are almost same,
+add a helper to implement this function for dt to use.
+
+Cc: Grant Likely <grant.likely@secretlab.ca>
+Acked-by: Rob Herring <rob.herring@calxeda.com>
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ include/linux/of.h | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+--- a/include/linux/of.h
++++ b/include/linux/of.h
+@@ -194,6 +194,17 @@ extern struct device_node *of_get_next_c
+ for (child = of_get_next_child(parent, NULL); child != NULL; \
+ child = of_get_next_child(parent, child))
+
++static inline int of_get_child_count(const struct device_node *np)
++{
++ struct device_node *child;
++ int num = 0;
++
++ for_each_child_of_node(np, child)
++ num++;
++
++ return num;
++}
++
+ extern struct device_node *of_find_node_with_property(
+ struct device_node *from, const char *prop_name);
+ #define for_each_node_with_property(dn, prop_name) \
+@@ -306,6 +317,11 @@ static inline bool of_have_populated_dt(
+ #define for_each_child_of_node(parent, child) \
+ while (0)
+
++static inline int of_get_child_count(const struct device_node *np)
++{
++ return 0;
++}
++
+ static inline int of_device_is_compatible(const struct device_node *device,
+ const char *name)
+ {
diff --git a/patches.at91/0207-arm-at91-use-macro-to-declare-soc-boot-data.patch b/patches.at91/0207-arm-at91-use-macro-to-declare-soc-boot-data.patch
new file mode 100644
index 00000000000000..d76e21996c4bf7
--- /dev/null
+++ b/patches.at91/0207-arm-at91-use-macro-to-declare-soc-boot-data.patch
@@ -0,0 +1,191 @@
+From f0e343643120ab803373244ed2996b9dd169a850 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Thu, 16 Aug 2012 17:36:55 +0800
+Subject: arm: at91: use macro to declare soc boot data
+
+Instead of check the pointer of the init function, check the new builtin bool
+to known if the soc is enabled.
+
+This is needed as with the switch to the pinctrl the init will be NULL on pure
+DT SoC.
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/mach-at91/at91rm9200.c | 4 ++--
+ arch/arm/mach-at91/at91sam9260.c | 4 ++--
+ arch/arm/mach-at91/at91sam9261.c | 4 ++--
+ arch/arm/mach-at91/at91sam9263.c | 4 ++--
+ arch/arm/mach-at91/at91sam9g45.c | 4 ++--
+ arch/arm/mach-at91/at91sam9n12.c | 4 ++--
+ arch/arm/mach-at91/at91sam9rl.c | 4 ++--
+ arch/arm/mach-at91/at91sam9x5.c | 4 ++--
+ arch/arm/mach-at91/soc.h | 12 +++++++++++-
+ 9 files changed, 27 insertions(+), 17 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
+index b4f0565..a454734 100644
+--- a/arch/arm/mach-at91/at91rm9200.c
++++ b/arch/arm/mach-at91/at91rm9200.c
+@@ -361,10 +361,10 @@ static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
+ 0 /* Advanced Interrupt Controller (IRQ6) */
+ };
+
+-struct at91_init_soc __initdata at91rm9200_soc = {
++AT91_SOC_START(rm9200)
+ .map_io = at91rm9200_map_io,
+ .default_irq_priority = at91rm9200_default_irq_priority,
+ .ioremap_registers = at91rm9200_ioremap_registers,
+ .register_clocks = at91rm9200_register_clocks,
+ .init = at91rm9200_initialize,
+-};
++AT91_SOC_END
+diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
+index 040f79a..bb9bc50 100644
+--- a/arch/arm/mach-at91/at91sam9260.c
++++ b/arch/arm/mach-at91/at91sam9260.c
+@@ -383,10 +383,10 @@ static unsigned int at91sam9260_default_irq_priority[NR_AIC_IRQS] __initdata = {
+ 0, /* Advanced Interrupt Controller */
+ };
+
+-struct at91_init_soc __initdata at91sam9260_soc = {
++AT91_SOC_START(sam9260)
+ .map_io = at91sam9260_map_io,
+ .default_irq_priority = at91sam9260_default_irq_priority,
+ .ioremap_registers = at91sam9260_ioremap_registers,
+ .register_clocks = at91sam9260_register_clocks,
+ .init = at91sam9260_initialize,
+-};
++AT91_SOC_END
+diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
+index 8d999eb..93a24e9 100644
+--- a/arch/arm/mach-at91/at91sam9261.c
++++ b/arch/arm/mach-at91/at91sam9261.c
+@@ -334,10 +334,10 @@ static unsigned int at91sam9261_default_irq_priority[NR_AIC_IRQS] __initdata = {
+ 0, /* Advanced Interrupt Controller */
+ };
+
+-struct at91_init_soc __initdata at91sam9261_soc = {
++AT91_SOC_START(sam9261)
+ .map_io = at91sam9261_map_io,
+ .default_irq_priority = at91sam9261_default_irq_priority,
+ .ioremap_registers = at91sam9261_ioremap_registers,
+ .register_clocks = at91sam9261_register_clocks,
+ .init = at91sam9261_initialize,
+-};
++AT91_SOC_END
+diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
+index 00723ec..76499a6 100644
+--- a/arch/arm/mach-at91/at91sam9263.c
++++ b/arch/arm/mach-at91/at91sam9263.c
+@@ -367,10 +367,10 @@ static unsigned int at91sam9263_default_irq_priority[NR_AIC_IRQS] __initdata = {
+ 0, /* Advanced Interrupt Controller (IRQ1) */
+ };
+
+-struct at91_init_soc __initdata at91sam9263_soc = {
++AT91_SOC_START(sam9263)
+ .map_io = at91sam9263_map_io,
+ .default_irq_priority = at91sam9263_default_irq_priority,
+ .ioremap_registers = at91sam9263_ioremap_registers,
+ .register_clocks = at91sam9263_register_clocks,
+ .init = at91sam9263_initialize,
+-};
++AT91_SOC_END
+diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
+index 4b791bf..5e7a1dd 100644
+--- a/arch/arm/mach-at91/at91sam9g45.c
++++ b/arch/arm/mach-at91/at91sam9g45.c
+@@ -405,10 +405,10 @@ static unsigned int at91sam9g45_default_irq_priority[NR_AIC_IRQS] __initdata = {
+ 0, /* Advanced Interrupt Controller (IRQ0) */
+ };
+
+-struct at91_init_soc __initdata at91sam9g45_soc = {
++AT91_SOC_START(sam9g45)
+ .map_io = at91sam9g45_map_io,
+ .default_irq_priority = at91sam9g45_default_irq_priority,
+ .ioremap_registers = at91sam9g45_ioremap_registers,
+ .register_clocks = at91sam9g45_register_clocks,
+ .init = at91sam9g45_initialize,
+-};
++AT91_SOC_END
+diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
+index d09baf1..6fa0df1 100644
+--- a/arch/arm/mach-at91/at91sam9n12.c
++++ b/arch/arm/mach-at91/at91sam9n12.c
+@@ -246,8 +246,8 @@ void __init at91sam9n12_initialize(void)
+ at91_gpio_init(NULL, 0);
+ }
+
+-struct at91_init_soc __initdata at91sam9n12_soc = {
++AT91_SOC_START(sam9n12)
+ .map_io = at91sam9n12_map_io,
+ .register_clocks = at91sam9n12_register_clocks,
+ .init = at91sam9n12_initialize,
+-};
++AT91_SOC_END
+diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
+index 72e9084..cbe72e4 100644
+--- a/arch/arm/mach-at91/at91sam9rl.c
++++ b/arch/arm/mach-at91/at91sam9rl.c
+@@ -338,10 +338,10 @@ static unsigned int at91sam9rl_default_irq_priority[NR_AIC_IRQS] __initdata = {
+ 0, /* Advanced Interrupt Controller */
+ };
+
+-struct at91_init_soc __initdata at91sam9rl_soc = {
++AT91_SOC_START(sam9rl)
+ .map_io = at91sam9rl_map_io,
+ .default_irq_priority = at91sam9rl_default_irq_priority,
+ .ioremap_registers = at91sam9rl_ioremap_registers,
+ .register_clocks = at91sam9rl_register_clocks,
+ .init = at91sam9rl_initialize,
+-};
++AT91_SOC_END
+diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
+index f40c1ab..af00de4 100644
+--- a/arch/arm/mach-at91/at91sam9x5.c
++++ b/arch/arm/mach-at91/at91sam9x5.c
+@@ -323,8 +323,8 @@ void __init at91sam9x5_initialize(void)
+ * Interrupt initialization
+ * -------------------------------------------------------------------- */
+
+-struct at91_init_soc __initdata at91sam9x5_soc = {
++AT91_SOC_START(sam9x5)
+ .map_io = at91sam9x5_map_io,
+ .register_clocks = at91sam9x5_register_clocks,
+ .init = at91sam9x5_initialize,
+-};
++AT91_SOC_END
+diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h
+index a9cfeb1..9c6d3d4 100644
+--- a/arch/arm/mach-at91/soc.h
++++ b/arch/arm/mach-at91/soc.h
+@@ -5,6 +5,7 @@
+ */
+
+ struct at91_init_soc {
++ int builtin;
+ unsigned int *default_irq_priority;
+ void (*map_io)(void);
+ void (*ioremap_registers)(void);
+@@ -22,9 +23,18 @@ extern struct at91_init_soc at91sam9rl_soc;
+ extern struct at91_init_soc at91sam9x5_soc;
+ extern struct at91_init_soc at91sam9n12_soc;
+
++#define AT91_SOC_START(_name) \
++struct at91_init_soc __initdata at91##_name##_soc \
++ __used \
++ = { \
++ .builtin = 1, \
++
++#define AT91_SOC_END \
++};
++
+ static inline int at91_soc_is_enabled(void)
+ {
+- return at91_boot_soc.init != NULL;
++ return at91_boot_soc.builtin;
+ }
+
+ #if !defined(CONFIG_SOC_AT91RM9200)
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0208-ARM-at91-gpio-implement-request.patch b/patches.at91/0208-ARM-at91-gpio-implement-request.patch
new file mode 100644
index 00000000000000..076f49b820badb
--- /dev/null
+++ b/patches.at91/0208-ARM-at91-gpio-implement-request.patch
@@ -0,0 +1,58 @@
+From 0fac5d6d7ef4c0cd717f58efa59df743cb5621a4 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Fri, 6 Jul 2012 06:48:33 +0800
+Subject: ARM: at91: gpio: implement request
+
+Configure the pin as pio when requested.
+
+It is needed to configure the pin as PIO at "request time" when we are
+using DT. Indeed, the muxing via old AT91 API is not allowed anymore if
+we are using the plain gpiolib.
+
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/mach-at91/gpio.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
+index be42cf0..3b8f463 100644
+--- a/arch/arm/mach-at91/gpio.c
++++ b/arch/arm/mach-at91/gpio.c
+@@ -46,6 +46,7 @@ struct at91_gpio_chip {
+
+ #define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip)
+
++static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset);
+ static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip);
+ static void at91_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val);
+ static int at91_gpiolib_get(struct gpio_chip *chip, unsigned offset);
+@@ -59,6 +60,7 @@ static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset);
+ { \
+ .chip = { \
+ .label = name, \
++ .request = at91_gpiolib_request, \
+ .direction_input = at91_gpiolib_direction_input, \
+ .direction_output = at91_gpiolib_direction_output, \
+ .get = at91_gpiolib_get, \
+@@ -862,6 +864,16 @@ void __init at91_gpio_irq_setup(void)
+ }
+
+ /* gpiolib support */
++static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset)
++{
++ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
++ void __iomem *pio = at91_gpio->regbase;
++ unsigned mask = 1 << offset;
++
++ __raw_writel(mask, pio + PIO_PER);
++ return 0;
++}
++
+ static int at91_gpiolib_direction_input(struct gpio_chip *chip,
+ unsigned offset)
+ {
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0209-at91-regroup-gpio-and-pinctrl-under-the-same-ranges.patch b/patches.at91/0209-at91-regroup-gpio-and-pinctrl-under-the-same-ranges.patch
new file mode 100644
index 00000000000000..ef367698120efa
--- /dev/null
+++ b/patches.at91/0209-at91-regroup-gpio-and-pinctrl-under-the-same-ranges.patch
@@ -0,0 +1,505 @@
+From 7355b7402f8791117cdb9086cf45eb02a65b4cf0 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Wed, 4 Jul 2012 17:20:46 +0800
+Subject: at91: regroup gpio and pinctrl under the same ranges
+
+Fix also the reg size as we have 512 bytes bank not 256 bytes per gpio/mux
+controller
+
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/boot/dts/at91sam9260.dtsi | 59 +++++++++++----------
+ arch/arm/boot/dts/at91sam9263.dtsi | 94 +++++++++++++++++----------------
+ arch/arm/boot/dts/at91sam9g45.dtsi | 103 ++++++++++++++++++++-----------------
+ arch/arm/boot/dts/at91sam9n12.dtsi | 83 ++++++++++++++++--------------
+ arch/arm/boot/dts/at91sam9x5.dtsi | 83 ++++++++++++++++--------------
+ 5 files changed, 228 insertions(+), 194 deletions(-)
+
+diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
+index 0352bf8..e50261d 100644
+--- a/arch/arm/boot/dts/at91sam9260.dtsi
++++ b/arch/arm/boot/dts/at91sam9260.dtsi
+@@ -98,34 +98,41 @@
+ interrupts = <26 4 0 27 4 0 28 4 0>;
+ };
+
+- pioA: gpio@fffff400 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff400 0x100>;
+- interrupts = <2 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
++ pinctrl@fffff400 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
++ ranges = <0xfffff400 0xfffff400 0x600>;
+
+- pioB: gpio@fffff600 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff600 0x100>;
+- interrupts = <3 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
++ pioA: gpio@fffff400 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff400 0x200>;
++ interrupts = <2 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
+
+- pioC: gpio@fffff800 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff800 0x100>;
+- interrupts = <4 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
++ pioB: gpio@fffff600 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff600 0x200>;
++ interrupts = <3 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioC: gpio@fffff800 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff800 0x200>;
++ interrupts = <4 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
+ };
+
+ dbgu: serial@fffff200 {
+diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
+index 26ab452..45e5363 100644
+--- a/arch/arm/boot/dts/at91sam9263.dtsi
++++ b/arch/arm/boot/dts/at91sam9263.dtsi
+@@ -89,54 +89,60 @@
+ reg = <0xfffffd10 0x10>;
+ };
+
+- pioA: gpio@fffff200 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff200 0x100>;
+- interrupts = <2 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
++ pinctrl@fffff200 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
++ ranges = <0xfffff200 0xfffff200 0xa00>;
+
+- pioB: gpio@fffff400 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff400 0x100>;
+- interrupts = <3 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
++ pioA: gpio@fffff200 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff200 0x200>;
++ interrupts = <2 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
+
+- pioC: gpio@fffff600 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff600 0x100>;
+- interrupts = <4 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
++ pioB: gpio@fffff400 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff400 0x200>;
++ interrupts = <3 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
+
+- pioD: gpio@fffff800 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff800 0x100>;
+- interrupts = <4 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
++ pioC: gpio@fffff600 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff600 0x200>;
++ interrupts = <4 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
+
+- pioE: gpio@fffffa00 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffffa00 0x100>;
+- interrupts = <4 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
++ pioD: gpio@fffff800 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff800 0x200>;
++ interrupts = <4 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioE: gpio@fffffa00 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffffa00 0x200>;
++ interrupts = <4 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ dbgu: serial@ffffee00 {
+diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
+index 948dc96..59a21c1 100644
+--- a/arch/arm/boot/dts/at91sam9g45.dtsi
++++ b/arch/arm/boot/dts/at91sam9g45.dtsi
+@@ -109,54 +109,61 @@
+ #dma-cells = <1>;
+ };
+
+- pioA: gpio@fffff200 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff200 0x100>;
+- interrupts = <2 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- pioB: gpio@fffff400 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff400 0x100>;
+- interrupts = <3 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- pioC: gpio@fffff600 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff600 0x100>;
+- interrupts = <4 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- pioD: gpio@fffff800 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff800 0x100>;
+- interrupts = <5 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- pioE: gpio@fffffa00 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffffa00 0x100>;
+- interrupts = <5 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
++ pinctrl@fffff200 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
++ ranges = <0xfffff200 0xfffff200 0xa00>;
++
++ pioA: gpio@fffff200 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff200 0x200>;
++ interrupts = <2 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioB: gpio@fffff400 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff400 0x200>;
++ interrupts = <3 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioC: gpio@fffff600 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff600 0x200>;
++ interrupts = <4 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioD: gpio@fffff800 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff800 0x200>;
++ interrupts = <5 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioE: gpio@fffffa00 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffffa00 0x200>;
++ interrupts = <5 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
+ };
+
+ dbgu: serial@ffffee00 {
+diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
+index 42b53bd..135ecef 100644
+--- a/arch/arm/boot/dts/at91sam9n12.dtsi
++++ b/arch/arm/boot/dts/at91sam9n12.dtsi
+@@ -112,44 +112,51 @@
+ #dma-cells = <1>;
+ };
+
+- pioA: gpio@fffff400 {
+- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+- reg = <0xfffff400 0x100>;
+- interrupts = <2 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- pioB: gpio@fffff600 {
+- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+- reg = <0xfffff600 0x100>;
+- interrupts = <2 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- pioC: gpio@fffff800 {
+- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+- reg = <0xfffff800 0x100>;
+- interrupts = <3 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- pioD: gpio@fffffa00 {
+- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+- reg = <0xfffffa00 0x100>;
+- interrupts = <3 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
++ pinctrl@fffff400 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
++ ranges = <0xfffff400 0xfffff400 0x800>;
++
++ pioA: gpio@fffff400 {
++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
++ reg = <0xfffff400 0x200>;
++ interrupts = <2 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioB: gpio@fffff600 {
++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
++ reg = <0xfffff600 0x200>;
++ interrupts = <2 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioC: gpio@fffff800 {
++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
++ reg = <0xfffff800 0x200>;
++ interrupts = <3 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioD: gpio@fffffa00 {
++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
++ reg = <0xfffffa00 0x200>;
++ interrupts = <3 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
+ };
+
+ dbgu: serial@fffff200 {
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 027b9eb..df5f307 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -113,44 +113,51 @@
+ #dma-cells = <1>;
+ };
+
+- pioA: gpio@fffff400 {
+- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+- reg = <0xfffff400 0x100>;
+- interrupts = <2 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- pioB: gpio@fffff600 {
+- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+- reg = <0xfffff600 0x100>;
+- interrupts = <2 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- pioC: gpio@fffff800 {
+- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+- reg = <0xfffff800 0x100>;
+- interrupts = <3 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- pioD: gpio@fffffa00 {
+- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+- reg = <0xfffffa00 0x100>;
+- interrupts = <3 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
++ pinctrl@fffff200 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
++ ranges = <0xfffff400 0xfffff400 0x800>;
++
++ pioA: gpio@fffff400 {
++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
++ reg = <0xfffff400 0x200>;
++ interrupts = <2 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioB: gpio@fffff600 {
++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
++ reg = <0xfffff600 0x200>;
++ interrupts = <2 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioC: gpio@fffff800 {
++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
++ reg = <0xfffff800 0x200>;
++ interrupts = <3 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioD: gpio@fffffa00 {
++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
++ reg = <0xfffffa00 0x200>;
++ interrupts = <3 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
+ };
+
+ dbgu: serial@fffff200 {
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0210-arm-at91-at91sam9x5-fix-gpio-number-per-bank.patch b/patches.at91/0210-arm-at91-at91sam9x5-fix-gpio-number-per-bank.patch
new file mode 100644
index 00000000000000..6a5f3c16513fa5
--- /dev/null
+++ b/patches.at91/0210-arm-at91-at91sam9x5-fix-gpio-number-per-bank.patch
@@ -0,0 +1,166 @@
+From 00cd8cb7267db4aa30fa31dd14ec41c7f86198ab Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Sat, 14 Jul 2012 15:26:08 +0800
+Subject: arm: at91: at91sam9x5: fix gpio number per bank
+
+On the at91sam9x5 SoC series, GPIO banks B and D only have 19 and 22
+pins. So add a property to set this parameter.
+
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ .../devicetree/bindings/gpio/gpio_atmel.txt | 5 ++++
+ arch/arm/boot/dts/at91sam9x5.dtsi | 2 ++
+ arch/arm/mach-at91/gpio.c | 33 ++++++++++++++--------
+ 3 files changed, 29 insertions(+), 11 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/gpio/gpio_atmel.txt b/Documentation/devicetree/bindings/gpio/gpio_atmel.txt
+index 66efc80..85f8c0d 100644
+--- a/Documentation/devicetree/bindings/gpio/gpio_atmel.txt
++++ b/Documentation/devicetree/bindings/gpio/gpio_atmel.txt
+@@ -9,6 +9,10 @@ Required properties:
+ unused).
+ - gpio-controller: Marks the device node as a GPIO controller.
+
++optional properties:
++- #gpio-lines: Number of gpio if absent 32.
++
++
+ Example:
+ pioA: gpio@fffff200 {
+ compatible = "atmel,at91rm9200-gpio";
+@@ -16,5 +20,6 @@ Example:
+ interrupts = <2 4>;
+ #gpio-cells = <2>;
+ gpio-controller;
++ #gpio-lines = <19>;
+ };
+
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index df5f307..4e61a5d 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -135,6 +135,7 @@
+ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
++ #gpio-lines = <19>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+@@ -155,6 +156,7 @@
+ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
++ #gpio-lines = <22>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
+index 3b8f463..a34f0ed 100644
+--- a/arch/arm/mach-at91/gpio.c
++++ b/arch/arm/mach-at91/gpio.c
+@@ -33,6 +33,8 @@
+
+ #include "generic.h"
+
++#define MAX_NB_GPIO_PER_BANK 32
++
+ struct at91_gpio_chip {
+ struct gpio_chip chip;
+ struct at91_gpio_chip *next; /* Bank sharing same clock */
+@@ -56,7 +58,7 @@ static int at91_gpiolib_direction_input(struct gpio_chip *chip,
+ unsigned offset);
+ static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset);
+
+-#define AT91_GPIO_CHIP(name, nr_gpio) \
++#define AT91_GPIO_CHIP(name) \
+ { \
+ .chip = { \
+ .label = name, \
+@@ -67,16 +69,16 @@ static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset);
+ .set = at91_gpiolib_set, \
+ .dbg_show = at91_gpiolib_dbg_show, \
+ .to_irq = at91_gpiolib_to_irq, \
+- .ngpio = nr_gpio, \
++ .ngpio = MAX_NB_GPIO_PER_BANK, \
+ }, \
+ }
+
+ static struct at91_gpio_chip gpio_chip[] = {
+- AT91_GPIO_CHIP("pioA", 32),
+- AT91_GPIO_CHIP("pioB", 32),
+- AT91_GPIO_CHIP("pioC", 32),
+- AT91_GPIO_CHIP("pioD", 32),
+- AT91_GPIO_CHIP("pioE", 32),
++ AT91_GPIO_CHIP("pioA"),
++ AT91_GPIO_CHIP("pioB"),
++ AT91_GPIO_CHIP("pioC"),
++ AT91_GPIO_CHIP("pioD"),
++ AT91_GPIO_CHIP("pioE"),
+ };
+
+ static int gpio_banks;
+@@ -91,7 +93,7 @@ static unsigned long at91_gpio_caps;
+
+ static inline void __iomem *pin_to_controller(unsigned pin)
+ {
+- pin /= 32;
++ pin /= MAX_NB_GPIO_PER_BANK;
+ if (likely(pin < gpio_banks))
+ return gpio_chip[pin].regbase;
+
+@@ -100,7 +102,7 @@ static inline void __iomem *pin_to_controller(unsigned pin)
+
+ static inline unsigned pin_to_mask(unsigned pin)
+ {
+- return 1 << (pin % 32);
++ return 1 << (pin % MAX_NB_GPIO_PER_BANK);
+ }
+
+
+@@ -992,6 +994,7 @@ static void __init of_at91_gpio_init_one(struct device_node *np)
+ {
+ int alias_idx;
+ struct at91_gpio_chip *at91_gpio;
++ uint32_t ngpio;
+
+ if (!np)
+ return;
+@@ -1004,7 +1007,7 @@ static void __init of_at91_gpio_init_one(struct device_node *np)
+ }
+
+ at91_gpio = &gpio_chip[alias_idx];
+- at91_gpio->chip.base = alias_idx * at91_gpio->chip.ngpio;
++ at91_gpio->chip.base = alias_idx * MAX_NB_GPIO_PER_BANK;
+
+ at91_gpio->regbase = of_iomap(np, 0);
+ if (!at91_gpio->regbase) {
+@@ -1024,6 +1027,14 @@ static void __init of_at91_gpio_init_one(struct device_node *np)
+ if (of_device_is_compatible(np, "atmel,at91sam9x5-gpio"))
+ at91_gpio_caps |= AT91_GPIO_CAP_PIO3;
+
++ if (!of_property_read_u32(np, "#gpio-lines", &ngpio)) {
++ if (ngpio >= MAX_NB_GPIO_PER_BANK)
++ pr_err("at91_gpio.%d, gpio-nb >= %d failback to %d\n",
++ alias_idx, MAX_NB_GPIO_PER_BANK, MAX_NB_GPIO_PER_BANK);
++ else
++ at91_gpio->chip.ngpio = ngpio;
++ }
++
+ /* Setup clock */
+ if (at91_gpio_setup_clk(alias_idx))
+ goto ioremap_err;
+@@ -1061,7 +1072,7 @@ static void __init at91_gpio_init_one(int idx, u32 regbase, int pioc_hwirq)
+ {
+ struct at91_gpio_chip *at91_gpio = &gpio_chip[idx];
+
+- at91_gpio->chip.base = idx * at91_gpio->chip.ngpio;
++ at91_gpio->chip.base = idx * MAX_NB_GPIO_PER_BANK;
+ at91_gpio->pioc_hwirq = pioc_hwirq;
+ at91_gpio->pioc_idx = idx;
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0211-ARM-at91-add-dummies-pinctrl-for-non-dt-platform.patch b/patches.at91/0211-ARM-at91-add-dummies-pinctrl-for-non-dt-platform.patch
new file mode 100644
index 00000000000000..0b7c5df3dd94f4
--- /dev/null
+++ b/patches.at91/0211-ARM-at91-add-dummies-pinctrl-for-non-dt-platform.patch
@@ -0,0 +1,34 @@
+From 76aa1bd70d58b3bdbf4bdf271b04807421d0a4d4 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Thu, 12 Jul 2012 23:35:02 +0800
+Subject: ARM: at91: add dummies pinctrl for non dt platform
+
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/mach-at91/setup.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
+index 944bffb..50c69b5 100644
+--- a/arch/arm/mach-at91/setup.c
++++ b/arch/arm/mach-at91/setup.c
+@@ -10,6 +10,7 @@
+ #include <linux/mm.h>
+ #include <linux/pm.h>
+ #include <linux/of_address.h>
++#include <linux/pinctrl/machine.h>
+
+ #include <asm/system_misc.h>
+ #include <asm/mach/map.h>
+@@ -463,4 +464,6 @@ void __init at91_initialize(unsigned long main_clock)
+ at91_boot_soc.register_clocks();
+
+ at91_boot_soc.init();
++
++ pinctrl_provide_dummies();
+ }
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0212-ARM-at91-add-pinctrl-support.patch b/patches.at91/0212-ARM-at91-add-pinctrl-support.patch
new file mode 100644
index 00000000000000..9db9121984947b
--- /dev/null
+++ b/patches.at91/0212-ARM-at91-add-pinctrl-support.patch
@@ -0,0 +1,1872 @@
+From 88a0c589d8c7e8e3a2c93012a28978855f5e32d8 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Thu, 18 Oct 2012 17:48:34 +0200
+Subject: ARM: at91: add pinctrl support
+
+This is also include the gpio controller as the IP share both.
+Each soc will have to describe the SoC limitation and pin configuration via
+DT.
+
+This will allow to do not need to touch the C code when adding new SoC if the
+IP version is supported.
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+
+Conflicts:
+ arch/arm/mach-at91/board-dt.c
+---
+ .../bindings/pinctrl/atmel,at91-pinctrl.txt | 84 ++
+ arch/arm/Kconfig | 2 +
+ arch/arm/mach-at91/board-dt.c | 2 -
+ arch/arm/mach-at91/gpio.c | 165 +--
+ drivers/pinctrl/Kconfig | 9 +
+ drivers/pinctrl/Makefile | 1 +
+ drivers/pinctrl/pinctrl-at91.c | 1490 ++++++++++++++++++++
+ 7 files changed, 1591 insertions(+), 162 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
+ create mode 100644 drivers/pinctrl/pinctrl-at91.c
+
+diff --git a/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
+new file mode 100644
+index 0000000..0296ef4
+--- /dev/null
++++ b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
+@@ -0,0 +1,84 @@
++* Atmel AT91 Pinmux Controller
++
++The AT91 Pinmux Controler, enables the IC
++to share one PAD to several functional blocks. The sharing is done by
++multiplexing the PAD input/output signals. For each PAD there are up to
++8 muxing options (called periph modes). Since different modules require
++different PAD settings (like pull up, keeper, etc) the contoller controls
++also the PAD settings parameters.
++
++Please refer to pinctrl-bindings.txt in this directory for details of the
++common pinctrl bindings used by client devices, including the meaning of the
++phrase "pin configuration node".
++
++Atmel AT91 pin configuration node is a node of a group of pins which can be
++used for a specific device or function. This node represents both mux and config
++of the pins in that group. The 'pins' selects the function mode(also named pin
++mode) this pin can work on and the 'config' configures various pad settings
++such as pull-up, multi drive, etc.
++
++Required properties for iomux controller:
++- compatible: "atmel,at91rm9200-pinctrl"
++- atmel,mux-mask: array of mask (periph per bank) to describe if a pin can be
++ configured in this periph mode. All the periph and bank need to be describe.
++
++Required properties for pin configuration node:
++- atmel,pins: 4 integers array, represents a group of pins mux and config
++ setting. The format is atmel,pins = <PIN_BANK PIN_BANK_NUM PERIPH CONFIG>.
++ The PERIPH 0 means gpio.
++
++Bits used for CONFIG:
++PULL_UP(1 << 0): indicate this pin need a pull up.
++MULTIDRIVE(1 << 1): indicate this pin need to be configured as multidrive.
++
++NOTE:
++Some requirements for using atmel,at91rm9200-pinctrl binding:
++1. We have pin function node defined under at91 controller node to represent
++ what pinmux functions this SoC supports.
++2. The pin configuration node intends to work on a specific function should
++ to be defined under that specific function node.
++ The function node's name should represent well about what function
++ this group of pins in this pin configuration node are working on.
++3. The driver can use the function node's name and pin configuration node's
++ name describe the pin function and group hierarchy.
++ For example, Linux Iat91 pinctrl driver takes the function node's name
++ as the function name and pin configuration node's name as group name to
++ create the map table.
++4. Each pin configuration node should have a phandle, devices can set pins
++ configurations by referring to the phandle of that pin configuration node.
++5. The gpio controller must be describe in the pinctrl simple-bus.
++
++Examples:
++
++pinctrl@fffff400 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges;
++ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
++ reg = <0xfffff400 0x600>;
++
++ atmel,mux-mask = <
++ /* A B */
++ 0xffffffff 0xffc00c3b /* pioA */
++ 0xffffffff 0x7fff3ccf /* pioB */
++ 0xffffffff 0x007fffff /* pioC */
++ >;
++
++ /* shared pinctrl settings */
++ dbgu {
++ pinctrl_dbgu: dbgu-0 {
++ atmel,pins =
++ <1 14 0x1 0x0 /* PB14 periph A */
++ 1 15 0x1 0x1>; /* PB15 periph with pullup */
++ };
++ };
++};
++
++dbgu: serial@fffff200 {
++ compatible = "atmel,at91sam9260-usart";
++ reg = <0xfffff200 0x200>;
++ interrupts = <1 4 7>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_dbgu>;
++ status = "disabled";
++};
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index ddef021..ea72f88 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -339,6 +339,8 @@ config ARCH_AT91
+ select CLKDEV_LOOKUP
+ select IRQ_DOMAIN
+ select NEED_MACH_IO_H if PCCARD
++ select PINCTRL
++ select PINCTRL_AT91 if USE_OF
+ help
+ This enables support for systems based on Atmel
+ AT91RM9200 and AT91SAM9* processors.
+diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
+index c0d242c..b1a5d3c 100644
+--- a/arch/arm/mach-at91/board-dt.c
++++ b/arch/arm/mach-at91/board-dt.c
+@@ -127,8 +127,6 @@ struct of_dev_auxdata at91_auxdata_lookup[] __initdata = {
+ static const struct of_device_id irq_of_match[] __initconst = {
+
+ { .compatible = "atmel,at91rm9200-aic", .data = at91_aic_of_init },
+- { .compatible = "atmel,at91rm9200-gpio", .data = at91_gpio_of_irq_setup },
+- { .compatible = "atmel,at91sam9x5-gpio", .data = at91_gpio_of_irq_setup },
+ { /*sentinel*/ }
+ };
+
+diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
+index a34f0ed..c5d7e1e 100644
+--- a/arch/arm/mach-at91/gpio.c
++++ b/arch/arm/mach-at91/gpio.c
+@@ -23,8 +23,6 @@
+ #include <linux/io.h>
+ #include <linux/irqdomain.h>
+ #include <linux/of_address.h>
+-#include <linux/of_irq.h>
+-#include <linux/of_gpio.h>
+
+ #include <asm/mach/irq.h>
+
+@@ -717,80 +715,6 @@ postcore_initcall(at91_gpio_debugfs_init);
+ */
+ static struct lock_class_key gpio_lock_class;
+
+-#if defined(CONFIG_OF)
+-static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq,
+- irq_hw_number_t hw)
+-{
+- struct at91_gpio_chip *at91_gpio = h->host_data;
+-
+- irq_set_lockdep_class(virq, &gpio_lock_class);
+-
+- /*
+- * Can use the "simple" and not "edge" handler since it's
+- * shorter, and the AIC handles interrupts sanely.
+- */
+- irq_set_chip_and_handler(virq, &gpio_irqchip,
+- handle_simple_irq);
+- set_irq_flags(virq, IRQF_VALID);
+- irq_set_chip_data(virq, at91_gpio);
+-
+- return 0;
+-}
+-
+-static struct irq_domain_ops at91_gpio_ops = {
+- .map = at91_gpio_irq_map,
+- .xlate = irq_domain_xlate_twocell,
+-};
+-
+-int __init at91_gpio_of_irq_setup(struct device_node *node,
+- struct device_node *parent)
+-{
+- struct at91_gpio_chip *prev = NULL;
+- int alias_idx = of_alias_get_id(node, "gpio");
+- struct at91_gpio_chip *at91_gpio = &gpio_chip[alias_idx];
+-
+- /* Setup proper .irq_set_type function */
+- if (has_pio3())
+- gpio_irqchip.irq_set_type = alt_gpio_irq_type;
+- else
+- gpio_irqchip.irq_set_type = gpio_irq_type;
+-
+- /* Disable irqs of this PIO controller */
+- __raw_writel(~0, at91_gpio->regbase + PIO_IDR);
+-
+- /* Setup irq domain */
+- at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio,
+- &at91_gpio_ops, at91_gpio);
+- if (!at91_gpio->domain)
+- panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n",
+- at91_gpio->pioc_idx);
+-
+- /* Setup chained handler */
+- if (at91_gpio->pioc_idx)
+- prev = &gpio_chip[at91_gpio->pioc_idx - 1];
+-
+- /* The toplevel handler handles one bank of GPIOs, except
+- * on some SoC it can handles up to three...
+- * We only set up the handler for the first of the list.
+- */
+- if (prev && prev->next == at91_gpio)
+- return 0;
+-
+- at91_gpio->pioc_virq = irq_create_mapping(irq_find_host(parent),
+- at91_gpio->pioc_hwirq);
+- irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio);
+- irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler);
+-
+- return 0;
+-}
+-#else
+-int __init at91_gpio_of_irq_setup(struct device_node *node,
+- struct device_node *parent)
+-{
+- return -EINVAL;
+-}
+-#endif
+-
+ /*
+ * irqdomain initialization: pile up irqdomains on top of AIC range
+ */
+@@ -989,85 +913,6 @@ err:
+ return -EINVAL;
+ }
+
+-#ifdef CONFIG_OF_GPIO
+-static void __init of_at91_gpio_init_one(struct device_node *np)
+-{
+- int alias_idx;
+- struct at91_gpio_chip *at91_gpio;
+- uint32_t ngpio;
+-
+- if (!np)
+- return;
+-
+- alias_idx = of_alias_get_id(np, "gpio");
+- if (alias_idx >= MAX_GPIO_BANKS) {
+- pr_err("at91_gpio, failed alias idx(%d) > MAX_GPIO_BANKS(%d), ignoring.\n",
+- alias_idx, MAX_GPIO_BANKS);
+- return;
+- }
+-
+- at91_gpio = &gpio_chip[alias_idx];
+- at91_gpio->chip.base = alias_idx * MAX_NB_GPIO_PER_BANK;
+-
+- at91_gpio->regbase = of_iomap(np, 0);
+- if (!at91_gpio->regbase) {
+- pr_err("at91_gpio.%d, failed to map registers, ignoring.\n",
+- alias_idx);
+- return;
+- }
+-
+- /* Get the interrupts property */
+- if (of_property_read_u32(np, "interrupts", &at91_gpio->pioc_hwirq)) {
+- pr_err("at91_gpio.%d, failed to get interrupts property, ignoring.\n",
+- alias_idx);
+- goto ioremap_err;
+- }
+-
+- /* Get capabilities from compatibility property */
+- if (of_device_is_compatible(np, "atmel,at91sam9x5-gpio"))
+- at91_gpio_caps |= AT91_GPIO_CAP_PIO3;
+-
+- if (!of_property_read_u32(np, "#gpio-lines", &ngpio)) {
+- if (ngpio >= MAX_NB_GPIO_PER_BANK)
+- pr_err("at91_gpio.%d, gpio-nb >= %d failback to %d\n",
+- alias_idx, MAX_NB_GPIO_PER_BANK, MAX_NB_GPIO_PER_BANK);
+- else
+- at91_gpio->chip.ngpio = ngpio;
+- }
+-
+- /* Setup clock */
+- if (at91_gpio_setup_clk(alias_idx))
+- goto ioremap_err;
+-
+- at91_gpio->chip.of_node = np;
+- gpio_banks = max(gpio_banks, alias_idx + 1);
+- at91_gpio->pioc_idx = alias_idx;
+- return;
+-
+-ioremap_err:
+- iounmap(at91_gpio->regbase);
+-}
+-
+-static int __init of_at91_gpio_init(void)
+-{
+- struct device_node *np = NULL;
+-
+- /*
+- * This isn't ideal, but it gets things hooked up until this
+- * driver is converted into a platform_device
+- */
+- for_each_compatible_node(np, NULL, "atmel,at91rm9200-gpio")
+- of_at91_gpio_init_one(np);
+-
+- return gpio_banks > 0 ? 0 : -EINVAL;
+-}
+-#else
+-static int __init of_at91_gpio_init(void)
+-{
+- return -EINVAL;
+-}
+-#endif
+-
+ static void __init at91_gpio_init_one(int idx, u32 regbase, int pioc_hwirq)
+ {
+ struct at91_gpio_chip *at91_gpio = &gpio_chip[idx];
+@@ -1102,11 +947,11 @@ void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks)
+
+ BUG_ON(nr_banks > MAX_GPIO_BANKS);
+
+- if (of_at91_gpio_init() < 0) {
+- /* No GPIO controller found in device tree */
+- for (i = 0; i < nr_banks; i++)
+- at91_gpio_init_one(i, data[i].regbase, data[i].id);
+- }
++ if (of_have_populated_dt())
++ return;
++
++ for (i = 0; i < nr_banks; i++)
++ at91_gpio_init_one(i, data[i].regbase, data[i].id);
+
+ for (i = 0; i < gpio_banks; i++) {
+ at91_gpio = &gpio_chip[i];
+diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
+index f73a5ea..6a03072 100644
+--- a/drivers/pinctrl/Kconfig
++++ b/drivers/pinctrl/Kconfig
+@@ -26,6 +26,15 @@ config DEBUG_PINCTRL
+ help
+ Say Y here to add some extra checks and diagnostics to PINCTRL calls.
+
++config PINCTRL_AT91
++ bool "AT91 pinctrl driver"
++ depends on OF
++ depends on ARCH_AT91
++ select PINMUX
++ select PINCONF
++ help
++ Say Y here to enable the at91 pinctrl driver
++
+ config PINCTRL_PXA3xx
+ bool
+ select PINMUX
+diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
+index 8e3c95a..84f4670 100644
+--- a/drivers/pinctrl/Makefile
++++ b/drivers/pinctrl/Makefile
+@@ -9,6 +9,7 @@ ifeq ($(CONFIG_OF),y)
+ obj-$(CONFIG_PINCTRL) += devicetree.o
+ endif
+ obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
++obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o
+ obj-$(CONFIG_PINCTRL_PXA3xx) += pinctrl-pxa3xx.o
+ obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o
+ obj-$(CONFIG_PINCTRL_PXA168) += pinctrl-pxa168.o
+diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
+new file mode 100644
+index 0000000..e4712d1
+--- /dev/null
++++ b/drivers/pinctrl/pinctrl-at91.c
+@@ -0,0 +1,1490 @@
++/*
++ * at91 pinctrl driver based on at91 pinmux core
++ *
++ * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
++ *
++ * Under GPLv2 only
++ */
++
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/irqdomain.h>
++#include <linux/io.h>
++#include <linux/gpio.h>
++#include <linux/irqdomain.h>
++#include <linux/pinctrl/machine.h>
++#include <linux/pinctrl/pinconf.h>
++#include <linux/pinctrl/pinctrl.h>
++#include <linux/pinctrl/pinmux.h>
++/* Since we request GPIOs from ourself */
++#include <linux/pinctrl/consumer.h>
++
++#include <asm/mach/irq.h>
++
++#include <mach/hardware.h>
++#include <mach/at91_pio.h>
++
++#include "core.h"
++
++#define MAX_NB_GPIO_PER_BANK 32
++
++struct at91_pinctrl_mux_ops;
++
++struct at91_gpio_chip {
++ struct gpio_chip chip;
++ struct pinctrl_gpio_range range;
++ struct at91_gpio_chip *next; /* Bank sharing same clock */
++ int pioc_hwirq; /* PIO bank interrupt identifier on AIC */
++ int pioc_virq; /* PIO bank Linux virtual interrupt */
++ int pioc_idx; /* PIO bank index */
++ void __iomem *regbase; /* PIO bank virtual address */
++ struct clk *clock; /* associated clock */
++ struct irq_domain *domain; /* associated irq domain */
++ struct at91_pinctrl_mux_ops *ops; /* ops */
++};
++
++#define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip)
++
++static struct at91_gpio_chip *gpio_chips[MAX_GPIO_BANKS];
++
++static int gpio_banks;
++
++#define PULL_UP (0 << 1)
++#define MULTI_DRIVE (1 << 1)
++
++/**
++ * struct at91_pmx_func - describes AT91 pinmux functions
++ * @name: the name of this specific function
++ * @groups: corresponding pin groups
++ * @ngroups: the number of groups
++ */
++struct at91_pmx_func {
++ const char *name;
++ const char **groups;
++ unsigned ngroups;
++};
++
++enum at91_mux {
++ AT91_MUX_GPIO = 0,
++ AT91_MUX_PERIPH_A = 1,
++ AT91_MUX_PERIPH_B = 2,
++ AT91_MUX_PERIPH_C = 3,
++ AT91_MUX_PERIPH_D = 4,
++};
++
++/**
++ * struct at91_pmx_pin - describes an At91 pin mux
++ * @bank: the bank of the pin
++ * @pin: the pin number in the @bank
++ * @mux: the mux mode : gpio or periph_x of the pin i.e. alternate function.
++ * @conf: the configuration of the pin: PULL_UP, MULTIDRIVE etc...
++ */
++struct at91_pmx_pin {
++ uint32_t bank;
++ uint32_t pin;
++ enum at91_mux mux;
++ unsigned long conf;
++};
++
++/**
++ * struct at91_pin_group - describes an At91 pin group
++ * @name: the name of this specific pin group
++ * @pins_conf: the mux mode for each pin in this group. The size of this
++ * array is the same as pins.
++ * @pins: an array of discrete physical pins used in this group, taken
++ * from the driver-local pin enumeration space
++ * @npins: the number of pins in this group array, i.e. the number of
++ * elements in .pins so we can iterate over that array
++ */
++struct at91_pin_group {
++ const char *name;
++ struct at91_pmx_pin *pins_conf;
++ unsigned int *pins;
++ unsigned npins;
++};
++
++/**
++ * struct at91_pinctrl_mux_ops - describes an At91 mux ops group
++ * on new IP with support for periph C and D the way to mux in
++ * periph A and B has changed
++ * So provide the right call back
++ * if not present means the IP does not support it
++ * @get_periph: return the periph mode configured
++ * @mux_A_periph: mux as periph A
++ * @mux_B_periph: mux as periph B
++ * @mux_C_periph: mux as periph C
++ * @mux_D_periph: mux as periph D
++ * @irq_type: return irq type
++ */
++struct at91_pinctrl_mux_ops {
++ enum at91_mux (*get_periph)(void __iomem *pio, unsigned mask);
++ void (*mux_A_periph)(void __iomem *pio, unsigned mask);
++ void (*mux_B_periph)(void __iomem *pio, unsigned mask);
++ void (*mux_C_periph)(void __iomem *pio, unsigned mask);
++ void (*mux_D_periph)(void __iomem *pio, unsigned mask);
++ /* irq */
++ int (*irq_type)(struct irq_data *d, unsigned type);
++};
++
++static int gpio_irq_type(struct irq_data *d, unsigned type);
++static int alt_gpio_irq_type(struct irq_data *d, unsigned type);
++
++struct at91_pinctrl {
++ struct device *dev;
++ struct pinctrl_dev *pctl;
++
++ int nbanks;
++
++ uint32_t *mux_mask;
++ int nmux;
++
++ struct at91_pmx_func *functions;
++ int nfunctions;
++
++ struct at91_pin_group *groups;
++ int ngroups;
++
++ struct at91_pinctrl_mux_ops *ops;
++};
++
++static const inline struct at91_pin_group *at91_pinctrl_find_group_by_name(
++ const struct at91_pinctrl *info,
++ const char *name)
++{
++ const struct at91_pin_group *grp = NULL;
++ int i;
++
++ for (i = 0; i < info->ngroups; i++) {
++ if (strcmp(info->groups[i].name, name))
++ continue;
++
++ grp = &info->groups[i];
++ dev_dbg(info->dev, "%s: %d 0:%d\n", name, grp->npins, grp->pins[0]);
++ break;
++ }
++
++ return grp;
++}
++
++static int at91_get_groups_count(struct pinctrl_dev *pctldev)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++
++ return info->ngroups;
++}
++
++static const char *at91_get_group_name(struct pinctrl_dev *pctldev,
++ unsigned selector)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++
++ return info->groups[selector].name;
++}
++
++static int at91_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
++ const unsigned **pins,
++ unsigned *npins)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++
++ if (selector >= info->ngroups)
++ return -EINVAL;
++
++ *pins = info->groups[selector].pins;
++ *npins = info->groups[selector].npins;
++
++ return 0;
++}
++
++static void at91_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
++ unsigned offset)
++{
++ seq_printf(s, "%s", dev_name(pctldev->dev));
++}
++
++static int at91_dt_node_to_map(struct pinctrl_dev *pctldev,
++ struct device_node *np,
++ struct pinctrl_map **map, unsigned *num_maps)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++ const struct at91_pin_group *grp;
++ struct pinctrl_map *new_map;
++ struct device_node *parent;
++ int map_num = 1;
++ int i;
++ struct at91_pmx_pin *pin;
++
++ /*
++ * first find the group of this node and check if we need create
++ * config maps for pins
++ */
++ grp = at91_pinctrl_find_group_by_name(info, np->name);
++ if (!grp) {
++ dev_err(info->dev, "unable to find group for node %s\n",
++ np->name);
++ return -EINVAL;
++ }
++
++ map_num += grp->npins;
++ new_map = devm_kzalloc(pctldev->dev, sizeof(*new_map) * map_num, GFP_KERNEL);
++ if (!new_map)
++ return -ENOMEM;
++
++ *map = new_map;
++ *num_maps = map_num;
++
++ /* create mux map */
++ parent = of_get_parent(np);
++ if (!parent) {
++ kfree(new_map);
++ return -EINVAL;
++ }
++ new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
++ new_map[0].data.mux.function = parent->name;
++ new_map[0].data.mux.group = np->name;
++ of_node_put(parent);
++
++ /* create config map */
++ new_map++;
++ for (i = 0; i < grp->npins; i++) {
++ pin = &grp->pins_conf[i];
++
++ new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN;
++ new_map[i].data.configs.group_or_pin =
++ pin_get_name(pctldev, grp->pins[i]);
++ new_map[i].data.configs.configs = &grp->pins_conf[i].conf;
++ new_map[i].data.configs.num_configs = 1;
++ }
++
++ dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n",
++ (*map)->data.mux.function, (*map)->data.mux.group, map_num);
++
++ return 0;
++}
++
++static void at91_dt_free_map(struct pinctrl_dev *pctldev,
++ struct pinctrl_map *map, unsigned num_maps)
++{
++}
++
++static struct pinctrl_ops at91_pctrl_ops = {
++ .get_groups_count = at91_get_groups_count,
++ .get_group_name = at91_get_group_name,
++ .get_group_pins = at91_get_group_pins,
++ .pin_dbg_show = at91_pin_dbg_show,
++ .dt_node_to_map = at91_dt_node_to_map,
++ .dt_free_map = at91_dt_free_map,
++};
++
++static void __iomem * pin_to_controller(struct at91_pinctrl *info,
++ unsigned int bank)
++{
++ return gpio_chips[bank]->regbase;
++}
++
++static inline int pin_to_bank(unsigned pin)
++{
++ return pin /= MAX_NB_GPIO_PER_BANK;
++}
++
++static unsigned pin_to_mask(unsigned int pin)
++{
++ return 1 << pin;
++}
++
++static void at91_mux_disable_interrupt(void __iomem *pio, unsigned mask)
++{
++ writel_relaxed(mask, pio + PIO_IDR);
++}
++
++static unsigned at91_mux_get_pullup(void __iomem *pio, unsigned pin)
++{
++ return (readl_relaxed(pio + PIO_PUSR) >> pin) & 0x1;
++}
++
++static void at91_mux_set_pullup(void __iomem *pio, unsigned mask, bool on)
++{
++ writel_relaxed(mask, pio + (on ? PIO_PUER : PIO_PUDR));
++}
++
++static unsigned at91_mux_get_multidrive(void __iomem *pio, unsigned pin)
++{
++ return (readl_relaxed(pio + PIO_MDSR) >> pin) & 0x1;
++}
++
++static void at91_mux_set_multidrive(void __iomem *pio, unsigned mask, bool on)
++{
++ writel_relaxed(mask, pio + (on ? PIO_MDER : PIO_MDDR));
++}
++
++static void at91_mux_set_A_periph(void __iomem *pio, unsigned mask)
++{
++ writel_relaxed(mask, pio + PIO_ASR);
++}
++
++static void at91_mux_set_B_periph(void __iomem *pio, unsigned mask)
++{
++ writel_relaxed(mask, pio + PIO_BSR);
++}
++
++static void at91_mux_pio3_set_A_periph(void __iomem *pio, unsigned mask)
++{
++
++ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) & ~mask,
++ pio + PIO_ABCDSR1);
++ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) & ~mask,
++ pio + PIO_ABCDSR2);
++}
++
++static void at91_mux_pio3_set_B_periph(void __iomem *pio, unsigned mask)
++{
++ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) | mask,
++ pio + PIO_ABCDSR1);
++ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) & ~mask,
++ pio + PIO_ABCDSR2);
++}
++
++static void at91_mux_pio3_set_C_periph(void __iomem *pio, unsigned mask)
++{
++ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) & ~mask, pio + PIO_ABCDSR1);
++ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
++}
++
++static void at91_mux_pio3_set_D_periph(void __iomem *pio, unsigned mask)
++{
++ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) | mask, pio + PIO_ABCDSR1);
++ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
++}
++
++static enum at91_mux at91_mux_pio3_get_periph(void __iomem *pio, unsigned mask)
++{
++ unsigned select;
++
++ if (readl_relaxed(pio + PIO_PSR) & mask)
++ return AT91_MUX_GPIO;
++
++ select = !!(readl_relaxed(pio + PIO_ABCDSR1) & mask);
++ select |= (!!(readl_relaxed(pio + PIO_ABCDSR2) & mask) << 1);
++
++ return select + 1;
++}
++
++static enum at91_mux at91_mux_get_periph(void __iomem *pio, unsigned mask)
++{
++ unsigned select;
++
++ if (readl_relaxed(pio + PIO_PSR) & mask)
++ return AT91_MUX_GPIO;
++
++ select = readl_relaxed(pio + PIO_ABSR) & mask;
++
++ return select + 1;
++}
++
++static struct at91_pinctrl_mux_ops at91rm9200_ops = {
++ .get_periph = at91_mux_get_periph,
++ .mux_A_periph = at91_mux_set_A_periph,
++ .mux_B_periph = at91_mux_set_B_periph,
++ .irq_type = gpio_irq_type,
++};
++
++static struct at91_pinctrl_mux_ops at91sam9x5_ops = {
++ .get_periph = at91_mux_pio3_get_periph,
++ .mux_A_periph = at91_mux_pio3_set_A_periph,
++ .mux_B_periph = at91_mux_pio3_set_B_periph,
++ .mux_C_periph = at91_mux_pio3_set_C_periph,
++ .mux_D_periph = at91_mux_pio3_set_D_periph,
++ .irq_type = alt_gpio_irq_type,
++};
++
++static void at91_pin_dbg(const struct device *dev, const struct at91_pmx_pin *pin)
++{
++ if (pin->mux) {
++ dev_dbg(dev, "pio%c%d configured as periph%c with conf = 0x%lu\n",
++ pin->bank + 'A', pin->pin, pin->mux - 1 + 'A', pin->conf);
++ } else {
++ dev_dbg(dev, "pio%c%d configured as gpio with conf = 0x%lu\n",
++ pin->bank + 'A', pin->pin, pin->conf);
++ }
++}
++
++static int pin_check_config(struct at91_pinctrl *info, const char* name,
++ int index, const struct at91_pmx_pin *pin)
++{
++ int mux;
++
++ /* check if it's a valid config */
++ if (pin->bank >= info->nbanks) {
++ dev_err(info->dev, "%s: pin conf %d bank_id %d >= nbanks %d\n",
++ name, index, pin->bank, info->nbanks);
++ return -EINVAL;
++ }
++
++ if (pin->pin >= MAX_NB_GPIO_PER_BANK) {
++ dev_err(info->dev, "%s: pin conf %d pin_bank_id %d >= %d\n",
++ name, index, pin->pin, MAX_NB_GPIO_PER_BANK);
++ return -EINVAL;
++ }
++
++ if (!pin->mux)
++ return 0;
++
++ mux = pin->mux - 1;
++
++ if (mux >= info->nmux) {
++ dev_err(info->dev, "%s: pin conf %d mux_id %d >= nmux %d\n",
++ name, index, mux, info->nmux);
++ return -EINVAL;
++ }
++
++ if (!(info->mux_mask[pin->bank * info->nmux + mux] & 1 << pin->pin)) {
++ dev_err(info->dev, "%s: pin conf %d mux_id %d not supported for pio%c%d\n",
++ name, index, mux, pin->bank + 'A', pin->pin);
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static void at91_mux_gpio_disable(void __iomem *pio, unsigned mask)
++{
++ writel_relaxed(mask, pio + PIO_PDR);
++}
++
++static void at91_mux_gpio_enable(void __iomem *pio, unsigned mask, bool input)
++{
++ writel_relaxed(mask, pio + PIO_PER);
++ writel_relaxed(mask, pio + (input ? PIO_ODR : PIO_OER));
++}
++
++static int at91_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector,
++ unsigned group)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++ const struct at91_pmx_pin *pins_conf = info->groups[group].pins_conf;
++ const struct at91_pmx_pin *pin;
++ uint32_t npins = info->groups[group].npins;
++ int i, ret;
++ unsigned mask;
++ void __iomem *pio;
++
++ dev_dbg(info->dev, "enable function %s group %s\n",
++ info->functions[selector].name, info->groups[group].name);
++
++ /* first check that all the pins of the group are valid with a valid
++ * paramter */
++ for (i = 0; i < npins; i++) {
++ pin = &pins_conf[i];
++ ret = pin_check_config(info, info->groups[group].name, i, pin);
++ if (ret)
++ return ret;
++ }
++
++ for (i = 0; i < npins; i++) {
++ pin = &pins_conf[i];
++ at91_pin_dbg(info->dev, pin);
++ pio = pin_to_controller(info, pin->bank);
++ mask = pin_to_mask(pin->pin);
++ at91_mux_disable_interrupt(pio, mask);
++ switch(pin->mux) {
++ case AT91_MUX_GPIO:
++ at91_mux_gpio_enable(pio, mask, 1);
++ break;
++ case AT91_MUX_PERIPH_A:
++ info->ops->mux_A_periph(pio, mask);
++ break;
++ case AT91_MUX_PERIPH_B:
++ info->ops->mux_B_periph(pio, mask);
++ break;
++ case AT91_MUX_PERIPH_C:
++ if (!info->ops->mux_C_periph)
++ return -EINVAL;
++ info->ops->mux_C_periph(pio, mask);
++ break;
++ case AT91_MUX_PERIPH_D:
++ if (!info->ops->mux_D_periph)
++ return -EINVAL;
++ info->ops->mux_D_periph(pio, mask);
++ break;
++ }
++ if (pin->mux)
++ at91_mux_gpio_disable(pio, mask);
++ }
++
++ return 0;
++}
++
++static void at91_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector,
++ unsigned group)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++ const struct at91_pmx_pin *pins_conf = info->groups[group].pins_conf;
++ const struct at91_pmx_pin *pin;
++ uint32_t npins = info->groups[group].npins;
++ int i;
++ unsigned mask;
++ void __iomem *pio;
++
++ for (i = 0; i < npins; i++) {
++ pin = &pins_conf[i];
++ at91_pin_dbg(info->dev, pin);
++ pio = pin_to_controller(info, pin->bank);
++ mask = pin_to_mask(pin->pin);
++ at91_mux_gpio_enable(pio, mask, 1);
++ }
++}
++
++static int at91_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++
++ return info->nfunctions;
++}
++
++static const char *at91_pmx_get_func_name(struct pinctrl_dev *pctldev,
++ unsigned selector)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++
++ return info->functions[selector].name;
++}
++
++static int at91_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
++ const char * const **groups,
++ unsigned * const num_groups)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++
++ *groups = info->functions[selector].groups;
++ *num_groups = info->functions[selector].ngroups;
++
++ return 0;
++}
++
++int at91_gpio_request_enable(struct pinctrl_dev *pctldev,
++ struct pinctrl_gpio_range *range,
++ unsigned offset)
++{
++ struct at91_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
++ struct at91_gpio_chip *at91_chip;
++ struct gpio_chip *chip;
++ unsigned mask;
++
++ if (!range) {
++ dev_err(npct->dev, "invalid range\n");
++ return -EINVAL;
++ }
++ if (!range->gc) {
++ dev_err(npct->dev, "missing GPIO chip in range\n");
++ return -EINVAL;
++ }
++ chip = range->gc;
++ at91_chip = container_of(chip, struct at91_gpio_chip, chip);
++
++ dev_dbg(npct->dev, "enable pin %u as GPIO\n", offset);
++
++ mask = 1 << (offset - chip->base);
++
++ dev_dbg(npct->dev, "enable pin %u as PIO%c%d 0x%x\n",
++ offset, 'A' + range->id, offset - chip->base, mask);
++
++ writel_relaxed(mask, at91_chip->regbase + PIO_PER);
++
++ return 0;
++}
++
++void at91_gpio_disable_free(struct pinctrl_dev *pctldev,
++ struct pinctrl_gpio_range *range,
++ unsigned offset)
++{
++ struct at91_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
++
++ dev_dbg(npct->dev, "disable pin %u as GPIO\n", offset);
++ /* Set the pin to some default state, GPIO is usually default */
++}
++
++static struct pinmux_ops at91_pmx_ops = {
++ .get_functions_count = at91_pmx_get_funcs_count,
++ .get_function_name = at91_pmx_get_func_name,
++ .get_function_groups = at91_pmx_get_groups,
++ .enable = at91_pmx_enable,
++ .disable = at91_pmx_disable,
++ .gpio_request_enable = at91_gpio_request_enable,
++ .gpio_disable_free = at91_gpio_disable_free,
++};
++
++static int at91_pinconf_get(struct pinctrl_dev *pctldev,
++ unsigned pin_id, unsigned long *config)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++ void __iomem *pio;
++ unsigned pin;
++
++ dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, *config);
++ pio = pin_to_controller(info, pin_to_bank(pin_id));
++ pin = pin_id % MAX_NB_GPIO_PER_BANK;
++
++ if (at91_mux_get_multidrive(pio, pin))
++ *config |= MULTI_DRIVE;
++
++ if (at91_mux_get_pullup(pio, pin))
++ *config |= PULL_UP;
++
++ return 0;
++}
++
++static int at91_pinconf_set(struct pinctrl_dev *pctldev,
++ unsigned pin_id, unsigned long config)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++ unsigned mask;
++ void __iomem *pio;
++
++ dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, config);
++ pio = pin_to_controller(info, pin_to_bank(pin_id));
++ mask = pin_to_mask(pin_id % MAX_NB_GPIO_PER_BANK);
++
++ at91_mux_set_pullup(pio, mask, config & PULL_UP);
++ at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE);
++ return 0;
++}
++
++static void at91_pinconf_dbg_show(struct pinctrl_dev *pctldev,
++ struct seq_file *s, unsigned pin_id)
++{
++
++}
++
++static void at91_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
++ struct seq_file *s, unsigned group)
++{
++}
++
++struct pinconf_ops at91_pinconf_ops = {
++ .pin_config_get = at91_pinconf_get,
++ .pin_config_set = at91_pinconf_set,
++ .pin_config_dbg_show = at91_pinconf_dbg_show,
++ .pin_config_group_dbg_show = at91_pinconf_group_dbg_show,
++};
++
++static struct pinctrl_desc at91_pinctrl_desc = {
++ .pctlops = &at91_pctrl_ops,
++ .pmxops = &at91_pmx_ops,
++ .confops = &at91_pinconf_ops,
++ .owner = THIS_MODULE,
++};
++
++static const char *gpio_compat = "atmel,at91rm9200-gpio";
++
++static void __devinit at91_pinctrl_child_count(struct at91_pinctrl *info,
++ struct device_node *np)
++{
++ struct device_node *child;
++
++ for_each_child_of_node(np, child) {
++ if (of_device_is_compatible(child, gpio_compat)) {
++ info->nbanks++;
++ } else {
++ info->nfunctions++;
++ info->ngroups += of_get_child_count(child);
++ }
++ }
++}
++
++static int __devinit at91_pinctrl_mux_mask(struct at91_pinctrl *info,
++ struct device_node *np)
++{
++ int ret = 0;
++ int size;
++ const const __be32 *list;
++
++ list = of_get_property(np, "atmel,mux-mask", &size);
++ if (!list) {
++ dev_err(info->dev, "can not read the mux-mask of %d\n", size);
++ return -EINVAL;
++ }
++
++ size /= sizeof(*list);
++ if (!size || size % info->nbanks) {
++ dev_err(info->dev, "wrong mux mask array should be by %d\n", info->nbanks);
++ return -EINVAL;
++ }
++ info->nmux = size / info->nbanks;
++
++ info->mux_mask = devm_kzalloc(info->dev, sizeof(u32) * size, GFP_KERNEL);
++ if (!info->mux_mask) {
++ dev_err(info->dev, "could not alloc mux_mask\n");
++ return -ENOMEM;
++ }
++
++ ret = of_property_read_u32_array(np, "atmel,mux-mask",
++ info->mux_mask, size);
++ if (ret)
++ dev_err(info->dev, "can not read the mux-mask of %d\n", size);
++ return ret;
++}
++
++static int __devinit at91_pinctrl_parse_groups(struct device_node *np,
++ struct at91_pin_group *grp,
++ struct at91_pinctrl *info,
++ u32 index)
++{
++ struct at91_pmx_pin *pin;
++ int size;
++ const const __be32 *list;
++ int i, j;
++
++ dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
++
++ /* Initialise group */
++ grp->name = np->name;
++
++ /*
++ * the binding format is fsl,pins = <bank pin mux CONFIG ...>,
++ * do sanity check and calculate pins number
++ */
++ list = of_get_property(np, "atmel,pins", &size);
++ /* we do not check return since it's safe node passed down */
++ size /= sizeof(*list);
++ if (!size || size % 4) {
++ dev_err(info->dev, "wrong pins number or pins and configs should be by 4\n");
++ return -EINVAL;
++ }
++
++ grp->npins = size / 4;
++ pin = grp->pins_conf = devm_kzalloc(info->dev, grp->npins * sizeof(struct at91_pmx_pin),
++ GFP_KERNEL);
++ grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
++ GFP_KERNEL);
++ if (!grp->pins_conf || !grp->pins)
++ return -ENOMEM;
++
++ for (i = 0, j = 0; i < size; i += 4, j++) {
++ pin->bank = be32_to_cpu(*list++);
++ pin->pin = be32_to_cpu(*list++);
++ grp->pins[j] = pin->bank * MAX_NB_GPIO_PER_BANK + pin->pin;
++ pin->mux = be32_to_cpu(*list++);
++ pin->conf = be32_to_cpu(*list++);
++
++ at91_pin_dbg(info->dev, pin);
++ pin++;
++ }
++
++ return 0;
++}
++
++static int __devinit at91_pinctrl_parse_functions(struct device_node *np,
++ struct at91_pinctrl *info, u32 index)
++{
++ struct device_node *child;
++ struct at91_pmx_func *func;
++ struct at91_pin_group *grp;
++ int ret;
++ static u32 grp_index;
++ u32 i = 0;
++
++ dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name);
++
++ func = &info->functions[index];
++
++ /* Initialise function */
++ func->name = np->name;
++ func->ngroups = of_get_child_count(np);
++ if (func->ngroups <= 0) {
++ dev_err(info->dev, "no groups defined\n");
++ return -EINVAL;
++ }
++ func->groups = devm_kzalloc(info->dev,
++ func->ngroups * sizeof(char *), GFP_KERNEL);
++ if (!func->groups)
++ return -ENOMEM;
++
++ for_each_child_of_node(np, child) {
++ func->groups[i] = child->name;
++ grp = &info->groups[grp_index++];
++ ret = at91_pinctrl_parse_groups(child, grp, info, i++);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
++}
++
++static struct of_device_id at91_pinctrl_of_match[] __devinitdata = {
++ { .compatible = "atmel,at91rm9200-pinctrl", .data = &at91rm9200_ops },
++ { .compatible = "atmel,at91sam9x5-pinctrl", .data = &at91sam9x5_ops },
++ { /* sentinel */ }
++};
++
++static int __devinit at91_pinctrl_probe_dt(struct platform_device *pdev,
++ struct at91_pinctrl *info)
++{
++ int ret = 0;
++ int i, j;
++ uint32_t *tmp;
++ struct device_node *np = pdev->dev.of_node;
++ struct device_node *child;
++
++ if (!np)
++ return -ENODEV;
++
++ info->dev = &pdev->dev;
++ info->ops =
++ of_match_device(at91_pinctrl_of_match, &pdev->dev)->data;
++ at91_pinctrl_child_count(info, np);
++
++ if (info->nbanks < 1) {
++ dev_err(&pdev->dev, "you need to specify atleast one gpio-controller\n");
++ return -EINVAL;
++ }
++
++ ret = at91_pinctrl_mux_mask(info, np);
++ if (ret)
++ return ret;
++
++ dev_dbg(&pdev->dev, "nmux = %d\n", info->nmux);
++
++ dev_dbg(&pdev->dev, "mux-mask\n");
++ tmp = info->mux_mask;
++ for (i = 0; i < info->nbanks; i++) {
++ for (j = 0; j < info->nmux; j++, tmp++) {
++ dev_dbg(&pdev->dev, "%d:%d\t0x%x\n", i, j, tmp[0]);
++ }
++ }
++
++ dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
++ dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups);
++ info->functions = devm_kzalloc(&pdev->dev, info->nfunctions * sizeof(struct at91_pmx_func),
++ GFP_KERNEL);
++ if (!info->functions)
++ return -ENOMEM;
++
++ info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct at91_pin_group),
++ GFP_KERNEL);
++ if (!info->groups)
++ return -ENOMEM;
++
++ dev_dbg(&pdev->dev, "nbanks = %d\n", info->nbanks);
++ dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
++ dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups);
++
++ i = 0;
++
++ for_each_child_of_node(np, child) {
++ if (of_device_is_compatible(child, gpio_compat))
++ continue;
++ ret = at91_pinctrl_parse_functions(child, info, i++);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to parse function\n");
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
++static int __devinit at91_pinctrl_probe(struct platform_device *pdev)
++{
++ struct at91_pinctrl *info;
++ struct pinctrl_pin_desc *pdesc;
++ int ret, i, j ,k;
++
++ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
++ if (!info)
++ return -ENOMEM;
++
++ ret = at91_pinctrl_probe_dt(pdev, info);
++ if (ret)
++ return ret;
++
++ /*
++ * We need all the GPIO drivers to probe FIRST, or we will not be able
++ * to obtain references to the struct gpio_chip * for them, and we
++ * need this to proceed.
++ */
++ for (i = 0; i < info->nbanks; i++) {
++ if (!gpio_chips[i]) {
++ dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i);
++ devm_kfree(&pdev->dev, info);
++ return -EPROBE_DEFER;
++ }
++ }
++
++ at91_pinctrl_desc.name = dev_name(&pdev->dev);
++ at91_pinctrl_desc.npins = info->nbanks * MAX_NB_GPIO_PER_BANK;
++ at91_pinctrl_desc.pins = pdesc =
++ devm_kzalloc(&pdev->dev, sizeof(*pdesc) * at91_pinctrl_desc.npins, GFP_KERNEL);
++
++ if (!at91_pinctrl_desc.pins)
++ return -ENOMEM;
++
++ for (i = 0 , k = 0; i < info->nbanks; i++) {
++ for (j = 0; j < MAX_NB_GPIO_PER_BANK; j++, k++) {
++ pdesc->number = k;
++ pdesc->name = kasprintf(GFP_KERNEL, "pio%c%d", i + 'A', j);
++ pdesc++;
++ }
++ }
++
++ platform_set_drvdata(pdev, info);
++ info->pctl = pinctrl_register(&at91_pinctrl_desc, &pdev->dev, info);
++
++ if (!info->pctl) {
++ dev_err(&pdev->dev, "could not register AT91 pinctrl driver\n");
++ ret = -EINVAL;
++ goto err;
++ }
++
++ /* We will handle a range of GPIO pins */
++ for (i = 0; i < info->nbanks; i++)
++ pinctrl_add_gpio_range(info->pctl, &gpio_chips[i]->range);
++
++ dev_info(&pdev->dev, "initialized AT91 pinctrl driver\n");
++
++ return 0;
++
++err:
++ return ret;
++}
++
++int __devexit at91_pinctrl_remove(struct platform_device *pdev)
++{
++ struct at91_pinctrl *info = platform_get_drvdata(pdev);
++
++ pinctrl_unregister(info->pctl);
++
++ return 0;
++}
++
++static int at91_gpio_request(struct gpio_chip *chip, unsigned offset)
++{
++ /*
++ * Map back to global GPIO space and request muxing, the direction
++ * parameter does not matter for this controller.
++ */
++ int gpio = chip->base + offset;
++ int bank = chip->base / chip->ngpio;
++
++ dev_dbg(chip->dev, "%s:%d pio%c%d(%d)\n", __func__, __LINE__,
++ 'A' + bank, offset, gpio);
++
++ return pinctrl_request_gpio(gpio);
++}
++
++static void at91_gpio_free(struct gpio_chip *chip, unsigned offset)
++{
++ int gpio = chip->base + offset;
++
++ pinctrl_free_gpio(gpio);
++}
++
++static int at91_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
++{
++ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
++ void __iomem *pio = at91_gpio->regbase;
++ unsigned mask = 1 << offset;
++
++ writel_relaxed(mask, pio + PIO_ODR);
++ return 0;
++}
++
++static int at91_gpio_get(struct gpio_chip *chip, unsigned offset)
++{
++ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
++ void __iomem *pio = at91_gpio->regbase;
++ unsigned mask = 1 << offset;
++ u32 pdsr;
++
++ pdsr = readl_relaxed(pio + PIO_PDSR);
++ return (pdsr & mask) != 0;
++}
++
++static void at91_gpio_set(struct gpio_chip *chip, unsigned offset,
++ int val)
++{
++ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
++ void __iomem *pio = at91_gpio->regbase;
++ unsigned mask = 1 << offset;
++
++ writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR));
++}
++
++static int at91_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
++ int val)
++{
++ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
++ void __iomem *pio = at91_gpio->regbase;
++ unsigned mask = 1 << offset;
++
++ writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR));
++ writel_relaxed(mask, pio + PIO_OER);
++
++ return 0;
++}
++
++static int at91_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
++{
++ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
++ int virq;
++
++ if (offset < chip->ngpio)
++ virq = irq_create_mapping(at91_gpio->domain, offset);
++ else
++ virq = -ENXIO;
++
++ dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
++ chip->label, offset + chip->base, virq);
++ return virq;
++}
++
++#ifdef CONFIG_DEBUG_FS
++static void at91_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
++{
++ enum at91_mux mode;
++ int i;
++ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
++ void __iomem *pio = at91_gpio->regbase;
++
++ for (i = 0; i < chip->ngpio; i++) {
++ unsigned pin = chip->base + i;
++ unsigned mask = pin_to_mask(pin);
++ const char *gpio_label;
++ u32 pdsr;
++
++ gpio_label = gpiochip_is_requested(chip, i);
++ if (!gpio_label)
++ continue;
++ mode = at91_gpio->ops->get_periph(pio, mask);
++ seq_printf(s, "[%s] GPIO%s%d: ",
++ gpio_label, chip->label, i);
++ if (mode == AT91_MUX_GPIO) {
++ pdsr = readl_relaxed(pio + PIO_PDSR);
++
++ seq_printf(s, "[gpio] %s\n",
++ pdsr & mask ?
++ "set" : "clear");
++ } else {
++ seq_printf(s, "[periph %c]\n",
++ mode + 'A' - 1);
++ }
++ }
++}
++#else
++#define at91_gpio_dbg_show NULL
++#endif
++
++/* Several AIC controller irqs are dispatched through this GPIO handler.
++ * 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.
++ * First implementation always triggers on rising and falling edges
++ * whereas the newer PIO3 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().
++ * IRQ0..IRQ6 should be configurable, e.g. level vs edge triggering.
++ */
++
++static void gpio_irq_mask(struct irq_data *d)
++{
++ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
++ void __iomem *pio = at91_gpio->regbase;
++ unsigned mask = 1 << d->hwirq;
++
++ if (pio)
++ writel_relaxed(mask, pio + PIO_IDR);
++}
++
++static void gpio_irq_unmask(struct irq_data *d)
++{
++ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
++ void __iomem *pio = at91_gpio->regbase;
++ unsigned mask = 1 << d->hwirq;
++
++ if (pio)
++ writel_relaxed(mask, pio + PIO_IER);
++}
++
++static int gpio_irq_type(struct irq_data *d, unsigned type)
++{
++ switch (type) {
++ case IRQ_TYPE_NONE:
++ case IRQ_TYPE_EDGE_BOTH:
++ return 0;
++ default:
++ return -EINVAL;
++ }
++}
++
++/* Alternate irq type for PIO3 support */
++static int alt_gpio_irq_type(struct irq_data *d, unsigned type)
++{
++ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
++ void __iomem *pio = at91_gpio->regbase;
++ unsigned mask = 1 << d->hwirq;
++
++ switch (type) {
++ case IRQ_TYPE_EDGE_RISING:
++ writel_relaxed(mask, pio + PIO_ESR);
++ writel_relaxed(mask, pio + PIO_REHLSR);
++ break;
++ case IRQ_TYPE_EDGE_FALLING:
++ writel_relaxed(mask, pio + PIO_ESR);
++ writel_relaxed(mask, pio + PIO_FELLSR);
++ break;
++ case IRQ_TYPE_LEVEL_LOW:
++ writel_relaxed(mask, pio + PIO_LSR);
++ writel_relaxed(mask, pio + PIO_FELLSR);
++ break;
++ case IRQ_TYPE_LEVEL_HIGH:
++ writel_relaxed(mask, pio + PIO_LSR);
++ writel_relaxed(mask, pio + PIO_REHLSR);
++ break;
++ case IRQ_TYPE_EDGE_BOTH:
++ /*
++ * disable additional interrupt modes:
++ * fall back to default behavior
++ */
++ writel_relaxed(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 */
++ writel_relaxed(mask, pio + PIO_AIMER);
++
++ return 0;
++}
++
++#ifdef CONFIG_PM
++static int gpio_irq_set_wake(struct irq_data *d, unsigned state)
++{
++ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
++ unsigned bank = at91_gpio->pioc_idx;
++
++ if (unlikely(bank >= MAX_GPIO_BANKS))
++ return -EINVAL;
++
++ irq_set_irq_wake(at91_gpio->pioc_virq, state);
++
++ return 0;
++}
++#else
++#define gpio_irq_set_wake NULL
++#endif
++
++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 is set dynamically */
++ .irq_set_wake = gpio_irq_set_wake,
++};
++
++static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
++{
++ struct irq_chip *chip = irq_desc_get_chip(desc);
++ struct irq_data *idata = irq_desc_get_irq_data(desc);
++ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(idata);
++ void __iomem *pio = at91_gpio->regbase;
++ unsigned long isr;
++ int n;
++
++ chained_irq_enter(chip, desc);
++ for (;;) {
++ /* Reading ISR acks pending (edge triggered) GPIO interrupts.
++ * When there none are pending, we're finished unless we need
++ * to process multiple banks (like ID_PIOCDE on sam9263).
++ */
++ isr = readl_relaxed(pio + PIO_ISR) & readl_relaxed(pio + PIO_IMR);
++ if (!isr) {
++ if (!at91_gpio->next)
++ break;
++ at91_gpio = at91_gpio->next;
++ pio = at91_gpio->regbase;
++ continue;
++ }
++
++ n = find_first_bit(&isr, BITS_PER_LONG);
++ while (n < BITS_PER_LONG) {
++ generic_handle_irq(irq_find_mapping(at91_gpio->domain, n));
++ n = find_next_bit(&isr, BITS_PER_LONG, n + 1);
++ }
++ }
++ chained_irq_exit(chip, desc);
++ /* now it may re-trigger */
++}
++
++/*
++ * This lock class tells lockdep that GPIO irqs are in a different
++ * category than their parents, so it won't report false recursion.
++ */
++static struct lock_class_key gpio_lock_class;
++
++static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq,
++ irq_hw_number_t hw)
++{
++ struct at91_gpio_chip *at91_gpio = h->host_data;
++
++ irq_set_lockdep_class(virq, &gpio_lock_class);
++
++ /*
++ * Can use the "simple" and not "edge" handler since it's
++ * shorter, and the AIC handles interrupts sanely.
++ */
++ irq_set_chip_and_handler(virq, &gpio_irqchip,
++ handle_simple_irq);
++ set_irq_flags(virq, IRQF_VALID);
++ irq_set_chip_data(virq, at91_gpio);
++
++ return 0;
++}
++
++static struct irq_domain_ops at91_gpio_ops = {
++ .map = at91_gpio_irq_map,
++ .xlate = irq_domain_xlate_twocell,
++};
++
++static int at91_gpio_of_irq_setup(struct device_node *node,
++ struct at91_gpio_chip *at91_gpio)
++{
++ struct at91_gpio_chip *prev = NULL;
++ struct irq_data *d = irq_get_irq_data(at91_gpio->pioc_virq);
++
++ at91_gpio->pioc_hwirq = irqd_to_hwirq(d);
++
++ /* Setup proper .irq_set_type function */
++ gpio_irqchip.irq_set_type = at91_gpio->ops->irq_type;
++
++ /* Disable irqs of this PIO controller */
++ writel_relaxed(~0, at91_gpio->regbase + PIO_IDR);
++
++ /* Setup irq domain */
++ at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio,
++ &at91_gpio_ops, at91_gpio);
++ if (!at91_gpio->domain)
++ panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n",
++ at91_gpio->pioc_idx);
++
++ /* Setup chained handler */
++ if (at91_gpio->pioc_idx)
++ prev = gpio_chips[at91_gpio->pioc_idx - 1];
++
++ /* The toplevel handler handles one bank of GPIOs, except
++ * on some SoC it can handles up to three...
++ * We only set up the handler for the first of the list.
++ */
++ if (prev && prev->next == at91_gpio)
++ return 0;
++
++ irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio);
++ irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler);
++
++ return 0;
++}
++
++/* This structure is replicated for each GPIO block allocated at probe time */
++static struct gpio_chip at91_gpio_template = {
++ .request = at91_gpio_request,
++ .free = at91_gpio_free,
++ .direction_input = at91_gpio_direction_input,
++ .get = at91_gpio_get,
++ .direction_output = at91_gpio_direction_output,
++ .set = at91_gpio_set,
++ .to_irq = at91_gpio_to_irq,
++ .dbg_show = at91_gpio_dbg_show,
++ .can_sleep = 0,
++ .ngpio = MAX_NB_GPIO_PER_BANK,
++};
++
++static void __devinit at91_gpio_probe_fixup(void)
++{
++ unsigned i;
++ struct at91_gpio_chip *at91_gpio, *last = NULL;
++
++ for (i = 0; i < gpio_banks; i++) {
++ at91_gpio = gpio_chips[i];
++
++ /*
++ * GPIO controller are grouped on some SoC:
++ * PIOC, PIOD and PIOE can share the same IRQ line
++ */
++ if (last && last->pioc_virq == at91_gpio->pioc_virq)
++ last->next = at91_gpio;
++ last = at91_gpio;
++ }
++}
++
++static struct of_device_id at91_gpio_of_match[] __devinitdata = {
++ { .compatible = "atmel,at91rm9200-gpio", .data = &at91rm9200_ops },
++ { .compatible = "atmel,at91sam9x5-gpio", .data = &at91sam9x5_ops, },
++ { /* sentinel */ }
++};
++
++static int __devinit at91_gpio_probe(struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ struct resource *res;
++ struct at91_gpio_chip *at91_chip = NULL;
++ struct gpio_chip *chip;
++ struct pinctrl_gpio_range *range;
++ int ret = 0;
++ int irq;
++ int alias_idx = of_alias_get_id(np, "gpio");
++ uint32_t ngpio;
++
++ BUG_ON(alias_idx >= ARRAY_SIZE(gpio_chips));
++ if (gpio_chips[alias_idx]) {
++ ret = -EBUSY;
++ goto err;
++ }
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ ret = -ENOENT;
++ goto err;
++ }
++
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0) {
++ ret = irq;
++ goto err;
++ }
++
++ at91_chip = devm_kzalloc(&pdev->dev, sizeof(*at91_chip), GFP_KERNEL);
++ if (!at91_chip) {
++ ret = -ENOMEM;
++ goto err;
++ }
++
++ at91_chip->regbase = devm_request_and_ioremap(&pdev->dev, res);
++ if (!at91_chip->regbase) {
++ dev_err(&pdev->dev, "failed to map registers, ignoring.\n");
++ ret = -EBUSY;
++ goto err;
++ }
++
++ at91_chip->ops =
++ of_match_device(at91_gpio_of_match, &pdev->dev)->data;
++ at91_chip->pioc_virq = irq;
++ at91_chip->pioc_idx = alias_idx;
++
++ at91_chip->clock = clk_get(&pdev->dev, NULL);
++ if (IS_ERR(at91_chip->clock)) {
++ dev_err(&pdev->dev, "failed to get clock, ignoring.\n");
++ goto err;
++ }
++
++ if (clk_prepare(at91_chip->clock))
++ goto clk_prep_err;
++
++ /* enable PIO controller's clock */
++ if (clk_enable(at91_chip->clock)) {
++ dev_err(&pdev->dev, "failed to enable clock, ignoring.\n");
++ goto clk_err;
++ }
++
++ at91_chip->chip = at91_gpio_template;
++
++ chip = &at91_chip->chip;
++ chip->of_node = np;
++ chip->label = dev_name(&pdev->dev);
++ chip->dev = &pdev->dev;
++ chip->owner = THIS_MODULE;
++ chip->base = alias_idx * MAX_NB_GPIO_PER_BANK;
++
++ if (!of_property_read_u32(np, "#gpio-lines", &ngpio)) {
++ if (ngpio >= MAX_NB_GPIO_PER_BANK)
++ pr_err("at91_gpio.%d, gpio-nb >= %d failback to %d\n",
++ alias_idx, MAX_NB_GPIO_PER_BANK, MAX_NB_GPIO_PER_BANK);
++ else
++ chip->ngpio = ngpio;
++ }
++
++ range = &at91_chip->range;
++ range->name = chip->label;
++ range->id = alias_idx;
++ range->pin_base = range->base = range->id * MAX_NB_GPIO_PER_BANK;
++
++ range->npins = chip->ngpio;
++ range->gc = chip;
++
++ ret = gpiochip_add(chip);
++ if (ret)
++ goto clk_err;
++
++ gpio_chips[alias_idx] = at91_chip;
++ gpio_banks = max(gpio_banks, alias_idx + 1);
++
++ at91_gpio_probe_fixup();
++
++ at91_gpio_of_irq_setup(np, at91_chip);
++
++ dev_info(&pdev->dev, "at address %p\n", at91_chip->regbase);
++
++ return 0;
++
++clk_err:
++ clk_unprepare(at91_chip->clock);
++clk_prep_err:
++ clk_put(at91_chip->clock);
++err:
++ dev_err(&pdev->dev, "Failure %i for GPIO %i\n", ret, alias_idx);
++
++ return ret;
++}
++
++static struct platform_driver at91_gpio_driver = {
++ .driver = {
++ .name = "gpio-at91",
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(at91_gpio_of_match),
++ },
++ .probe = at91_gpio_probe,
++};
++
++static struct platform_driver at91_pinctrl_driver = {
++ .driver = {
++ .name = "pinctrl-at91",
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(at91_pinctrl_of_match),
++ },
++ .probe = at91_pinctrl_probe,
++ .remove = __devexit_p(at91_pinctrl_remove),
++};
++
++static int __init at91_pinctrl_init(void)
++{
++ int ret;
++
++ ret = platform_driver_register(&at91_gpio_driver);
++ if (ret)
++ return ret;
++ return platform_driver_register(&at91_pinctrl_driver);
++}
++arch_initcall(at91_pinctrl_init);
++
++static void __exit at91_pinctrl_exit(void)
++{
++ platform_driver_unregister(&at91_pinctrl_driver);
++}
++
++module_exit(at91_pinctrl_exit);
++MODULE_AUTHOR("Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>");
++MODULE_DESCRIPTION("Atmel AT91 pinctrl driver");
++MODULE_LICENSE("GPL v2");
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0213-arm-at91-dt-at91sam9-add-pinctrl-support.patch b/patches.at91/0213-arm-at91-dt-at91sam9-add-pinctrl-support.patch
new file mode 100644
index 00000000000000..0e84ffca60ce92
--- /dev/null
+++ b/patches.at91/0213-arm-at91-dt-at91sam9-add-pinctrl-support.patch
@@ -0,0 +1,405 @@
+From 34452935eb56aac56b666dd664766bc115b452c6 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Mon, 22 Oct 2012 16:08:50 +0200
+Subject: arm: at91: dt: at91sam9 add pinctrl support
+
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+
+Conflicts:
+ arch/arm/mach-at91/at91sam9263.c
+ arch/arm/mach-at91/at91sam9n12.c
+ arch/arm/mach-at91/at91sam9x5.c
+---
+ .../bindings/pinctrl/atmel,at91-pinctrl.txt | 68 +++++++++++++++++++---
+ arch/arm/boot/dts/at91sam9260.dtsi | 9 +++
+ arch/arm/boot/dts/at91sam9263.dtsi | 12 ++++
+ arch/arm/boot/dts/at91sam9g45.dtsi | 11 ++++
+ arch/arm/boot/dts/at91sam9n12.dtsi | 12 +++-
+ arch/arm/boot/dts/at91sam9x5.dtsi | 12 +++-
+ arch/arm/configs/at91_dt_defconfig | 1 +
+ arch/arm/mach-at91/at91sam9260.c | 3 +
+ arch/arm/mach-at91/at91sam9263.c | 5 ++
+ arch/arm/mach-at91/at91sam9g45.c | 6 ++
+ arch/arm/mach-at91/at91sam9n12.c | 11 ++--
+ arch/arm/mach-at91/at91sam9x5.c | 18 ++----
+ arch/arm/mach-at91/setup.c | 3 +-
+ drivers/pinctrl/pinctrl-at91.c | 2 +-
+ 14 files changed, 140 insertions(+), 33 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
+index 0296ef4..20a987e 100644
+--- a/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
++++ b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
+@@ -22,6 +22,62 @@ Required properties for iomux controller:
+ - atmel,mux-mask: array of mask (periph per bank) to describe if a pin can be
+ configured in this periph mode. All the periph and bank need to be describe.
+
++How to create such array:
++
++Each column will represent the possible peripheral of the pinctrl
++Each line will represent a pio bank
++
++Take an example on the 9260
++Peripheral: 2 ( A and B)
++Bank: 3 (A, B and C)
++=>
++
++ /* A B */
++ 0xffffffff 0xffc00c3b /* pioA */
++ 0xffffffff 0x7fff3ccf /* pioB */
++ 0xffffffff 0x007fffff /* pioC */
++
++For each peripheral/bank we will descibe in a u32 if a pin can can be
++configured in it by putting 1 to the pin bit (1 << pin)
++
++Let's take the pioA on peripheral B
++From the datasheet Table 10-2.
++Peripheral B
++PA0 MCDB0
++PA1 MCCDB
++PA2
++PA3 MCDB3
++PA4 MCDB2
++PA5 MCDB1
++PA6
++PA7
++PA8
++PA9
++PA10 ETX2
++PA11 ETX3
++PA12
++PA13
++PA14
++PA15
++PA16
++PA17
++PA18
++PA19
++PA20
++PA21
++PA22 ETXER
++PA23 ETX2
++PA24 ETX3
++PA25 ERX2
++PA26 ERX3
++PA27 ERXCK
++PA28 ECRS
++PA29 ECOL
++PA30 RXD4
++PA31 TXD4
++
++=> 0xffc00c3b
++
+ Required properties for pin configuration node:
+ - atmel,pins: 4 integers array, represents a group of pins mux and config
+ setting. The format is atmel,pins = <PIN_BANK PIN_BANK_NUM PERIPH CONFIG>.
+@@ -35,18 +91,14 @@ NOTE:
+ Some requirements for using atmel,at91rm9200-pinctrl binding:
+ 1. We have pin function node defined under at91 controller node to represent
+ what pinmux functions this SoC supports.
+-2. The pin configuration node intends to work on a specific function should
+- to be defined under that specific function node.
+- The function node's name should represent well about what function
+- this group of pins in this pin configuration node are working on.
+-3. The driver can use the function node's name and pin configuration node's
++2. The driver can use the function node's name and pin configuration node's
+ name describe the pin function and group hierarchy.
+- For example, Linux Iat91 pinctrl driver takes the function node's name
++ For example, Linux at91 pinctrl driver takes the function node's name
+ as the function name and pin configuration node's name as group name to
+ create the map table.
+-4. Each pin configuration node should have a phandle, devices can set pins
++3. Each pin configuration node should have a phandle, devices can set pins
+ configurations by referring to the phandle of that pin configuration node.
+-5. The gpio controller must be describe in the pinctrl simple-bus.
++4. The gpio controller must be describe in the pinctrl simple-bus.
+
+ Examples:
+
+diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
+index e50261d..3654ace 100644
+--- a/arch/arm/boot/dts/at91sam9260.dtsi
++++ b/arch/arm/boot/dts/at91sam9260.dtsi
+@@ -104,6 +104,15 @@
+ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
+ ranges = <0xfffff400 0xfffff400 0x600>;
+
++ atmel,mux-mask = <
++ /* A B */
++ 0xffffffff 0xffc00c3b /* pioA */
++ 0xffffffff 0x7fff3ccf /* pioB */
++ 0xffffffff 0x007fffff /* pioC */
++ >;
++
++ /* shared pinctrl settings */
++
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x200>;
+diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
+index 45e5363..d7f416d 100644
+--- a/arch/arm/boot/dts/at91sam9263.dtsi
++++ b/arch/arm/boot/dts/at91sam9263.dtsi
+@@ -95,6 +95,17 @@
+ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
+ ranges = <0xfffff200 0xfffff200 0xa00>;
+
++ atmel,mux-mask = <
++ /* A B */
++ 0xfffffffb 0xffffe07f /* pioA */
++ 0x0007ffff 0x39072fff /* pioB */
++ 0xffffffff 0x3ffffff8 /* pioC */
++ 0xfffffbff 0xffffffff /* pioD */
++ 0xffe00fff 0xfbfcff00 /* pioE */
++ >;
++
++ /* shared pinctrl settings */
++
+ pioA: gpio@fffff200 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff200 0x200>;
+@@ -143,6 +154,7 @@
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
++ };
+ };
+
+ dbgu: serial@ffffee00 {
+diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
+index 59a21c1..e2fa457 100644
+--- a/arch/arm/boot/dts/at91sam9g45.dtsi
++++ b/arch/arm/boot/dts/at91sam9g45.dtsi
+@@ -115,6 +115,17 @@
+ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
+ ranges = <0xfffff200 0xfffff200 0xa00>;
+
++ atmel,mux-mask = <
++ /* A B */
++ 0xffffffff 0xffc003ff /* pioA */
++ 0xffffffff 0x800f8f00 /* pioB */
++ 0xffffffff 0x00000e00 /* pioC */
++ 0xffffffff 0xff0c1381 /* pioD */
++ 0xffffffff 0x81ffff81 /* pioE */
++ >;
++
++ /* shared pinctrl settings */
++
+ pioA: gpio@fffff200 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff200 0x200>;
+diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
+index 135ecef..fc451f9 100644
+--- a/arch/arm/boot/dts/at91sam9n12.dtsi
++++ b/arch/arm/boot/dts/at91sam9n12.dtsi
+@@ -115,9 +115,19 @@
+ pinctrl@fffff400 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+- compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
++ compatible = "atmel,at91sam9x5-pinctrl", "atmel,at91rm9200-pinctrl", "simple-bus";
+ ranges = <0xfffff400 0xfffff400 0x800>;
+
++ atmel,mux-mask = <
++ /* A B C */
++ 0xffffffff 0xffe07983 0x00000000 /* pioA */
++ 0x00040000 0x00047e0f 0x00000000 /* pioB */
++ 0xfdffffff 0x07c00000 0xb83fffff /* pioC */
++ 0x003fffff 0x003f8000 0x00000000 /* pioD */
++ >;
++
++ /* shared pinctrl settings */
++
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x200>;
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 4e61a5d..84baa90 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -116,9 +116,19 @@
+ pinctrl@fffff200 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+- compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
++ compatible = "atmel,at91sam9x5-pinctrl", "atmel,at91rm9200-pinctrl", "simple-bus";
+ ranges = <0xfffff400 0xfffff400 0x800>;
+
++ atmel,mux-mask = <
++ /* A B C */
++ 0xffffffff 0xffe0399f 0xc000001c /* pioA */
++ 0xffffffff 0xffc003ff 0xffc003ff /* pioB */
++ 0xffffffff 0xffc003ff 0xffc003ff /* pioC */
++ 0xffffffff 0xffc003ff 0xffc003ff /* pioD */
++ >;
++
++ /* shared pinctrl settings */
++
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x200>;
+diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig
+index 67bc571..b175577 100644
+--- a/arch/arm/configs/at91_dt_defconfig
++++ b/arch/arm/configs/at91_dt_defconfig
+@@ -111,6 +111,7 @@ CONFIG_I2C=y
+ CONFIG_I2C_GPIO=y
+ CONFIG_SPI=y
+ CONFIG_SPI_ATMEL=y
++CONFIG_PINCTRL_AT91=y
+ # CONFIG_HWMON is not set
+ CONFIG_WATCHDOG=y
+ CONFIG_AT91SAM9X_WATCHDOG=y
+diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
+index bb9bc50..23a8cfb 100644
+--- a/arch/arm/mach-at91/at91sam9260.c
++++ b/arch/arm/mach-at91/at91sam9260.c
+@@ -228,6 +228,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+ CLKDEV_CON_ID("pioB", &pioB_clk),
+ CLKDEV_CON_ID("pioC", &pioC_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioA_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioB_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioC_clk),
+ };
+
+ static struct clk_lookup usart_clocks_lookups[] = {
+diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
+index 76499a6..7639f6b 100644
+--- a/arch/arm/mach-at91/at91sam9263.c
++++ b/arch/arm/mach-at91/at91sam9263.c
+@@ -214,6 +214,11 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("mci_clk", "fff80000.mmc", &mmc0_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "fff84000.mmc", &mmc1_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff200.gpio", &pioA_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioB_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioCDE_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioCDE_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioCDE_clk),
+ };
+
+ static struct clk_lookup usart_clocks_lookups[] = {
+diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
+index 5e7a1dd..2575bbf 100644
+--- a/arch/arm/mach-at91/at91sam9g45.c
++++ b/arch/arm/mach-at91/at91sam9g45.c
+@@ -258,6 +258,12 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("sha_clk", "fffc8000.sha", &aestdessha_clk),
+ /* fake hclk clock */
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff200.gpio", &pioA_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioB_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioC_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioDE_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioDE_clk),
++
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+ CLKDEV_CON_ID("pioB", &pioB_clk),
+ CLKDEV_CON_ID("pioC", &pioC_clk),
+diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
+index 6fa0df1..f313142 100644
+--- a/arch/arm/mach-at91/at91sam9n12.c
++++ b/arch/arm/mach-at91/at91sam9n12.c
+@@ -186,12 +186,12 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma_clk),
+ CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
+ CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
+- CLKDEV_CON_ID("pioA", &pioAB_clk),
+- CLKDEV_CON_ID("pioB", &pioAB_clk),
+- CLKDEV_CON_ID("pioC", &pioCD_clk),
+- CLKDEV_CON_ID("pioD", &pioCD_clk),
+ CLKDEV_CON_DEV_ID("aes_clk", "f000c000.aes", &aes_clk),
+ CLKDEV_CON_DEV_ID("sha_clk", "f0014000.sha", &sha_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioAB_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioAB_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioCD_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioCD_clk),
+ /* additional fake clock for macb_hclk */
+ CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &uhp_clk),
+ CLKDEV_CON_DEV_ID("ohci_clk", "500000.ohci", &uhp_clk),
+@@ -241,9 +241,6 @@ static void __init at91sam9n12_map_io(void)
+ void __init at91sam9n12_initialize(void)
+ {
+ at91_extern_irq = (1 << AT91SAM9N12_ID_IRQ0);
+-
+- /* Register GPIO subsystem (using DT) */
+- at91_gpio_init(NULL, 0);
+ }
+
+ AT91_SOC_START(sam9n12)
+diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
+index af00de4..2870367 100644
+--- a/arch/arm/mach-at91/at91sam9x5.c
++++ b/arch/arm/mach-at91/at91sam9x5.c
+@@ -227,16 +227,13 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "f0008000.mmc", &mmc0_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "f000c000.mmc", &mmc1_clk),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.0", &twi0_clk),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.2", &twi2_clk),
+ CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
+ CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
+ CLKDEV_CON_DEV_ID(NULL, "f8018000.i2c", &twi2_clk),
+- CLKDEV_CON_ID("pioA", &pioAB_clk),
+- CLKDEV_CON_ID("pioB", &pioAB_clk),
+- CLKDEV_CON_ID("pioC", &pioCD_clk),
+- CLKDEV_CON_ID("pioD", &pioCD_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioAB_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioAB_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioCD_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioCD_clk),
+ /* additional fake clock for macb_hclk */
+ CLKDEV_CON_DEV_ID("hclk", "f802c000.ethernet", &macb0_clk),
+ CLKDEV_CON_DEV_ID("hclk", "f8030000.ethernet", &macb1_clk),
+@@ -313,12 +310,6 @@ static void __init at91sam9x5_map_io(void)
+ init_consistent_dma_size(SZ_8M);
+ }
+
+-void __init at91sam9x5_initialize(void)
+-{
+- /* Register GPIO subsystem (using DT) */
+- at91_gpio_init(NULL, 0);
+-}
+-
+ /* --------------------------------------------------------------------
+ * Interrupt initialization
+ * -------------------------------------------------------------------- */
+@@ -326,5 +317,4 @@ void __init at91sam9x5_initialize(void)
+ AT91_SOC_START(sam9x5)
+ .map_io = at91sam9x5_map_io,
+ .register_clocks = at91sam9x5_register_clocks,
+- .init = at91sam9x5_initialize,
+ AT91_SOC_END
+diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
+index 50c69b5..fcb66ea 100644
+--- a/arch/arm/mach-at91/setup.c
++++ b/arch/arm/mach-at91/setup.c
+@@ -449,7 +449,8 @@ void __init at91_dt_initialize(void)
+ /* Register the processor-specific clocks */
+ at91_boot_soc.register_clocks();
+
+- at91_boot_soc.init();
++ if (at91_boot_soc.init)
++ at91_boot_soc.init();
+ }
+ #endif
+
+diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
+index e4712d1..9c0fe11 100644
+--- a/drivers/pinctrl/pinctrl-at91.c
++++ b/drivers/pinctrl/pinctrl-at91.c
+@@ -749,7 +749,7 @@ static int __devinit at91_pinctrl_parse_groups(struct device_node *np,
+ grp->name = np->name;
+
+ /*
+- * the binding format is fsl,pins = <bank pin mux CONFIG ...>,
++ * the binding format is atmel,pins = <bank pin mux CONFIG ...>,
+ * do sanity check and calculate pins number
+ */
+ list = of_get_property(np, "atmel,pins", &size);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0214-tty-atmel_serial-add-pinctrl-support.patch b/patches.at91/0214-tty-atmel_serial-add-pinctrl-support.patch
new file mode 100644
index 00000000000000..c0bbc438a91bb0
--- /dev/null
+++ b/patches.at91/0214-tty-atmel_serial-add-pinctrl-support.patch
@@ -0,0 +1,49 @@
+From e56cc54a58d4f2b37ec46f5a3281ce346417a24f Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Fri, 6 Jul 2012 00:41:57 +0800
+Subject: tty: atmel_serial: add pinctrl support
+
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ drivers/tty/serial/atmel_serial.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
+index 3d7e1ee..65f891b 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/pinctrl/consumer.h>
+
+ #include <asm/io.h>
+ #include <asm/ioctls.h>
+@@ -1773,6 +1774,7 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
+ struct atmel_uart_data *pdata = pdev->dev.platform_data;
+ void *data;
+ int ret = -ENODEV;
++ struct pinctrl *pinctrl;
+
+ BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
+
+@@ -1805,6 +1807,12 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
+
+ atmel_init_port(port, pdev);
+
++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
++ if (IS_ERR(pinctrl)) {
++ ret = PTR_ERR(pinctrl);
++ goto err;
++ }
++
+ if (!atmel_use_dma_rx(&port->uart)) {
+ ret = -ENOMEM;
+ data = kmalloc(sizeof(struct atmel_uart_char)
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0215-arm-at91-dt-sam9m10g45ek-use-rts-cts-pinctrl-group-f.patch b/patches.at91/0215-arm-at91-dt-sam9m10g45ek-use-rts-cts-pinctrl-group-f.patch
new file mode 100644
index 00000000000000..4cfbed0ae4d573
--- /dev/null
+++ b/patches.at91/0215-arm-at91-dt-sam9m10g45ek-use-rts-cts-pinctrl-group-f.patch
@@ -0,0 +1,27 @@
+From d608a2b7366014469707cdbdc97753856476a35b Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Fri, 6 Jul 2012 00:41:57 +0800
+Subject: arm: at91: dt: sam9m10g45ek: use rts/cts pinctrl group for uart1
+
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/boot/dts/at91sam9m10g45ek.dts | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts
+index 6a4aedd..94a8399 100644
+--- a/arch/arm/boot/dts/at91sam9m10g45ek.dts
++++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts
+@@ -39,6 +39,7 @@
+ };
+
+ usart1: serial@fff90000 {
++ pinctrl-0 = <&pinctrl_uart0 &pinctrl_uart1_rts_cts>;
+ status = "okay";
+ };
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0216-arm-at91-dt-sam9263ek-use-rts-cts-pinctrl-group-for-.patch b/patches.at91/0216-arm-at91-dt-sam9263ek-use-rts-cts-pinctrl-group-for-.patch
new file mode 100644
index 00000000000000..19082b15459a48
--- /dev/null
+++ b/patches.at91/0216-arm-at91-dt-sam9263ek-use-rts-cts-pinctrl-group-for-.patch
@@ -0,0 +1,27 @@
+From e287f769608c1e8e9304f25461efecbe18362996 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Fri, 10 Aug 2012 03:38:36 +0800
+Subject: arm: at91: dt: sam9263ek: use rts/cts pinctrl group for uart0
+
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/boot/dts/at91sam9263ek.dts | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9263ek.dts b/arch/arm/boot/dts/at91sam9263ek.dts
+index 05028ed..4c25adf 100644
+--- a/arch/arm/boot/dts/at91sam9263ek.dts
++++ b/arch/arm/boot/dts/at91sam9263ek.dts
+@@ -38,6 +38,7 @@
+ };
+
+ usart0: serial@fff8c000 {
++ pinctrl-0 = <&pinctrl_uart0 &pinctrl_uart0_rts_cts>;
+ status = "okay";
+ };
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0217-arm-at91-dt-sam9g20ek-use-rts-cts-dtr-dsr-dcd-ri-pin.patch b/patches.at91/0217-arm-at91-dt-sam9g20ek-use-rts-cts-dtr-dsr-dcd-ri-pin.patch
new file mode 100644
index 00000000000000..c1f8c4c922c74b
--- /dev/null
+++ b/patches.at91/0217-arm-at91-dt-sam9g20ek-use-rts-cts-dtr-dsr-dcd-ri-pin.patch
@@ -0,0 +1,33 @@
+From bfacb28b16dac225e1c58a72f629cb0d2e9f5120 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Fri, 10 Aug 2012 13:07:57 +0800
+Subject: arm: at91: dt: sam9g20ek: use rts/cts/dtr/dsr/dcd/ri pinctrl group
+ for uart0
+
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/boot/dts/at91sam9g20ek_common.dtsi | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+index 7da326a..6820417 100644
+--- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
++++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+@@ -35,6 +35,12 @@
+ };
+
+ usart0: serial@fffb0000 {
++ pinctrl-0 =
++ <&pinctrl_uart0
++ &pinctrl_uart0_rts_cts
++ &pinctrl_uart0_dtr_dsr
++ &pinctrl_uart0_dcd
++ &pinctrl_uart0_ri>;
+ status = "okay";
+ };
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0218-MTD-atmel-nand-fix-gpio-missing-request.patch b/patches.at91/0218-MTD-atmel-nand-fix-gpio-missing-request.patch
new file mode 100644
index 00000000000000..88a7d8f648baee
--- /dev/null
+++ b/patches.at91/0218-MTD-atmel-nand-fix-gpio-missing-request.patch
@@ -0,0 +1,86 @@
+From 57ce21ce09125413ed6f01cd028b7721ac0abd00 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Thu, 12 Jul 2012 13:20:22 +0800
+Subject: MTD: atmel nand: fix gpio missing request
+
+without this the gpio will not be muxed as a gpio by the current custom pinmux
+or later by the pinctrl
+
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ drivers/mtd/nand/atmel_nand.c | 50 ++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 49 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index 980ffdd..3978336 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -1411,8 +1411,41 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ nand_chip->IO_ADDR_W = host->io_base;
+ nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
+
+- if (gpio_is_valid(host->board.rdy_pin))
++ if (gpio_is_valid(host->board.rdy_pin)) {
++ res = devm_gpio_request(&pdev->dev,
++ host->board.rdy_pin, "nand_rdy");
++ if (res < 0) {
++ dev_err(&pdev->dev,
++ "can't request rdy gpio %d\n", host->board.rdy_pin);
++ goto err_ecc_ioremap;
++ }
++
++ res = gpio_direction_input(host->board.rdy_pin);
++ if (res < 0) {
++ dev_err(&pdev->dev,
++ "can't request input direction rdy gpio %d\n", host->board.rdy_pin);
++ goto err_ecc_ioremap;
++ }
++
+ nand_chip->dev_ready = atmel_nand_device_ready;
++ }
++
++ if (gpio_is_valid(host->board.enable_pin)) {
++ res = devm_gpio_request(&pdev->dev,
++ host->board.enable_pin, "nand_enable");
++ if (res < 0) {
++ dev_err(&pdev->dev,
++ "can't request enable gpio %d\n", host->board.enable_pin);
++ goto err_ecc_ioremap;
++ }
++
++ res = gpio_direction_output(host->board.enable_pin, 1);
++ if (res < 0) {
++ dev_err(&pdev->dev,
++ "can't request output direction enable gpio %d\n", host->board.enable_pin);
++ goto err_ecc_ioremap;
++ }
++ }
+
+ nand_chip->ecc.mode = host->board.ecc_mode;
+
+@@ -1431,6 +1464,21 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ atmel_nand_enable(host);
+
+ if (gpio_is_valid(host->board.det_pin)) {
++ res = devm_gpio_request(&pdev->dev,
++ host->board.det_pin, "nand_det");
++ if (res < 0) {
++ dev_err(&pdev->dev,
++ "can't request det gpio %d\n", host->board.det_pin);
++ goto err_no_card;
++ }
++
++ res = gpio_direction_input(host->board.det_pin);
++ if (res < 0) {
++ dev_err(&pdev->dev,
++ "can't request input direction det gpio %d\n", host->board.det_pin);
++ goto err_no_card;
++ }
++
+ if (gpio_get_value(host->board.det_pin)) {
+ printk(KERN_INFO "No SmartMedia card inserted.\n");
+ res = -ENXIO;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0219-arm-at91-dt-at91sam9-add-nand-pinctrl-support.patch b/patches.at91/0219-arm-at91-dt-at91sam9-add-nand-pinctrl-support.patch
new file mode 100644
index 00000000000000..eff83224f66176
--- /dev/null
+++ b/patches.at91/0219-arm-at91-dt-at91sam9-add-nand-pinctrl-support.patch
@@ -0,0 +1,158 @@
+From e624846db6e105762542cb6c09276609a7932ea3 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Thu, 12 Jul 2012 23:36:52 +0800
+Subject: arm: at91: dt: at91sam9 add nand pinctrl support
+
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/boot/dts/at91sam9260.dtsi | 10 ++++++++++
+ arch/arm/boot/dts/at91sam9263.dtsi | 10 ++++++++++
+ arch/arm/boot/dts/at91sam9g45.dtsi | 10 ++++++++++
+ arch/arm/boot/dts/at91sam9n12.dtsi | 10 ++++++++++
+ arch/arm/boot/dts/at91sam9x5.dtsi | 10 ++++++++++
+ 5 files changed, 50 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
+index 3654ace..2dd4e0b 100644
+--- a/arch/arm/boot/dts/at91sam9260.dtsi
++++ b/arch/arm/boot/dts/at91sam9260.dtsi
+@@ -113,6 +113,14 @@
+
+ /* shared pinctrl settings */
+
++ nand {
++ pinctrl_nand: nand-0 {
++ atmel,pins =
++ <2 13 0x0 0x1 /* PC13 gpio RDY pin pull_up */
++ 2 14 0x0 0x1>; /* PC14 gpio enable pin pull_up */
++ };
++ };
++
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x200>;
+@@ -247,6 +255,8 @@
+ >;
+ atmel,nand-addr-offset = <21>;
+ atmel,nand-cmd-offset = <22>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_nand>;
+ gpios = <&pioC 13 0
+ &pioC 14 0
+ 0
+diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
+index d7f416d..5aa07e4 100644
+--- a/arch/arm/boot/dts/at91sam9263.dtsi
++++ b/arch/arm/boot/dts/at91sam9263.dtsi
+@@ -106,6 +106,14 @@
+
+ /* shared pinctrl settings */
+
++ nand {
++ pinctrl_nand: nand-0 {
++ atmel,pins =
++ <0 22 0x0 0x1 /* PA22 gpio RDY pin pull_up*/
++ 3 15 0x0 0x1>; /* PD15 gpio enable pin pull_up */
++ };
++ };
++
+ pioA: gpio@fffff200 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff200 0x200>;
+@@ -242,6 +250,8 @@
+ >;
+ atmel,nand-addr-offset = <21>;
+ atmel,nand-cmd-offset = <22>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_nand>;
+ gpios = <&pioA 22 0
+ &pioD 15 0
+ 0
+diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
+index e2fa457..f08b8c2 100644
+--- a/arch/arm/boot/dts/at91sam9g45.dtsi
++++ b/arch/arm/boot/dts/at91sam9g45.dtsi
+@@ -126,6 +126,14 @@
+
+ /* shared pinctrl settings */
+
++ nand {
++ pinctrl_nand: nand-0 {
++ atmel,pins =
++ <2 8 0x0 0x1 /* PC8 gpio RDY pin pull_up*/
++ 2 14 0x0 0x1>; /* PC14 gpio enable pin pull_up */
++ };
++ };
++
+ pioA: gpio@fffff200 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff200 0x200>;
+@@ -297,6 +305,8 @@
+ >;
+ atmel,nand-addr-offset = <21>;
+ atmel,nand-cmd-offset = <22>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_nand>;
+ gpios = <&pioC 8 0
+ &pioC 14 0
+ 0
+diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
+index fc451f9..ec9b573 100644
+--- a/arch/arm/boot/dts/at91sam9n12.dtsi
++++ b/arch/arm/boot/dts/at91sam9n12.dtsi
+@@ -128,6 +128,14 @@
+
+ /* shared pinctrl settings */
+
++ nand {
++ pinctrl_nand: nand-0 {
++ atmel,pins =
++ <3 5 0x0 0x1 /* PD5 gpio RDY pin pull_up*/
++ 3 4 0x0 0x1>; /* PD4 gpio enable pin pull_up */
++ };
++ };
++
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x200>;
+@@ -265,6 +273,8 @@
+ >;
+ atmel,nand-addr-offset = <21>;
+ atmel,nand-cmd-offset = <22>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_nand>;
+ gpios = <&pioD 5 0
+ &pioD 4 0
+ 0
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 84baa90..28e053a 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -129,6 +129,14 @@
+
+ /* shared pinctrl settings */
+
++ nand {
++ pinctrl_nand: nand-0 {
++ atmel,pins =
++ <3 4 0x0 0x1 /* PD5 gpio RDY pin pull_up */
++ 3 5 0x0 0x1>; /* PD4 gpio enable pin pull_up */
++ };
++ };
++
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x200>;
+@@ -305,6 +313,8 @@
+ atmel,pmecc-lookup-table-offset = <0x8000 0x10000>;
+ atmel,nand-addr-offset = <21>;
+ atmel,nand-cmd-offset = <22>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_nand>;
+ gpios = <&pioD 5 0
+ &pioD 4 0
+ 0
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0220-MTD-atmel_nand-add-pinctrl-consumer-support.patch b/patches.at91/0220-MTD-atmel_nand-add-pinctrl-consumer-support.patch
new file mode 100644
index 00000000000000..92e48d491d4aed
--- /dev/null
+++ b/patches.at91/0220-MTD-atmel_nand-add-pinctrl-consumer-support.patch
@@ -0,0 +1,50 @@
+From 38bb2e5fb1310a6e4f4a6750037dc5a824c3cfdc Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Thu, 12 Jul 2012 23:31:39 +0800
+Subject: MTD: atmel_nand: add pinctrl consumer support
+
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ drivers/mtd/nand/atmel_nand.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index 3978336..625898e 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -41,6 +41,7 @@
+ #include <linux/gpio.h>
+ #include <linux/io.h>
+ #include <linux/platform_data/atmel.h>
++#include <linux/pinctrl/consumer.h>
+
+ #include <mach/cpu.h>
+
+@@ -1367,6 +1368,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ struct resource *mem;
+ struct mtd_part_parser_data ppdata = {};
+ int res;
++ struct pinctrl *pinctrl;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+@@ -1411,6 +1413,13 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ nand_chip->IO_ADDR_W = host->io_base;
+ nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
+
++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
++ if (IS_ERR(pinctrl)) {
++ dev_err(host->dev, "Failed to request pinctrl\n");
++ res = PTR_ERR(pinctrl);
++ goto err_ecc_ioremap;
++ }
++
+ if (gpio_is_valid(host->board.rdy_pin)) {
+ res = devm_gpio_request(&pdev->dev,
+ host->board.rdy_pin, "nand_rdy");
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0221-pinctrl-at91-add-deglitch-debounce-pull-down-and-sch.patch b/patches.at91/0221-pinctrl-at91-add-deglitch-debounce-pull-down-and-sch.patch
new file mode 100644
index 00000000000000..d21da117a93e60
--- /dev/null
+++ b/patches.at91/0221-pinctrl-at91-add-deglitch-debounce-pull-down-and-sch.patch
@@ -0,0 +1,194 @@
+From 07549383aa7e1b5c99ca47f9bd75600ba1b159fc Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Wed, 26 Sep 2012 14:57:45 +0800
+Subject: pinctrl: at91 add deglitch, debounce, pull down and schmitt trigger
+ mux option support
+
+add :
+ set_deglitch: enable/disable deglitch
+ set_debounce: enable/disable debounce
+ set_pulldown: enable/disable pulldown
+ disable_schmitt_trig: disable schmitt trigger
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ drivers/pinctrl/pinctrl-at91.c | 110 +++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 110 insertions(+)
+
+diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
+index 9c0fe11..73f7245 100644
+--- a/drivers/pinctrl/pinctrl-at91.c
++++ b/drivers/pinctrl/pinctrl-at91.c
+@@ -60,6 +60,12 @@ static int gpio_banks;
+
+ #define PULL_UP (0 << 1)
+ #define MULTI_DRIVE (1 << 1)
++#define DEGLITCH (1 << 2)
++#define PULL_DOWN (1 << 3)
++#define DIS_SCHMIT (1 << 4)
++#define DEBOUNCE (1 << 16)
++#define DEBOUNCE_VAL_SHIFT 17
++#define DEBOUNCE_VAL (0x3fff << DEBOUNCE_VAL_SHIFT)
+
+ /**
+ * struct at91_pmx_func - describes AT91 pinmux functions
+@@ -123,6 +129,14 @@ struct at91_pin_group {
+ * @mux_B_periph: mux as periph B
+ * @mux_C_periph: mux as periph C
+ * @mux_D_periph: mux as periph D
++ * @get_deglitch: get deglitch status
++ * @set_deglitch: enable/disable deglitch
++ * @get_debounce: get debounce status
++ * @set_debounce: enable/disable debounce
++ * @get_pulldown: get pulldown status
++ * @set_pulldown: enable/disable pulldown
++ * @get_schmitt_trig: get schmitt trigger status
++ * @disable_schmitt_trig: disable schmitt trigger
+ * @irq_type: return irq type
+ */
+ struct at91_pinctrl_mux_ops {
+@@ -131,6 +145,14 @@ struct at91_pinctrl_mux_ops {
+ void (*mux_B_periph)(void __iomem *pio, unsigned mask);
+ void (*mux_C_periph)(void __iomem *pio, unsigned mask);
+ void (*mux_D_periph)(void __iomem *pio, unsigned mask);
++ bool (*get_deglitch)(void __iomem *pio, unsigned pin);
++ void (*set_deglitch)(void __iomem *pio, unsigned mask, bool in_on);
++ bool (*get_debounce)(void __iomem *pio, unsigned pin, u32 *div);
++ void (*set_debounce)(void __iomem *pio, unsigned mask, bool in_on, u32 div);
++ bool (*get_pulldown)(void __iomem *pio, unsigned pin);
++ void (*set_pulldown)(void __iomem *pio, unsigned mask, bool in_on);
++ bool (*get_schmitt_trig)(void __iomem *pio, unsigned pin);
++ void (*disable_schmitt_trig)(void __iomem *pio, unsigned mask);
+ /* irq */
+ int (*irq_type)(struct irq_data *d, unsigned type);
+ };
+@@ -390,10 +412,70 @@ static enum at91_mux at91_mux_get_periph(void __iomem *pio, unsigned mask)
+ return select + 1;
+ }
+
++static bool at91_mux_get_deglitch(void __iomem *pio, unsigned pin)
++{
++ return (__raw_readl(pio + PIO_IFSR) >> pin) & 0x1;
++}
++
++static void at91_mux_set_deglitch(void __iomem *pio, unsigned mask, bool is_on)
++{
++ __raw_writel(mask, pio + (is_on ? PIO_IFER : PIO_IFDR));
++}
++
++static void at91_mux_pio3_set_deglitch(void __iomem *pio, unsigned mask, bool is_on)
++{
++ if (is_on)
++ __raw_writel(mask, pio + PIO_IFSCDR);
++ at91_mux_set_deglitch(pio, mask, is_on);
++}
++
++static bool at91_mux_pio3_get_debounce(void __iomem *pio, unsigned pin, u32 *div)
++{
++ *div = __raw_readl(pio + PIO_SCDR);
++
++ return (__raw_readl(pio + PIO_IFSCSR) >> pin) & 0x1;
++}
++
++static void at91_mux_pio3_set_debounce(void __iomem *pio, unsigned mask,
++ bool is_on, u32 div)
++{
++ 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);
++ }
++}
++
++static bool at91_mux_pio3_get_pulldown(void __iomem *pio, unsigned pin)
++{
++ return (__raw_readl(pio + PIO_PPDSR) >> pin) & 0x1;
++}
++
++static void at91_mux_pio3_set_pulldown(void __iomem *pio, unsigned mask, bool is_on)
++{
++ /* Disable pull-up anyway */
++ __raw_writel(mask, pio + PIO_PUDR);
++ __raw_writel(mask, pio + (is_on ? PIO_PPDER : PIO_PPDDR));
++}
++
++static void at91_mux_pio3_disable_schmitt_trig(void __iomem *pio, unsigned mask)
++{
++ __raw_writel(__raw_readl(pio + PIO_SCHMITT) | mask, pio + PIO_SCHMITT);
++}
++
++static bool at91_mux_pio3_get_schmitt_trig(void __iomem *pio, unsigned pin)
++{
++ return (__raw_readl(pio + PIO_SCHMITT) >> pin) & 0x1;
++}
++
+ static struct at91_pinctrl_mux_ops at91rm9200_ops = {
+ .get_periph = at91_mux_get_periph,
+ .mux_A_periph = at91_mux_set_A_periph,
+ .mux_B_periph = at91_mux_set_B_periph,
++ .get_deglitch = at91_mux_get_deglitch,
++ .set_deglitch = at91_mux_set_deglitch,
+ .irq_type = gpio_irq_type,
+ };
+
+@@ -403,6 +485,14 @@ static struct at91_pinctrl_mux_ops at91sam9x5_ops = {
+ .mux_B_periph = at91_mux_pio3_set_B_periph,
+ .mux_C_periph = at91_mux_pio3_set_C_periph,
+ .mux_D_periph = at91_mux_pio3_set_D_periph,
++ .get_deglitch = at91_mux_get_deglitch,
++ .set_deglitch = at91_mux_pio3_set_deglitch,
++ .get_debounce = at91_mux_pio3_get_debounce,
++ .set_debounce = at91_mux_pio3_set_debounce,
++ .get_pulldown = at91_mux_pio3_get_pulldown,
++ .set_pulldown = at91_mux_pio3_set_pulldown,
++ .get_schmitt_trig = at91_mux_pio3_get_schmitt_trig,
++ .disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig,
+ .irq_type = alt_gpio_irq_type,
+ };
+
+@@ -628,6 +718,7 @@ static int at91_pinconf_get(struct pinctrl_dev *pctldev,
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+ void __iomem *pio;
+ unsigned pin;
++ int div;
+
+ dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, *config);
+ pio = pin_to_controller(info, pin_to_bank(pin_id));
+@@ -639,6 +730,15 @@ static int at91_pinconf_get(struct pinctrl_dev *pctldev,
+ if (at91_mux_get_pullup(pio, pin))
+ *config |= PULL_UP;
+
++ if (info->ops->get_deglitch && info->ops->get_deglitch(pio, pin))
++ *config |= DEGLITCH;
++ if (info->ops->get_debounce && info->ops->get_debounce(pio, pin, &div))
++ *config |= DEBOUNCE | (div << DEBOUNCE_VAL_SHIFT);
++ if (info->ops->get_pulldown && info->ops->get_pulldown(pio, pin))
++ *config |= PULL_DOWN;
++ if (info->ops->get_schmitt_trig && info->ops->get_schmitt_trig(pio, pin))
++ *config |= DIS_SCHMIT;
++
+ return 0;
+ }
+
+@@ -655,6 +755,16 @@ static int at91_pinconf_set(struct pinctrl_dev *pctldev,
+
+ at91_mux_set_pullup(pio, mask, config & PULL_UP);
+ at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE);
++ if (info->ops->set_deglitch)
++ info->ops->set_deglitch(pio, mask, config & DEGLITCH);
++ if (info->ops->set_debounce)
++ info->ops->set_debounce(pio, mask, DEBOUNCE,
++ (config & DEBOUNCE_VAL) >> DEBOUNCE_VAL_SHIFT);
++ if (info->ops->set_pulldown)
++ info->ops->set_pulldown(pio, mask, config & PULL_DOWN);
++ if (info->ops->disable_schmitt_trig && config & DIS_SCHMIT)
++ info->ops->disable_schmitt_trig(pio, mask);
++
+ return 0;
+ }
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0222-mtd-atmel_nand-fix-the-compile-error-which-miss-labe.patch b/patches.at91/0222-mtd-atmel_nand-fix-the-compile-error-which-miss-labe.patch
new file mode 100644
index 00000000000000..25ec8466be9ff9
--- /dev/null
+++ b/patches.at91/0222-mtd-atmel_nand-fix-the-compile-error-which-miss-labe.patch
@@ -0,0 +1,50 @@
+From 9924801dfee9489e8df05d857df0d872a4f02193 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Mon, 24 Sep 2012 08:06:30 +0800
+Subject: mtd: atmel_nand: fix the compile error which miss label
+ "err_ecc_ioremap"
+
+Add err_ecc_ioremap label to fix following errors:
+---8<---
+ CC drivers/mtd/nand/atmel_nand.o
+drivers/mtd/nand/atmel_nand.c: In function 'atmel_nand_probe':
+drivers/mtd/nand/atmel_nand.c:1423: error: label 'err_ecc_ioremap' used but not defined
+make[3]: *** [drivers/mtd/nand/atmel_nand.o] Error 1
+make[2]: *** [drivers/mtd/nand] Error 2
+make[1]: *** [drivers/mtd] Error 2
+make: *** [drivers] Error 2
+--->8---
+
+This error was introduced in b654a9a46fc2100b318050483f8c5b5d0f187303 (mtd: atmel nand: fix gpio missing request)
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ drivers/mtd/nand/atmel_nand.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index 625898e..fadec27 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -1398,7 +1398,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ if (pdev->dev.of_node) {
+ res = atmel_of_init_port(host, pdev->dev.of_node);
+ if (res)
+- goto err_nand_ioremap;
++ goto err_ecc_ioremap;
+ } else {
+ memcpy(&host->board, pdev->dev.platform_data,
+ sizeof(struct atmel_nand_data));
+@@ -1554,6 +1554,8 @@ err_scan_tail:
+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
+ pmecc_data_free(host);
+ }
++
++err_ecc_ioremap:
+ if (host->ecc)
+ iounmap(host->ecc);
+ if (host->pmerrloc_base)
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0223-pinctrl-at91-fix-compatible-order.patch b/patches.at91/0223-pinctrl-at91-fix-compatible-order.patch
new file mode 100644
index 00000000000000..883f4c0c75c91f
--- /dev/null
+++ b/patches.at91/0223-pinctrl-at91-fix-compatible-order.patch
@@ -0,0 +1,39 @@
+From 31a329d0cb5502f8076601608f2591adccbda8b7 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Tue, 16 Oct 2012 17:05:33 +0200
+Subject: pinctrl/at91: fix compatible order
+
+sam9x5 is newer than rm9200
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ drivers/pinctrl/pinctrl-at91.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
+index 73f7245..a26dcb3 100644
+--- a/drivers/pinctrl/pinctrl-at91.c
++++ b/drivers/pinctrl/pinctrl-at91.c
+@@ -930,8 +930,8 @@ static int __devinit at91_pinctrl_parse_functions(struct device_node *np,
+ }
+
+ static struct of_device_id at91_pinctrl_of_match[] __devinitdata = {
+- { .compatible = "atmel,at91rm9200-pinctrl", .data = &at91rm9200_ops },
+ { .compatible = "atmel,at91sam9x5-pinctrl", .data = &at91sam9x5_ops },
++ { .compatible = "atmel,at91rm9200-pinctrl", .data = &at91rm9200_ops },
+ { /* sentinel */ }
+ };
+
+@@ -1441,8 +1441,8 @@ static void __devinit at91_gpio_probe_fixup(void)
+ }
+
+ static struct of_device_id at91_gpio_of_match[] __devinitdata = {
++ { .compatible = "atmel,at91sam9x5-gpio", .data = &at91sam9x5_ops },
+ { .compatible = "atmel,at91rm9200-gpio", .data = &at91rm9200_ops },
+- { .compatible = "atmel,at91sam9x5-gpio", .data = &at91sam9x5_ops, },
+ { /* sentinel */ }
+ };
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0224-pinctrl-at91-fix-gpio-irq-support.patch b/patches.at91/0224-pinctrl-at91-fix-gpio-irq-support.patch
new file mode 100644
index 00000000000000..a24fc578442441
--- /dev/null
+++ b/patches.at91/0224-pinctrl-at91-fix-gpio-irq-support.patch
@@ -0,0 +1,46 @@
+From 54090e0c3b619793d8058ceb1d717ea453f65893 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Fri, 19 Oct 2012 08:45:55 +0800
+Subject: pinctrl: at91: fix gpio irq support
+
+we can not use readl/writel_relaxed for interrupts
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ drivers/pinctrl/pinctrl-at91.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
+index a26dcb3..605fffd 100644
+--- a/drivers/pinctrl/pinctrl-at91.c
++++ b/drivers/pinctrl/pinctrl-at91.c
+@@ -1213,7 +1213,7 @@ static void gpio_irq_mask(struct irq_data *d)
+ unsigned mask = 1 << d->hwirq;
+
+ if (pio)
+- writel_relaxed(mask, pio + PIO_IDR);
++ __raw_writel(mask, pio + PIO_IDR);
+ }
+
+ static void gpio_irq_unmask(struct irq_data *d)
+@@ -1223,7 +1223,7 @@ static void gpio_irq_unmask(struct irq_data *d)
+ unsigned mask = 1 << d->hwirq;
+
+ if (pio)
+- writel_relaxed(mask, pio + PIO_IER);
++ __raw_writel(mask, pio + PIO_IER);
+ }
+
+ static int gpio_irq_type(struct irq_data *d, unsigned type)
+@@ -1321,7 +1321,7 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+ * When there none are pending, we're finished unless we need
+ * to process multiple banks (like ID_PIOCDE on sam9263).
+ */
+- isr = readl_relaxed(pio + PIO_ISR) & readl_relaxed(pio + PIO_IMR);
++ isr = __raw_readl(pio + PIO_ISR) & __raw_readl(pio + PIO_IMR);
+ if (!isr) {
+ if (!at91_gpio->next)
+ break;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0225-i2c-at91-add-pinctrl.patch b/patches.at91/0225-i2c-at91-add-pinctrl.patch
new file mode 100644
index 00000000000000..3651777c3bab3c
--- /dev/null
+++ b/patches.at91/0225-i2c-at91-add-pinctrl.patch
@@ -0,0 +1,46 @@
+From 15398d1b5861b197b75d85e9cfd4c2560ecc49de Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Tue, 16 Oct 2012 17:06:37 +0200
+Subject: i2c: at91: add pinctrl
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ drivers/i2c/busses/i2c-at91.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
+index c004b34..f471747 100644
+--- a/drivers/i2c/busses/i2c-at91.c
++++ b/drivers/i2c/busses/i2c-at91.c
+@@ -30,6 +30,7 @@
+ #include <linux/of_device.h>
+ #include <linux/of_i2c.h>
+ #include <linux/platform_device.h>
++#include <linux/pinctrl/consumer.h>
+ #include <linux/slab.h>
+
+ #include <mach/at_hdmac.h>
+@@ -767,6 +768,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
+ struct resource *mem;
+ int rc;
+ u32 phy_addr;
++ struct pinctrl *pinctrl;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+@@ -779,6 +781,12 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
+ return -ENODEV;
+ phy_addr = mem->start;
+
++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
++ if (IS_ERR(pinctrl)) {
++ dev_err(&pdev->dev, "Failed to request pinctrl\n");
++ return PTR_ERR(pinctrl);
++ }
++
+ dev->pdata = at91_twi_get_driver_data(pdev);
+ if (!dev->pdata)
+ return -ENODEV;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0226-media-atmel_isi-add-pinctrl.patch b/patches.at91/0226-media-atmel_isi-add-pinctrl.patch
new file mode 100644
index 00000000000000..8c020fba78f9dc
--- /dev/null
+++ b/patches.at91/0226-media-atmel_isi-add-pinctrl.patch
@@ -0,0 +1,46 @@
+From d7ab9be8967e1884bba0228ea65f2893b10b019e Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Tue, 16 Oct 2012 17:07:17 +0200
+Subject: media: atmel_isi: add pinctrl
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ drivers/media/video/atmel-isi.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c
+index 7a44df4..ef80695 100644
+--- a/drivers/media/video/atmel-isi.c
++++ b/drivers/media/video/atmel-isi.c
+@@ -20,6 +20,7 @@
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
++#include <linux/pinctrl/consumer.h>
+ #include <linux/slab.h>
+
+ #include <media/atmel-isi.h>
+@@ -949,6 +950,7 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev)
+ struct device *dev = &pdev->dev;
+ struct soc_camera_host *soc_host;
+ struct isi_platform_data *pdata;
++ struct pinctrl *pinctrl;
+
+ pdata = dev->platform_data;
+ if (!pdata || !pdata->data_width_flags || !pdata->mck_hz) {
+@@ -961,6 +963,12 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev)
+ if (!regs)
+ return -ENXIO;
+
++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
++ if (IS_ERR(pinctrl)) {
++ dev_err(&pdev->dev, "Failed to request pinctrl\n");
++ return PTR_ERR(pinctrl);
++ }
++
+ pclk = clk_get(&pdev->dev, "isi_clk");
+ if (IS_ERR(pclk))
+ return PTR_ERR(pclk);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0227-mmc-at91-add-pinctrl.patch b/patches.at91/0227-mmc-at91-add-pinctrl.patch
new file mode 100644
index 00000000000000..d041d96767a116
--- /dev/null
+++ b/patches.at91/0227-mmc-at91-add-pinctrl.patch
@@ -0,0 +1,91 @@
+From 6d2ed0a1963bcf555e5cdc12035ae105a94da9cf Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Tue, 16 Oct 2012 17:08:12 +0200
+Subject: mmc: at91: add pinctrl
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ drivers/mmc/host/atmel-mci.c | 36 ++++++++++++++++++++++++++++++------
+ 1 file changed, 30 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index 3d9c7b8..9739604 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -28,6 +28,7 @@
+ #include <linux/slab.h>
+ #include <linux/stat.h>
+ #include <linux/types.h>
++#include <linux/pinctrl/consumer.h>
+
+ #include <linux/mmc/host.h>
+ #include <linux/mmc/sdio.h>
+@@ -2154,12 +2155,20 @@ static int __init atmci_init_slot(struct atmel_mci *host,
+ /* Assume card is present initially */
+ set_bit(ATMCI_CARD_PRESENT, &slot->flags);
+ if (gpio_is_valid(slot->detect_pin)) {
+- if (gpio_request(slot->detect_pin, "mmc_detect")) {
+- dev_dbg(&mmc->class_dev, "no detect pin available\n");
++ if (devm_gpio_request(&mmc->class_dev, slot->detect_pin,
++ "mmc_detect")) {
++ dev_dbg(&mmc->class_dev, "can't request detect pin\n");
+ slot->detect_pin = -EBUSY;
+- } else if (gpio_get_value(slot->detect_pin) ^
+- slot->detect_is_active_high) {
+- clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
++ } else {
++ if (gpio_direction_input(slot->detect_pin)) {
++ dev_err(&mmc->class_dev,
++ "can't set detect pin direction\n");
++ devm_gpio_free(&mmc->class_dev, slot->detect_pin);
++ slot->detect_pin = -EBUSY;
++ } else if (gpio_get_value(slot->detect_pin) ^
++ slot->detect_is_active_high) {
++ clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
++ }
+ }
+ }
+
+@@ -2167,9 +2176,17 @@ static int __init atmci_init_slot(struct atmel_mci *host,
+ mmc->caps |= MMC_CAP_NEEDS_POLL;
+
+ if (gpio_is_valid(slot->wp_pin)) {
+- if (gpio_request(slot->wp_pin, "mmc_wp")) {
++ if (devm_gpio_request(&mmc->class_dev, slot->wp_pin,
++ "mmc_wp")) {
+ dev_dbg(&mmc->class_dev, "no WP pin available\n");
+ slot->wp_pin = -EBUSY;
++ } else {
++ if (gpio_direction_output(slot->wp_pin, 0)) {
++ dev_err(&mmc->class_dev,
++ "can't set WP pin direction\n");
++ devm_gpio_free(&mmc->class_dev, slot->wp_pin);
++ slot->wp_pin = -EBUSY;
++ }
+ }
+ }
+
+@@ -2339,6 +2356,7 @@ static int __init atmci_probe(struct platform_device *pdev)
+ unsigned int nr_slots;
+ int irq;
+ int ret;
++ struct pinctrl *pinctrl;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs)
+@@ -2352,6 +2370,12 @@ static int __init atmci_probe(struct platform_device *pdev)
+ }
+ }
+
++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
++ if (IS_ERR(pinctrl)) {
++ dev_err(&pdev->dev, "Failed to request pinctrl\n");
++ return PTR_ERR(pinctrl);
++ }
++
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0228-video-atmel_lcdfb-add-pinctrl.patch b/patches.at91/0228-video-atmel_lcdfb-add-pinctrl.patch
new file mode 100644
index 00000000000000..86ec57f83223e4
--- /dev/null
+++ b/patches.at91/0228-video-atmel_lcdfb-add-pinctrl.patch
@@ -0,0 +1,47 @@
+From 5bc80812222fefb18a5ea8b9fcf8bb93eec37942 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Tue, 16 Oct 2012 17:08:54 +0200
+Subject: video: atmel_lcdfb: add pinctrl
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ drivers/video/atmel_lcdfb_core.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index 133d4ad..b71a80c 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -11,6 +11,7 @@
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
++#include <linux/pinctrl/consumer.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/interrupt.h>
+ #include <linux/clk.h>
+@@ -556,6 +557,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ struct resource *regs = NULL, *clut = NULL;
+ struct resource *map = NULL;
+ int ret;
++ struct pinctrl *pinctrl;
+
+ dev_dbg(dev, "%s BEGIN\n", __func__);
+
+@@ -635,6 +637,13 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ goto stop_clk;
+ }
+
++ pinctrl = devm_pinctrl_get_select_default(dev);
++ if (IS_ERR(pinctrl)) {
++ dev_err(dev, "Failed to request pinctrl\n");
++ ret = PTR_ERR(pinctrl);
++ goto stop_clk;
++ }
++
+ /* No error checking, some devices can do without IRQ */
+ sinfo->irq_base = platform_get_irq(pdev, 0);
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0229-arm-at91sam9g45-add-missing-uart-pinctrl-node.patch b/patches.at91/0229-arm-at91sam9g45-add-missing-uart-pinctrl-node.patch
new file mode 100644
index 00000000000000..3e78d0b838f411
--- /dev/null
+++ b/patches.at91/0229-arm-at91sam9g45-add-missing-uart-pinctrl-node.patch
@@ -0,0 +1,132 @@
+From 56c99e16b3c2bc6e5820266d81118915508d5b08 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Fri, 19 Oct 2012 05:52:10 +0800
+Subject: arm: at91sam9g45: add missing uart pinctrl node
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/boot/dts/at91sam9g45.dtsi | 73 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 73 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
+index f08b8c2..e379b89 100644
+--- a/arch/arm/boot/dts/at91sam9g45.dtsi
++++ b/arch/arm/boot/dts/at91sam9g45.dtsi
+@@ -125,6 +125,69 @@
+ >;
+
+ /* shared pinctrl settings */
++ dbgu {
++ pinctrl_dbgu: dbgu-0 {
++ atmel,pins =
++ <1 12 0x1 0x0 /* PB12 periph A */
++ 1 13 0x1 0x0>; /* PB13 periph A */
++ };
++ };
++
++ uart0 {
++ pinctrl_uart0: uart0-0 {
++ atmel,pins =
++ <1 19 0x1 0x1 /* PB19 periph A with pullup */
++ 1 18 0x1 0x0>; /* PB18 periph A */
++ };
++
++ pinctrl_uart0_rts_cts: uart0_rts_cts-0 {
++ atmel,pins =
++ <1 17 0x2 0x0 /* PB17 periph B */
++ 1 15 0x2 0x0>; /* PB15 periph B */
++ };
++ };
++
++ uart1 {
++ pinctrl_uart1: uart1-0 {
++ atmel,pins =
++ <1 4 0x1 0x1 /* PB4 periph A with pullup */
++ 1 5 0x1 0x0>; /* PB5 periph A */
++ };
++
++ pinctrl_uart1_rts_cts: uart1_rts_cts-0 {
++ atmel,pins =
++ <3 16 0x1 0x0 /* PD16 periph A */
++ 3 17 0x1 0x0>; /* PD17 periph A */
++ };
++ };
++
++ uart2 {
++ pinctrl_uart2: uart2-0 {
++ atmel,pins =
++ <1 6 0x1 0x1 /* PB6 periph A with pullup */
++ 1 7 0x1 0x0>; /* PB7 periph A */
++ };
++
++ pinctrl_uart2_rts_cts: uart2_rts_cts-0 {
++ atmel,pins =
++ <2 9 0x2 0x0 /* PC9 periph B */
++ 2 11 0x2 0x0>; /* PC11 periph B */
++ };
++ };
++
++ uart3 {
++ pinctrl_uart3: uart3-0 {
++ atmel,pins =
++ <1 8 0x1 0x1 /* PB9 periph A with pullup */
++ 1 9 0x1 0x0>; /* PB8 periph A */
++ };
++
++ pinctrl_uart3_rts_cts: uart3_rts_cts-0 {
++ atmel,pins =
++ <0 23 0x2 0x0 /* PA23 periph B */
++ 0 24 0x2 0x0>; /* PA24 periph B */
++ };
++ };
+
+ nand {
+ pinctrl_nand: nand-0 {
+@@ -189,6 +252,8 @@
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xffffee00 0x200>;
+ interrupts = <1 4 7>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_dbgu>;
+ status = "disabled";
+ };
+
+@@ -198,6 +263,8 @@
+ interrupts = <7 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_uart0>;
+ status = "disabled";
+ };
+
+@@ -207,6 +274,8 @@
+ interrupts = <8 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_uart1>;
+ status = "disabled";
+ };
+
+@@ -216,6 +285,8 @@
+ interrupts = <9 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_uart2>;
+ status = "disabled";
+ };
+
+@@ -225,6 +296,8 @@
+ interrupts = <10 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_uart3>;
+ status = "disabled";
+ };
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0230-arm-at91sam9263-add-missing-uart-pinctrl-node.patch b/patches.at91/0230-arm-at91sam9263-add-missing-uart-pinctrl-node.patch
new file mode 100644
index 00000000000000..e8ae1df3a9c1ab
--- /dev/null
+++ b/patches.at91/0230-arm-at91sam9263-add-missing-uart-pinctrl-node.patch
@@ -0,0 +1,109 @@
+From 9f223333d037f72115defc10f27afaf6fc900721 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Fri, 19 Oct 2012 05:52:10 +0800
+Subject: arm: at91sam9263: add missing uart pinctrl node
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/boot/dts/at91sam9263.dtsi | 57 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 57 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
+index 5aa07e4..690e036 100644
+--- a/arch/arm/boot/dts/at91sam9263.dtsi
++++ b/arch/arm/boot/dts/at91sam9263.dtsi
+@@ -105,6 +105,55 @@
+ >;
+
+ /* shared pinctrl settings */
++ dbgu {
++ pinctrl_dbgu: dbgu-0 {
++ atmel,pins =
++ <2 30 0x1 0x0 /* PC30 periph A */
++ 2 31 0x1 0x1>; /* PC31 periph with pullup */
++ };
++ };
++
++ uart0 {
++ pinctrl_uart0: uart0-0 {
++ atmel,pins =
++ <0 26 0x1 0x1 /* PA26 periph A with pullup */
++ 0 27 0x1 0x0>; /* PA27 periph A */
++ };
++
++ pinctrl_uart0_rts_cts: uart0_rts_cts-0 {
++ atmel,pins =
++ <0 28 0x1 0x0 /* PA28 periph A */
++ 0 29 0x1 0x0>; /* PA29 periph A */
++ };
++ };
++
++ uart1 {
++ pinctrl_uart1: uart1-0 {
++ atmel,pins =
++ <3 0 0x1 0x1 /* PD0 periph A with pullup */
++ 3 1 0x1 0x0>; /* PD1 periph A */
++ };
++
++ pinctrl_uart1_rts_cts: uart1_rts_cts-0 {
++ atmel,pins =
++ <3 7 0x2 0x0 /* PD7 periph B */
++ 3 8 0x2 0x0>; /* PD8 periph B */
++ };
++ };
++
++ uart2 {
++ pinctrl_uart2: uart2-0 {
++ atmel,pins =
++ <3 2 0x1 0x1 /* PD2 periph A with pullup */
++ 3 3 0x1 0x0>; /* PD3 periph A */
++ };
++
++ pinctrl_uart2_rts_cts: uart2_rts_cts-0 {
++ atmel,pins =
++ <3 5 0x2 0x0 /* PD5 periph B */
++ 4 6 0x2 0x0>; /* PD6 periph B */
++ };
++ };
+
+ nand {
+ pinctrl_nand: nand-0 {
+@@ -169,6 +218,8 @@
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xffffee00 0x200>;
+ interrupts = <1 4 7>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_dbgu>;
+ status = "disabled";
+ };
+
+@@ -178,6 +229,8 @@
+ interrupts = <7 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_uart0>;
+ status = "disabled";
+ };
+
+@@ -187,6 +240,8 @@
+ interrupts = <8 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_uart1>;
+ status = "disabled";
+ };
+
+@@ -196,6 +251,8 @@
+ interrupts = <9 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_uart2>;
+ status = "disabled";
+ };
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0231-arm-at91sam9260-add-missing-uart-pinctrl-node.patch b/patches.at91/0231-arm-at91sam9260-add-missing-uart-pinctrl-node.patch
new file mode 100644
index 00000000000000..3da53f3de710a2
--- /dev/null
+++ b/patches.at91/0231-arm-at91sam9260-add-missing-uart-pinctrl-node.patch
@@ -0,0 +1,182 @@
+From b6ce595a610de9ed6ef5b27f824f43909de0db57 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Fri, 19 Oct 2012 05:52:10 +0800
+Subject: arm: at91sam9260: add missing uart pinctrl node
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/boot/dts/at91sam9260.dtsi | 109 +++++++++++++++++++++++++++++++++++++
+ 1 file changed, 109 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
+index 2dd4e0b..7c9d91a 100644
+--- a/arch/arm/boot/dts/at91sam9260.dtsi
++++ b/arch/arm/boot/dts/at91sam9260.dtsi
+@@ -112,6 +112,101 @@
+ >;
+
+ /* shared pinctrl settings */
++ dbgu {
++ pinctrl_dbgu: dbgu-0 {
++ atmel,pins =
++ <1 14 0x1 0x0 /* PB14 periph A */
++ 1 15 0x1 0x1>; /* PB15 periph with pullup */
++ };
++ };
++
++ uart0 {
++ pinctrl_uart0: uart0-0 {
++ atmel,pins =
++ <1 4 0x1 0x0 /* PB4 periph A */
++ 1 5 0x1 0x0>; /* PB5 periph A */
++ };
++
++ pinctrl_uart0_rts_cts: uart0_rts_cts-0 {
++ atmel,pins =
++ <1 26 0x1 0x0 /* PB26 periph A */
++ 1 27 0x1 0x0>; /* PB27 periph A */
++ };
++
++ pinctrl_uart0_dtr_dsr: uart0_dtr_dsr-0 {
++ atmel,pins =
++ <1 24 0x1 0x0 /* PB24 periph A */
++ 1 22 0x1 0x0>; /* PB22 periph A */
++ };
++
++ pinctrl_uart0_dcd: uart0_dcd-0 {
++ atmel,pins =
++ <1 23 0x1 0x0>; /* PB23 periph A */
++ };
++
++ pinctrl_uart0_ri: uart0_ri-0 {
++ atmel,pins =
++ <1 25 0x1 0x0>; /* PB25 periph A */
++ };
++ };
++
++ uart1 {
++ pinctrl_uart1: uart1-0 {
++ atmel,pins =
++ <2 6 0x1 0x1 /* PB6 periph A with pullup */
++ 2 7 0x1 0x0>; /* PB7 periph A */
++ };
++
++ pinctrl_uart1_rts_cts: uart1_rts_cts-0 {
++ atmel,pins =
++ <1 28 0x1 0x0 /* PB28 periph A */
++ 1 29 0x1 0x0>; /* PB29 periph A */
++ };
++ };
++
++ uart2 {
++ pinctrl_uart2: uart2-0 {
++ atmel,pins =
++ <1 8 0x1 0x1 /* PB8 periph A with pullup */
++ 1 9 0x1 0x0>; /* PB9 periph A */
++ };
++
++ pinctrl_uart2_rts_cts: uart2_rts_cts-0 {
++ atmel,pins =
++ <0 4 0x1 0x0 /* PA4 periph A */
++ 0 5 0x1 0x0>; /* PA5 periph A */
++ };
++ };
++
++ uart3 {
++ pinctrl_uart3: uart3-0 {
++ atmel,pins =
++ <2 10 0x1 0x1 /* PB10 periph A with pullup */
++ 2 11 0x1 0x0>; /* PB11 periph A */
++ };
++
++ pinctrl_uart3_rts_cts: uart3_rts_cts-0 {
++ atmel,pins =
++ <3 8 0x2 0x0 /* PB8 periph B */
++ 3 10 0x2 0x0>; /* PB10 periph B */
++ };
++ };
++
++ uart4 {
++ pinctrl_uart4: uart4-0 {
++ atmel,pins =
++ <0 31 0x2 0x1 /* PA31 periph B with pullup */
++ 0 30 0x2 0x0>; /* PA30 periph B */
++ };
++ };
++
++ uart5 {
++ pinctrl_uart5: uart5-0 {
++ atmel,pins =
++ <2 12 0x1 0x1 /* PB12 periph A with pullup */
++ 2 13 0x1 0x0>; /* PB13 periph A */
++ };
++ };
+
+ nand {
+ pinctrl_nand: nand-0 {
+@@ -156,6 +251,8 @@
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffff200 0x200>;
+ interrupts = <1 4 7>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_dbgu>;
+ status = "disabled";
+ };
+
+@@ -165,6 +262,8 @@
+ interrupts = <6 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_uart0>;
+ status = "disabled";
+ };
+
+@@ -174,6 +273,8 @@
+ interrupts = <7 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_uart1>;
+ status = "disabled";
+ };
+
+@@ -183,6 +284,8 @@
+ interrupts = <8 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_uart2>;
+ status = "disabled";
+ };
+
+@@ -192,6 +295,8 @@
+ interrupts = <23 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_uart3>;
+ status = "disabled";
+ };
+
+@@ -201,6 +306,8 @@
+ interrupts = <24 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_uart4>;
+ status = "disabled";
+ };
+
+@@ -210,6 +317,8 @@
+ interrupts = <25 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_uart5>;
+ status = "disabled";
+ };
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0232-arm-at91sam9x5-sync-with-the-mainline.patch b/patches.at91/0232-arm-at91sam9x5-sync-with-the-mainline.patch
new file mode 100644
index 00000000000000..6e529e5f38b6e7
--- /dev/null
+++ b/patches.at91/0232-arm-at91sam9x5-sync-with-the-mainline.patch
@@ -0,0 +1,620 @@
+From b07d6cfcdf6ec210b35e05e8d6ae9dc22feffcf1 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Fri, 19 Oct 2012 06:08:16 +0800
+Subject: arm: at91sam9x5: sync with the mainline
+
+where we have one dtsi per soc and one dts per board
+we have also a common dtsi name at91sam9x5ek.dtsi for the based board
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/boot/dts/at91sam9g15.dtsi | 28 +++++++
+ arch/arm/boot/dts/at91sam9g15ek.dts | 16 ++++
+ arch/arm/boot/dts/at91sam9g25.dtsi | 28 +++++++
+ arch/arm/boot/dts/at91sam9g25ek.dts | 42 +---------
+ arch/arm/boot/dts/at91sam9g35.dtsi | 28 +++++++
+ arch/arm/boot/dts/at91sam9g35ek.dts | 21 +----
+ arch/arm/boot/dts/at91sam9x25.dtsi | 28 +++++++
+ arch/arm/boot/dts/at91sam9x25ek.dts | 24 +-----
+ arch/arm/boot/dts/at91sam9x35.dtsi | 28 +++++++
+ arch/arm/boot/dts/at91sam9x35ek.dts | 16 ++++
+ arch/arm/boot/dts/at91sam9x5.dtsi | 97 ++++++++++++++++++++--
+ .../{at91sam9x5_common.dtsi => at91sam9x5ek.dtsi} | 32 ++++++-
+ arch/arm/mach-at91/Makefile.boot | 2 +
+ 13 files changed, 298 insertions(+), 92 deletions(-)
+ create mode 100644 arch/arm/boot/dts/at91sam9g15.dtsi
+ create mode 100644 arch/arm/boot/dts/at91sam9g15ek.dts
+ create mode 100644 arch/arm/boot/dts/at91sam9g25.dtsi
+ create mode 100644 arch/arm/boot/dts/at91sam9g35.dtsi
+ create mode 100644 arch/arm/boot/dts/at91sam9x25.dtsi
+ create mode 100644 arch/arm/boot/dts/at91sam9x35.dtsi
+ create mode 100644 arch/arm/boot/dts/at91sam9x35ek.dts
+ rename arch/arm/boot/dts/{at91sam9x5_common.dtsi => at91sam9x5ek.dtsi} (54%)
+
+diff --git a/arch/arm/boot/dts/at91sam9g15.dtsi b/arch/arm/boot/dts/at91sam9g15.dtsi
+new file mode 100644
+index 0000000..fbe7a70
+--- /dev/null
++++ b/arch/arm/boot/dts/at91sam9g15.dtsi
+@@ -0,0 +1,28 @@
++/*
++ * at91sam9g15.dtsi - Device Tree Include file for AT91SAM9G15 SoC
++ *
++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
++ *
++ * Licensed under GPLv2.
++ */
++
++/include/ "at91sam9x5.dtsi"
++
++/ {
++ model = "Atmel AT91SAM9G15 SoC";
++ compatible = "atmel, at91sam9g15, atmel,at91sam9x5";
++
++ ahb {
++ apb {
++ pinctrl@fffff400 {
++ atmel,mux-mask = <
++ /* A B C */
++ 0xffffffff 0xffe0399f 0x00000000 /* pioA */
++ 0x00040000 0x00047e3f 0x00000000 /* pioB */
++ 0xfdffffff 0x00000000 0xb83fffff /* pioC */
++ 0x003fffff 0x003f8000 0x00000000 /* pioD */
++ >;
++ };
++ };
++ };
++};
+diff --git a/arch/arm/boot/dts/at91sam9g15ek.dts b/arch/arm/boot/dts/at91sam9g15ek.dts
+new file mode 100644
+index 0000000..86dd3f6
+--- /dev/null
++++ b/arch/arm/boot/dts/at91sam9g15ek.dts
+@@ -0,0 +1,16 @@
++/*
++ * at91sam9g15ek.dts - Device Tree file for AT91SAM9G15-EK board
++ *
++ * Copyright (C) 2012 Atmel,
++ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com>
++ *
++ * Licensed under GPLv2 or later.
++ */
++/dts-v1/;
++/include/ "at91sam9g15.dtsi"
++/include/ "at91sam9x5ek.dtsi"
++
++/ {
++ model = "Atmel AT91SAM9G25-EK";
++ compatible = "atmel,at91sam9g15ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
++};
+diff --git a/arch/arm/boot/dts/at91sam9g25.dtsi b/arch/arm/boot/dts/at91sam9g25.dtsi
+new file mode 100644
+index 0000000..05a718f
+--- /dev/null
++++ b/arch/arm/boot/dts/at91sam9g25.dtsi
+@@ -0,0 +1,28 @@
++/*
++ * at91sam9g25.dtsi - Device Tree Include file for AT91SAM9G25 SoC
++ *
++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
++ *
++ * Licensed under GPLv2.
++ */
++
++/include/ "at91sam9x5.dtsi"
++
++/ {
++ model = "Atmel AT91SAM9G25 SoC";
++ compatible = "atmel, at91sam9g25, atmel,at91sam9x5";
++
++ ahb {
++ apb {
++ pinctrl@fffff400 {
++ atmel,mux-mask = <
++ /* A B C */
++ 0xffffffff 0xffe0399f 0xc000001c /* pioA */
++ 0x0007ffff 0x8000fe3f 0x00000000 /* pioB */
++ 0x80000000 0x07c0ffff 0xb83fffff /* pioC */
++ 0x003fffff 0x003f8000 0x00000000 /* pioD */
++ >;
++ };
++ };
++ };
++};
+diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts
+index 91c0f02..4abc978 100644
+--- a/arch/arm/boot/dts/at91sam9g25ek.dts
++++ b/arch/arm/boot/dts/at91sam9g25ek.dts
+@@ -7,55 +7,17 @@
+ * Licensed under GPLv2 or later.
+ */
+ /dts-v1/;
+-/include/ "at91sam9x5_common.dtsi"
++/include/ "at91sam9g25.dtsi"
++/include/ "at91sam9x5ek.dtsi"
+
+ / {
+ model = "Atmel AT91SAM9G25-EK";
+ compatible = "atmel,at91sam9g25ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
+
+- chosen {
+- bootargs = "console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
+- };
+-
+ ahb {
+ apb {
+- usart0: serial@f801c000 {
+- status = "okay";
+- };
+-
+- macb0: ethernet@f802c000 {
+- phy-mode = "rmii";
+- status = "okay";
+- };
+-
+- mmc0: mmc@f0008000 {
+- status = "okay";
+- slot@0 {
+- reg = <0>;
+- bus-width = <4>;
+- cd-gpios = <&pioD 15 0>;
+- };
+- };
+-
+ mmc1: mmc@f000c000 {
+ status = "okay";
+- slot@0 {
+- reg = <0>;
+- bus-width = <4>;
+- cd-gpios = <&pioD 14 0>;
+- };
+- };
+-
+- i2c0: i2c@f8010000 {
+- status = "okay";
+- };
+-
+- i2c1: i2c@f8014000 {
+- status = "okay";
+- };
+-
+- i2c2: i2c@f8018000 {
+- status = "okay";
+ };
+ };
+ };
+diff --git a/arch/arm/boot/dts/at91sam9g35.dtsi b/arch/arm/boot/dts/at91sam9g35.dtsi
+new file mode 100644
+index 0000000..f9d14a7
+--- /dev/null
++++ b/arch/arm/boot/dts/at91sam9g35.dtsi
+@@ -0,0 +1,28 @@
++/*
++ * at91sam9g35.dtsi - Device Tree Include file for AT91SAM9G35 SoC
++ *
++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
++ *
++ * Licensed under GPLv2.
++ */
++
++/include/ "at91sam9x5.dtsi"
++
++/ {
++ model = "Atmel AT91SAM9G35 SoC";
++ compatible = "atmel, at91sam9g35, atmel,at91sam9x5";
++
++ ahb {
++ apb {
++ pinctrl@fffff400 {
++ atmel,mux-mask = <
++ /* A B C */
++ 0xffffffff 0xffe0399f 0xc000000c /* pioA */
++ 0x000406ff 0x00047e3f 0x00000000 /* pioB */
++ 0xfdffffff 0x00000000 0xb83fffff /* pioC */
++ 0x003fffff 0x003f8000 0x00000000 /* pioD */
++ >;
++ };
++ };
++ };
++};
+diff --git a/arch/arm/boot/dts/at91sam9g35ek.dts b/arch/arm/boot/dts/at91sam9g35ek.dts
+index 0cb762e..2781a30 100644
+--- a/arch/arm/boot/dts/at91sam9g35ek.dts
++++ b/arch/arm/boot/dts/at91sam9g35ek.dts
+@@ -7,34 +7,17 @@
+ * Licensed under GPLv2 or later.
+ */
+ /dts-v1/;
+-/include/ "at91sam9x5_common.dtsi"
++/include/ "at91sam9g35.dtsi"
++/include/ "at91sam9x5ek.dtsi"
+
+ / {
+ model = "Atmel AT91SAM9G35-EK";
+ compatible = "atmel,at91sam9g35ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
+
+- chosen {
+- bootargs = "console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
+- };
+-
+ ahb {
+ apb {
+ mmc1: mmc@f000c000 {
+ status = "okay";
+- slot@0 {
+- reg = <0>;
+- bus-width = <4>;
+- cd-gpios = <&pioD 14 0>;
+- };
+- };
+-
+- usart0: serial@f801c000 {
+- status = "okay";
+- };
+-
+- macb0: ethernet@f802c000 {
+- phy-mode = "rmii";
+- status = "okay";
+ };
+
+ lcd@f8038000 {
+diff --git a/arch/arm/boot/dts/at91sam9x25.dtsi b/arch/arm/boot/dts/at91sam9x25.dtsi
+new file mode 100644
+index 0000000..956c65f
+--- /dev/null
++++ b/arch/arm/boot/dts/at91sam9x25.dtsi
+@@ -0,0 +1,28 @@
++/*
++ * at91sam9x25.dtsi - Device Tree Include file for AT91SAM9X25 SoC
++ *
++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
++ *
++ * Licensed under GPLv2.
++ */
++
++/include/ "at91sam9x5.dtsi"
++
++/ {
++ model = "Atmel AT91SAM9X25 SoC";
++ compatible = "atmel, at91sam9x25, atmel,at91sam9x5";
++
++ ahb {
++ apb {
++ pinctrl@fffff400 {
++ atmel,mux-mask = <
++ /* A B C */
++ 0xffffffff 0xffe03fff 0xc000001c /* pioA */
++ 0x0007ffff 0x00047e3f 0x00000000 /* pioB */
++ 0x80000000 0xfffd0000 0xb83fffff /* pioC */
++ 0x003fffff 0x003f8000 0x00000000 /* pioD */
++ >;
++ };
++ };
++ };
++};
+diff --git a/arch/arm/boot/dts/at91sam9x25ek.dts b/arch/arm/boot/dts/at91sam9x25ek.dts
+index cf903f5..7e38951 100644
+--- a/arch/arm/boot/dts/at91sam9x25ek.dts
++++ b/arch/arm/boot/dts/at91sam9x25ek.dts
+@@ -7,38 +7,20 @@
+ * Licensed under GPLv2 or later.
+ */
+ /dts-v1/;
+-/include/ "at91sam9x5_common.dtsi"
++/include/ "at91sam9x25.dtsi"
++/include/ "at91sam9x5ek.dtsi"
+
+ / {
+- model = "Atmel AT91SAM9X25-EK";
++ model = "Atmel AT91SAM9G25-EK";
+ compatible = "atmel,at91sam9x25ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
+
+- chosen {
+- bootargs = "console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
+- };
+-
+ ahb {
+ apb {
+ mmc1: mmc@f000c000 {
+ status = "okay";
+- slot@0 {
+- reg = <0>;
+- bus-width = <4>;
+- cd-gpios = <&pioD 14 0>;
+- };
+- };
+-
+- usart0: serial@f801c000 {
+- status = "okay";
+- };
+-
+- macb0: ethernet@f802c000 {
+- phy-mode = "rmii";
+- status = "okay";
+ };
+
+ macb1: ethernet@f8030000 {
+- phy-mode = "rmii";
+ status = "okay";
+ };
+ };
+diff --git a/arch/arm/boot/dts/at91sam9x35.dtsi b/arch/arm/boot/dts/at91sam9x35.dtsi
+new file mode 100644
+index 0000000..fb102d6
+--- /dev/null
++++ b/arch/arm/boot/dts/at91sam9x35.dtsi
+@@ -0,0 +1,28 @@
++/*
++ * at91sam9x35.dtsi - Device Tree Include file for AT91SAM9X35 SoC
++ *
++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
++ *
++ * Licensed under GPLv2.
++ */
++
++/include/ "at91sam9x5.dtsi"
++
++/ {
++ model = "Atmel AT91SAM9X35 SoC";
++ compatible = "atmel, at91sam9x35, atmel,at91sam9x5";
++
++ ahb {
++ apb {
++ pinctrl@fffff400 {
++ atmel,mux-mask = <
++ /* A B C */
++ 0xffffffff 0xffe03fff 0xc000000c /* pioA */
++ 0x000406ff 0x00047e3f 0x00000000 /* pioB */
++ 0xfdffffff 0x00000000 0xb83fffff /* pioC */
++ 0x003fffff 0x003f8000 0x00000000 /* pioD */
++ >;
++ };
++ };
++ };
++};
+diff --git a/arch/arm/boot/dts/at91sam9x35ek.dts b/arch/arm/boot/dts/at91sam9x35ek.dts
+new file mode 100644
+index 0000000..5ccb607
+--- /dev/null
++++ b/arch/arm/boot/dts/at91sam9x35ek.dts
+@@ -0,0 +1,16 @@
++/*
++ * at91sam9x35ek.dts - Device Tree file for AT91SAM9X35-EK board
++ *
++ * Copyright (C) 2012 Atmel,
++ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com>
++ *
++ * Licensed under GPLv2 or later.
++ */
++/dts-v1/;
++/include/ "at91sam9x35.dtsi"
++/include/ "at91sam9x5ek.dtsi"
++
++/ {
++ model = "Atmel AT91SAM9X35-EK";
++ compatible = "atmel,at91sam9x35ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
++};
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 28e053a..7cefc2c 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -113,21 +113,92 @@
+ #dma-cells = <1>;
+ };
+
+- pinctrl@fffff200 {
++ pinctrl@fffff400 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "atmel,at91sam9x5-pinctrl", "atmel,at91rm9200-pinctrl", "simple-bus";
+ ranges = <0xfffff400 0xfffff400 0x800>;
+
+- atmel,mux-mask = <
+- /* A B C */
+- 0xffffffff 0xffe0399f 0xc000001c /* pioA */
+- 0xffffffff 0xffc003ff 0xffc003ff /* pioB */
+- 0xffffffff 0xffc003ff 0xffc003ff /* pioC */
+- 0xffffffff 0xffc003ff 0xffc003ff /* pioD */
+- >;
+-
+ /* shared pinctrl settings */
++ dbgu {
++ pinctrl_dbgu: dbgu-0 {
++ atmel,pins =
++ <0 9 0x1 0x0 /* PA9 periph A */
++ 0 10 0x1 0x1>; /* PA10 periph A with pullup */
++ };
++ };
++
++ uart0 {
++ pinctrl_uart0: uart0-0 {
++ atmel,pins =
++ <0 0 0x1 0x1 /* PA0 periph A with pullup */
++ 0 1 0x1 0x0>; /* PA1 periph A */
++ };
++
++ pinctrl_uart0_rts_cts: uart0_rts_cts-0 {
++ atmel,pins =
++ <0 2 0x1 0x0 /* PA2 periph A */
++ 0 3 0x1 0x0>; /* PA3 periph A */
++ };
++ };
++
++ uart1 {
++ pinctrl_uart1: uart1-0 {
++ atmel,pins =
++ <0 5 0x1 0x1 /* PA5 periph A with pullup */
++ 0 6 0x1 0x0>; /* PA6 periph A */
++ };
++
++ pinctrl_uart1_rts_cts: uart1_rts_cts-0 {
++ atmel,pins =
++ <3 27 0x3 0x0 /* PC27 periph C */
++ 3 28 0x3 0x0>; /* PC28 periph C */
++ };
++ };
++
++ uart2 {
++ pinctrl_uart2: uart2-0 {
++ atmel,pins =
++ <0 7 0x1 0x1 /* PA7 periph A with pullup */
++ 0 8 0x1 0x0>; /* PA8 periph A */
++ };
++
++ pinctrl_uart2_rts_cts: uart2_rts_cts-0 {
++ atmel,pins =
++ <0 0 0x2 0x0 /* PB0 periph B */
++ 0 1 0x2 0x0>; /* PB1 periph B */
++ };
++ };
++
++ uart3 {
++ pinctrl_uart3: uart3-0 {
++ atmel,pins =
++ <3 23 0x2 0x1 /* PC22 periph B with pullup */
++ 3 23 0x2 0x0>; /* PC23 periph B */
++ };
++
++ pinctrl_uart3_rts_cts: uart3_rts_cts-0 {
++ atmel,pins =
++ <3 24 0x2 0x0 /* PC24 periph B */
++ 3 25 0x2 0x0>; /* PC25 periph B */
++ };
++ };
++
++ usart0 {
++ pinctrl_usart0: usart0-0 {
++ atmel,pins =
++ <3 8 0x3 0x0 /* PC8 periph C */
++ 3 9 0x3 0x1>; /* PC9 periph C with pullup */
++ };
++ };
++
++ usart1 {
++ pinctrl_usart1: usart1-0 {
++ atmel,pins =
++ <3 16 0x3 0x0 /* PC16 periph C */
++ 3 17 0x3 0x1>; /* PC17 periph C with pullup */
++ };
++ };
+
+ nand {
+ pinctrl_nand: nand-0 {
+@@ -184,6 +255,8 @@
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffff200 0x200>;
+ interrupts = <1 4 7>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_dbgu>;
+ status = "disabled";
+ };
+
+@@ -193,6 +266,8 @@
+ interrupts = <5 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_uart0>;
+ status = "disabled";
+ };
+
+@@ -202,6 +277,8 @@
+ interrupts = <6 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_uart1>;
+ status = "disabled";
+ };
+
+@@ -211,6 +288,8 @@
+ interrupts = <7 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_uart2>;
+ status = "disabled";
+ };
+
+diff --git a/arch/arm/boot/dts/at91sam9x5_common.dtsi b/arch/arm/boot/dts/at91sam9x5ek.dtsi
+similarity index 54%
+rename from arch/arm/boot/dts/at91sam9x5_common.dtsi
+rename to arch/arm/boot/dts/at91sam9x5ek.dtsi
+index b805425..8854794 100644
+--- a/arch/arm/boot/dts/at91sam9x5_common.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5ek.dtsi
+@@ -1,22 +1,31 @@
+ /*
+- * at91sam9x5_common.dtsi - Device Tree Include file for AT91SAM9x5 Evaluation Kit:
+- * common peripherals.
++ * at91sam9x5ek.dtsi - Device Tree file for AT91SAM9x5CM Base board
+ *
+ * Copyright (C) 2012 Atmel,
+ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+-/include/ "at91sam9x5.dtsi"
+ /include/ "at91sam9x5cm.dtsi"
+
+ / {
++ model = "Atmel AT91SAM9X5-EK";
++ compatible = "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
++
++ chosen {
++ bootargs = "128M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
++ };
++
+ ahb {
+ apb {
+ dbgu: serial@fffff200 {
+ status = "okay";
+ };
+
++ usart0: serial@f801c000 {
++ status = "okay";
++ };
++
+ mmc0: mmc@f0008000 {
+ status = "okay";
+ slot@0 {
+@@ -26,6 +35,23 @@
+ };
+ };
+
++ mmc1: mmc@f000c000 {
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioD 14 0>;
++ };
++ };
++
++ macb0: ethernet@f802c000 {
++ phy-mode = "rmii";
++ status = "okay";
++ };
++
++ macb1: ethernet@f8030000 {
++ phy-mode = "rmii";
++ };
++
+ i2c0: i2c@f8010000 {
+ status = "okay";
+ };
+diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
+index 410485a..f63b8bf 100644
+--- a/arch/arm/mach-at91/Makefile.boot
++++ b/arch/arm/mach-at91/Makefile.boot
+@@ -33,6 +33,8 @@ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb
+ # sam9n12
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9n12ek.dtb
+ # sam9x5
++dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g15ek.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g25ek.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g35ek.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9x25ek.dtb
++dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9x35ek.dtb
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0233-ARM-at91-DT-add-i2c-mmc-nand-pinctrl-in-device-tree-.patch b/patches.at91/0233-ARM-at91-DT-add-i2c-mmc-nand-pinctrl-in-device-tree-.patch
new file mode 100644
index 00000000000000..954f5f1bc57745
--- /dev/null
+++ b/patches.at91/0233-ARM-at91-DT-add-i2c-mmc-nand-pinctrl-in-device-tree-.patch
@@ -0,0 +1,336 @@
+From f3a49662b5055a2e766d0a9f327c51781f463283 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Fri, 19 Oct 2012 07:14:06 +0800
+Subject: ARM: at91/DT: add i2c mmc nand pinctrl in device tree support
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/boot/dts/at91sam9x5.dtsi | 132 +++++++++++++++++++++++++++++++-----
+ arch/arm/boot/dts/at91sam9x5ek.dtsi | 24 ++++---
+ arch/arm/mach-at91/board-dt.c | 27 --------
+ 3 files changed, 130 insertions(+), 53 deletions(-)
+
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 7cefc2c..726bb82 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -151,8 +151,8 @@
+
+ pinctrl_uart1_rts_cts: uart1_rts_cts-0 {
+ atmel,pins =
+- <3 27 0x3 0x0 /* PC27 periph C */
+- 3 28 0x3 0x0>; /* PC28 periph C */
++ <2 27 0x3 0x0 /* PC27 periph C */
++ 2 28 0x3 0x0>; /* PC28 periph C */
+ };
+ };
+
+@@ -165,46 +165,134 @@
+
+ pinctrl_uart2_rts_cts: uart2_rts_cts-0 {
+ atmel,pins =
+- <0 0 0x2 0x0 /* PB0 periph B */
+- 0 1 0x2 0x0>; /* PB1 periph B */
++ <1 0 0x2 0x0 /* PB0 periph B */
++ 1 1 0x2 0x0>; /* PB1 periph B */
+ };
+ };
+
+ uart3 {
+ pinctrl_uart3: uart3-0 {
+ atmel,pins =
+- <3 23 0x2 0x1 /* PC22 periph B with pullup */
+- 3 23 0x2 0x0>; /* PC23 periph B */
++ <2 22 0x2 0x1 /* PC22 periph B with pullup */
++ 2 23 0x2 0x0>; /* PC23 periph B */
+ };
+
+ pinctrl_uart3_rts_cts: uart3_rts_cts-0 {
+ atmel,pins =
+- <3 24 0x2 0x0 /* PC24 periph B */
+- 3 25 0x2 0x0>; /* PC25 periph B */
++ <2 24 0x2 0x0 /* PC24 periph B */
++ 2 25 0x2 0x0>; /* PC25 periph B */
+ };
+ };
+
+ usart0 {
+ pinctrl_usart0: usart0-0 {
+ atmel,pins =
+- <3 8 0x3 0x0 /* PC8 periph C */
+- 3 9 0x3 0x1>; /* PC9 periph C with pullup */
++ <2 8 0x3 0x0 /* PC8 periph C */
++ 2 9 0x3 0x1>; /* PC9 periph C with pullup */
+ };
+ };
+
+ usart1 {
+ pinctrl_usart1: usart1-0 {
+ atmel,pins =
+- <3 16 0x3 0x0 /* PC16 periph C */
+- 3 17 0x3 0x1>; /* PC17 periph C with pullup */
++ <2 16 0x3 0x0 /* PC16 periph C */
++ 2 17 0x3 0x1>; /* PC17 periph C with pullup */
+ };
+ };
+
+ nand {
+- pinctrl_nand: nand-0 {
++ pinctrl_nand_rdy_enable: nand_rdy_enable-0 {
+ atmel,pins =
+- <3 4 0x0 0x1 /* PD5 gpio RDY pin pull_up */
+- 3 5 0x0 0x1>; /* PD4 gpio enable pin pull_up */
++ <3 5 0x0 0x1 /* PD5 gpio RDY pin pull_up */
++ 3 4 0x0 0x1>; /* PD4 gpio enable pin pull_up */
++ };
++
++ pinctrl_nand_oe_we_ale_cle: nand_oe_we_ale_cle-0 {
++ atmel,pins =
++ <3 0 0x1 0x1 /* PD0 periph A with pullup */
++ 3 1 0x1 0x1 /* PD1 periph A with pullup */
++ 3 2 0x1 0x1 /* PD2 periph A with pullup */
++ 3 3 0x1 0x1>; /* PD3 periph A with pullup */
++ };
++
++ pinctrl_nand_bus_on_d16_8bit: nand_bus_on_d16_8bit-0 {
++ atmel,pins =
++ <3 6 0x1 0x1 /* PD6 periph A with pullup */
++ 3 7 0x1 0x1 /* PD7 periph A with pullup */
++ 3 8 0x1 0x1 /* PD8 periph A with pullup */
++ 3 9 0x1 0x1 /* PD9 periph A with pullup */
++ 3 10 0x1 0x1 /* PD10 periph A with pullup */
++ 3 11 0x1 0x1 /* PD11 periph A with pullup */
++ 3 12 0x1 0x1 /* PD12 periph A with pullup */
++ 3 13 0x1 0x1>; /* PD13 periph A with pullup */
++ };
++
++ pinctrl_nand_bus_on_d16_16bit: nand_bus_on_d16_16bit-0 {
++ atmel,pins =
++ <3 14 0x1 0x1 /* PD14 periph A with pullup */
++ 3 15 0x1 0x1 /* PD15 periph A with pullup */
++ 3 16 0x1 0x1 /* PD16 periph A with pullup */
++ 3 17 0x1 0x1 /* PD17 periph A with pullup */
++ 3 18 0x1 0x1 /* PD18 periph A with pullup */
++ 3 19 0x1 0x1 /* PD19 periph A with pullup */
++ 3 20 0x1 0x1 /* PD20 periph A with pullup */
++ 3 21 0x1 0x1>; /* PD21 periph A with pullup */
++ };
++ };
++
++ i2c0 {
++ pinctrl_i2c0: i2c0-0 {
++ atmel,pins =
++ <0 30 0x1 0x2 /* PA30 periph A Multidrive */
++ 0 31 0x1 0x3>; /* PA31 periph A Multidrive with pullup */
++ };
++ };
++
++ i2c1 {
++ pinctrl_i2c1: i2c1-0 {
++ atmel,pins =
++ <2 0 0x3 0x2 /* PC0 periph C Multidrive */
++ 2 1 0x3 0x3>; /* PC1 periph C Multidrive with pullup */
++ };
++ };
++
++ i2c2 {
++ pinctrl_i2c2: i2c2-0 {
++ atmel,pins =
++ <1 4 0x2 0x2 /* PB4 periph B Multidrive */
++ 1 5 0x2 0x3>; /* PB5 periph B Multidrive with pullup */
++ };
++ };
++
++ mmc0 {
++ pinctrl_mmc0_clk_cmd_dat0: mm0_clk_cmd_dat0 {
++ atmel,pins =
++ <0 17 0x1 0x0 /* PA17 periph A */
++ 0 16 0x1 0x1 /* PA16 periph A with pullpup */
++ 0 15 0x1 0x1>; /* PA15 periph A with pullpup */
++ };
++
++ pinctrl_mmc0_dat1_3: mm0_dat1_3 {
++ atmel,pins =
++ <0 18 0x1 0x1 /* PA18 periph A with pullpup */
++ 0 19 0x1 0x1 /* PA19 periph A with pullpup */
++ 0 20 0x1 0x1>; /* PA20 periph A with pullpup */
++ };
++ };
++
++ mmc1 {
++ pinctrl_mmc1_clk_cmd_dat0: mm1_clk_cmd_dat0 {
++ atmel,pins =
++ <0 13 0x2 0x0 /* PA13 periph B */
++ 0 12 0x2 0x1 /* PA12 periph B with pullpup */
++ 0 11 0x2 0x1>; /* PA11 periph B with pullpup */
++ };
++
++ pinctrl_mmc1_dat1_3: mm1_dat1_3 {
++ atmel,pins =
++ <0 2 0x2 0x1 /* PA2 periph B with pullpup */
++ 0 3 0x2 0x1 /* PA3 periph B with pullpup */
++ 0 4 0x2 0x1>; /* PA4 periph B with pullpup */
+ };
+ };
+
+@@ -311,20 +399,22 @@
+ compatible = "atmel,hsmci";
+ reg = <0xf0008000 0x600>;
+ interrupts = <12 4 0>;
+- status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ dma = <&dma0 0x10002200>;
++ pinctrl-names = "default";
++ status = "disabled";
+ };
+
+ mmc1: mmc@f000c000 {
+ compatible = "atmel,hsmci";
+ reg = <0xf000c000 0x600>;
+ interrupts = <26 4 0>;
+- status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ dma = <&dma1 0x10002200>;
++ pinctrl-names = "default";
++ status = "disabled";
+ };
+
+ i2c0: i2c@f8010000 {
+@@ -334,6 +424,8 @@
+ dma = <&dma0 0x10002278>;
+ #address-cells = <1>;
+ #size-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_i2c0>;
+ status = "disabled";
+ };
+
+@@ -344,6 +436,8 @@
+ dma = <&dma1 0x10002256>;
+ #address-cells = <1>;
+ #size-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_i2c1>;
+ status = "disabled";
+ };
+
+@@ -354,6 +448,8 @@
+ dma = <&dma0 0x1000229A>;
+ #address-cells = <1>;
+ #size-cells = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "disabled";
+ };
+
+@@ -393,7 +489,7 @@
+ atmel,nand-addr-offset = <21>;
+ atmel,nand-cmd-offset = <22>;
+ pinctrl-names = "default";
+- pinctrl-0 = <&pinctrl_nand>;
++ pinctrl-0 = <&pinctrl_nand_rdy_enable &pinctrl_nand_oe_we_ale_cle>;
+ gpios = <&pioD 5 0
+ &pioD 4 0
+ 0
+diff --git a/arch/arm/boot/dts/at91sam9x5ek.dtsi b/arch/arm/boot/dts/at91sam9x5ek.dtsi
+index 8854794..0406e0d 100644
+--- a/arch/arm/boot/dts/at91sam9x5ek.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5ek.dtsi
+@@ -18,6 +18,20 @@
+
+ ahb {
+ apb {
++ pinctrl@fffff400 {
++ board {
++ pinctrl_mmc0_cd: mmc0_cd {
++ atmel,pins =
++ <3 15 0x0 0x5>; /* PD15 gpio with pullup deglitch */
++ };
++
++ pinctrl_mmc1_cd: mmc1_cd {
++ atmel,pins =
++ <3 14 0x0 0x5>; /* PD14 gpio with pullup deglitch */
++ };
++ };
++ };
++
+ dbgu: serial@fffff200 {
+ status = "okay";
+ };
+@@ -27,6 +41,7 @@
+ };
+
+ mmc0: mmc@f0008000 {
++ pinctrl-0 = <&pinctrl_mmc0_clk_cmd_dat0 &pinctrl_mmc0_dat1_3 &pinctrl_mmc0_cd>;
+ status = "okay";
+ slot@0 {
+ reg = <0>;
+@@ -36,6 +51,7 @@
+ };
+
+ mmc1: mmc@f000c000 {
++ pinctrl-0 = <&pinctrl_mmc1_clk_cmd_dat0 &pinctrl_mmc1_dat1_3 &pinctrl_mmc1_cd>;
+ slot@0 {
+ reg = <0>;
+ bus-width = <4>;
+@@ -55,14 +71,6 @@
+ i2c0: i2c@f8010000 {
+ status = "okay";
+ };
+-
+- i2c1: i2c@f8014000 {
+- status = "okay";
+- };
+-
+- i2c2: i2c@f8018000 {
+- status = "okay";
+- };
+ };
+
+ usb0: ohci@00600000 {
+diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
+index b1a5d3c..95798f5 100644
+--- a/arch/arm/mach-at91/board-dt.c
++++ b/arch/arm/mach-at91/board-dt.c
+@@ -139,36 +139,9 @@ static void __init at91_dt_device_init(void)
+ {
+ /* Temporary pin mux stuff */
+ if (of_machine_is_compatible("atmel,at91sam9x5")) {
+- at91_set_A_periph(AT91_PIN_PA30, 0); /* TWD */
+- at91_set_A_periph(AT91_PIN_PA31, 0); /* TWCK */
+- printk("AT91: i2c pin mux done\n");
+ at91_set_gpio_input(AT91_PIN_PA7, 1);
+ printk("AT91: qt1070 pin mux done\n");
+
+- at91_set_gpio_input(AT91_PIN_PD14, 1);
+- at91_set_deglitch(AT91_PIN_PD14, 1);
+- at91_set_gpio_input(AT91_PIN_PD15, 1);
+- at91_set_deglitch(AT91_PIN_PD15, 1);
+- /* CLK */
+- at91_set_A_periph(AT91_PIN_PA17, 0);
+- /* CMD */
+- at91_set_A_periph(AT91_PIN_PA16, 1);
+- /* DAT0, DAT1..DAT3 */
+- at91_set_A_periph(AT91_PIN_PA15, 1);
+- at91_set_A_periph(AT91_PIN_PA18, 1);
+- at91_set_A_periph(AT91_PIN_PA19, 1);
+- at91_set_A_periph(AT91_PIN_PA20, 1);
+- /* CLK */
+- at91_set_B_periph(AT91_PIN_PA13, 0);
+- /* CMD */
+- at91_set_B_periph(AT91_PIN_PA12, 1);
+- /* DAT0, DAT1..DAT3 */
+- at91_set_B_periph(AT91_PIN_PA11, 1);
+- at91_set_B_periph(AT91_PIN_PA2, 1);
+- at91_set_B_periph(AT91_PIN_PA3, 1);
+- at91_set_B_periph(AT91_PIN_PA4, 1);
+- printk("AT91: mci0/1 pin mux done\n");
+-
+ at91sam9x5_pinmux_lcd();
+ }
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0234-at91sam9x5-add-lcd-pinctrl-support.patch b/patches.at91/0234-at91sam9x5-add-lcd-pinctrl-support.patch
new file mode 100644
index 00000000000000..300b6fbb65bb9a
--- /dev/null
+++ b/patches.at91/0234-at91sam9x5-add-lcd-pinctrl-support.patch
@@ -0,0 +1,69 @@
+From 0328d56fcf25103afd966706a035735d2bf77d9c Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Fri, 19 Oct 2012 13:44:54 +0800
+Subject: at91sam9x5: add lcd pinctrl support
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/boot/dts/at91sam9x5.dtsi | 38 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 38 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 726bb82..c1b0334 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -296,6 +296,42 @@
+ };
+ };
+
++ lcd {
++ pinctrl_lcd: lcd-0 {
++ atmel,pins =
++ <2 26 0x1 0x1 /* PC26 periph A */
++ 2 27 0x1 0x1 /* PC27 periph A */
++ 2 28 0x1 0x1 /* PC28 periph A */
++ 2 24 0x1 0x1 /* PC24 periph A */
++ 2 29 0x1 0x1 /* PC29 periph A */
++ 2 30 0x1 0x1 /* PC30 periph A */
++ 2 0 0x1 0x1 /* PC0 periph A */
++ 2 1 0x1 0x1 /* PC1 periph A */
++ 2 2 0x1 0x1 /* PC2 periph A */
++ 2 3 0x1 0x1 /* PC3 periph A */
++ 2 4 0x1 0x1 /* PC4 periph A */
++ 2 5 0x1 0x1 /* PC5 periph A */
++ 2 6 0x1 0x1 /* PC6 periph A */
++ 2 7 0x1 0x1 /* PC7 periph A */
++ 2 8 0x1 0x1 /* PC8 periph A */
++ 2 9 0x1 0x1 /* PC9 periph A */
++ 2 10 0x1 0x1 /* PC10 periph A */
++ 2 11 0x1 0x1 /* PC11 periph A */
++ 2 12 0x1 0x1 /* PC12 periph A */
++ 2 13 0x1 0x1 /* PC13 periph A */
++ 2 14 0x1 0x1 /* PC14 periph A */
++ 2 15 0x1 0x1 /* PC15 periph A */
++ 2 16 0x1 0x1 /* PC16 periph A */
++ 2 17 0x1 0x1 /* PC17 periph A */
++ 2 18 0x1 0x1 /* PC18 periph A */
++ 2 19 0x1 0x1 /* PC19 periph A */
++ 2 20 0x1 0x1 /* PC20 periph A */
++ 2 21 0x1 0x1 /* PC21 periph A */
++ 2 22 0x1 0x1 /* PC22 periph A */
++ 2 23 0x1 0x1>; /* PC23 periph A */
++ };
++ };
++
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x200>;
+@@ -458,6 +494,8 @@
+ reg = <0xf8038000 0xff
+ 0xf8038400 0x3ff>;
+ interrupts = <25 4 3>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_lcd>;
+ status = "disabled";
+ };
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0235-arm-at91sam9x5ek-drop-temporary-pinmux.patch b/patches.at91/0235-arm-at91sam9x5ek-drop-temporary-pinmux.patch
new file mode 100644
index 00000000000000..4843de1365456d
--- /dev/null
+++ b/patches.at91/0235-arm-at91sam9x5ek-drop-temporary-pinmux.patch
@@ -0,0 +1,72 @@
+From d97e722de56d81f2d86606ff2537c14bd7ec270f Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Fri, 19 Oct 2012 15:13:13 +0800
+Subject: arm: at91sam9x5ek: drop temporary pinmux
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/mach-at91/board-dt.c | 41 -----------------------------------------
+ 1 file changed, 41 deletions(-)
+
+diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
+index 95798f5..16b6b3c 100644
+--- a/arch/arm/mach-at91/board-dt.c
++++ b/arch/arm/mach-at91/board-dt.c
+@@ -79,45 +79,6 @@ static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+ .lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB,
+ };
+
+-void __init at91sam9x5_pinmux_lcd(void)
+-{
+- 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 */
+-
+- printk("AT91: lcd pin mux done\n");
+-}
+-
+ struct of_dev_auxdata at91_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("atmel,at91sam9x5-lcd", 0xf8038000, "atmel_hlcdfb_base", &ek_lcdc_data),
+ OF_DEV_AUXDATA("atmel,at91sam9x5-lcd", 0xf8038100, "atmel_hlcdfb_ovl", &ek_lcdc_data),
+@@ -141,8 +102,6 @@ static void __init at91_dt_device_init(void)
+ if (of_machine_is_compatible("atmel,at91sam9x5")) {
+ at91_set_gpio_input(AT91_PIN_PA7, 1);
+ printk("AT91: qt1070 pin mux done\n");
+-
+- at91sam9x5_pinmux_lcd();
+ }
+
+ of_platform_populate(NULL, of_default_bus_match_table, at91_auxdata_lookup, NULL);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0236-video-atmel-lcd-only-request-the-pinctrl-once.patch b/patches.at91/0236-video-atmel-lcd-only-request-the-pinctrl-once.patch
new file mode 100644
index 00000000000000..93684a0f290235
--- /dev/null
+++ b/patches.at91/0236-video-atmel-lcd-only-request-the-pinctrl-once.patch
@@ -0,0 +1,190 @@
+From e932c44de6861621566b9a74a1498c72b14dae49 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Fri, 19 Oct 2012 14:11:05 +0800
+Subject: video: atmel lcd only request the pinctrl once
+
+Introduce simple bus to represent the LCDC itself so we can attached the
+pinctrl to it
+
+signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+
+Conflicts:
+ arch/arm/boot/dts/at91sam9x5.dtsi
+---
+ arch/arm/boot/dts/at91sam9g35ek.dts | 17 ++++++++-----
+ arch/arm/boot/dts/at91sam9x5.dtsi | 42 +++++++++++++++++-------------
+ drivers/video/atmel_lcdfb_core.c | 51 +++++++++++++++++++++++++++++++------
+ 3 files changed, 78 insertions(+), 32 deletions(-)
+
+diff --git a/arch/arm/boot/dts/at91sam9g35ek.dts b/arch/arm/boot/dts/at91sam9g35ek.dts
+index 2781a30..9f91dbc 100644
+--- a/arch/arm/boot/dts/at91sam9g35ek.dts
++++ b/arch/arm/boot/dts/at91sam9g35ek.dts
+@@ -20,16 +20,19 @@
+ status = "okay";
+ };
+
+- lcd@f8038000 {
++ lcd_bus@f8038000 {
+ status = "okay";
+- };
++ lcd@f8038000 {
++ status = "okay";
++ };
+
+- lcdovl1@f8038100 {
+- status = "okay";
+- };
++ lcdovl1@f8038100 {
++ status = "okay";
++ };
+
+- lcdheo1@f8038280 {
+- status = "okay";
++ lcdheo1@f8038280 {
++ status = "okay";
++ };
+ };
+ };
+ };
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index c1b0334..1fcbbe8 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -489,28 +489,36 @@
+ status = "disabled";
+ };
+
+- lcd@f8038000 {
+- compatible = "atmel,at91sam9x5-lcd";
+- reg = <0xf8038000 0xff
+- 0xf8038400 0x3ff>;
+- interrupts = <25 4 3>;
++ lcd_bus@f8038000 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ compatible = "atmel,at91sam9x5-lcd-bus", "simple-bus";
++ ranges = <0xf8038000 0xf8038000 0x4000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lcd>;
+ status = "disabled";
+- };
+
+- lcdovl1@f8038100 {
+- compatible = "atmel,at91sam9x5-lcd";
+- reg = <0xf8038100 0xff
+- 0xf8038800 0x3ff>;
+- status = "disabled";
+- };
++ lcd@f8038000 {
++ compatible = "atmel,at91sam9x5-lcd";
++ reg = <0xf8038000 0xff
++ 0xf8038400 0x3ff>;
++ interrupts = <25 4 3>;
++ status = "disabled";
++ };
+
+- lcdheo1@f8038280 {
+- compatible = "atmel,at91sam9x5-heo";
+- reg = <0xf8038280 0xbf>;
+- interrupts = <25 4 3>;
+- status = "disabled";
++ lcdovl1@f8038100 {
++ compatible = "atmel,at91sam9x5-lcd";
++ reg = <0xf8038100 0xff
++ 0xf8038800 0x3ff>;
++ status = "disabled";
++ };
++
++ lcdheo1@f8038280 {
++ compatible = "atmel,at91sam9x5-heo";
++ reg = <0xf8038280 0xbf>;
++ interrupts = <25 4 3>;
++ status = "disabled";
++ };
+ };
+ };
+
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index b71a80c..4d272ee 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -19,6 +19,8 @@
+ #include <linux/init.h>
+ #include <linux/delay.h>
+ #include <linux/gfp.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
+
+ #include <mach/board.h>
+ #include <mach/cpu.h>
+@@ -557,7 +559,6 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ struct resource *regs = NULL, *clut = NULL;
+ struct resource *map = NULL;
+ int ret;
+- struct pinctrl *pinctrl;
+
+ dev_dbg(dev, "%s BEGIN\n", __func__);
+
+@@ -637,13 +638,6 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ goto stop_clk;
+ }
+
+- pinctrl = devm_pinctrl_get_select_default(dev);
+- if (IS_ERR(pinctrl)) {
+- dev_err(dev, "Failed to request pinctrl\n");
+- ret = PTR_ERR(pinctrl);
+- goto stop_clk;
+- }
+-
+ /* No error checking, some devices can do without IRQ */
+ sinfo->irq_base = platform_get_irq(pdev, 0);
+
+@@ -840,3 +834,44 @@ int __atmel_lcdfb_remove(struct platform_device *pdev)
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(__atmel_lcdfb_remove);
++
++static const struct of_device_id atmel_lcdfb_bus_dt_ids[] = {
++ { .compatible = "atmel,at91sam9x5-lcd-bus" },
++ { /* sentinel */ }
++};
++
++static int atmel_lcdfb_bus_probe(struct platform_device *pdev)
++{
++ struct pinctrl *pinctrl;
++ struct device *dev = &pdev->dev;
++
++ pinctrl = devm_pinctrl_get_select_default(dev);
++ if (IS_ERR(pinctrl)) {
++ dev_err(dev, "Failed to request pinctrl\n");
++ return PTR_ERR(pinctrl);
++ }
++
++ return 0;
++}
++
++static struct platform_driver atmel_lcdfb_bus = {
++ .probe = atmel_lcdfb_bus_probe,
++ .driver = {
++ .name = "atmel_lcdfb_bus",
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(atmel_lcdfb_bus_dt_ids),
++ },
++};
++
++static int __init atmel_lcdfb_bus_init(void)
++{
++ return platform_driver_register(&atmel_lcdfb_bus);
++}
++
++static void __exit atmel_lcdfb_bus_exit(void)
++{
++ platform_driver_unregister(&atmel_lcdfb_bus);
++}
++
++module_init(atmel_lcdfb_bus_init);
++module_exit(atmel_lcdfb_bus_exit);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0237-ARM-at91-add-at91-3.4-trunk-contents.txt-file.patch b/patches.at91/0237-ARM-at91-add-at91-3.4-trunk-contents.txt-file.patch
new file mode 100644
index 00000000000000..fdc35a625392f1
--- /dev/null
+++ b/patches.at91/0237-ARM-at91-add-at91-3.4-trunk-contents.txt-file.patch
@@ -0,0 +1,91 @@
+From 11e369f0f20f451f958d7ef2e37a813a9a83dcf4 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 26 Sep 2012 17:04:31 +0200
+Subject: ARM: at91: add at91-3.4-trunk-contents.txt file
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/at91-3.4-trunk-contents.txt | 71 ++++++++++++++++++++++++++
+ 1 file changed, 71 insertions(+)
+ create mode 100644 arch/arm/mach-at91/at91-3.4-trunk-contents.txt
+
+diff --git a/arch/arm/mach-at91/at91-3.4-trunk-contents.txt b/arch/arm/mach-at91/at91-3.4-trunk-contents.txt
+new file mode 100644
+index 0000000..bfc5a47
+--- /dev/null
++++ b/arch/arm/mach-at91/at91-3.4-trunk-contents.txt
+@@ -0,0 +1,71 @@
++This file lists all branches that are pulled into the at91-3.4-trunk_merge
++branch of git://rfolxts01.rfo.atmel.com/linux and their external dependencies.
++
++The at91-3.4-trunk/v3.4.x_* branches are kept in the order in which they
++get applied.
++
++external dependencies:
++NONE
++
++at91-3.4-trunk_merge:
++at91-3.4-trunk/v3.4.x_base git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_base
++
++at91-3.4-trunk/v3.4.x_cleanup+fixes git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_cleanup+fixes
++ depends on at91-3.4-trunk/v3.4.x_base
++
++at91-3.4-trunk/v3.4.x_aic5 git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_aic5
++ depends on at91-3.4-trunk/v3.4.x_base
++
++at91-3.4-trunk/v3.4.x_dma git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_dma
++at91-3.4-trunk/v3.4.x_ethernet git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_ethernet
++at91-3.4-trunk/v3.4.x_ac97 git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_ac97
++at91-3.4-trunk/v3.4.x_pmecc git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_pmecc
++at91-3.4-trunk/v3.4.x_touch git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_touch
++at91-3.4-trunk/v3.4.x_gmac git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_gmac
++at91-3.4-trunk/v3.4.x_phy git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_phy
++at91-3.4-trunk/v3.4.x_usb git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_usb
++at91-3.4-trunk/v3.4.x_isi git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_isi
++
++at91-3.4-trunk/v3.4.x_lcd git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_lcd
++at91-3.4-trunk/v3.4.x_soc_lcd git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_soc_lcd
++ depends on at91-3.4-trunk/v3.4.x_base
++ depends on at91-3.4-trunk/v3.4.x_lcd
++
++at91-3.4-trunk/v3.4.x_mci git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_mci
++ depends on at91-3.4-trunk/v3.4.x_base
++
++at91-3.4-trunk/v3.4.x_i2c git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_i2c
++ depends on at91-3.4-trunk/v3.4.x_base
++at91-3.4-trunk/v3.4.x_slaveDMA_i2c git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_slaveDMA_i2c
++ depends on at91-3.4-trunk/v3.4.x_i2c
++
++at91-3.4-trunk/v3.4.x_slaveDMA_mci git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_slaveDMA
++ depends on at91-3.4-trunk/v3.4.x_mci
++ depends on at91-3.4-trunk/v3.4.x_slaveDMA_i2c
++
++at91-3.4-trunk/v3.4.x_pinmux_sam9x5 git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_pinmux_sam9x5
++ depends on at91-3.4-trunk/v3.4.x_base
++
++at91-3.4-trunk/v3.4.x_pmecc_4k_support git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_pmecc_4k_support
++ depends on at91-3.4-trunk/v3.4.x_pmecc
++
++at91-3.4-trunk/v3.4.x_pmecc_dt_9x5 git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_pmecc_dt_9x5
++ depends on at91-3.4-trunk/v3.4.x_pmecc
++
++at91-3.4-trunk/v3.4.x_sam9x5_dt git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_sam9x5_dt
++ depends on at91-3.4-trunk/v3.4.x_pmecc_dt_9x5
++ depends on at91-3.4-trunk/v3.4.x_lcd
++ depends on at91-3.4-trunk/v3.4.x_pinmux_sam9x5
++
++at91-3.4-trunk/v3.4.x_crypto git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_crypto
++ depends on at91-3.4-trunk/v3.4.x_aic5
++
++at91-3.4-trunk/v3.4.x_pinctrl git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_pinctrl
++ depends on at91-3.4-trunk/v3.4.x_base
++ depends on at91-3.4-trunk/v3.4.x_cleanup+fixes
++ depends on at91-3.4-trunk/v3.4.x_aic5
++ depends on at91-3.4-trunk/v3.4.x_pmecc
++ depends on at91-3.4-trunk/v3.4.x_pmecc_4k_support
++
++at91-3.4-trunk/v3.4.x_pinctrl_drivers git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_pinctrl_drivers
++ depends on **ALL**
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0238-ARM-at91-add-defconfig-for-sam9x5-family.patch b/patches.at91/0238-ARM-at91-add-defconfig-for-sam9x5-family.patch
new file mode 100644
index 00000000000000..cac117dfe897b9
--- /dev/null
+++ b/patches.at91/0238-ARM-at91-add-defconfig-for-sam9x5-family.patch
@@ -0,0 +1,258 @@
+From 82c87f0c1d7b1077da380336e59180e3ed4c9407 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 17 Oct 2012 11:37:49 +0200
+Subject: ARM: at91: add defconfig for sam9x5 family
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/configs/at91sam9x5_defconfig | 238 ++++++++++++++++++++++++++++++++++
+ 1 file changed, 238 insertions(+)
+ create mode 100644 arch/arm/configs/at91sam9x5_defconfig
+
+diff --git a/arch/arm/configs/at91sam9x5_defconfig b/arch/arm/configs/at91sam9x5_defconfig
+new file mode 100644
+index 0000000..0dbbf71
+--- /dev/null
++++ b/arch/arm/configs/at91sam9x5_defconfig
+@@ -0,0 +1,238 @@
++CONFIG_EXPERIMENTAL=y
++# CONFIG_LOCALVERSION_AUTO is not set
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_IRQ_DOMAIN_DEBUG=y
++CONFIG_LOG_BUF_SHIFT=14
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_EMBEDDED=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_SOC_AT91SAM9X5=y
++CONFIG_MACH_AT91SAM_DT=y
++CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++CONFIG_LEDS=y
++CONFIG_LEDS_CPU=y
++CONFIG_UACCESS_WITH_MEMCPY=y
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_ARM_APPENDED_DTB=y
++CONFIG_ARM_ATAG_DTB_COMPAT=y
++CONFIG_CMDLINE="mem=128M console=ttyS0,115200 initrd=0x21100000,25165824 root=/dev/ram0 rw"
++CONFIG_AUTO_ZRELADDR=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_PNP=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_DIAG is not set
++CONFIG_IPV6=y
++# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET6_XFRM_MODE_BEET is not set
++CONFIG_IPV6_SIT_6RD=y
++CONFIG_CFG80211=y
++# CONFIG_CFG80211_DEFAULT_PS is not set
++CONFIG_CFG80211_DEBUGFS=y
++CONFIG_WIRELESS_EXT_SYSFS=y
++CONFIG_MAC80211=y
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++# CONFIG_STANDALONE is not set
++# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++CONFIG_MTD=y
++CONFIG_MTD_CMDLINE_PARTS=y
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++CONFIG_MTD_NAND=y
++CONFIG_MTD_NAND_ATMEL=y
++CONFIG_MTD_UBI=y
++CONFIG_PROC_DEVICETREE=y
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=4
++CONFIG_BLK_DEV_RAM_SIZE=8192
++CONFIG_ATMEL_TCLIB=y
++CONFIG_EEPROM_AT24=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_MACB=y
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_VENDOR_CHELSIO is not set
++# CONFIG_NET_VENDOR_CIRRUS is not set
++# CONFIG_NET_VENDOR_FARADAY is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++CONFIG_DAVICOM_PHY=y
++CONFIG_MICREL_PHY=y
++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=m
++CONFIG_ATH6KL=m
++CONFIG_ATH6KL_SDIO=m
++CONFIG_ATH6KL_USB=m
++CONFIG_B43=m
++CONFIG_B43_SDIO=y
++CONFIG_B43_DEBUG=y
++CONFIG_B43LEGACY=m
++CONFIG_BRCMFMAC=m
++CONFIG_BRCMFMAC_USB=y
++CONFIG_IWM=m
++CONFIG_LIBERTAS=m
++CONFIG_LIBERTAS_USB=m
++CONFIG_LIBERTAS_SDIO=m
++CONFIG_P54_COMMON=m
++CONFIG_RT2X00=m
++CONFIG_RT2500USB=m
++CONFIG_RT73USB=m
++CONFIG_RT2800USB=m
++CONFIG_RT2800USB_RT53XX=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_MWIFIEX=m
++CONFIG_MWIFIEX_SDIO=m
++CONFIG_INPUT_POLLDEV=m
++# CONFIG_INPUT_MOUSEDEV is not set
++CONFIG_INPUT_JOYDEV=y
++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_SERIO is not set
++CONFIG_LEGACY_PTY_COUNT=4
++CONFIG_SERIAL_ATMEL=y
++CONFIG_SERIAL_ATMEL_CONSOLE=y
++# CONFIG_HW_RANDOM is not set
++CONFIG_I2C=y
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_AT91=y
++CONFIG_GPIO_SYSFS=y
++# CONFIG_HWMON is not set
++CONFIG_MEDIA_SUPPORT=y
++CONFIG_MEDIA_CONTROLLER=y
++CONFIG_VIDEO_DEV=y
++CONFIG_VIDEO_V4L2_SUBDEV_API=y
++# CONFIG_RC_CORE is not set
++# CONFIG_MEDIA_TUNER_SIMPLE is not set
++# CONFIG_MEDIA_TUNER_TDA8290 is not set
++# CONFIG_MEDIA_TUNER_TDA827X is not set
++# CONFIG_MEDIA_TUNER_TDA18271 is not set
++# CONFIG_MEDIA_TUNER_TDA9887 is not set
++# CONFIG_MEDIA_TUNER_TEA5761 is not set
++# CONFIG_MEDIA_TUNER_TEA5767 is not set
++# CONFIG_MEDIA_TUNER_MT20XX is not set
++# CONFIG_MEDIA_TUNER_MT2060 is not set
++# CONFIG_MEDIA_TUNER_MT2063 is not set
++# CONFIG_MEDIA_TUNER_MT2266 is not set
++# CONFIG_MEDIA_TUNER_MT2131 is not set
++# CONFIG_MEDIA_TUNER_QT1010 is not set
++# CONFIG_MEDIA_TUNER_XC2028 is not set
++# CONFIG_MEDIA_TUNER_XC5000 is not set
++# CONFIG_MEDIA_TUNER_XC4000 is not set
++# CONFIG_MEDIA_TUNER_MXL5005S is not set
++# CONFIG_MEDIA_TUNER_MXL5007T is not set
++# CONFIG_MEDIA_TUNER_MC44S803 is not set
++# CONFIG_MEDIA_TUNER_MAX2165 is not set
++# CONFIG_MEDIA_TUNER_TDA18218 is not set
++# CONFIG_MEDIA_TUNER_TDA18212 is not set
++CONFIG_VIDEO_FIXED_MINOR_RANGES=y
++# CONFIG_V4L_USB_DRIVERS is not set
++CONFIG_V4L_PLATFORM_DRIVERS=y
++CONFIG_SOC_CAMERA=y
++CONFIG_SOC_CAMERA_OV2640=y
++CONFIG_VIDEO_ATMEL_ISI=y
++CONFIG_VIDEO_AT91SAM9X5=y
++# CONFIG_RADIO_ADAPTERS is not set
++CONFIG_FB=y
++CONFIG_FB_MODE_HELPERS=y
++CONFIG_FB_ATMEL_HLCD=y
++CONFIG_BACKLIGHT_LCD_SUPPORT=y
++# CONFIG_LCD_CLASS_DEVICE is not set
++CONFIG_BACKLIGHT_CLASS_DEVICE=y
++# CONFIG_BACKLIGHT_GENERIC is not set
++CONFIG_USB=y
++CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_STORAGE=y
++CONFIG_USB_SERIAL=y
++CONFIG_MMC=y
++# CONFIG_MMC_BLOCK_BOUNCE is not set
++CONFIG_SDIO_UART=m
++CONFIG_MMC_ATMELMCI=y
++CONFIG_LEDS_CLASS=y
++CONFIG_LEDS_GPIO=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_IOMMU_SUPPORT is not set
++CONFIG_EXT2_FS=y
++CONFIG_FANOTIFY=y
++CONFIG_VFAT_FS=y
++CONFIG_TMPFS=y
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_SUMMARY=y
++CONFIG_UBIFS_FS=y
++CONFIG_UBIFS_FS_XATTR=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++CONFIG_ROOT_NFS=y
++CONFIG_NLS_CODEPAGE_437=y
++CONFIG_NLS_CODEPAGE_850=y
++CONFIG_NLS_ISO8859_1=y
++CONFIG_STRIP_ASM_SYMS=y
++CONFIG_DEBUG_FS=y
++# CONFIG_SCHED_DEBUG is not set
++# CONFIG_FTRACE is not set
++CONFIG_DEBUG_USER=y
++CONFIG_DEBUG_LL=y
++CONFIG_EARLY_PRINTK=y
++CONFIG_CRYPTO_ECB=y
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++CONFIG_CRYPTO_USER_API_HASH=m
++CONFIG_CRYPTO_USER_API_SKCIPHER=m
++# CONFIG_CRYPTO_HW is not set
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0239-MMC-atmel-mci-add-device-tree-property-for-configura.patch b/patches.at91/0239-MMC-atmel-mci-add-device-tree-property-for-configura.patch
new file mode 100644
index 00000000000000..53a6009c49a8a5
--- /dev/null
+++ b/patches.at91/0239-MMC-atmel-mci-add-device-tree-property-for-configura.patch
@@ -0,0 +1,140 @@
+From ce5e15a7b1efddfd022dd72b9510b5ff85da6325 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 20 Jun 2012 18:05:56 +0200
+Subject: MMC: atmel-mci: add device tree property for configuration
+
+Configuration option is now handled by the "dma" device tree property
+that links to the corresponding DMA controller.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/mmc/host/atmel-mci.c | 82 ++++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 75 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index 9739604..17dc598 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -512,12 +512,65 @@ static const struct of_device_id atmci_dt_ids[] = {
+
+ MODULE_DEVICE_TABLE(of, atmci_dt_ids);
+
++static int atmci_dma_of_init(struct device_node *np,
++ struct at_dma_slave *atslave)
++{
++ struct of_phandle_args dma_spec;
++ struct device_node *dmac_np;
++ struct platform_device *dmac_pdev;
++ const __be32 *nbcells;
++ int ret;
++
++ ret = of_parse_phandle_with_args(np, "dma", "#dma-cells", 0, &dma_spec);
++ if (ret || !dma_spec.np) {
++ pr_err("%s: can't parse dma property (%d)\n", np->full_name, ret);
++ goto err0;
++ }
++ dmac_np = dma_spec.np;
++
++ /* check property format */
++ nbcells = of_get_property(dmac_np, "#dma-cells", NULL);
++ if (!nbcells) {
++ pr_err("%s: #dma-cells property is required\n", np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ if (dma_spec.args_count != be32_to_cpup(nbcells)
++ || dma_spec.args_count != 1) {
++ pr_err("%s: wrong #dma-cells for %s\n",
++ np->full_name, dmac_np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ /* retreive DMA controller information */
++ dmac_pdev = of_find_device_by_node(dmac_np);
++ if (!dmac_pdev) {
++ pr_err("%s: unable to find pdev from DMA controller\n",
++ dmac_np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ /* now fill in the at_dma_slave structure */
++ atslave->dma_dev = &dmac_pdev->dev;
++ atslave->cfg = dma_spec.args[0];
++
++err1:
++ of_node_put(dma_spec.np);
++err0:
++ pr_debug("%s exited with status %d\n", __func__, ret);
++ return ret;
++}
++
+ static struct mci_platform_data __devinit*
+ atmci_of_init(struct platform_device *pdev)
+ {
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *cnp;
+ struct mci_platform_data *pdata;
++ struct at_dma_slave *atslave;
+ u32 slot_id;
+
+ if (!np) {
+@@ -531,6 +584,24 @@ atmci_of_init(struct platform_device *pdev)
+ return ERR_PTR(-ENOMEM);
+ }
+
++ pdata->dma_slave = devm_kzalloc(&pdev->dev,
++ sizeof(*(pdata->dma_slave)),
++ GFP_KERNEL);
++ if (!pdata->dma_slave) {
++ dev_err(&pdev->dev, "could not allocate memory for dma_slave\n");
++ devm_kfree(&pdev->dev, pdata);
++ return ERR_PTR(-ENOMEM);
++ }
++ atslave = &pdata->dma_slave->sdata;
++
++ /* retrive DMA configuration first */
++ if (atmci_dma_of_init(np, atslave)) {
++ dev_err(&pdev->dev, "could not find DMA parameters\n");
++ devm_kfree(&pdev->dev, pdata->dma_slave);
++ devm_kfree(&pdev->dev, pdata);
++ return ERR_PTR(-EINVAL);
++ }
++
+ for_each_child_of_node(np, cnp) {
+ if (of_property_read_u32(cnp, "reg", &slot_id)) {
+ dev_warn(&pdev->dev, "reg property is missing for %s\n",
+@@ -2253,16 +2324,13 @@ static bool atmci_filter(struct dma_chan *chan, void *slave)
+ }
+ }
+
+-static bool atmci_configure_dma(struct atmel_mci *host)
++static bool atmci_configure_dma(struct atmel_mci *host,
++ struct mci_platform_data *pdata)
+ {
+- struct mci_platform_data *pdata;
+-
+ if (host == NULL)
+ return false;
+
+- pdata = host->pdev->dev.platform_data;
+-
+- if (pdata && find_slave_dev(pdata->dma_slave)) {
++ if (pdata && pdata->dma_slave && find_slave_dev(pdata->dma_slave)) {
+ dma_cap_mask_t mask;
+
+ /* Try to grab a DMA channel */
+@@ -2414,7 +2482,7 @@ static int __init atmci_probe(struct platform_device *pdev)
+
+ /* Get MCI capabilities and set operations according to it */
+ atmci_get_cap(host);
+- if (host->caps.has_dma && atmci_configure_dma(host)) {
++ if (host->caps.has_dma && atmci_configure_dma(host, pdata)) {
+ host->prepare_data = &atmci_prepare_data_dma;
+ host->submit_data = &atmci_submit_data_dma;
+ host->stop_transfer = &atmci_stop_transfer_dma;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0240-pinctrl-at19-fix-typo-on-PULL_UP.patch b/patches.at91/0240-pinctrl-at19-fix-typo-on-PULL_UP.patch
new file mode 100644
index 00000000000000..58380fba5f962a
--- /dev/null
+++ b/patches.at91/0240-pinctrl-at19-fix-typo-on-PULL_UP.patch
@@ -0,0 +1,26 @@
+From 0179610747d87250bfba95479c9410511c8158de Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Tue, 23 Oct 2012 13:47:30 +0800
+Subject: pinctrl: at19: fix typo on PULL_UP
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ drivers/pinctrl/pinctrl-at91.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
+index 605fffd..1a2404b 100644
+--- a/drivers/pinctrl/pinctrl-at91.c
++++ b/drivers/pinctrl/pinctrl-at91.c
+@@ -58,7 +58,7 @@ static struct at91_gpio_chip *gpio_chips[MAX_GPIO_BANKS];
+
+ static int gpio_banks;
+
+-#define PULL_UP (0 << 1)
++#define PULL_UP (1 << 0)
+ #define MULTI_DRIVE (1 << 1)
+ #define DEGLITCH (1 << 2)
+ #define PULL_DOWN (1 << 3)
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0241-pinctrl-at91-fix-pull-down-support.patch b/patches.at91/0241-pinctrl-at91-fix-pull-down-support.patch
new file mode 100644
index 00000000000000..ce7077f91ab0cc
--- /dev/null
+++ b/patches.at91/0241-pinctrl-at91-fix-pull-down-support.patch
@@ -0,0 +1,40 @@
+From 5adaa6978db065d84ab39eb02b1035efca7ae7c6 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Tue, 23 Oct 2012 14:25:36 +0800
+Subject: pinctrl: at91: fix pull down support
+
+Drop pullup disable in set_pulldown
+if the pullup is not needed the pull will be disable by set_pullup
+otherwise we will end up by always disabling the pullup
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ drivers/pinctrl/pinctrl-at91.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
+index 1a2404b..b836567 100644
+--- a/drivers/pinctrl/pinctrl-at91.c
++++ b/drivers/pinctrl/pinctrl-at91.c
+@@ -455,8 +455,6 @@ static bool at91_mux_pio3_get_pulldown(void __iomem *pio, unsigned pin)
+
+ static void at91_mux_pio3_set_pulldown(void __iomem *pio, unsigned mask, bool is_on)
+ {
+- /* Disable pull-up anyway */
+- __raw_writel(mask, pio + PIO_PUDR);
+ __raw_writel(mask, pio + (is_on ? PIO_PPDER : PIO_PPDDR));
+ }
+
+@@ -753,6 +751,9 @@ static int at91_pinconf_set(struct pinctrl_dev *pctldev,
+ pio = pin_to_controller(info, pin_to_bank(pin_id));
+ mask = pin_to_mask(pin_id % MAX_NB_GPIO_PER_BANK);
+
++ if (config & PULL_UP && config & PULL_DOWN)
++ return -EINVAL;
++
+ at91_mux_set_pullup(pio, mask, config & PULL_UP);
+ at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE);
+ if (info->ops->set_deglitch)
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0242-arm-at91sam9xcm-add-specific-nand-pinctrl.patch b/patches.at91/0242-arm-at91sam9xcm-add-specific-nand-pinctrl.patch
new file mode 100644
index 00000000000000..28cde507aa70ae
--- /dev/null
+++ b/patches.at91/0242-arm-at91sam9xcm-add-specific-nand-pinctrl.patch
@@ -0,0 +1,27 @@
+From 4d69b49852403ccd7ac2103908b455a65138aa95 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Tue, 23 Oct 2012 15:06:54 +0800
+Subject: arm: at91sam9xcm: add specific nand pinctrl
+
+the nand is on d16 and 8bit
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/boot/dts/at91sam9x5cm.dtsi | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9x5cm.dtsi b/arch/arm/boot/dts/at91sam9x5cm.dtsi
+index 4027ac7..ca049fb 100644
+--- a/arch/arm/boot/dts/at91sam9x5cm.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5cm.dtsi
+@@ -31,6 +31,7 @@
+ atmel,pmecc-cap = <2>;
+ atmel,pmecc-sector-size = <512>;
+ nand-on-flash-bbt;
++ pinctrl-0 = <&pinctrl_nand_rdy_enable &pinctrl_nand_oe_we_ale_cle &pinctrl_nand_bus_on_d16_8bit>;
+ status = "okay";
+
+ at91bootstrap@0 {
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0243-pinctrl-at91-fix-debounce-support.patch b/patches.at91/0243-pinctrl-at91-fix-debounce-support.patch
new file mode 100644
index 00000000000000..f1b3dffeb7bcd9
--- /dev/null
+++ b/patches.at91/0243-pinctrl-at91-fix-debounce-support.patch
@@ -0,0 +1,28 @@
+From b325d161ba97b1a84b3dc3fc2edcb60cd4254902 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Wed, 24 Oct 2012 01:15:51 +0800
+Subject: pinctrl: at91: fix debounce support
+
+add missing mask check
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ drivers/pinctrl/pinctrl-at91.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
+index b836567..f2e4ef5 100644
+--- a/drivers/pinctrl/pinctrl-at91.c
++++ b/drivers/pinctrl/pinctrl-at91.c
+@@ -759,7 +759,7 @@ static int at91_pinconf_set(struct pinctrl_dev *pctldev,
+ if (info->ops->set_deglitch)
+ info->ops->set_deglitch(pio, mask, config & DEGLITCH);
+ if (info->ops->set_debounce)
+- info->ops->set_debounce(pio, mask, DEBOUNCE,
++ info->ops->set_debounce(pio, mask, config & DEBOUNCE,
+ (config & DEBOUNCE_VAL) >> DEBOUNCE_VAL_SHIFT);
+ if (info->ops->set_pulldown)
+ info->ops->set_pulldown(pio, mask, config & PULL_DOWN);
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0245-ARM-at91-dts-at91sam9g20ek_common-Fix-typos-in-butto.patch b/patches.at91/0245-ARM-at91-dts-at91sam9g20ek_common-Fix-typos-in-butto.patch
new file mode 100644
index 00000000000000..7e19cbdb8810cd
--- /dev/null
+++ b/patches.at91/0245-ARM-at91-dts-at91sam9g20ek_common-Fix-typos-in-butto.patch
@@ -0,0 +1,36 @@
+From b3b0a725ce779a5ff6fa9b05edced0ee2f9dd836 Mon Sep 17 00:00:00 2001
+From: Marek Belisko <marek.belisko@open-nandra.com>
+Date: Mon, 1 Oct 2012 22:46:09 +0200
+Subject: ARM: at91/dts: at91sam9g20ek_common: Fix typos in buttons labels.
+
+Signed-off-by: Marek Belisko <marek.belisko@open-nandra.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/boot/dts/at91sam9g20ek_common.dtsi | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+index 6820417..e24116d 100644
+--- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
++++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+@@ -141,14 +141,14 @@
+ #size-cells = <0>;
+
+ btn3 {
+- label = "Buttin 3";
++ label = "Button 3";
+ gpios = <&pioA 30 1>;
+ linux,code = <0x103>;
+ gpio-key,wakeup;
+ };
+
+ btn4 {
+- label = "Buttin 4";
++ label = "Button 4";
+ gpios = <&pioA 31 1>;
+ linux,code = <0x104>;
+ gpio-key,wakeup;
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0246-ARM-at91-fix-external-interrupt-specification-in-boa.patch b/patches.at91/0246-ARM-at91-fix-external-interrupt-specification-in-boa.patch
new file mode 100644
index 00000000000000..56da209e40f6ad
--- /dev/null
+++ b/patches.at91/0246-ARM-at91-fix-external-interrupt-specification-in-boa.patch
@@ -0,0 +1,61 @@
+From 2bc3ffd68ba8a607974259eac81a93889a576c8d Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 24 Oct 2012 16:19:47 +0200
+Subject: ARM: at91: fix external interrupt specification in board code
+
+Since the switch to sparse irq, we have to add the NR_IRQS_LEGACY
+offset to static irq numbers. It has been forgotten on these
+SPI irq definitions in board code.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Cc: stable <stable@vger.kernel.org> [v3.6]
+---
+ arch/arm/mach-at91/board-neocore926.c | 2 +-
+ arch/arm/mach-at91/board-sam9261ek.c | 2 +-
+ arch/arm/mach-at91/board-sam9263ek.c | 2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
+index 7fb2a8f..05e2566 100644
+--- a/arch/arm/mach-at91/board-neocore926.c
++++ b/arch/arm/mach-at91/board-neocore926.c
+@@ -131,7 +131,7 @@ static struct spi_board_info neocore926_spi_devices[] = {
+ .max_speed_hz = 125000 * 16,
+ .bus_num = 0,
+ .platform_data = &ads_info,
+- .irq = AT91SAM9263_ID_IRQ1,
++ .irq = NR_IRQS_LEGACY + AT91SAM9263_ID_IRQ1,
+ },
+ #endif
+ };
+diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
+index b8900d5..a043192 100644
+--- a/arch/arm/mach-at91/board-sam9261ek.c
++++ b/arch/arm/mach-at91/board-sam9261ek.c
+@@ -311,7 +311,7 @@ static struct spi_board_info ek_spi_devices[] = {
+ .max_speed_hz = 125000 * 26, /* (max sample rate @ 3V) * (cmd + data + overhead) */
+ .bus_num = 0,
+ .platform_data = &ads_info,
+- .irq = AT91SAM9261_ID_IRQ0,
++ .irq = NR_IRQS_LEGACY + AT91SAM9261_ID_IRQ0,
+ .controller_data = (void *) AT91_PIN_PA28, /* CS pin */
+ },
+ #endif
+diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
+index d4dd017..e0cef65 100644
+--- a/arch/arm/mach-at91/board-sam9263ek.c
++++ b/arch/arm/mach-at91/board-sam9263ek.c
+@@ -134,7 +134,7 @@ static struct spi_board_info ek_spi_devices[] = {
+ .max_speed_hz = 125000 * 26, /* (max sample rate @ 3V) * (cmd + data + overhead) */
+ .bus_num = 0,
+ .platform_data = &ads_info,
+- .irq = AT91SAM9263_ID_IRQ1,
++ .irq = NR_IRQS_LEGACY + AT91SAM9263_ID_IRQ1,
+ },
+ #endif
+ };
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0248-ARM-at91-drop-duplicated-config-SOC_AT91SAM9-entry.patch b/patches.at91/0248-ARM-at91-drop-duplicated-config-SOC_AT91SAM9-entry.patch
new file mode 100644
index 00000000000000..12f7c8740efd22
--- /dev/null
+++ b/patches.at91/0248-ARM-at91-drop-duplicated-config-SOC_AT91SAM9-entry.patch
@@ -0,0 +1,43 @@
+From 075b74ccf13912a227ca33f103e29f3b645fb4da Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Wed, 24 Oct 2012 18:31:50 +0200
+Subject: ARM: at91: drop duplicated config SOC_AT91SAM9 entry
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/Kconfig | 12 +++---------
+ 1 file changed, 3 insertions(+), 9 deletions(-)
+
+diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
+index 79d08ed..b2ce9c4 100644
+--- a/arch/arm/mach-at91/Kconfig
++++ b/arch/arm/mach-at91/Kconfig
+@@ -19,21 +19,15 @@ config AT91_SAM9G45_RESET
+
+ config SOC_AT91SAM9
+ bool
+- select GENERIC_CLOCKEVENTS
+ select CPU_ARM926T
++ select GENERIC_CLOCKEVENTS
++ select MULTI_IRQ_HANDLER
++ select SPARSE_IRQ
+
+ menu "Atmel AT91 System-on-Chip"
+
+ comment "Atmel AT91 Processor"
+
+-config SOC_AT91SAM9
+- bool
+- select CPU_ARM926T
+- select MULTI_IRQ_HANDLER
+- select SPARSE_IRQ
+- select AT91_SAM9_TIME
+- select AT91_SAM9_SMC
+-
+ config SOC_AT91RM9200
+ bool "AT91RM9200"
+ select CPU_ARM920T
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0249-ARM-at91-fix-at91x40-build.patch b/patches.at91/0249-ARM-at91-fix-at91x40-build.patch
new file mode 100644
index 00000000000000..a4d8b6f8bf8ff0
--- /dev/null
+++ b/patches.at91/0249-ARM-at91-fix-at91x40-build.patch
@@ -0,0 +1,33 @@
+From e5e253baa31df4db3db0db218019e425bd4df9cd Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Fri, 26 Oct 2012 22:49:09 +0200
+Subject: ARM: at91: fix at91x40 build
+
+patch 738a0fd7 "ARM: at91: fix external interrupts in non-DT case"
+fixed a run-time error on some at91 platforms but did not apply
+the same change to at91x40, which now doesn't build.
+
+This changes at91x40 in the same way that the other platforms
+were changed.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/mach-at91/at91x40.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm/mach-at91/at91x40.c b/arch/arm/mach-at91/at91x40.c
+index 46090e6..efbb93f 100644
+--- a/arch/arm/mach-at91/at91x40.c
++++ b/arch/arm/mach-at91/at91x40.c
+@@ -88,6 +88,6 @@ void __init at91x40_init_interrupts(unsigned int priority[NR_AIC_IRQS])
+ if (!priority)
+ priority = at91x40_default_irq_priority;
+
+- at91_aic_init(priority);
++ at91_aic_init(priority, at91_extern_irq);
+ }
+
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0250-ARM-at91-fix-external-interrupts-in-non-DT-case.patch b/patches.at91/0250-ARM-at91-fix-external-interrupts-in-non-DT-case.patch
new file mode 100644
index 00000000000000..1949b65ee7b39e
--- /dev/null
+++ b/patches.at91/0250-ARM-at91-fix-external-interrupts-in-non-DT-case.patch
@@ -0,0 +1,76 @@
+From a2dcc54f95495c63504c6ee51ff1082343e5f4be Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 24 Oct 2012 16:09:57 +0200
+Subject: ARM: at91: fix external interrupts in non-DT case
+
+Management of external interrupts has changed but the
+non-DT code has not integrated these changes.
+Add a mask to pass external irq specification from SoC
+specific code to the at91_aic_init() function.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Cc: stable <stable@vger.kernel.org> [v3.6]
+---
+ arch/arm/mach-at91/generic.h | 3 ++-
+ arch/arm/mach-at91/irq.c | 9 +++++++--
+ arch/arm/mach-at91/setup.c | 2 +-
+ 3 files changed, 10 insertions(+), 4 deletions(-)
+
+diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
+index f496506..b62f560e 100644
+--- a/arch/arm/mach-at91/generic.h
++++ b/arch/arm/mach-at91/generic.h
+@@ -26,7 +26,8 @@ extern void __init at91_dt_initialize(void);
+ extern void __init at91_init_irq_default(void);
+ extern void __init at91_init_interrupts(unsigned int priority[]);
+ extern void __init at91x40_init_interrupts(unsigned int priority[]);
+-extern void __init at91_aic_init(unsigned int priority[]);
++extern void __init at91_aic_init(unsigned int priority[],
++ unsigned int ext_irq_mask);
+ extern int __init at91_aic_of_init(struct device_node *node,
+ struct device_node *parent);
+ extern int __init at91_aic5_of_init(struct device_node *node,
+diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
+index 1e02c0e..febc2ee 100644
+--- a/arch/arm/mach-at91/irq.c
++++ b/arch/arm/mach-at91/irq.c
+@@ -502,14 +502,19 @@ int __init at91_aic5_of_init(struct device_node *node,
+ /*
+ * Initialize the AIC interrupt controller.
+ */
+-void __init at91_aic_init(unsigned int *priority)
++void __init at91_aic_init(unsigned int *priority, unsigned int ext_irq_mask)
+ {
+ unsigned int i;
+ int irq_base;
+
+- if (at91_aic_pm_init())
++ at91_extern_irq = kzalloc(BITS_TO_LONGS(n_irqs)
++ * sizeof(*at91_extern_irq), GFP_KERNEL);
++
++ if (at91_aic_pm_init() || at91_extern_irq == NULL)
+ panic("Unable to allocate bit maps\n");
+
++ *at91_extern_irq = ext_irq_mask;
++
+ at91_aic_base = ioremap(AT91_AIC, 512);
+ if (!at91_aic_base)
+ panic("Unable to ioremap AIC registers\n");
+diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
+index a37bebc..7cf3fef 100644
+--- a/arch/arm/mach-at91/setup.c
++++ b/arch/arm/mach-at91/setup.c
+@@ -48,7 +48,7 @@ void __init at91_init_irq_default(void)
+ void __init at91_init_interrupts(unsigned int *priority)
+ {
+ /* Initialize the AIC interrupt controller */
+- at91_aic_init(priority);
++ at91_aic_init(priority, at91_extern_irq);
+
+ /* Enable GPIO interrupts */
+ at91_gpio_irq_setup();
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0251-ARM-at91-i2c-change-id-to-let-i2c-at91-work.patch b/patches.at91/0251-ARM-at91-i2c-change-id-to-let-i2c-at91-work.patch
new file mode 100644
index 00000000000000..033f4624ebe894
--- /dev/null
+++ b/patches.at91/0251-ARM-at91-i2c-change-id-to-let-i2c-at91-work.patch
@@ -0,0 +1,154 @@
+From c4e770c2e3cb8a3c8372f2f7a7cddcc8aa5e1160 Mon Sep 17 00:00:00 2001
+From: Bo Shen <voice.shen@atmel.com>
+Date: Mon, 15 Oct 2012 17:30:28 +0800
+Subject: ARM: at91/i2c: change id to let i2c-at91 work
+
+The i2c core driver will turn the platform device ID to busnum
+When using platfrom device ID as -1, it means dynamically assigned
+the busnum. When writing code, we need to make sure the busnum,
+and call i2c_register_board_info(int busnum, ...) to register device
+if using -1, we do not know the value of busnum
+
+In order to solve this issue, set the platform device ID as a fix number
+Here using 0 to match the busnum used in i2c_regsiter_board_info()
+
+Signed-off-by: Bo Shen <voice.shen@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ arch/arm/mach-at91/at91rm9200.c | 2 +-
+ arch/arm/mach-at91/at91rm9200_devices.c | 2 +-
+ arch/arm/mach-at91/at91sam9260.c | 4 ++--
+ arch/arm/mach-at91/at91sam9260_devices.c | 2 +-
+ arch/arm/mach-at91/at91sam9261.c | 4 ++--
+ arch/arm/mach-at91/at91sam9261_devices.c | 2 +-
+ arch/arm/mach-at91/at91sam9263.c | 2 +-
+ arch/arm/mach-at91/at91sam9263_devices.c | 2 +-
+ arch/arm/mach-at91/at91sam9rl_devices.c | 2 +-
+ 9 files changed, 11 insertions(+), 11 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
+index a454734..a3e4710 100644
+--- a/arch/arm/mach-at91/at91rm9200.c
++++ b/arch/arm/mach-at91/at91rm9200.c
+@@ -187,7 +187,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
+- CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200", &twi_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200.0", &twi_clk),
+ /* fake hclk clock */
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
+index 7cd8053..1e122bc 100644
+--- a/arch/arm/mach-at91/at91rm9200_devices.c
++++ b/arch/arm/mach-at91/at91rm9200_devices.c
+@@ -512,7 +512,7 @@ static struct resource twi_resources[] = {
+
+ static struct platform_device at91rm9200_twi_device = {
+ .name = "i2c-at91rm9200",
+- .id = -1,
++ .id = 0,
+ .resource = twi_resources,
+ .num_resources = ARRAY_SIZE(twi_resources),
+ };
+diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
+index 23a8cfb..50b27d0 100644
+--- a/arch/arm/mach-at91/at91sam9260.c
++++ b/arch/arm/mach-at91/at91sam9260.c
+@@ -203,8 +203,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
+ CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc_clk),
+- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk),
+- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20", &twi_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260.0", &twi_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi_clk),
+ /* more usart lookup table for DT entries */
+ CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
+ CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk),
+diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
+index b169d64..e2a3e14 100644
+--- a/arch/arm/mach-at91/at91sam9260_devices.c
++++ b/arch/arm/mach-at91/at91sam9260_devices.c
+@@ -418,7 +418,7 @@ static struct resource twi_resources[] = {
+ };
+
+ static struct platform_device at91sam9260_twi_device = {
+- .id = -1,
++ .id = 0,
+ .resource = twi_resources,
+ .num_resources = ARRAY_SIZE(twi_resources),
+ };
+diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
+index 93a24e9..4d262f3 100644
+--- a/arch/arm/mach-at91/at91sam9261.c
++++ b/arch/arm/mach-at91/at91sam9261.c
+@@ -178,8 +178,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &hck0),
+- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9261", &twi_clk),
+- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10", &twi_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9261.0", &twi_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.0", &twi_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+ CLKDEV_CON_ID("pioB", &pioB_clk),
+ CLKDEV_CON_ID("pioC", &pioC_clk),
+diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
+index ac212e9..cf444a6 100644
+--- a/arch/arm/mach-at91/at91sam9261_devices.c
++++ b/arch/arm/mach-at91/at91sam9261_devices.c
+@@ -319,7 +319,7 @@ static struct resource twi_resources[] = {
+ };
+
+ static struct platform_device at91sam9261_twi_device = {
+- .id = -1,
++ .id = 0,
+ .resource = twi_resources,
+ .num_resources = ARRAY_SIZE(twi_resources),
+ };
+diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
+index 7639f6b..ed390f6 100644
+--- a/arch/arm/mach-at91/at91sam9263.c
++++ b/arch/arm/mach-at91/at91sam9263.c
+@@ -193,7 +193,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
+- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260.0", &twi_clk),
+ /* fake hclk clock */
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
+index ac61544..095ecc9e 100644
+--- a/arch/arm/mach-at91/at91sam9263_devices.c
++++ b/arch/arm/mach-at91/at91sam9263_devices.c
+@@ -602,7 +602,7 @@ static struct resource twi_resources[] = {
+
+ static struct platform_device at91sam9263_twi_device = {
+ .name = "i2c-at91sam9260",
+- .id = -1,
++ .id = 0,
+ .resource = twi_resources,
+ .num_resources = ARRAY_SIZE(twi_resources),
+ };
+diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
+index a3e9b08..5374e24 100644
+--- a/arch/arm/mach-at91/at91sam9rl_devices.c
++++ b/arch/arm/mach-at91/at91sam9rl_devices.c
+@@ -349,7 +349,7 @@ static struct resource twi_resources[] = {
+
+ static struct platform_device at91sam9rl_twi_device = {
+ .name = "i2c-at91sam9g20",
+- .id = -1,
++ .id = 0,
+ .resource = twi_resources,
+ .num_resources = ARRAY_SIZE(twi_resources),
+ };
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0252-net-macb-align-ring-buffer-function-with-mainline.patch b/patches.at91/0252-net-macb-align-ring-buffer-function-with-mainline.patch
new file mode 100644
index 00000000000000..0d588cfdb363a5
--- /dev/null
+++ b/patches.at91/0252-net-macb-align-ring-buffer-function-with-mainline.patch
@@ -0,0 +1,43 @@
+From 550797fd7773e9ebe542e55e770381273fe1a2f7 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Fri, 16 Nov 2012 16:47:44 +0100
+Subject: net/macb: align ring buffer function with mainline
+
+Available number of descriptors in ring buffer function by David Laight.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index e3168bf..1f7b3a3 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -31,12 +31,12 @@
+ #include "macb.h"
+
+ #define RX_BUFFER_SIZE 128
+-#define RX_RING_SIZE 512
++#define RX_RING_SIZE 512 /* must be power of 2 */
+ #define RX_RING_BYTES (sizeof(struct macb_dma_desc) * RX_RING_SIZE)
+ #define RX_BUFFERS_PER_PAGE (PAGE_SIZE / RX_BUFFER_SIZE)
+ #define RX_RING_PAGES (RX_RING_SIZE / RX_BUFFERS_PER_PAGE)
+
+-#define TX_RING_SIZE 128
++#define TX_RING_SIZE 128 /* must be power of 2 */
+ #define TX_RING_BYTES (sizeof(struct macb_dma_desc) * TX_RING_SIZE)
+
+ /* minimum number of free TX descriptors before waking up TX process */
+@@ -63,7 +63,7 @@ static unsigned int macb_tx_ring_wrap(unsigned int index)
+
+ static unsigned int macb_tx_ring_avail(struct macb *bp)
+ {
+- return TX_RING_SIZE - (bp->tx_head - bp->tx_tail);
++ return (bp->tx_tail - bp->tx_head) & (TX_RING_SIZE - 1);
+ }
+
+ static struct macb_dma_desc *macb_tx_desc(struct macb *bp, unsigned int index)
+--
+1.8.0.197.g5a90748
+
diff --git a/patches.at91/0253-net-macb-move-to-circ_buf-macros-and-fix-initial-con.patch b/patches.at91/0253-net-macb-move-to-circ_buf-macros-and-fix-initial-con.patch
new file mode 100644
index 00000000000000..74d82eb3c53740
--- /dev/null
+++ b/patches.at91/0253-net-macb-move-to-circ_buf-macros-and-fix-initial-con.patch
@@ -0,0 +1,90 @@
+From 10c4df2b1b3697e748032c8729d26b262eca651d Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 19 Nov 2012 16:05:28 +0100
+Subject: net/macb: move to circ_buf macros and fix initial condition
+
+Move to circular buffers management macro and correct an error
+with circular buffer initial condition.
+
+Without this patch, the macb_tx_ring_avail() function was
+not reporting the proper ring availability at startup:
+macb macb: eth0: BUG! Tx Ring full when queue awake!
+macb macb: eth0: tx_head = 0, tx_tail = 0
+And hanginig forever...
+
+I remove the macb_tx_ring_avail() function and use the
+proven macros from circ_buf.h. CIRC_CNT() is used in the
+"consumer" part of the driver: macb_tx_interrupt() to match
+advice from Documentation/circular-buffers.txt.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 17 +++++++----------
+ 1 file changed, 7 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index 1f7b3a3..9647d37 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -15,6 +15,7 @@
+ #include <linux/moduleparam.h>
+ #include <linux/kernel.h>
+ #include <linux/types.h>
++#include <linux/circ_buf.h>
+ #include <linux/slab.h>
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+@@ -39,8 +40,8 @@
+ #define TX_RING_SIZE 128 /* must be power of 2 */
+ #define TX_RING_BYTES (sizeof(struct macb_dma_desc) * TX_RING_SIZE)
+
+-/* minimum number of free TX descriptors before waking up TX process */
+-#define MACB_TX_WAKEUP_THRESH (TX_RING_SIZE / 4)
++/* level of occupied TX descriptors under which we wake up TX process */
++#define MACB_TX_WAKEUP_THRESH (3 * TX_RING_SIZE / 4)
+
+ #define MACB_RX_INT_FLAGS (MACB_BIT(RCOMP) | MACB_BIT(RXUBR) \
+ | MACB_BIT(ISR_ROVR))
+@@ -61,11 +62,6 @@ static unsigned int macb_tx_ring_wrap(unsigned int index)
+ return index & (TX_RING_SIZE - 1);
+ }
+
+-static unsigned int macb_tx_ring_avail(struct macb *bp)
+-{
+- return (bp->tx_tail - bp->tx_head) & (TX_RING_SIZE - 1);
+-}
+-
+ static struct macb_dma_desc *macb_tx_desc(struct macb *bp, unsigned int index)
+ {
+ return &bp->tx_ring[macb_tx_ring_wrap(index)];
+@@ -495,7 +491,8 @@ static void macb_tx_interrupt(struct macb *bp)
+
+ bp->tx_tail = tail;
+ if (netif_queue_stopped(bp->dev)
+- && macb_tx_ring_avail(bp) > MACB_TX_WAKEUP_THRESH)
++ && CIRC_CNT(bp->tx_head, bp->tx_tail,
++ TX_RING_SIZE) <= MACB_TX_WAKEUP_THRESH)
+ netif_wake_queue(bp->dev);
+ }
+
+@@ -808,7 +805,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ spin_lock_irqsave(&bp->lock, flags);
+
+ /* This is a hard error, log it. */
+- if (macb_tx_ring_avail(bp) < 1) {
++ if (CIRC_SPACE(bp->tx_head, bp->tx_tail, TX_RING_SIZE) < 1) {
+ netif_stop_queue(dev);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ netdev_err(bp->dev, "BUG! Tx Ring full when queue awake!\n");
+@@ -845,7 +842,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
+
+ macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
+
+- if (macb_tx_ring_avail(bp) < 1)
++ if (CIRC_SPACE(bp->tx_head, bp->tx_tail, TX_RING_SIZE) < 1)
+ netif_stop_queue(dev);
+
+ spin_unlock_irqrestore(&bp->lock, flags);
+--
+1.8.0.197.g5a90748
+
diff --git a/series b/series
index 4f3b0d3a2439d3..14756f7fcd2373 100644
--- a/series
+++ b/series
@@ -289,3 +289,253 @@ patches.armadillo800/0104-ARM-mach-shmobile-armadillo800eva-Fix-GPIO-buttons-d.p
patches.armadillo800/0105-ARM-mach-shmobile-armadillo800eva-Enable-power-butto.patch
patches.armadillo800/0106-ARM-shmobile-armadillo800eva-fixup-sound-card-detect.patch
patches.armadillo800/0107-ARM-shmobile-armadillo800eva-enable-rw-rootfs-mount.patch
+
+
+patches.at91/0001-MAINTAINERS-add-entry-for-Atmel-isi-driver.patch
+patches.at91/0002-MAINTAINERS-add-entry-for-Atmel-touch-screen-ADC-con.patch
+patches.at91/0003-MAINTAINERS-add-entry-for-Atmel-DMA-driver.patch
+patches.at91/0004-MAINTAINERS-add-entry-for-Atmel-timer-counter-TC.patch
+patches.at91/0005-MAINTAINERS-remove-non-responding-web-link-for-atmel.patch
+patches.at91/0006-ARM-at91-change-AT91-Kconfig-entry-comment.patch
+patches.at91/0007-ARM-at91-Kconfig-change-at91sam9g45-entry.patch
+patches.at91/0008-ARM-at91-Kconfig-add-comment-to-at91sam9x5-family-en.patch
+patches.at91/0009-ARM-at91-Kconfig-add-clarifications-to-AT91SAM9M10G4.patch
+patches.at91/0010-ARM-at91-Kconfig-add-AT91SAM9x5-family-to-AT91_EARLY.patch
+patches.at91/0011-ARM-at91-Kconfig-website-link-for-AT91SAM9G20-EK.patch
+patches.at91/0012-rtc-Kconfig-remove-dependency-for-AT91-rtc-driver.patch
+patches.at91/0013-Input-Kconfig-remove-dependency-for-atmel_tsadcc-dri.patch
+patches.at91/0014-hwrng-Kconfig-remove-dependency-for-atmel-rng-driver.patch
+patches.at91/0015-ARM-at91-uncompress-Store-UART-address-in-a-variable.patch
+patches.at91/0016-ARM-at91-uncompress-autodetect-the-uart-to-use.patch
+patches.at91/0017-ARM-at91-drop-at91_set_serial_console.patch
+patches.at91/0018-ARM-at91-do-not-pin-mux-the-UARTs-in-init_early.patch
+patches.at91/0019-ARM-at91-move-at91_init_leds-to-board-init.patch
+patches.at91/0020-ARM-at91-pm-select-memory-controler-at-runtime.patch
+patches.at91/0021-ARM-at91-add-SOC_AT91SAM9-kconfig-option-to-factoris.patch
+patches.at91/0022-ARN-at91-introduce-SOC_AT91xxx-define-to-allow-to-co.patch
+patches.at91/0023-ARM-at91-dt-do-not-specify-the-board-any-more.patch
+patches.at91/0024-ARM-at91-add-defconfig-for-device-tree.patch
+patches.at91/0025-ARM-at91-add-at91sam9260-DT-support.patch
+patches.at91/0026-arm-at91-add-Calao-TNY-A9260-and-TNY-A9G20-board-sup.patch
+patches.at91/0027-ARM-at91-add-at91sam9g20ek-boards-dt-support.patch
+patches.at91/0028-ARM-at91-USB-A926x-update-nand-partition.patch
+patches.at91/0029-ARM-at91-Calao-USB-A926x-factorize-common-binding-in.patch
+patches.at91/0030-ARM-at91-DT-add-Calao-USB-A9260-DT-support.patch
+patches.at91/0031-ARM-at91-standard-device-init-only-if-DT-is-not-popu.patch
+patches.at91/0032-ARM-at91-add-at91sam9263-DT-support.patch
+patches.at91/0033-ARM-at91-add-at91sam9263ek-DT-support.patch
+patches.at91/0034-ARM-at91-DT-add-Calao-USB-A9263-board-support.patch
+patches.at91/0035-ARM-at91-DT-add-Calao-TNY-A9263-board-support.patch
+patches.at91/0036-ARM-at91-add-kizbox-board-dt-support.patch
+patches.at91/0037-Ethernut-5-board-support.patch
+patches.at91/0038-ARM-at91-Add-machine-header-file-for-AT91SAM9N12-SoC.patch
+patches.at91/0039-ARM-at91-Add-machine-files-for-AT91SAM9N12-SoC.patch
+patches.at91/0040-ARM-at91-Add-DT-description-files-for-AT91SAM9N12-EK.patch
+patches.at91/0041-ARM-at91-remove-two-unused-headers.patch
+patches.at91/0042-ARM-at91-fix-at91_aic_write-macro.patch
+patches.at91/0043-USB-ohci-at91-use-resource_size-for-memory-io-resour.patch
+patches.at91/0044-USB-Kconfig-add-Atmel-usba-driver-entry.patch
+patches.at91/0045-ARM-at91-clock-fix-PLLA-overclock-warning.patch
+patches.at91/0046-ARM-at91-dts-remove-partial-parameter-in-at91sam9g25.patch
+patches.at91/0047-ARM-at91-set-i2c_board_info.type-to-ds1339-directly.patch
+patches.at91/0048-ARM-at91-defconfig-Remove-unaffected-config-option.patch
+patches.at91/0049-ARM-at91-fix-missing-interrupt-cells-on-gpio-control.patch
+patches.at91/0051-ARM-at91-missing-header-file-for-rtc-at91rm9200.c.patch
+patches.at91/0052-ASoC-atmel-ssc-include-linux-io.h-for-raw-io.patch
+patches.at91/0053-ARM-at91-aic-can-use-fast-eoi-handler-type.patch
+patches.at91/0054-ARM-at91-aic-add-dt-support-for-external-irqs.patch
+patches.at91/0055-ARM-at91-add-of-irq-priorities-support.patch
+patches.at91/0056-ARM-at91-remove-static-irq-priorities-for-sam9x5.patch
+patches.at91/0057-ARM-at91-at91-based-machines-specify-their-own-irq-h.patch
+patches.at91/0058-ARM-at91-sparse-irq-support.patch
+patches.at91/0059-ARM-at91-remove-mach-irqs.h.patch
+patches.at91/0060-ARM-at91-add-AIC5-support.patch
+patches.at91/0061-dt-add-property-iteration-helpers.patch
+patches.at91/0062-ARM-at91-fix-new-build-errors.patch
+patches.at91/0063-dmaengine-at_hdmac-remove-some-at_dma_slave-comments.patch
+patches.at91/0064-dmaengine-at_hdmac-remove-ATC_DEFAULT_CTRLA-constant.patch
+patches.at91/0065-dmaengine-at_hdmac-take-maxburst-from-slave-configur.patch
+patches.at91/0066-dmaengine-at_hdmac-trivial-fix-comment-in-header.patch
+patches.at91/0069-AT91-Remove-fixed-mapping-for-AT91RM9200-ethernet.patch
+patches.at91/0070-net-at91_ether-use-gpio_to_irq-for-phy-IRQ-line.patch
+patches.at91/0071-net-macb-manage-carrier-state-with-call-to-netif_car.patch
+patches.at91/0072-ALSA-atmel-ac97c-correct-the-unexpected-behavior-whe.patch
+patches.at91/0073-MTD-at91-extract-hw-ecc-initialization-to-one-functi.patch
+patches.at91/0074-MTD-at91-add-dt-parameters-for-Atmel-PMECC.patch
+patches.at91/0075-MTD-at91-atmel_nand-Update-driver-to-support-Program.patch
+patches.at91/0076-MTD-nand-add-return-value-for-write_page-write_page_.patch
+patches.at91/0077-MTD-atmel_nand-revet-the-oob_required-parameter-in-e.patch
+patches.at91/0078-MTD-atmel_nand-add-9x5-to-list-of-SoC-with-DMA.patch
+patches.at91/0079-MTD-atmel_nand-POI-fall-back-is-not-an-issue-change-.patch
+patches.at91/0080-MTD-atmel_nand-add-9n12-to-list-of-SoC-with-DMA.patch
+patches.at91/0081-input-atmel_tsadcc-add-support-for-ARCH_AT91SAM9X5.patch
+patches.at91/0082-input-atmel_tsadcc-add-touch-screen-pressure-measure.patch
+patches.at91/0083-input-atmel_tsadcc-enable-touchscreen-averaging-and-.patch
+patches.at91/0084-input-atmel_tsadcc-add-ACR-register-and-change-trigg.patch
+patches.at91/0085-AT91-input-atmel_tsadcc-rework-irq-infrastructure-an.patch
+patches.at91/0086-input-at91-add-tsadcc_data-for-9x5.patch
+patches.at91/0087-input-at91-add-dt-support-for-atmel-touch-screen-adc.patch
+patches.at91/0088-net-macb-Add-support-for-Gigabit-Ethernet-mode.patch
+patches.at91/0089-net-macb-memory-barriers-cleanup.patch
+patches.at91/0090-net-macb-change-debugging-messages.patch
+patches.at91/0091-net-macb-remove-macb_get_drvinfo.patch
+patches.at91/0092-net-macb-tx-status-is-more-than-8-bits-now.patch
+patches.at91/0093-net-macb-clean-up-ring-buffer-logic.patch
+patches.at91/0094-net-macb-ethtool-interface-add-register-dump-feature.patch
+patches.at91/0095-net-macb-better-manage-tx-errors.patch
+patches.at91/0096-net-macb-Offset-first-RX-buffer-by-two-bytes.patch
+patches.at91/0097-net-macb-GEM-DMA-configuration-register-update.patch
+patches.at91/0098-net-macb-Use-non-coherent-memory-for-rx-buffers.patch
+patches.at91/0099-phy-micrel-Use-proper-phy-in-gmac.patch
+patches.at91/0100-phy-micrel-we-need-to-register-ks8051-phy-for-emac.patch
+patches.at91/0101-usb-gadget-at91_udc-move-the-dereference-below-the-N.patch
+patches.at91/0103-USB-ohci-at91-fix-PIO-handling-in-relation-with-numb.patch
+patches.at91/0104-usb-gadget-at91_udc-Propagate-devicetree-to-gadget-d.patch
+patches.at91/0105-USB-ohci-at91.c-remove-err-usage.patch
+patches.at91/0107-media-video-atmel-isi-add-dumb-set_parm.patch
+patches.at91/0108-video-atmel_lcdfb-add-support-for-AT91SAM9x5.patch
+patches.at91/0109-video-atmel_lcdfb-The-output-bpp-should-not-change-a.patch
+patches.at91/0110-video-atmelfb-initially-split-atmelfb-into-a-driver-.patch
+patches.at91/0111-video-atmelfb-refactor-core-setup.patch
+patches.at91/0112-video-atmelfb-refactor-start-stop.patch
+patches.at91/0113-video-atmelfb-refactor-isr.patch
+patches.at91/0114-video-atmelfb-refactor-backlight-routines.patch
+patches.at91/0115-video-atmelfb-refactor-dma_update.patch
+patches.at91/0116-video-atmelfb-refactor-LUT.patch
+patches.at91/0117-video-atmelfb-refactor-limit_screeninfo.patch
+patches.at91/0118-arm-at91-refactor-lcdc-includes.patch
+patches.at91/0119-video-atmel_hlcdfb-add-new-driver.patch
+patches.at91/0120-WIP-add-clut-resource.patch
+patches.at91/0121-video-atmel_lcdfb-add-error-msg-when-out-of-memory.patch
+patches.at91/0122-video-atmel_lcdfb-HLCD-modifications.patch
+patches.at91/0123-atmel_lcdfb-change-pixel-clock-ratio-calculation.patch
+patches.at91/0124-media-at91sam9x5-video-new-driver-for-the-high-end-o.patch
+patches.at91/0125-video-atmel_lcdfb-protect-bl_power-with-CONFIG_BACKL.patch
+patches.at91/0126-ARM-at91-9x5-modify-consistent-DMA-size.patch
+patches.at91/0127-video-atmel_lcdfb-adapt-to-all-IP-configurations.patch
+patches.at91/0128-media-at91sam9x5-video-cleanup-modifications.patch
+patches.at91/0129-media-at91sam9x5-video-align-DMA-descriptors-on-64-b.patch
+patches.at91/0130-media-at91sam9x5-video-change-scaling-factor-calcula.patch
+patches.at91/0131-media-at91sam9x5-video-add-device-tree-support.patch
+patches.at91/0132-ARM-at91-video-Atmel-HLCD-is-only-selected-by-newer-.patch
+patches.at91/0133-mmc-atmel-mci-the-r-w-proof-capability-lack-was-not-.patch
+patches.at91/0134-mmc-atmel-mci-change-the-state-machine-for-compatibi.patch
+patches.at91/0135-mmc-atmel-mci-add-support-for-version-lower-than-v2x.patch
+patches.at91/0136-mmc-atmel-mci-add-debug-logs.patch
+patches.at91/0137-mmc-atmel-mci-fix-data-timeout-issue.patch
+patches.at91/0138-ARM-at91-add-atmel-mci-support-for-chips-and-boards-.patch
+patches.at91/0139-ARM-at91-defconfig-change-the-MCI-driver-to-use-in-d.patch
+patches.at91/0140-mmc-atmel-mci-fix-burst-chunk-size-modification.patch
+patches.at91/0141-mmc-atmel-mci-add-device-tree-support.patch
+patches.at91/0142-ARM-at91-add-clocks-for-DT-entries.patch
+patches.at91/0143-ARM-dts-add-nodes-for-atmel-hsmci-controllers-for-at.patch
+patches.at91/0144-ARM-dts-add-nodes-for-atmel-hsmci-controllers-for-at.patch
+patches.at91/0145-mmc-atmel-mci-remove-not-needed-DMA-capability-test.patch
+patches.at91/0146-ARM-at91-atmel-mci-remove-unused-setup_dma_addr-macr.patch
+patches.at91/0147-mmc-atmel-mci-remove-the-need-for-CONFIG_MMC_ATMELMC.patch
+patches.at91/0148-ARM-dts-fix-add-mmc-irq-priority.patch
+patches.at91/0149-mmc-atmel-mci-support-8-bit-buswidth.patch
+patches.at91/0150-mmc-atmel-mci-fix-incorrect-setting-of-host-data-to-.patch
+patches.at91/0151-mmc-block-fix-the-data-timeout-issue-with-ACMD22.patch
+patches.at91/0152-mmc-atmel-mci-modify-CLKDIV-displaying-in-debugfs.patch
+patches.at91/0153-mmc-atmel-mci-increase-dma-threshold.patch
+patches.at91/0154-mmc-atmel-mci-not-busy-flag-has-also-to-be-used-for-.patch
+patches.at91/0155-Replace-clk_lookup.con_id-with-clk_lookup.dev_id-ent.patch
+patches.at91/0156-i2c-at91-remove-old-polling-driver.patch
+patches.at91/0157-i2c-at91-add-new-driver.patch
+patches.at91/0158-arm-at91-G45-TWI-remove-open-drain-setting-for-twi-f.patch
+patches.at91/0159-ARM-at91-do-not-configure-at91sam9g10-twi-pio-as-ope.patch
+patches.at91/0160-i2c-at91-add-dt-support-to-i2c-at91.patch
+patches.at91/0161-ARM-at91-add-clocks-for-I2C-DT-entries.patch
+patches.at91/0162-ARM-dts-add-twi-nodes-for-atmel-SoCs.patch
+patches.at91/0163-ARM-dts-add-twi-nodes-for-atmel-boards.patch
+patches.at91/0164-i2c-at91-add-dma-support.patch
+patches.at91/0165-i2c-at91-backport-fix-for-devm_clk_get.patch
+patches.at91/0166-i2c-at91-add-dt-property-for-DMA-configuration.patch
+patches.at91/0167-ARM-at91-add-MCI-DMA-for-at91sam9x5.dtsi.patch
+patches.at91/0168-ARM-at91-add-i2c-and-qt1070-pin-muxing.patch
+patches.at91/0169-AT91-board-dt-add-mci-pinmux-for-9x5.patch
+patches.at91/0170-mtd-atmel_nand-add-4k-page-nand-flash-support-for-PM.patch
+patches.at91/0171-mtd-atmel_nand-incease-the-chip_delay-time-tR-for-su.patch
+patches.at91/0172-at91-9x5-add-DT-parameters-to-enable-PMECC.patch
+patches.at91/0173-ARM-at91-split-9x5-dts-dtsi-in-a-common-set-of-perip.patch
+patches.at91/0174-ARM-at91-9x5-family-add-at91sam9x25ek.dts.patch
+patches.at91/0175-ARM-at91-add-new-at91sam9g35ek.dts.patch
+patches.at91/0176-ARM-at91-add-pinmux-for-9x5-LCD.patch
+patches.at91/0177-ARM-at91-add-LCD-HEO-DT-entry-for-at91sam9x5.patch
+patches.at91/0178-AT91SAM9G45-add-crypto-peripherals.patch
+patches.at91/0179-crypto-add-Atmel-AES-driver.patch
+patches.at91/0180-crypto-add-Atmel-DES-TDES-driver.patch
+patches.at91/0181-crypto-add-Atmel-SHA1-SHA256-driver.patch
+patches.at91/0182-crypto-add-atmel-test-driver.patch
+patches.at91/0183-crypto-add-new-tests-to-tcrypt.patch
+patches.at91/0184-AT91SAM9G45-crypto-same-platform-data-header-for-all.patch
+patches.at91/0185-AT91SAM9G45-dts-add-crypto-peripherals.patch
+patches.at91/0186-AT91SAM9N12-add-crypto-peripherals.patch
+patches.at91/0187-AT91SAM9N12-dts-add-crypto-peripherals.patch
+patches.at91/0188-crypto-Atmel-AES-add-device-tree-support.patch
+patches.at91/0189-crypto-Atmel-TDES-add-device-tree-support.patch
+patches.at91/0190-crypto-Atmel-SHA-add-device-tree-support.patch
+patches.at91/0191-crypto-Atmel-Test-add-SHA224-SHA384-and-SHA512-suppo.patch
+patches.at91/0192-pinctrl-core-device-tree-mapping-table-parsing-suppo.patch
+patches.at91/0193-pinctrl-fix-build-when-CONFIG_OF-CONFIG_PINCTRL.patch
+patches.at91/0194-pinctrl-fix-dangling-comment.patch
+patches.at91/0195-pinctrl-implement-devm_pinctrl_get-put.patch
+patches.at91/0196-pinctrl-add-pinctrl_provide_dummies-interface-for-pl.patch
+patches.at91/0197-pinctrl-remove-pinctrl_remove_gpio_range.patch
+patches.at91/0198-pinctrl-add-pinctrl_add_gpio_ranges-function.patch
+patches.at91/0199-pinctrl-support-gpio-request-deferred-probing.patch
+patches.at91/0200-pinctrl-propagate-map-validation-errors.patch
+patches.at91/0201-pinctrl-mark-non-EXPERIMENTAL.patch
+patches.at91/0202-pinctrl-implement-pinctrl-deferred-probing.patch
+patches.at91/0203-pinctrl-replace-list_-with-get_-_count.patch
+patches.at91/0204-pinctrl-show-pin-name-when-request-pins.patch
+patches.at91/0205-pinctrl-show-pin-name-for-pingroups-in-sysfs.patch
+patches.at91/0206-dt-add-of_get_child_count-helper-function.patch
+patches.at91/0207-arm-at91-use-macro-to-declare-soc-boot-data.patch
+patches.at91/0208-ARM-at91-gpio-implement-request.patch
+patches.at91/0209-at91-regroup-gpio-and-pinctrl-under-the-same-ranges.patch
+patches.at91/0210-arm-at91-at91sam9x5-fix-gpio-number-per-bank.patch
+patches.at91/0211-ARM-at91-add-dummies-pinctrl-for-non-dt-platform.patch
+patches.at91/0212-ARM-at91-add-pinctrl-support.patch
+patches.at91/0213-arm-at91-dt-at91sam9-add-pinctrl-support.patch
+patches.at91/0214-tty-atmel_serial-add-pinctrl-support.patch
+patches.at91/0215-arm-at91-dt-sam9m10g45ek-use-rts-cts-pinctrl-group-f.patch
+patches.at91/0216-arm-at91-dt-sam9263ek-use-rts-cts-pinctrl-group-for-.patch
+patches.at91/0217-arm-at91-dt-sam9g20ek-use-rts-cts-dtr-dsr-dcd-ri-pin.patch
+patches.at91/0218-MTD-atmel-nand-fix-gpio-missing-request.patch
+patches.at91/0219-arm-at91-dt-at91sam9-add-nand-pinctrl-support.patch
+patches.at91/0220-MTD-atmel_nand-add-pinctrl-consumer-support.patch
+patches.at91/0221-pinctrl-at91-add-deglitch-debounce-pull-down-and-sch.patch
+patches.at91/0222-mtd-atmel_nand-fix-the-compile-error-which-miss-labe.patch
+patches.at91/0223-pinctrl-at91-fix-compatible-order.patch
+patches.at91/0224-pinctrl-at91-fix-gpio-irq-support.patch
+patches.at91/0225-i2c-at91-add-pinctrl.patch
+patches.at91/0226-media-atmel_isi-add-pinctrl.patch
+patches.at91/0227-mmc-at91-add-pinctrl.patch
+patches.at91/0228-video-atmel_lcdfb-add-pinctrl.patch
+patches.at91/0229-arm-at91sam9g45-add-missing-uart-pinctrl-node.patch
+patches.at91/0230-arm-at91sam9263-add-missing-uart-pinctrl-node.patch
+patches.at91/0231-arm-at91sam9260-add-missing-uart-pinctrl-node.patch
+patches.at91/0232-arm-at91sam9x5-sync-with-the-mainline.patch
+patches.at91/0233-ARM-at91-DT-add-i2c-mmc-nand-pinctrl-in-device-tree-.patch
+patches.at91/0234-at91sam9x5-add-lcd-pinctrl-support.patch
+patches.at91/0235-arm-at91sam9x5ek-drop-temporary-pinmux.patch
+patches.at91/0236-video-atmel-lcd-only-request-the-pinctrl-once.patch
+patches.at91/0237-ARM-at91-add-at91-3.4-trunk-contents.txt-file.patch
+patches.at91/0238-ARM-at91-add-defconfig-for-sam9x5-family.patch
+patches.at91/0239-MMC-atmel-mci-add-device-tree-property-for-configura.patch
+patches.at91/0240-pinctrl-at19-fix-typo-on-PULL_UP.patch
+patches.at91/0241-pinctrl-at91-fix-pull-down-support.patch
+patches.at91/0242-arm-at91sam9xcm-add-specific-nand-pinctrl.patch
+patches.at91/0243-pinctrl-at91-fix-debounce-support.patch
+patches.at91/0245-ARM-at91-dts-at91sam9g20ek_common-Fix-typos-in-butto.patch
+patches.at91/0246-ARM-at91-fix-external-interrupt-specification-in-boa.patch
+patches.at91/0248-ARM-at91-drop-duplicated-config-SOC_AT91SAM9-entry.patch
+patches.at91/0249-ARM-at91-fix-at91x40-build.patch
+patches.at91/0250-ARM-at91-fix-external-interrupts-in-non-DT-case.patch
+patches.at91/0251-ARM-at91-i2c-change-id-to-let-i2c-at91-work.patch
+patches.at91/0252-net-macb-align-ring-buffer-function-with-mainline.patch
+patches.at91/0253-net-macb-move-to-circ_buf-macros-and-fix-initial-con.patch
+
+