[oe] [pcm043 2/2] linux-2.6.31 config and patch files for pcm043

Jan Kobler eng1 at koblersystems.de
Tue Mar 1 13:01:38 UTC 2011


These config and patch files are from the Phytec Linux BSP for phyCORE-i.MX35 PD10.1.1.
They were taken from the archive
ftp://ftp.phytec.de/pub/Products/phyCORE-iMX350/Linux/PD10.1.1/OSELAS.BSP-Phytec-phyCORE-i.MX35-PD10.1.1.tar.gz

The patch files are from the folder in this archive
OSELAS.BSP-Phytec-phyCORE-i.MX35-PD10.1.1/configs/phyCORE-i.MX35-2010.08.0/patches/linux-2.6.31.6/generic

The patch files have been shipped for linux-2.6.31.6 and are used here on linux-2.6.31.12. Because it seems to work,
pcm043 is added to linux-2.6.31.bb.

The sequence of the patches for pcm043 in linux-2.6.31.bb is derived from the file
OSELAS.BSP-Phytec-phyCORE-i.MX35-PD10.1.1/configs/phyCORE-i.MX35-2010.08.0/patches/linux-2.6.31.6/generic/series

The defconfig file is the file
OSELAS.BSP-Phytec-phyCORE-i.MX35-PD10.1.1/configs/phyCORE-i.MX35-2010.08.0/kernelconfig

These patch files from the folder
OSELAS.BSP-Phytec-phyCORE-i.MX35-PD10.1.1/configs/phyCORE-i.MX35-2010.08.0/patches/linux-2.6.31.6/generic
are NOT used:
0063-add-generic-platform-bus-based-sja1000-driver.patch
0076-mx3fb-pretty-printing-update.patch
0078-sja1000-driver-Fix-net-device-stats.patch
patch-2.6.31.6-rt19.gz
because they are not referenced by the file
OSELAS.BSP-Phytec-phyCORE-i.MX35-PD10.1.1/configs/phyCORE-i.MX35-2010.08.0/patches/linux-2.6.31.6/generic/series

Signed-off-by: Jan Kobler <eng1 at koblersystems.de>
---
 .../pcm043/0001-mxcv2-nand-driver.patch            | 1130 ++++++++++
 ...i-add-SPI-driver-for-most-known-i.MX-SoCs.patch | 2337 ++++++++++++++++++++
 ...2-MXC-NFC-Remove-useless-structure-member.patch |   45 +
 .../0002-mfd-Add-Freescale-MC13783-driver.patch    |  984 ++++++++
 ...0002-mxc_nand-cleanup-eccoob-descriptions.patch |  111 +
 ...d-a-real-NAND-flash-data-width-setup-func.patch |   51 +
 .../0003-mx3-Add-SSI-pins-to-iomux-table.patch     |   48 +
 .../0003-mxc_nand-cleanup-initialization.patch     |  124 ++
 ...4-MXC-NFC-Use-generic-bad-block-detection.patch |  148 ++
 ...004-mxc-iomux-v3-remove-resource-handling.patch |  111 +
 ...d-merge-send_read_page-and-send_prog_page.patch |  104 +
 ...vide-flash-device-detection-into-two-step.patch |   48 +
 ...31-clock-rename-SSI-clocks-to-driver-name.patch |   28 +
 ...0005-mxc_nand-introduce-mxc_do_addr_cycle.patch |  122 +
 ...order-structure-setup-to-use-NAND-informa.patch |  129 ++
 .../0006-i.MX2-Add-sound-ssi-resources.patch       |  132 ++
 .../pcm043/0006-mxc-nand-remove-debug-param.patch  |   82 +
 .../pcm043/0007-MXC-NFC-Fix-OOB-layout.patch       |  104 +
 .../0007-i.MX3-Add-sound-ssi-resources.patch       |  101 +
 .../pcm043/0007-mxc-nand-remove-dead-code.patch    |   41 +
 ...XC-Add-a-digital-audio-multiplexer-driver.patch |  281 +++
 ...C-NFC-The-i.MX35-CPU-also-uses-a-V2.1-NFC.patch |   26 +
 .../pcm043/0008-mxc-nand-use-resource_size.patch   |   26 +
 .../pcm043/0009-MX31-Fix-spi-clock-names.patch     |   32 +
 ...-MXC-NFC-Fix-NFC-s-address-area-on-i.MX35.patch |   28 +
 .../pcm043/0009-mxc-nand-use-buffers.patch         |  473 ++++
 ...dd-the-clock-resource-to-support-NFC-in-i.patch |   61 +
 .../pcm043/0010-i.MX35-Fix-audmux-clock.patch      |   52 +
 ...0010-mxc-nand-simplify-command-processing.patch |  143 ++
 ...MX31-add-spi-controller-devices-resources.patch |   97 +
 .../pcm043/0011-MXC-NFC-Fix-NFC-s-clock-name.patch |   28 +
 ...modify-send_page-to-send-all-pages-not-on.patch |   87 +
 ....MX35-can-work-with-the-v2-not-with-v1-of.patch |   34 +
 ...7-clock-rename-spi-clocks-to-match-device.patch |   30 +
 .../0012-mxc_nand-remove-unused-defines.patch      |   31 +
 .../0013-MXC-NFC-Add-the-cpu_is_mx25-macro.patch   |   38 +
 .../pcm043/0013-add-a-mc13783-codec-driver.patch   |  834 +++++++
 ...ake-main-spare-areas-runtime-configurable.patch |  142 ++
 ...FC-Add-NAND-device-to-the-pcm043-platform.patch |   47 +
 .../pcm043/0014-imx-ssi-sound-driver.patch         | 1911 ++++++++++++++++
 ...0014-mxc_nand-Get-rid-of-pagesize_2k-flag.patch |  128 ++
 ...unlock_addr-is-only-used-while-__init-pha.patch |   28 +
 .../0015-add-phycore-ac97-sound-support.patch      |  140 ++
 .../pcm043/0015-mxc_nand-Add-NFC-V2-support.patch  |  191 ++
 .../0016-add-phycore-mc13783-sound-support.patch   |  211 ++
 ...0016-mxc_nand-disable-sp_en-bit-only-once.patch |   66 +
 .../0017-mxc_nand-Allow-flash-based-bbt.patch      |   79 +
 .../pcm043/0017-pcm043-add-sound-support.patch     |  161 ++
 .../0018-mxc_nand-remove-TROP_US_DELAY.patch       |   88 +
 .../0018-pcm038-Add-SPI-MC13783-support.patch      |  146 ++
 ...support-for-phytec-pca100-phyCARD-s-board.patch |  293 +++
 ...xc_nand-use-DRIVER_NAME-where-appropriate.patch |   35 +
 .../0020-MX2-Add-SPI-devices-resources.patch       |   92 +
 .../linux-2.6.31/pcm043/0021-Early-printk.patch    |  106 +
 ...-DMA-add-a-possibility-to-create-an-endle.patch |   50 +
 ...0022-ASoC-Allow-32-bit-registers-for-DAPM.patch |  203 ++
 .../pcm043/0023-pca100-add-sound-support.patch     |   99 +
 .../pcm043/0024-MX31-Clock-updates.patch           |   40 +
 .../pcm043/0024-pcm038-add-sound-support.patch     |   72 +
 .../pcm043/0025-pcm037-Add-sound-support.patch     |  144 ++
 .../pcm043/0026-imx-ssi-Fix-AC97-rates.patch       |   37 +
 ...CI-support-for-MX27-and-MX31-based-boards.patch |  347 +++
 .../pcm043/0027-imx-ssi-flush-fifos.patch          |   29 +
 ...imx-ssi-Fix-occasional-AC97-reset-failure.patch |   37 +
 ...31-Add-USB-platform-devices-and-resources.patch |  100 +
 .../pcm043/0053-Watchdog-driver-for-IMX-MXC.patch  |  490 ++++
 ...CK-increase-default-tx_queue_len-to-10000.patch |   36 +
 .../0084-i.MX35-clock-support-Add-USB-clocks.patch |   30 +
 .../pcm043/0088-ehci-mxc-Fix-clocks.patch          |   33 +
 .../0090-mx3x-Fixup-USB-base-addresses.patch       |   93 +
 ...-mx31-clock-remove-obsolete-FIXME-comment.patch |   25 +
 .../0092-mx35-clock-give-ehci-clocks-names.patch   |   30 +
 ...MX35-implement-get_rate-for-usb-otg-clock.patch |   54 +
 .../0097-fsl-udc-driver-add-mx35-support.patch     |   83 +
 .../pcm043/Update-PCM043-board-support.patch       |  134 ++
 .../linux/linux-2.6.31/pcm043/add-led-gpio.patch   |   17 +
 recipes/linux/linux-2.6.31/pcm043/add_mmc.diff     | 1396 ++++++++++++
 recipes/linux/linux-2.6.31/pcm043/fix_can.patch    |   16 +
 .../linux/linux-2.6.31/pcm043/fix_clock_calc.patch |   27 +
 .../linux/linux-2.6.31/pcm043/fix_max7301.patch    |   28 +
 .../linux-2.6.31/pcm043/fix_mmc_for_highspeed.diff |   63 +
 .../linux/linux-2.6.31/pcm043/fix_oob_layout.diff  |   67 +
 .../linux/linux-2.6.31/pcm043/fix_owire_clk.patch  |   17 +
 .../pcm043/linux-2.6.31.6-flexcan.patch            | 2168 ++++++++++++++++++
 .../linux-2.6.31/pcm043/linux-2.6.31.6-spi.patch   |  116 +
 recipes/linux/linux-2.6.31/pcm043/w1_master.patch  |   26 +
 recipes/linux/linux/pcm043/defconfig               | 1659 ++++++++++++++
 87 files changed, 19911 insertions(+), 0 deletions(-)
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0001-mxcv2-nand-driver.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0001-spi-add-SPI-driver-for-most-known-i.MX-SoCs.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0002-MXC-NFC-Remove-useless-structure-member.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0002-mfd-Add-Freescale-MC13783-driver.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0002-mxc_nand-cleanup-eccoob-descriptions.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0003-MXC-NFC-Add-a-real-NAND-flash-data-width-setup-func.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0003-mx3-Add-SSI-pins-to-iomux-table.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0003-mxc_nand-cleanup-initialization.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0004-MXC-NFC-Use-generic-bad-block-detection.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0004-mxc-iomux-v3-remove-resource-handling.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0004-mxc_nand-merge-send_read_page-and-send_prog_page.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0005-MXC-NFC-Divide-flash-device-detection-into-two-step.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0005-i.MX31-clock-rename-SSI-clocks-to-driver-name.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0005-mxc_nand-introduce-mxc_do_addr_cycle.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0006-MXC-NFC-Reorder-structure-setup-to-use-NAND-informa.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0006-i.MX2-Add-sound-ssi-resources.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0006-mxc-nand-remove-debug-param.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0007-MXC-NFC-Fix-OOB-layout.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0007-i.MX3-Add-sound-ssi-resources.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0007-mxc-nand-remove-dead-code.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0008-MXC-Add-a-digital-audio-multiplexer-driver.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0008-MXC-NFC-The-i.MX35-CPU-also-uses-a-V2.1-NFC.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0008-mxc-nand-use-resource_size.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0009-MX31-Fix-spi-clock-names.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0009-MXC-NFC-Fix-NFC-s-address-area-on-i.MX35.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0009-mxc-nand-use-buffers.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0010-MXC-NFC-Add-the-clock-resource-to-support-NFC-in-i.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0010-i.MX35-Fix-audmux-clock.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0010-mxc-nand-simplify-command-processing.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0011-MX31-add-spi-controller-devices-resources.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0011-MXC-NFC-Fix-NFC-s-clock-name.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0011-mxc-nand-modify-send_page-to-send-all-pages-not-on.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0012-MXC-NFC-i.MX35-can-work-with-the-v2-not-with-v1-of.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0012-i.MX27-clock-rename-spi-clocks-to-match-device.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0012-mxc_nand-remove-unused-defines.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0013-MXC-NFC-Add-the-cpu_is_mx25-macro.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0013-add-a-mc13783-codec-driver.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0013-mxc_nand-Make-main-spare-areas-runtime-configurable.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0014-MXC-NFC-Add-NAND-device-to-the-pcm043-platform.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0014-imx-ssi-sound-driver.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0014-mxc_nand-Get-rid-of-pagesize_2k-flag.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0015-MXC-NFC-unlock_addr-is-only-used-while-__init-pha.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0015-add-phycore-ac97-sound-support.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0015-mxc_nand-Add-NFC-V2-support.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0016-add-phycore-mc13783-sound-support.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0016-mxc_nand-disable-sp_en-bit-only-once.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0017-mxc_nand-Allow-flash-based-bbt.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0017-pcm043-add-sound-support.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0018-mxc_nand-remove-TROP_US_DELAY.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0018-pcm038-Add-SPI-MC13783-support.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0019-mx27-add-support-for-phytec-pca100-phyCARD-s-board.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0019-mxc_nand-use-DRIVER_NAME-where-appropriate.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0020-MX2-Add-SPI-devices-resources.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0021-Early-printk.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0021-mxc-mx1-mx2-DMA-add-a-possibility-to-create-an-endle.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0022-ASoC-Allow-32-bit-registers-for-DAPM.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0023-pca100-add-sound-support.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0024-MX31-Clock-updates.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0024-pcm038-add-sound-support.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0025-pcm037-Add-sound-support.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0026-imx-ssi-Fix-AC97-rates.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0027-Add-EHCI-support-for-MX27-and-MX31-based-boards.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0027-imx-ssi-flush-fifos.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0028-imx-ssi-Fix-occasional-AC97-reset-failure.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0029-MX31-Add-USB-platform-devices-and-resources.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0053-Watchdog-driver-for-IMX-MXC.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0066-HACK-increase-default-tx_queue_len-to-10000.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0084-i.MX35-clock-support-Add-USB-clocks.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0088-ehci-mxc-Fix-clocks.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0090-mx3x-Fixup-USB-base-addresses.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0091-mx31-clock-remove-obsolete-FIXME-comment.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0092-mx35-clock-give-ehci-clocks-names.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0096-i.MX35-implement-get_rate-for-usb-otg-clock.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/0097-fsl-udc-driver-add-mx35-support.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/Update-PCM043-board-support.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/add-led-gpio.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/add_mmc.diff
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/fix_can.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/fix_clock_calc.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/fix_max7301.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/fix_mmc_for_highspeed.diff
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/fix_oob_layout.diff
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/fix_owire_clk.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/linux-2.6.31.6-flexcan.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/linux-2.6.31.6-spi.patch
 create mode 100644 recipes/linux/linux-2.6.31/pcm043/w1_master.patch
 create mode 100644 recipes/linux/linux/pcm043/defconfig

diff --git a/recipes/linux/linux-2.6.31/pcm043/0001-mxcv2-nand-driver.patch b/recipes/linux/linux-2.6.31/pcm043/0001-mxcv2-nand-driver.patch
new file mode 100644
index 0000000..fbbf023
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0001-mxcv2-nand-driver.patch
@@ -0,0 +1,1130 @@
+From cd56a2552db22ae5464b68074ad35bf0700bb790 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Thu, 4 Jun 2009 11:26:22 +0200
+Subject: [PATCH 01/15] mxcv2 nand driver
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+
+rebased to  2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel at phytec.de>
+---
+ drivers/mtd/nand/Kconfig       |    7 
+ drivers/mtd/nand/Makefile      |    1 
+ drivers/mtd/nand/mxc_nand_v2.c | 1079 +++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 1087 insertions(+)
+ create mode 100644 drivers/mtd/nand/mxc_nand_v2.c
+
+Index: drivers/mtd/nand/Kconfig
+===================================================================
+--- drivers/mtd/nand/Kconfig.orig	2009-12-08 10:02:55.061888995 +0100
++++ drivers/mtd/nand/Kconfig	2009-12-08 10:02:59.468654404 +0100
+@@ -426,6 +426,13 @@
+ 	  This enables the driver for the NAND flash controller on the
+ 	  MXC processors.
+ 
++config MTD_NAND_MXC_V2
++	tristate "MXC NAND support"
++	depends on ARCH_MX25
++	help
++	  This enables the driver for the NAND flash controller on the
++	  MXC processors.
++
+ config MTD_NAND_SH_FLCTL
+ 	tristate "Support for NAND on Renesas SuperH FLCTL"
+ 	depends on MTD_NAND && SUPERH && CPU_SUBTYPE_SH7723
+Index: drivers/mtd/nand/Makefile
+===================================================================
+--- drivers/mtd/nand/Makefile.orig	2009-12-08 10:02:55.079723657 +0100
++++ drivers/mtd/nand/Makefile	2009-12-08 10:02:59.468654404 +0100
+@@ -38,6 +38,7 @@
+ obj-$(CONFIG_MTD_NAND_FSL_UPM)		+= fsl_upm.o
+ obj-$(CONFIG_MTD_NAND_SH_FLCTL)		+= sh_flctl.o
+ obj-$(CONFIG_MTD_NAND_MXC)		+= mxc_nand.o
++obj-$(CONFIG_MTD_NAND_MXC_V2)		+= mxc_nand_v2.o
+ obj-$(CONFIG_MTD_NAND_SOCRATES)		+= socrates_nand.o
+ obj-$(CONFIG_MTD_NAND_TXX9NDFMC)	+= txx9ndfmc.o
+ 
+Index: drivers/mtd/nand/mxc_nand_v2.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ drivers/mtd/nand/mxc_nand_v2.c	2009-12-08 10:02:59.468654404 +0100
+@@ -0,0 +1,1079 @@
++/*
++ * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Copyright 2009 Sascha Hauer, kernel at pengutronix.de
++ *
++ * 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., 51 Franklin Street, Fifth Floor, Boston,
++ * MA 02110-1301, USA.
++ */
++
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/interrupt.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/io.h>
++
++#include <asm/mach/flash.h>
++#include <mach/hardware.h>
++#include <mach/mxc_nand.h>
++
++#define NFC_SET_RBA			0xe04
++#define NFC_FLASH_ADDR			0xe06
++#define NFC_FLASH_CMD			0xe08
++#define NFC_BLS				0xe0a
++#define NFC_ECC_STATUS_RESULT		0xe0c
++#define NFC_V21_SPAS			0xe10
++#define NFC_WR_PROT			0xe12
++
++#define NFC_CONFIG1			0xe1a
++#define NFC_CONFIG2			0xe1c
++
++#define NFC_V21_UNLOCKSTART_BLKADDR  	0xe20
++#define NFC_V21_UNLOCKEND_BLKADDR    	0xe22
++#define NFC_V1_UNLOCKSTART_BLKADDR  	0xe14
++#define NFC_V1_UNLOCKEND_BLKADDR    	0xe16
++
++#define nfc_is_v21()		cpu_is_mx25()
++#define nfc_is_v2x()		cpu_is_mx31()
++
++#define NFC_ECC_EN          		(1 << 3)
++
++#define NFC_WPC_UNLOCK			(1 << 2)
++
++#define NFC_CMD            		(1 << 0)
++#define NFC_ADDR           		(1 << 1)
++#define NFC_INPUT          		(1 << 2)
++#define NFC_OUTPUT         		(1 << 3)
++#define NFC_ID             		(1 << 4)
++#define NFC_STATUS         		(1 << 5)
++
++#define NFC_RBA_SHIFT       		4
++
++#define NFC_INT				(1 << 15)
++
++#define NFC_BLS_RESET			(3 << 16)
++#define NFC_V2_BLS_UNLOCKED		2
++
++#define NFC_V2_SP_EN			(1 << 2)
++
++#define NFC_INT_MSK			(1 << 4)
++
++#define NFMS_NF_DWIDTH 0
++#define NFMS_NF_PG_SZ  1
++#define NFC_SPAS_WIDTH 8
++#define NFC_SPAS_SHIFT 16
++
++#define NFC_V21_SPAS_SHIFT		(0)
++#define NFC_V21_SPAS_MASK	(0xFF00)
++
++struct mxc_nand_host {
++	struct mtd_info		mtd;
++	struct nand_chip	nand;
++	struct mtd_partition	*parts;
++	struct device		*dev;
++
++	int			version;
++	void			*spare0;
++	int			spare_len;
++	int			spare_size;
++	void			*main_area0;
++	void			*main_area1;
++	void __iomem		*base;
++	void __iomem		*regs;
++
++	int			status_request;
++
++	unsigned int		buf_start;
++
++	wait_queue_head_t	irq_waitq;
++	int			g_page_mask;
++
++	struct clk		*clk;
++	int			clk_enabled;
++
++	uint8_t			*data_buf;
++
++	int			irq;
++};
++
++/* Define delays in microsec for NAND device operations */
++#define TROP_US_DELAY   2000
++
++/*
++ * OOB placement block for use with hardware ecc generation
++ */
++static struct nand_ecclayout nand_hw_eccoob_512 = {
++	.eccbytes = 9,
++	.eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15},
++	.oobavail = 4,
++	.oobfree = {{0, 4}}
++};
++
++static struct nand_ecclayout nand_hw_eccoob_2k = {
++	.eccbytes = 9,
++	.eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15},
++	.oobavail = 4,
++	.oobfree = {{2, 4}}
++};
++
++static struct nand_ecclayout nand_hw_eccoob_4k = {
++	.eccbytes = 9,
++	.eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15},
++	.oobavail = 4,
++	.oobfree = {{2, 4}}
++};
++
++#ifdef CONFIG_MTD_PARTITIONS
++static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL };
++#endif
++
++static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
++{
++	struct mxc_nand_host *host = dev_id;
++
++	uint16_t tmp;
++
++	tmp = readw(host->regs + NFC_CONFIG1);
++	tmp |= NFC_INT_MSK; /* Disable interrupt */
++	writew(tmp, host->regs + NFC_CONFIG1);
++
++	wake_up(&host->irq_waitq);
++
++	return IRQ_HANDLED;
++}
++
++/* This function polls the NANDFC to wait for the basic operation to
++ * complete by checking the INT bit of config2 register.
++ */
++static void wait_op_done(struct mxc_nand_host *host, int max_retries,
++				int useirq)
++{
++	uint32_t tmp;
++
++	if (useirq) {
++		if ((readw(host->regs + NFC_CONFIG2) & NFC_INT) == 0) {
++
++			tmp = readw(host->regs + NFC_CONFIG1);
++			tmp  &= ~NFC_INT_MSK;	/* Enable interrupt */
++			writew(tmp, host->regs + NFC_CONFIG1);
++
++			wait_event(host->irq_waitq,
++				readw(host->regs + NFC_CONFIG2) & NFC_INT);
++
++			tmp = readw(host->regs + NFC_CONFIG2);
++			tmp  &= ~NFC_INT;
++			writew(tmp, host->regs + NFC_CONFIG2);
++		}
++	} else {
++		while (max_retries-- > 0) {
++			if (readw(host->regs + NFC_CONFIG2) & NFC_INT) {
++				tmp = readw(host->regs + NFC_CONFIG2);
++				tmp &= ~NFC_INT;
++				writew(tmp, host->regs + NFC_CONFIG2);
++				break;
++			}
++			udelay(1);
++		}
++		if (max_retries <= 0) {
++			printk("%s timed out: 0x%04x\n", __func__, readw(host->regs + NFC_CONFIG2));
++			BUG();
++		}
++	}
++}
++
++/* This function issues the specified command to the NAND device and
++ * waits for completion. */
++static void send_cmd(struct mxc_nand_host *host, uint16_t cmd, int useirq)
++{
++	DEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x, %d)\n", cmd, useirq);
++
++	writew(cmd, host->regs + NFC_FLASH_CMD);
++	writew(NFC_CMD, host->regs + NFC_CONFIG2);
++
++	/* Wait for operation to complete */
++	wait_op_done(host, TROP_US_DELAY, useirq);
++}
++
++/*
++ * This function sends an address (or partial address) to the
++ * NAND device.  The address is used to select the source/destination for
++ * a NAND command.
++ */
++static void send_addr(struct mxc_nand_host *host, u16 addr)
++{
++	DEBUG(MTD_DEBUG_LEVEL3, "send_addr(0x%x)\n", addr);
++
++	writew(addr, host->regs + NFC_FLASH_ADDR);
++	writew(NFC_ADDR, host->regs + NFC_CONFIG2);
++
++	/* Wait for operation to complete */
++	wait_op_done(host, TROP_US_DELAY, 0);
++}
++
++/*
++ * This function requests the NFC to initate the transfer
++ * of data currently in the NFC RAM buffer to the NAND device.
++ *
++ */
++static void send_page(struct mtd_info *mtd, unsigned int ops)
++{
++	struct nand_chip *this = mtd->priv;
++	struct mxc_nand_host *host = this->priv;
++	int bufs, i;
++
++	if (nfc_is_v2x() && mtd->writesize > 512)
++		bufs = 4;
++	else
++		bufs = 1;
++
++	for (i = 0; i < bufs; i++) {
++
++		/* set ram buffer id */
++		writew(i, host->regs + NFC_SET_RBA);
++
++		/* transfer data from NFC ram to nand */
++		writew(ops, host->regs + NFC_CONFIG2);
++
++		/* Wait for operation to complete */
++		wait_op_done(host, TROP_US_DELAY, false);
++	}
++}
++
++/* This function requests the NANDFC to perform a read of the
++ * NAND device status and returns the current status. */
++static uint16_t get_dev_status(struct mxc_nand_host *host)
++{
++	uint16_t ret;
++
++	/* Set ram buffer id */
++	writew(1, host->regs + NFC_SET_RBA);
++
++	/* Read status into main buffer */
++	writew(NFC_STATUS, host->regs + NFC_CONFIG2);
++
++	/* Wait for operation to complete */
++	wait_op_done(host, TROP_US_DELAY, true);
++
++	/* Status is placed in first word of main buffer */
++	/* get status, then recovery area 1 data */
++	ret = readw(host->main_area1);
++
++	return ret;
++}
++
++static void mxc_nand_hwecc(struct mxc_nand_host *host, int on)
++{
++	unsigned int tmp;
++
++	tmp = readw(host->regs + NFC_CONFIG1);
++
++	if (on)
++		tmp |= NFC_ECC_EN;
++	else
++		tmp &= ~NFC_ECC_EN;
++
++	writew(tmp, host->regs + NFC_CONFIG1);
++}
++
++static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode)
++{
++	struct nand_chip *this = mtd->priv;
++	struct mxc_nand_host *host = this->priv;
++
++	mxc_nand_hwecc(host, 1);
++	return;
++}
++
++/*
++ * Function to correct the detected errors. This NFC corrects all the errors
++ * detected. So this function just return 0.
++ */
++static int mxc_nand_correct_data(struct mtd_info *mtd, u_char * dat,
++				 u_char * read_ecc, u_char * calc_ecc)
++{
++	return 0;
++}
++
++/*
++ * Function to calculate the ECC for the data to be stored in the Nand device.
++ * This NFC has a hardware RS(511,503) ECC engine together with the RS ECC
++ * CONTROL blocks are responsible for detection  and correction of up to
++ * 8 symbols of 9 bits each in 528 byte page.
++ * So this function is just return 0.
++ */
++static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
++				  u_char *ecc_code)
++{
++	return 0;
++}
++
++static uint8_t mxc_nand_read_byte(struct mtd_info *mtd)
++{
++	struct nand_chip *this = mtd->priv;
++	struct mxc_nand_host *host = this->priv;
++	uint8_t ret;
++
++	/* Check for status request */
++	if (host->status_request)
++		return get_dev_status(host) & 0xff;
++
++	ret = *(uint8_t *)(host->data_buf + host->buf_start);
++	host->buf_start++;
++
++	return ret;
++}
++
++static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
++{
++	struct nand_chip *nand_chip = mtd->priv;
++	struct mxc_nand_host *host = nand_chip->priv;
++	uint16_t ret;
++
++	ret = *(uint16_t *)(host->data_buf + host->buf_start);
++	host->buf_start += 2;
++
++	return ret;
++}
++
++/* Write data of length len to buffer buf. The data to be
++ * written on NAND Flash is first copied to RAMbuffer. After the Data Input
++ * Operation by the NFC, the data is written to NAND Flash */
++static void mxc_nand_write_buf(struct mtd_info *mtd,
++				const u_char *buf, int len)
++{
++	struct nand_chip *nand_chip = mtd->priv;
++	struct mxc_nand_host *host = nand_chip->priv;
++	u16 col = host->buf_start;
++	int n = mtd->oobsize + mtd->writesize - col;
++
++	n = min(n, len);
++
++	memcpy(host->data_buf + col, buf, n);
++
++	host->buf_start += n;
++}
++
++/* Read the data buffer from the NAND Flash. To read the data from NAND
++ * Flash first the data output cycle is initiated by the NFC, which copies
++ * the data to RAMbuffer. This data of length len is then copied to buffer buf.
++ */
++static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++{
++	struct nand_chip *nand_chip = mtd->priv;
++	struct mxc_nand_host *host = nand_chip->priv;
++	u16 col = host->buf_start;
++	int n = mtd->oobsize + mtd->writesize - col;
++
++	n = min(n, len);
++
++	memcpy(buf, host->data_buf + col, len);
++
++	host->buf_start += len;
++}
++
++/* Used by the upper layer to verify the data in NAND Flash
++ * with the data in the buf. */
++static int mxc_nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf,
++			       int len)
++{
++	struct nand_chip *this = mtd->priv;
++	struct mxc_nand_host *host = this->priv;
++
++	return memcmp(buf, host->data_buf, len) ? -EFAULT : 0;
++}
++
++/* This function is used by upper layer for select and
++ * deselect of the NAND chip */
++static void mxc_nand_select_chip(struct mtd_info *mtd, int chip)
++{
++	struct nand_chip *nand_chip = mtd->priv;
++	struct mxc_nand_host *host = nand_chip->priv;
++
++	switch (chip) {
++	case -1:
++		if (host->clk_enabled) {
++			clk_disable(host->clk);
++			host->clk_enabled = 0;
++		}
++		break;
++	case 0 ... 7:
++		if (!host->clk_enabled) {
++			clk_enable(host->clk);
++			host->clk_enabled = 1;
++		}
++		break;
++
++	default:
++		break;
++	}
++}
++
++/*
++ * Function to transfer data to/from spare area.
++ */
++static void copy_spare(struct mtd_info *mtd, bool bfrom)
++{
++	struct nand_chip *this = mtd->priv;
++	struct mxc_nand_host *host = this->priv;
++	u16 i, j;
++	u16 n = mtd->writesize >> 9;
++	u8 *d = host->data_buf + mtd->writesize;
++	u8 *s = host->spare0;
++	u16 t = host->spare_len;
++
++	j = (mtd->oobsize / n >> 1) << 1;
++
++	if (bfrom) {
++		for (i = 0; i < n - 1; i++)
++			memcpy(d + i * j, s + i * t, j);
++
++		/* the last section */
++		memcpy(d + i * j, s + i * t, mtd->oobsize - i * j);
++	} else {
++		for (i = 0; i < n - 1; i++)
++			memcpy(&s[i * t], &d[i * j], j);
++
++		/* the last section */
++		memcpy(&s[i * t], &d[i * j], mtd->oobsize - i * j);
++	}
++}
++
++#define NFC_V2_ECC_MODE_4    		 (1 << 0)
++
++#define NFC_SPAS_16			8
++#define NFC_SPAS_64		 	32
++#define NFC_SPAS_128			64
++#define NFC_SPAS_218		 	109
++#define NFC_IPC_CREQ			(1 << 0)
++#define NFC_IPC_ACK			(1 << 1)
++
++/*
++ * Function to perform the address cycles.
++ */
++static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
++{
++	struct nand_chip *nand_chip = mtd->priv;
++	struct mxc_nand_host *host = nand_chip->priv;
++
++	u32 page_mask = host->g_page_mask;
++
++	if (column != -1) {
++		send_addr(host, column & 0xFF);
++		if (mtd->writesize == 2048) {
++			/* another col addr cycle for 2k page */
++			send_addr(host, (column >> 8) & 0xF);
++		} else if (mtd->writesize == 4096) {
++			/* another col addr cycle for 4k page */
++			send_addr(host, (column >> 8) & 0x1F);
++		}
++	}
++	if (page_addr != -1) {
++		do {
++			send_addr(host, (page_addr & 0xff));
++			page_mask >>= 8;
++			page_addr >>= 8;
++		} while (page_mask != 0);
++	}
++}
++
++/*
++ * Function to record the ECC corrected/uncorrected errors resulted
++ * after a page read. This NFC detects and corrects upto to 4 symbols
++ * of 9-bits each.
++ */
++
++static int mxc_check_ecc_status(struct mtd_info *mtd)
++{
++	struct nand_chip *this = mtd->priv;
++	struct mxc_nand_host *host = this->priv;
++	u32 ecc_stat, err;
++	int no_subpages = 1;
++	int ret = 0, is_4bit_ecc = 0;
++	u8 ecc_bit_mask, err_limit;
++
++	if (nfc_is_v21()) {
++		is_4bit_ecc = readw(host->regs + NFC_CONFIG1) & NFC_V2_ECC_MODE_4;
++		ecc_stat = readw(host->regs + NFC_ECC_STATUS_RESULT);
++	} else if (nfc_is_v2x()) {
++		is_4bit_ecc = 1;
++		ecc_stat = readw(host->regs + NFC_ECC_STATUS_RESULT);
++	} else
++		BUG();
++
++	ecc_bit_mask = is_4bit_ecc ? 0x7 : 0xf;
++	err_limit = is_4bit_ecc ? 0x4 : 0x8;
++
++	no_subpages = mtd->writesize >> 9;
++
++	do {
++		err = ecc_stat & ecc_bit_mask;
++		if (err > err_limit) {
++			mtd->ecc_stats.failed++;
++			printk(KERN_WARNING "uncorrectable RS-ECC Error\n");
++			return -1;
++		} else {
++			ret += err;
++		}
++		ecc_stat >>= 4;
++	} while (--no_subpages);
++
++	mtd->ecc_stats.corrected += ret;
++	pr_debug("%d Symbol Correctable RS-ECC Error\n", ret);
++
++	return ret;
++}
++
++/*
++ * This function reads byte from the NAND Flash
++ *
++ * @param     mtd     MTD structure for the NAND Flash
++ *
++ * @return    data read from the NAND Flash
++ */
++static u_char mxc_nand_read_byte16(struct mtd_info *mtd)
++{
++	struct nand_chip *this = mtd->priv;
++	struct mxc_nand_host *host = this->priv;
++
++	if (host->status_request)
++		return get_dev_status(host) & 0xff;
++
++	return mxc_nand_read_word(mtd) & 0xff;
++}
++
++/* Used by the upper layer to write command to NAND Flash for
++ * different operations to be carried out on NAND Flash */
++static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
++			     int column, int page_addr)
++{
++	struct nand_chip *nand_chip = mtd->priv;
++	struct mxc_nand_host *host = nand_chip->priv;
++
++	DEBUG(MTD_DEBUG_LEVEL3,
++	      "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",
++	      command, column, page_addr);
++
++	/*
++	 * Reset command state information
++	 */
++	host->status_request = false;
++
++	switch (command) {
++
++	case NAND_CMD_STATUS:
++		host->buf_start = 0;
++		host->status_request = true;
++
++		send_cmd(host, command, true);
++		mxc_do_addr_cycle(mtd, column, page_addr);
++		break;
++
++	case NAND_CMD_READOOB:
++		command = NAND_CMD_READ0;
++		/* Fallthrough */
++
++	case NAND_CMD_READ0:
++		host->buf_start = column;
++
++		send_cmd(host, command, false);
++		mxc_do_addr_cycle(mtd, column, page_addr);
++
++		if (mtd->writesize > 512)
++			/* send read confirm command */
++			send_cmd(host, NAND_CMD_READSTART, true);
++
++		send_page(mtd, NFC_OUTPUT);
++
++		memcpy(host->data_buf, host->main_area0, mtd->writesize);
++		copy_spare(mtd, true);
++
++		break;
++
++	case NAND_CMD_SEQIN:
++
++		/* FIXME: before send SEQIN command for
++		 * partial write,We need read one page out.
++		 * FSL NFC does not support partial write
++		 * It always sends out 512 + ecc + 512 + ecc ...
++		 * for large page nand flash. But for small
++		 * page nand flash, it did support SPARE
++		 * ONLY operation. But to make driver
++		 * simple. We take the same as large page,read
++		 * whole page out and update. As for MLC nand
++		 * NOP(num of operation) = 1. Partial written
++		 * on one programed page is not allowed! We
++		 * can't limit it on the driver, it need the
++		 * upper layer applicaiton take care it
++		 */
++
++		if (column)
++			mxc_nand_command(mtd, NAND_CMD_READ0, 0, page_addr);
++
++		host->buf_start = column;
++		send_cmd(host, command, false);
++		mxc_do_addr_cycle(mtd, column, page_addr);
++		break;
++
++	case NAND_CMD_PAGEPROG:
++		memcpy(host->main_area0, host->data_buf, mtd->writesize);
++		copy_spare(mtd, false);
++
++		send_page(mtd, NFC_INPUT);
++
++		send_cmd(host, command, true);
++		mxc_do_addr_cycle(mtd, column, page_addr);
++		break;
++
++	case NAND_CMD_ERASE1:
++	case NAND_CMD_ERASE2:
++		send_cmd(host, command, false);
++		mxc_do_addr_cycle(mtd, column, page_addr);
++		break;
++
++	case NAND_CMD_READID:
++		send_cmd(host, command, true);
++		mxc_do_addr_cycle(mtd, column, page_addr);
++		/* Set RBA bits for BUFFER0 */
++		writew(0, host->regs + NFC_SET_RBA);
++
++		/* Read ID into main buffer */
++		writew(NFC_ID, host->regs + NFC_CONFIG2);
++
++		wait_op_done(host, TROP_US_DELAY, true);
++		host->buf_start = column;
++		memcpy(host->data_buf, host->main_area0, 2048);
++		break;
++
++	case NAND_CMD_RESET:
++		send_cmd(host, command, true);
++		mxc_do_addr_cycle(mtd, column, page_addr);
++		break;
++	}
++}
++
++static int mxc_nand_read_oob(struct mtd_info *mtd,
++			     struct nand_chip *chip, int page, int sndcmd)
++{
++	struct nand_chip *this = mtd->priv;
++	struct mxc_nand_host *host = this->priv;
++
++	if (sndcmd) {
++		chip->cmdfunc(mtd, NAND_CMD_READOOB, 0x00, page);
++		sndcmd = 0;
++	}
++
++	memcpy(chip->oob_poi, host->data_buf + mtd->writesize, mtd->oobsize);
++
++	return sndcmd;
++}
++
++static int mxc_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
++			      uint8_t *buf)
++{
++	struct nand_chip *this = mtd->priv;
++	struct mxc_nand_host *host = this->priv;
++
++	mxc_check_ecc_status(mtd);
++
++	memcpy(buf, host->data_buf, mtd->writesize);
++	memcpy(chip->oob_poi, host->data_buf + mtd->writesize, mtd->oobsize);
++
++	return 0;
++}
++
++static void mxc_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++				const uint8_t *buf)
++{
++	struct nand_chip *this = mtd->priv;
++	struct mxc_nand_host *host = this->priv;
++
++	memcpy(host->data_buf, buf, mtd->writesize);
++	memcpy(host->data_buf + mtd->writesize, chip->oob_poi, mtd->oobsize);
++}
++
++/* Define some generic bad / good block scan pattern which are used
++ * while scanning a device for factory marked good / bad blocks. */
++static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
++
++static struct nand_bbt_descr smallpage_memorybased = {
++	.options = NAND_BBT_SCAN2NDPAGE,
++	.offs = 5,
++	.len = 1,
++	.pattern = scan_ff_pattern
++};
++
++static struct nand_bbt_descr largepage_memorybased = {
++	.options = 0,
++	.offs = 0,
++	.len = 2,
++	.pattern = scan_ff_pattern
++};
++
++/* Generic flash bbt decriptors
++*/
++static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
++static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' };
++
++static struct nand_bbt_descr bbt_main_descr = {
++	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++	    | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
++	.offs = 0,
++	.len = 4,
++	.veroffs = 4,
++	.maxblocks = 4,
++	.pattern = bbt_pattern
++};
++
++static struct nand_bbt_descr bbt_mirror_descr = {
++	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++	    | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
++	.offs = 0,
++	.len = 4,
++	.veroffs = 4,
++	.maxblocks = 4,
++	.pattern = mirror_pattern
++};
++
++static void mxc_set_nfms_v21(struct mtd_info *mtd, unsigned int val)
++{
++	struct nand_chip *this = mtd->priv;
++	struct mxc_nand_host *host = this->priv;
++	unsigned int spas, tmp;
++
++//	NFMS |= val; /* FIXME */
++
++	if (val & (1 << NFMS_NF_PG_SZ)) {
++		if (mtd->writesize == 2048)
++			spas = NFC_SPAS_64;
++		else if (mtd->writesize == 4096)
++			spas = NFC_SPAS_128;
++		else
++			spas = NFC_SPAS_16;
++
++		tmp = readw(host->regs + NFC_CONFIG1);
++		tmp |= NFC_V2_ECC_MODE_4;
++		writew(tmp, host->regs + NFC_CONFIG1);
++
++		tmp = readw(host->regs + NFC_V21_SPAS);
++		tmp &= NFC_V21_SPAS_MASK;
++		tmp |= spas << NFC_V21_SPAS_SHIFT;
++		writew(tmp, host->regs + NFC_V21_SPAS);
++	}
++}
++
++static void mxc_set_nfms(struct mtd_info *mtd, unsigned int val)
++{
++	if (nfc_is_v21())
++		mxc_set_nfms_v21(mtd, val);
++}
++
++static int mxc_nand_scan_bbt(struct mtd_info *mtd)
++{
++	struct nand_chip *this = mtd->priv;
++	struct mxc_nand_host *host = this->priv;
++
++	host->g_page_mask = this->pagemask;
++
++	if (mtd->writesize == 2048) {
++		mxc_set_nfms(mtd, 1 << NFMS_NF_PG_SZ);
++		this->ecc.layout = &nand_hw_eccoob_2k;
++	} else if (mtd->writesize == 4096) {
++		mxc_set_nfms(mtd, 1 << NFMS_NF_PG_SZ);
++		this->ecc.layout = &nand_hw_eccoob_4k;
++	} else {
++		this->ecc.layout = &nand_hw_eccoob_512;
++	}
++
++	/* propagate ecc.layout to mtd_info */
++	mtd->ecclayout = this->ecc.layout;
++
++	/* use flash based bbt */
++	this->bbt_td = &bbt_main_descr;
++	this->bbt_md = &bbt_mirror_descr;
++
++	/* update flash based bbt */
++	this->options |= NAND_USE_FLASH_BBT;
++
++	if (!this->badblock_pattern) {
++		this->badblock_pattern = (mtd->writesize > 512) ?
++		    &largepage_memorybased : &smallpage_memorybased;
++	}
++
++	/* Build bad block table */
++	return nand_scan_bbt(mtd, this->badblock_pattern);
++}
++
++static void unlock_addr(struct mxc_nand_host *host, unsigned int start_addr, unsigned int end_addr)
++{
++	if (nfc_is_v21()) {
++		writew(start_addr, host->regs + NFC_V21_UNLOCKSTART_BLKADDR);
++	        writew(end_addr, host->regs + NFC_V21_UNLOCKEND_BLKADDR);
++	} else if (nfc_is_v2x()) {
++		writew(start_addr, host->regs + NFC_V1_UNLOCKSTART_BLKADDR);
++	        writew(end_addr, host->regs + NFC_V1_UNLOCKEND_BLKADDR);
++	} else
++		BUG();
++}
++
++static int __init mxcnd_probe(struct platform_device *pdev)
++{
++	struct nand_chip *this;
++	struct mtd_info *mtd;
++	struct mxc_nand_platform_data *pdata = pdev->dev.platform_data;
++	struct mxc_nand_host *host;
++	int nr_parts = 0, err = 0;
++	struct resource *res;
++
++	/* Allocate memory for MTD device structure and private data */
++	host = kzalloc(sizeof(*host) + NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE, GFP_KERNEL);
++	if (!host)
++		return -ENOMEM;
++
++	host->data_buf = (uint8_t *)(host + 1);
++
++	host->dev = &pdev->dev;
++
++	this = &host->nand;
++	mtd = &host->mtd;
++	mtd->priv = this;
++	mtd->owner = THIS_MODULE;
++	mtd->name = "mxc_nand";
++
++	this->priv = host;
++	this->cmdfunc = mxc_nand_command;
++	this->select_chip = mxc_nand_select_chip;
++	this->read_byte = mxc_nand_read_byte;
++	this->read_word = mxc_nand_read_word;
++	this->write_buf = mxc_nand_write_buf;
++	this->read_buf = mxc_nand_read_buf;
++	this->verify_buf = mxc_nand_verify_buf;
++	this->scan_bbt = mxc_nand_scan_bbt;
++
++	host->clk = clk_get(&pdev->dev, "nfc_clk");
++	if (IS_ERR(host->clk)) {
++		err = PTR_ERR(host->clk);
++		goto eclk;
++	}
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		err = -ENODEV;
++		goto eres;
++	}
++
++	host->base = ioremap(res->start, resource_size(res));
++	if (!host->base) {
++		err = -EIO;
++		goto eres;
++	}
++
++	host->main_area0 = host->base;
++	host->main_area1 = host->base + 0x200;
++
++	if (nfc_is_v21()) {
++		host->regs = host->base + 0x1000;
++		host->spare0 = host->base + 0x1000;
++		host->spare_size = 64 * 8;
++		host->spare_len = 64;
++	} else if (nfc_is_v2x()) {
++		host->regs = host->base;
++		host->spare0 = host->base + 0x800;
++		host->spare_size = 16 * 4;
++		host->spare_len = 16;
++	} else
++		BUG();
++
++	/* NAND bus width determines access funtions used by upper layer */
++	if (pdata->width == 2) {
++		this->read_byte = mxc_nand_read_byte16;
++		this->options |= NAND_BUSWIDTH_16;
++		mxc_set_nfms(mtd, 1 << NFMS_NF_DWIDTH);
++	}
++
++	init_waitqueue_head(&host->irq_waitq);
++
++	host->irq = platform_get_irq(pdev, 0);
++
++	err = request_irq(host->irq, mxc_nfc_irq, 0, "mxc_nd", host);
++	if (err)
++		goto eirq;
++
++	if (pdata->hw_ecc) {
++		this->ecc.read_page = mxc_nand_read_page;
++		this->ecc.write_page = mxc_nand_write_page;
++		this->ecc.read_oob = mxc_nand_read_oob;
++		this->ecc.layout = &nand_hw_eccoob_512;
++		this->ecc.calculate = mxc_nand_calculate_ecc;
++		this->ecc.hwctl = mxc_nand_enable_hwecc;
++		this->ecc.correct = mxc_nand_correct_data;
++		this->ecc.mode = NAND_ECC_HW;
++		this->ecc.size = 512;
++		this->ecc.bytes = 9;
++		mxc_nand_hwecc(host, 1);
++	} else {
++		this->ecc.mode = NAND_ECC_SOFT;
++		mxc_nand_hwecc(host, 0);
++	}
++
++	clk_enable(host->clk);
++
++	/* Disable interrupt */
++	writew(readw(host->regs + NFC_CONFIG1) | NFC_INT_MSK, host->regs + NFC_CONFIG1);
++
++	/* disable spare enable */
++	writew(readw(host->regs + NFC_CONFIG1) & ~NFC_V2_SP_EN, host->regs + NFC_CONFIG1);
++
++	/* Unlock the internal RAM Buffer */
++	writew(NFC_V2_BLS_UNLOCKED, host->regs + NFC_BLS);
++
++	/* Blocks to be unlocked */
++	unlock_addr(host, 0x0, 0xFFFF);
++
++	/* Unlock Block Command for given address range */
++	writew(NFC_WPC_UNLOCK, host->regs + NFC_WR_PROT);
++
++	clk_disable(host->clk);
++
++	/* Scan to find existence of the device */
++	if (nand_scan(mtd, 1)) {
++		DEBUG(MTD_DEBUG_LEVEL0,
++		      "MXC_ND2: Unable to find any NAND device.\n");
++		err = -ENXIO;
++		goto escan;
++	}
++
++	/* Register the partitions */
++#ifdef CONFIG_MTD_PARTITIONS
++	nr_parts =
++	    parse_mtd_partitions(mtd, part_probes, &host->parts, 0);
++	if (nr_parts > 0)
++		add_mtd_partitions(mtd, host->parts, nr_parts);
++	else
++#endif
++	{
++		pr_info("Registering %s as whole device\n", mtd->name);
++		add_mtd_device(mtd);
++	}
++
++	platform_set_drvdata(pdev, mtd);
++
++	return 0;
++
++escan:
++	free_irq(host->irq, NULL);
++eirq:
++	iounmap(host->regs);
++eres:
++	clk_put(host->clk);
++eclk:
++	kfree(host);
++
++	return err;
++
++}
++
++static int __exit mxcnd_remove(struct platform_device *pdev)
++{
++	struct mtd_info *mtd = platform_get_drvdata(pdev);
++	struct nand_chip *this = mtd->priv;
++	struct mxc_nand_host *host = this->priv;
++
++	clk_disable(host->clk);
++	clk_put(host->clk);
++	platform_set_drvdata(pdev, NULL);
++
++	nand_release(mtd);
++	free_irq(host->irq, NULL);
++	kfree(host);
++
++	return 0;
++}
++
++#ifdef CONFIG_PM
++static int mxcnd_suspend(struct platform_device *pdev, pm_message_t state)
++{
++	struct mtd_info *mtd = platform_get_drvdata(pdev);
++	struct nand_chip *this = mtd->priv;
++	struct mxc_nand_host *host = this->priv;
++	int ret = 0;
++
++	if (mtd)
++		ret = mtd->suspend(mtd);
++
++	/* Disable the NFC clock */
++	clk_disable(host->clk);
++
++	return ret;
++}
++
++static int mxcnd_resume(struct platform_device *pdev)
++{
++	struct mtd_info *mtd = platform_get_drvdata(pdev);
++	struct nand_chip *this = mtd->priv;
++	struct mxc_nand_host *host = this->priv;
++
++	/* Enable the NFC clock */
++	clk_enable(host->clk);
++
++	if (mtd)
++		mtd->resume(mtd);
++
++	return 0;
++}
++
++#else
++#define mxcnd_suspend   NULL
++#define mxcnd_resume    NULL
++#endif				/* CONFIG_PM */
++
++static struct platform_driver mxcnd_driver = {
++	.driver = {
++		   .name = "mxc_nand",
++		   },
++	.probe = mxcnd_probe,
++	.remove = __exit_p(mxcnd_remove),
++	.suspend = mxcnd_suspend,
++	.resume = mxcnd_resume,
++};
++
++static int __init mxc_nd_init(void)
++{
++	/* Register the device driver structure. */
++	pr_info("MXC MTD nand Driver\n");
++	if (platform_driver_register(&mxcnd_driver) != 0) {
++		printk(KERN_ERR "Driver register failed for mxcnd_driver\n");
++		return -ENODEV;
++	}
++	return 0;
++}
++
++static void __exit mxc_nd_cleanup(void)
++{
++	/* Unregister the device structure */
++	platform_driver_unregister(&mxcnd_driver);
++}
++
++module_init(mxc_nd_init);
++module_exit(mxc_nd_cleanup);
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("MXC NAND MTD driver");
++MODULE_LICENSE("GPL");
diff --git a/recipes/linux/linux-2.6.31/pcm043/0001-spi-add-SPI-driver-for-most-known-i.MX-SoCs.patch b/recipes/linux/linux-2.6.31/pcm043/0001-spi-add-SPI-driver-for-most-known-i.MX-SoCs.patch
new file mode 100644
index 0000000..19981d6
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0001-spi-add-SPI-driver-for-most-known-i.MX-SoCs.patch
@@ -0,0 +1,2337 @@
+From 9cb993fcb56f4033b6336c88e3f45bdd990403cd Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Tue, 22 Sep 2009 16:45:56 -0700
+Subject: [PATCH 01/28] spi: add SPI driver for most known i.MX SoCs
+
+This driver has been tested on i.MX1/i.MX27/i.MX35 with an AT25 type
+EEPROM and on i.MX27/i.MX31 with a Freescale MC13783 PMIC.
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+Tested-by: Guennadi Liakhovetski <g.liakhovetski at gmx.de>
+Acked-by: David Brownell <david-b at pacbell.net>
+Cc: Andrea Paterniani <a.paterniani at swapp-eng.it>
+Cc: Russell King <rmk at arm.linux.org.uk>
+Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
+---
+ arch/arm/plat-mxc/include/mach/spi.h |   27 +
+ drivers/spi/Kconfig                  |    7 +-
+ drivers/spi/spi_imx.c                | 2060 ++++++++--------------------------
+ 3 files changed, 516 insertions(+), 1578 deletions(-)
+ create mode 100644 arch/arm/plat-mxc/include/mach/spi.h
+
+diff --git a/arch/arm/plat-mxc/include/mach/spi.h b/arch/arm/plat-mxc/include/mach/spi.h
+new file mode 100644
+index 0000000..08be445
+--- /dev/null
++++ b/arch/arm/plat-mxc/include/mach/spi.h
+@@ -0,0 +1,27 @@
++
++#ifndef __MACH_SPI_H_
++#define __MACH_SPI_H_
++
++/*
++ * struct spi_imx_master - device.platform_data for SPI controller devices.
++ * @chipselect: Array of chipselects for this master. Numbers >= 0 mean gpio
++ *              pins, numbers < 0 mean internal CSPI chipselects according
++ *              to MXC_SPI_CS(). Normally you want to use gpio based chip
++ *              selects as the CSPI module tries to be intelligent about
++ *              when to assert the chipselect: The CSPI module deasserts the
++ *              chipselect once it runs out of input data. The other problem
++ *              is that it is not possible to mix between high active and low
++ *              active chipselects on one single bus using the internal
++ *              chipselects. Unfortunately Freescale decided to put some
++ *              chipselects on dedicated pins which are not usable as gpios,
++ *              so we have to support the internal chipselects.
++ * @num_chipselect: ARRAY_SIZE(chipselect)
++ */
++struct spi_imx_master {
++	int	*chipselect;
++	int	num_chipselect;
++};
++
++#define MXC_SPI_CS(no)	((no) - 32)
++
++#endif /* __MACH_SPI_H_*/
+diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
+index 2c733c2..885d6c4 100644
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -117,10 +117,11 @@ config SPI_GPIO
+ 	  speed with a custom version of this driver; see the source code.
+ 
+ config SPI_IMX
+-	tristate "Freescale iMX SPI controller"
+-	depends on ARCH_MX1 && EXPERIMENTAL
++	tristate "Freescale i.MX SPI controllers"
++	depends on ARCH_MXC
++	select SPI_BITBANG
+ 	help
+-	  This enables using the Freescale iMX SPI controller in master
++	  This enables using the Freescale i.MX SPI controllers in master
+ 	  mode.
+ 
+ config SPI_LM70_LLP
+diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c
+index c195e45..89c22ef 100644
+--- a/drivers/spi/spi_imx.c
++++ b/drivers/spi/spi_imx.c
+@@ -1,1770 +1,680 @@
+ /*
+- * drivers/spi/spi_imx.c
+- *
+- * Copyright (C) 2006 SWAPP
+- *	Andrea Paterniani <a.paterniani at swapp-eng.it>
+- *
+- * Initial version inspired by:
+- *	linux-2.6.17-rc3-mm1/drivers/spi/pxa2xx_spi.c
+- *
+- * 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.
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Copyright (C) 2008 Juergen Beisert
+  *
++ * 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
++ * 51 Franklin Street, Fifth Floor
++ * Boston, MA  02110-1301, USA.
+  */
+ 
++#include <linux/clk.h>
++#include <linux/completion.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/gpio.h>
+ #include <linux/init.h>
+-#include <linux/module.h>
+-#include <linux/device.h>
+-#include <linux/ioport.h>
+-#include <linux/errno.h>
+ #include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/irq.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
+ #include <linux/platform_device.h>
+-#include <linux/dma-mapping.h>
+ #include <linux/spi/spi.h>
+-#include <linux/workqueue.h>
+-#include <linux/delay.h>
+-#include <linux/clk.h>
++#include <linux/spi/spi_bitbang.h>
++#include <linux/types.h>
+ 
+-#include <asm/io.h>
+-#include <asm/irq.h>
+-#include <asm/delay.h>
+-
+-#include <mach/hardware.h>
+-#include <mach/imx-dma.h>
+-#include <mach/spi_imx.h>
+-
+-/*-------------------------------------------------------------------------*/
+-/* SPI Registers offsets from peripheral base address */
+-#define SPI_RXDATA		(0x00)
+-#define SPI_TXDATA		(0x04)
+-#define SPI_CONTROL		(0x08)
+-#define SPI_INT_STATUS		(0x0C)
+-#define SPI_TEST		(0x10)
+-#define SPI_PERIOD		(0x14)
+-#define SPI_DMA			(0x18)
+-#define SPI_RESET		(0x1C)
+-
+-/* SPI Control Register Bit Fields & Masks */
+-#define SPI_CONTROL_BITCOUNT_MASK	(0xF)		/* Bit Count Mask */
+-#define SPI_CONTROL_BITCOUNT(n)		(((n) - 1) & SPI_CONTROL_BITCOUNT_MASK)
+-#define SPI_CONTROL_POL			(0x1 << 4)      /* Clock Polarity Mask */
+-#define SPI_CONTROL_POL_ACT_HIGH	(0x0 << 4)      /* Active high pol. (0=idle) */
+-#define SPI_CONTROL_POL_ACT_LOW		(0x1 << 4)      /* Active low pol. (1=idle) */
+-#define SPI_CONTROL_PHA			(0x1 << 5)      /* Clock Phase Mask */
+-#define SPI_CONTROL_PHA_0		(0x0 << 5)      /* Clock Phase 0 */
+-#define SPI_CONTROL_PHA_1		(0x1 << 5)      /* Clock Phase 1 */
+-#define SPI_CONTROL_SSCTL		(0x1 << 6)      /* /SS Waveform Select Mask */
+-#define SPI_CONTROL_SSCTL_0		(0x0 << 6)      /* Master: /SS stays low between SPI burst
+-							   Slave: RXFIFO advanced by BIT_COUNT */
+-#define SPI_CONTROL_SSCTL_1		(0x1 << 6)      /* Master: /SS insert pulse between SPI burst
+-							   Slave: RXFIFO advanced by /SS rising edge */
+-#define SPI_CONTROL_SSPOL		(0x1 << 7)      /* /SS Polarity Select Mask */
+-#define SPI_CONTROL_SSPOL_ACT_LOW	(0x0 << 7)      /* /SS Active low */
+-#define SPI_CONTROL_SSPOL_ACT_HIGH	(0x1 << 7)      /* /SS Active high */
+-#define SPI_CONTROL_XCH			(0x1 << 8)      /* Exchange */
+-#define SPI_CONTROL_SPIEN		(0x1 << 9)      /* SPI Module Enable */
+-#define SPI_CONTROL_MODE		(0x1 << 10)     /* SPI Mode Select Mask */
+-#define SPI_CONTROL_MODE_SLAVE		(0x0 << 10)     /* SPI Mode Slave */
+-#define SPI_CONTROL_MODE_MASTER		(0x1 << 10)     /* SPI Mode Master */
+-#define SPI_CONTROL_DRCTL		(0x3 << 11)     /* /SPI_RDY Control Mask */
+-#define SPI_CONTROL_DRCTL_0		(0x0 << 11)     /* Ignore /SPI_RDY */
+-#define SPI_CONTROL_DRCTL_1		(0x1 << 11)     /* /SPI_RDY falling edge triggers input */
+-#define SPI_CONTROL_DRCTL_2		(0x2 << 11)     /* /SPI_RDY active low level triggers input */
+-#define SPI_CONTROL_DATARATE		(0x7 << 13)     /* Data Rate Mask */
+-#define SPI_PERCLK2_DIV_MIN		(0)		/* PERCLK2:4 */
+-#define SPI_PERCLK2_DIV_MAX		(7)		/* PERCLK2:512 */
+-#define SPI_CONTROL_DATARATE_MIN	(SPI_PERCLK2_DIV_MAX << 13)
+-#define SPI_CONTROL_DATARATE_MAX	(SPI_PERCLK2_DIV_MIN << 13)
+-#define SPI_CONTROL_DATARATE_BAD	(SPI_CONTROL_DATARATE_MIN + 1)
+-
+-/* SPI Interrupt/Status Register Bit Fields & Masks */
+-#define SPI_STATUS_TE	(0x1 << 0)	/* TXFIFO Empty Status */
+-#define SPI_STATUS_TH	(0x1 << 1)      /* TXFIFO Half Status */
+-#define SPI_STATUS_TF	(0x1 << 2)      /* TXFIFO Full Status */
+-#define SPI_STATUS_RR	(0x1 << 3)      /* RXFIFO Data Ready Status */
+-#define SPI_STATUS_RH	(0x1 << 4)      /* RXFIFO Half Status */
+-#define SPI_STATUS_RF	(0x1 << 5)      /* RXFIFO Full Status */
+-#define SPI_STATUS_RO	(0x1 << 6)      /* RXFIFO Overflow */
+-#define SPI_STATUS_BO	(0x1 << 7)      /* Bit Count Overflow */
+-#define SPI_STATUS	(0xFF)		/* SPI Status Mask */
+-#define SPI_INTEN_TE	(0x1 << 8)      /* TXFIFO Empty Interrupt Enable */
+-#define SPI_INTEN_TH	(0x1 << 9)      /* TXFIFO Half Interrupt Enable */
+-#define SPI_INTEN_TF	(0x1 << 10)     /* TXFIFO Full Interrupt Enable */
+-#define SPI_INTEN_RE	(0x1 << 11)     /* RXFIFO Data Ready Interrupt Enable */
+-#define SPI_INTEN_RH	(0x1 << 12)     /* RXFIFO Half Interrupt Enable */
+-#define SPI_INTEN_RF	(0x1 << 13)     /* RXFIFO Full Interrupt Enable */
+-#define SPI_INTEN_RO	(0x1 << 14)     /* RXFIFO Overflow Interrupt Enable */
+-#define SPI_INTEN_BO	(0x1 << 15)     /* Bit Count Overflow Interrupt Enable */
+-#define SPI_INTEN	(0xFF << 8)	/* SPI Interrupt Enable Mask */
+-
+-/* SPI Test Register Bit Fields & Masks */
+-#define SPI_TEST_TXCNT		(0xF << 0)	/* TXFIFO Counter */
+-#define SPI_TEST_RXCNT_LSB	(4)		/* RXFIFO Counter LSB */
+-#define SPI_TEST_RXCNT		(0xF << 4)	/* RXFIFO Counter */
+-#define SPI_TEST_SSTATUS	(0xF << 8)	/* State Machine Status */
+-#define SPI_TEST_LBC		(0x1 << 14)	/* Loop Back Control */
+-
+-/* SPI Period Register Bit Fields & Masks */
+-#define SPI_PERIOD_WAIT		(0x7FFF << 0)	/* Wait Between Transactions */
+-#define SPI_PERIOD_MAX_WAIT	(0x7FFF)	/* Max Wait Between
+-							Transactions */
+-#define SPI_PERIOD_CSRC		(0x1 << 15)	/* Period Clock Source Mask */
+-#define SPI_PERIOD_CSRC_BCLK	(0x0 << 15)	/* Period Clock Source is
+-							Bit Clock */
+-#define SPI_PERIOD_CSRC_32768	(0x1 << 15)	/* Period Clock Source is
+-							32.768 KHz Clock */
+-
+-/* SPI DMA Register Bit Fields & Masks */
+-#define SPI_DMA_RHDMA	(0x1 << 4)	/* RXFIFO Half Status */
+-#define SPI_DMA_RFDMA	(0x1 << 5)      /* RXFIFO Full Status */
+-#define SPI_DMA_TEDMA	(0x1 << 6)      /* TXFIFO Empty Status */
+-#define SPI_DMA_THDMA	(0x1 << 7)      /* TXFIFO Half Status */
+-#define SPI_DMA_RHDEN	(0x1 << 12)	/* RXFIFO Half DMA Request Enable */
+-#define SPI_DMA_RFDEN	(0x1 << 13)     /* RXFIFO Full DMA Request Enable */
+-#define SPI_DMA_TEDEN	(0x1 << 14)     /* TXFIFO Empty DMA Request Enable */
+-#define SPI_DMA_THDEN	(0x1 << 15)     /* TXFIFO Half DMA Request Enable */
+-
+-/* SPI Soft Reset Register Bit Fields & Masks */
+-#define SPI_RESET_START	(0x1)		/* Start */
+-
+-/* Default SPI configuration values */
+-#define SPI_DEFAULT_CONTROL		\
+-(					\
+-	SPI_CONTROL_BITCOUNT(16) | 	\
+-	SPI_CONTROL_POL_ACT_HIGH |	\
+-	SPI_CONTROL_PHA_0 |		\
+-	SPI_CONTROL_SPIEN |		\
+-	SPI_CONTROL_SSCTL_1 |		\
+-	SPI_CONTROL_MODE_MASTER |	\
+-	SPI_CONTROL_DRCTL_0 |		\
+-	SPI_CONTROL_DATARATE_MIN	\
+-)
+-#define SPI_DEFAULT_ENABLE_LOOPBACK	(0)
+-#define SPI_DEFAULT_ENABLE_DMA		(0)
+-#define SPI_DEFAULT_PERIOD_WAIT		(8)
+-/*-------------------------------------------------------------------------*/
+-
+-
+-/*-------------------------------------------------------------------------*/
+-/* TX/RX SPI FIFO size */
+-#define SPI_FIFO_DEPTH			(8)
+-#define SPI_FIFO_BYTE_WIDTH		(2)
+-#define SPI_FIFO_OVERFLOW_MARGIN	(2)
+-
+-/* DMA burst length for half full/empty request trigger */
+-#define SPI_DMA_BLR			(SPI_FIFO_DEPTH * SPI_FIFO_BYTE_WIDTH / 2)
+-
+-/* Dummy char output to achieve reads.
+-   Choosing something different from all zeroes may help pattern recogition
+-   for oscilloscope analysis, but may break some drivers. */
+-#define SPI_DUMMY_u8			0
+-#define SPI_DUMMY_u16			((SPI_DUMMY_u8 << 8) | SPI_DUMMY_u8)
+-#define SPI_DUMMY_u32			((SPI_DUMMY_u16 << 16) | SPI_DUMMY_u16)
+-
+-/**
+- * Macro to change a u32 field:
+- * @r : register to edit
+- * @m : bit mask
+- * @v : new value for the field correctly bit-alligned
+-*/
+-#define u32_EDIT(r, m, v)		r = (r & ~(m)) | (v)
+-
+-/* Message state */
+-#define START_STATE			((void*)0)
+-#define RUNNING_STATE			((void*)1)
+-#define DONE_STATE			((void*)2)
+-#define ERROR_STATE			((void*)-1)
+-
+-/* Queue state */
+-#define QUEUE_RUNNING			(0)
+-#define QUEUE_STOPPED			(1)
+-
+-#define IS_DMA_ALIGNED(x) 		(((u32)(x) & 0x03) == 0)
+-#define DMA_ALIGNMENT			4
+-/*-------------------------------------------------------------------------*/
+-
+-
+-/*-------------------------------------------------------------------------*/
+-/* Driver data structs */
+-
+-/* Context */
+-struct driver_data {
+-	/* Driver model hookup */
+-	struct platform_device *pdev;
+-
+-	/* SPI framework hookup */
+-	struct spi_master *master;
++#include <mach/spi.h>
+ 
+-	/* IMX hookup */
+-	struct spi_imx_master *master_info;
+-
+-	/* Memory resources and SPI regs virtual address */
+-	struct resource *ioarea;
+-	void __iomem *regs;
+-
+-	/* SPI RX_DATA physical address */
+-	dma_addr_t rd_data_phys;
+-
+-	/* Driver message queue */
+-	struct workqueue_struct	*workqueue;
+-	struct work_struct work;
+-	spinlock_t lock;
+-	struct list_head queue;
+-	int busy;
+-	int run;
+-
+-	/* Message Transfer pump */
+-	struct tasklet_struct pump_transfers;
+-
+-	/* Current message, transfer and state */
+-	struct spi_message *cur_msg;
+-	struct spi_transfer *cur_transfer;
+-	struct chip_data *cur_chip;
+-
+-	/* Rd / Wr buffers pointers */
+-	size_t len;
+-	void *tx;
+-	void *tx_end;
+-	void *rx;
+-	void *rx_end;
+-
+-	u8 rd_only;
+-	u8 n_bytes;
+-	int cs_change;
+-
+-	/* Function pointers */
+-	irqreturn_t (*transfer_handler)(struct driver_data *drv_data);
+-	void (*cs_control)(u32 command);
+-
+-	/* DMA setup */
+-	int rx_channel;
+-	int tx_channel;
+-	dma_addr_t rx_dma;
+-	dma_addr_t tx_dma;
+-	int rx_dma_needs_unmap;
+-	int tx_dma_needs_unmap;
+-	size_t tx_map_len;
+-	u32 dummy_dma_buf ____cacheline_aligned;
++#define DRIVER_NAME "spi_imx"
+ 
+-	struct clk *clk;
+-};
++#define MXC_CSPIRXDATA		0x00
++#define MXC_CSPITXDATA		0x04
++#define MXC_CSPICTRL		0x08
++#define MXC_CSPIINT		0x0c
++#define MXC_RESET		0x1c
+ 
+-/* Runtime state */
+-struct chip_data {
+-	u32 control;
+-	u32 period;
+-	u32 test;
++/* generic defines to abstract from the different register layouts */
++#define MXC_INT_RR	(1 << 0) /* Receive data ready interrupt */
++#define MXC_INT_TE	(1 << 1) /* Transmit FIFO empty interrupt */
+ 
+-	u8 enable_dma:1;
+-	u8 bits_per_word;
+-	u8 n_bytes;
+-	u32 max_speed_hz;
+-
+-	void (*cs_control)(u32 command);
++struct spi_imx_config {
++	unsigned int speed_hz;
++	unsigned int bpw;
++	unsigned int mode;
++	int cs;
+ };
+-/*-------------------------------------------------------------------------*/
+-
+ 
+-static void pump_messages(struct work_struct *work);
++struct spi_imx_data {
++	struct spi_bitbang bitbang;
+ 
+-static void flush(struct driver_data *drv_data)
+-{
+-	void __iomem *regs = drv_data->regs;
+-	u32 control;
++	struct completion xfer_done;
++	void *base;
++	int irq;
++	struct clk *clk;
++	unsigned long spi_clk;
++	int *chipselect;
++
++	unsigned int count;
++	void (*tx)(struct spi_imx_data *);
++	void (*rx)(struct spi_imx_data *);
++	void *rx_buf;
++	const void *tx_buf;
++	unsigned int txfifo; /* number of words pushed in tx FIFO */
++
++	/* SoC specific functions */
++	void (*intctrl)(struct spi_imx_data *, int);
++	int (*config)(struct spi_imx_data *, struct spi_imx_config *);
++	void (*trigger)(struct spi_imx_data *);
++	int (*rx_available)(struct spi_imx_data *);
++};
+ 
+-	dev_dbg(&drv_data->pdev->dev, "flush\n");
++#define MXC_SPI_BUF_RX(type)						\
++static void spi_imx_buf_rx_##type(struct spi_imx_data *spi_imx)		\
++{									\
++	unsigned int val = readl(spi_imx->base + MXC_CSPIRXDATA);	\
++									\
++	if (spi_imx->rx_buf) {						\
++		*(type *)spi_imx->rx_buf = val;				\
++		spi_imx->rx_buf += sizeof(type);			\
++	}								\
++}
++
++#define MXC_SPI_BUF_TX(type)						\
++static void spi_imx_buf_tx_##type(struct spi_imx_data *spi_imx)		\
++{									\
++	type val = 0;							\
++									\
++	if (spi_imx->tx_buf) {						\
++		val = *(type *)spi_imx->tx_buf;				\
++		spi_imx->tx_buf += sizeof(type);			\
++	}								\
++									\
++	spi_imx->count -= sizeof(type);					\
++									\
++	writel(val, spi_imx->base + MXC_CSPITXDATA);			\
++}
++
++MXC_SPI_BUF_RX(u8)
++MXC_SPI_BUF_TX(u8)
++MXC_SPI_BUF_RX(u16)
++MXC_SPI_BUF_TX(u16)
++MXC_SPI_BUF_RX(u32)
++MXC_SPI_BUF_TX(u32)
++
++/* First entry is reserved, second entry is valid only if SDHC_SPIEN is set
++ * (which is currently not the case in this driver)
++ */
++static int mxc_clkdivs[] = {0, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192,
++	256, 384, 512, 768, 1024};
+ 
+-	/* Wait for end of transaction */
+-	do {
+-		control = readl(regs + SPI_CONTROL);
+-	} while (control & SPI_CONTROL_XCH);
++/* MX21, MX27 */
++static unsigned int spi_imx_clkdiv_1(unsigned int fin,
++		unsigned int fspi)
++{
++	int i, max;
+ 
+-	/* Release chip select if requested, transfer delays are
+-	   handled in pump_transfers */
+-	if (drv_data->cs_change)
+-		drv_data->cs_control(SPI_CS_DEASSERT);
++	if (cpu_is_mx21())
++		max = 18;
++	else
++		max = 16;
+ 
+-	/* Disable SPI to flush FIFOs */
+-	writel(control & ~SPI_CONTROL_SPIEN, regs + SPI_CONTROL);
+-	writel(control, regs + SPI_CONTROL);
+-}
++	for (i = 2; i < max; i++)
++		if (fspi * mxc_clkdivs[i] >= fin)
++			return i;
+ 
+-static void restore_state(struct driver_data *drv_data)
+-{
+-	void __iomem *regs = drv_data->regs;
+-	struct chip_data *chip = drv_data->cur_chip;
+-
+-	/* Load chip registers */
+-	dev_dbg(&drv_data->pdev->dev,
+-		"restore_state\n"
+-		"    test    = 0x%08X\n"
+-		"    control = 0x%08X\n",
+-		chip->test,
+-		chip->control);
+-	writel(chip->test, regs + SPI_TEST);
+-	writel(chip->period, regs + SPI_PERIOD);
+-	writel(0, regs + SPI_INT_STATUS);
+-	writel(chip->control, regs + SPI_CONTROL);
++	return max;
+ }
+ 
+-static void null_cs_control(u32 command)
++/* MX1, MX31, MX35 */
++static unsigned int spi_imx_clkdiv_2(unsigned int fin,
++		unsigned int fspi)
+ {
+-}
++	int i, div = 4;
+ 
+-static inline u32 data_to_write(struct driver_data *drv_data)
+-{
+-	return ((u32)(drv_data->tx_end - drv_data->tx)) / drv_data->n_bytes;
+-}
++	for (i = 0; i < 7; i++) {
++		if (fspi * div >= fin)
++			return i;
++		div <<= 1;
++	}
+ 
+-static inline u32 data_to_read(struct driver_data *drv_data)
+-{
+-	return ((u32)(drv_data->rx_end - drv_data->rx)) / drv_data->n_bytes;
++	return 7;
+ }
+ 
+-static int write(struct driver_data *drv_data)
+-{
+-	void __iomem *regs = drv_data->regs;
+-	void *tx = drv_data->tx;
+-	void *tx_end = drv_data->tx_end;
+-	u8 n_bytes = drv_data->n_bytes;
+-	u32 remaining_writes;
+-	u32 fifo_avail_space;
+-	u32 n;
+-	u16 d;
+-
+-	/* Compute how many fifo writes to do */
+-	remaining_writes = (u32)(tx_end - tx) / n_bytes;
+-	fifo_avail_space = SPI_FIFO_DEPTH -
+-				(readl(regs + SPI_TEST) & SPI_TEST_TXCNT);
+-	if (drv_data->rx && (fifo_avail_space > SPI_FIFO_OVERFLOW_MARGIN))
+-		/* Fix misunderstood receive overflow */
+-		fifo_avail_space -= SPI_FIFO_OVERFLOW_MARGIN;
+-	n = min(remaining_writes, fifo_avail_space);
+-
+-	dev_dbg(&drv_data->pdev->dev,
+-		"write type %s\n"
+-		"    remaining writes = %d\n"
+-		"    fifo avail space = %d\n"
+-		"    fifo writes      = %d\n",
+-		(n_bytes == 1) ? "u8" : "u16",
+-		remaining_writes,
+-		fifo_avail_space,
+-		n);
+-
+-	if (n > 0) {
+-		/* Fill SPI TXFIFO */
+-		if (drv_data->rd_only) {
+-			tx += n * n_bytes;
+-			while (n--)
+-				writel(SPI_DUMMY_u16, regs + SPI_TXDATA);
+-		} else {
+-			if (n_bytes == 1) {
+-				while (n--) {
+-					d = *(u8*)tx;
+-					writel(d, regs + SPI_TXDATA);
+-					tx += 1;
+-				}
+-			} else {
+-				while (n--) {
+-					d = *(u16*)tx;
+-					writel(d, regs + SPI_TXDATA);
+-					tx += 2;
+-				}
+-			}
+-		}
+-
+-		/* Trigger transfer */
+-		writel(readl(regs + SPI_CONTROL) | SPI_CONTROL_XCH,
+-			regs + SPI_CONTROL);
++#define MX31_INTREG_TEEN	(1 << 0)
++#define MX31_INTREG_RREN	(1 << 3)
+ 
+-		/* Update tx pointer */
+-		drv_data->tx = tx;
+-	}
++#define MX31_CSPICTRL_ENABLE	(1 << 0)
++#define MX31_CSPICTRL_MASTER	(1 << 1)
++#define MX31_CSPICTRL_XCH	(1 << 2)
++#define MX31_CSPICTRL_POL	(1 << 4)
++#define MX31_CSPICTRL_PHA	(1 << 5)
++#define MX31_CSPICTRL_SSCTL	(1 << 6)
++#define MX31_CSPICTRL_SSPOL	(1 << 7)
++#define MX31_CSPICTRL_BC_SHIFT	8
++#define MX35_CSPICTRL_BL_SHIFT	20
++#define MX31_CSPICTRL_CS_SHIFT	24
++#define MX35_CSPICTRL_CS_SHIFT	12
++#define MX31_CSPICTRL_DR_SHIFT	16
+ 
+-	return (tx >= tx_end);
+-}
++#define MX31_CSPISTATUS		0x14
++#define MX31_STATUS_RR		(1 << 3)
+ 
+-static int read(struct driver_data *drv_data)
++/* These functions also work for the i.MX35, but be aware that
++ * the i.MX35 has a slightly different register layout for bits
++ * we do not use here.
++ */
++static void mx31_intctrl(struct spi_imx_data *spi_imx, int enable)
+ {
+-	void __iomem *regs = drv_data->regs;
+-	void *rx = drv_data->rx;
+-	void *rx_end = drv_data->rx_end;
+-	u8 n_bytes = drv_data->n_bytes;
+-	u32 remaining_reads;
+-	u32 fifo_rxcnt;
+-	u32 n;
+-	u16 d;
+-
+-	/* Compute how many fifo reads to do */
+-	remaining_reads = (u32)(rx_end - rx) / n_bytes;
+-	fifo_rxcnt = (readl(regs + SPI_TEST) & SPI_TEST_RXCNT) >>
+-			SPI_TEST_RXCNT_LSB;
+-	n = min(remaining_reads, fifo_rxcnt);
+-
+-	dev_dbg(&drv_data->pdev->dev,
+-		"read type %s\n"
+-		"    remaining reads = %d\n"
+-		"    fifo rx count   = %d\n"
+-		"    fifo reads      = %d\n",
+-		(n_bytes == 1) ? "u8" : "u16",
+-		remaining_reads,
+-		fifo_rxcnt,
+-		n);
+-
+-	if (n > 0) {
+-		/* Read SPI RXFIFO */
+-		if (n_bytes == 1) {
+-			while (n--) {
+-				d = readl(regs + SPI_RXDATA);
+-				*((u8*)rx) = d;
+-				rx += 1;
+-			}
+-		} else {
+-			while (n--) {
+-				d = readl(regs + SPI_RXDATA);
+-				*((u16*)rx) = d;
+-				rx += 2;
+-			}
+-		}
++	unsigned int val = 0;
+ 
+-		/* Update rx pointer */
+-		drv_data->rx = rx;
+-	}
++	if (enable & MXC_INT_TE)
++		val |= MX31_INTREG_TEEN;
++	if (enable & MXC_INT_RR)
++		val |= MX31_INTREG_RREN;
+ 
+-	return (rx >= rx_end);
++	writel(val, spi_imx->base + MXC_CSPIINT);
+ }
+ 
+-static void *next_transfer(struct driver_data *drv_data)
++static void mx31_trigger(struct spi_imx_data *spi_imx)
+ {
+-	struct spi_message *msg = drv_data->cur_msg;
+-	struct spi_transfer *trans = drv_data->cur_transfer;
+-
+-	/* Move to next transfer */
+-	if (trans->transfer_list.next != &msg->transfers) {
+-		drv_data->cur_transfer =
+-			list_entry(trans->transfer_list.next,
+-					struct spi_transfer,
+-					transfer_list);
+-		return RUNNING_STATE;
+-	}
++	unsigned int reg;
+ 
+-	return DONE_STATE;
++	reg = readl(spi_imx->base + MXC_CSPICTRL);
++	reg |= MX31_CSPICTRL_XCH;
++	writel(reg, spi_imx->base + MXC_CSPICTRL);
+ }
+ 
+-static int map_dma_buffers(struct driver_data *drv_data)
++static int mx31_config(struct spi_imx_data *spi_imx,
++		struct spi_imx_config *config)
+ {
+-	struct spi_message *msg;
+-	struct device *dev;
+-	void *buf;
+-
+-	drv_data->rx_dma_needs_unmap = 0;
+-	drv_data->tx_dma_needs_unmap = 0;
+-
+-	if (!drv_data->master_info->enable_dma ||
+-		!drv_data->cur_chip->enable_dma)
+-			return -1;
+-
+-	msg = drv_data->cur_msg;
+-	dev = &msg->spi->dev;
+-	if (msg->is_dma_mapped) {
+-		if (drv_data->tx_dma)
+-			/* The caller provided at least dma and cpu virtual
+-			   address for write; pump_transfers() will consider the
+-			   transfer as write only if cpu rx virtual address is
+-			   NULL */
+-			return 0;
+-
+-		if (drv_data->rx_dma) {
+-			/* The caller provided dma and cpu virtual address to
+-			   performe read only transfer -->
+-			   use drv_data->dummy_dma_buf for dummy writes to
+-			   achive reads */
+-			buf = &drv_data->dummy_dma_buf;
+-			drv_data->tx_map_len = sizeof(drv_data->dummy_dma_buf);
+-			drv_data->tx_dma = dma_map_single(dev,
+-							buf,
+-							drv_data->tx_map_len,
+-							DMA_TO_DEVICE);
+-			if (dma_mapping_error(dev, drv_data->tx_dma))
+-				return -1;
+-
+-			drv_data->tx_dma_needs_unmap = 1;
+-
+-			/* Flags transfer as rd_only for pump_transfers() DMA
+-			   regs programming (should be redundant) */
+-			drv_data->tx = NULL;
+-
+-			return 0;
+-		}
+-	}
++	unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER;
+ 
+-	if (!IS_DMA_ALIGNED(drv_data->rx) || !IS_DMA_ALIGNED(drv_data->tx))
+-		return -1;
+-
+-	if (drv_data->tx == NULL) {
+-		/* Read only message --> use drv_data->dummy_dma_buf for dummy
+-		   writes to achive reads */
+-		buf = &drv_data->dummy_dma_buf;
+-		drv_data->tx_map_len = sizeof(drv_data->dummy_dma_buf);
+-	} else {
+-		buf = drv_data->tx;
+-		drv_data->tx_map_len = drv_data->len;
++	reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) <<
++		MX31_CSPICTRL_DR_SHIFT;
++
++	if (cpu_is_mx31())
++		reg |= (config->bpw - 1) << MX31_CSPICTRL_BC_SHIFT;
++	else if (cpu_is_mx35()) {
++		reg |= (config->bpw - 1) << MX35_CSPICTRL_BL_SHIFT;
++		reg |= MX31_CSPICTRL_SSCTL;
+ 	}
+-	drv_data->tx_dma = dma_map_single(dev,
+-					buf,
+-					drv_data->tx_map_len,
+-					DMA_TO_DEVICE);
+-	if (dma_mapping_error(dev, drv_data->tx_dma))
+-		return -1;
+-	drv_data->tx_dma_needs_unmap = 1;
+-
+-	/* NULL rx means write-only transfer and no map needed
+-	 * since rx DMA will not be used */
+-	if (drv_data->rx) {
+-		buf = drv_data->rx;
+-		drv_data->rx_dma = dma_map_single(dev,
+-						buf,
+-						drv_data->len,
+-						DMA_FROM_DEVICE);
+-		if (dma_mapping_error(dev, drv_data->rx_dma)) {
+-			if (drv_data->tx_dma) {
+-				dma_unmap_single(dev,
+-						drv_data->tx_dma,
+-						drv_data->tx_map_len,
+-						DMA_TO_DEVICE);
+-				drv_data->tx_dma_needs_unmap = 0;
+-			}
+-			return -1;
+-		}
+-		drv_data->rx_dma_needs_unmap = 1;
++
++	if (config->mode & SPI_CPHA)
++		reg |= MX31_CSPICTRL_PHA;
++	if (config->mode & SPI_CPOL)
++		reg |= MX31_CSPICTRL_POL;
++	if (config->mode & SPI_CS_HIGH)
++		reg |= MX31_CSPICTRL_SSPOL;
++	if (config->cs < 0) {
++		if (cpu_is_mx31())
++			reg |= (config->cs + 32) << MX31_CSPICTRL_CS_SHIFT;
++		else if (cpu_is_mx35())
++			reg |= (config->cs + 32) << MX35_CSPICTRL_CS_SHIFT;
+ 	}
+ 
++	writel(reg, spi_imx->base + MXC_CSPICTRL);
++
+ 	return 0;
+ }
+ 
+-static void unmap_dma_buffers(struct driver_data *drv_data)
++static int mx31_rx_available(struct spi_imx_data *spi_imx)
+ {
+-	struct spi_message *msg = drv_data->cur_msg;
+-	struct device *dev = &msg->spi->dev;
+-
+-	if (drv_data->rx_dma_needs_unmap) {
+-		dma_unmap_single(dev,
+-				drv_data->rx_dma,
+-				drv_data->len,
+-				DMA_FROM_DEVICE);
+-		drv_data->rx_dma_needs_unmap = 0;
+-	}
+-	if (drv_data->tx_dma_needs_unmap) {
+-		dma_unmap_single(dev,
+-				drv_data->tx_dma,
+-				drv_data->tx_map_len,
+-				DMA_TO_DEVICE);
+-		drv_data->tx_dma_needs_unmap = 0;
+-	}
++	return readl(spi_imx->base + MX31_CSPISTATUS) & MX31_STATUS_RR;
+ }
+ 
+-/* Caller already set message->status (dma is already blocked) */
+-static void giveback(struct spi_message *message, struct driver_data *drv_data)
+-{
+-	void __iomem *regs = drv_data->regs;
+-
+-	/* Bring SPI to sleep; restore_state() and pump_transfer()
+-	   will do new setup */
+-	writel(0, regs + SPI_INT_STATUS);
+-	writel(0, regs + SPI_DMA);
+-
+-	/* Unconditioned deselct */
+-	drv_data->cs_control(SPI_CS_DEASSERT);
++#define MX27_INTREG_RR		(1 << 4)
++#define MX27_INTREG_TEEN	(1 << 9)
++#define MX27_INTREG_RREN	(1 << 13)
+ 
+-	message->state = NULL;
+-	if (message->complete)
+-		message->complete(message->context);
++#define MX27_CSPICTRL_POL	(1 << 5)
++#define MX27_CSPICTRL_PHA	(1 << 6)
++#define MX27_CSPICTRL_SSPOL	(1 << 8)
++#define MX27_CSPICTRL_XCH	(1 << 9)
++#define MX27_CSPICTRL_ENABLE	(1 << 10)
++#define MX27_CSPICTRL_MASTER	(1 << 11)
++#define MX27_CSPICTRL_DR_SHIFT	14
++#define MX27_CSPICTRL_CS_SHIFT	19
+ 
+-	drv_data->cur_msg = NULL;
+-	drv_data->cur_transfer = NULL;
+-	drv_data->cur_chip = NULL;
+-	queue_work(drv_data->workqueue, &drv_data->work);
+-}
+-
+-static void dma_err_handler(int channel, void *data, int errcode)
++static void mx27_intctrl(struct spi_imx_data *spi_imx, int enable)
+ {
+-	struct driver_data *drv_data = data;
+-	struct spi_message *msg = drv_data->cur_msg;
+-
+-	dev_dbg(&drv_data->pdev->dev, "dma_err_handler\n");
+-
+-	/* Disable both rx and tx dma channels */
+-	imx_dma_disable(drv_data->rx_channel);
+-	imx_dma_disable(drv_data->tx_channel);
+-	unmap_dma_buffers(drv_data);
++	unsigned int val = 0;
+ 
+-	flush(drv_data);
++	if (enable & MXC_INT_TE)
++		val |= MX27_INTREG_TEEN;
++	if (enable & MXC_INT_RR)
++		val |= MX27_INTREG_RREN;
+ 
+-	msg->state = ERROR_STATE;
+-	tasklet_schedule(&drv_data->pump_transfers);
++	writel(val, spi_imx->base + MXC_CSPIINT);
+ }
+ 
+-static void dma_tx_handler(int channel, void *data)
++static void mx27_trigger(struct spi_imx_data *spi_imx)
+ {
+-	struct driver_data *drv_data = data;
++	unsigned int reg;
+ 
+-	dev_dbg(&drv_data->pdev->dev, "dma_tx_handler\n");
+-
+-	imx_dma_disable(channel);
+-
+-	/* Now waits for TX FIFO empty */
+-	writel(SPI_INTEN_TE, drv_data->regs + SPI_INT_STATUS);
++	reg = readl(spi_imx->base + MXC_CSPICTRL);
++	reg |= MX27_CSPICTRL_XCH;
++	writel(reg, spi_imx->base + MXC_CSPICTRL);
+ }
+ 
+-static irqreturn_t dma_transfer(struct driver_data *drv_data)
++static int mx27_config(struct spi_imx_data *spi_imx,
++		struct spi_imx_config *config)
+ {
+-	u32 status;
+-	struct spi_message *msg = drv_data->cur_msg;
+-	void __iomem *regs = drv_data->regs;
+-
+-	status = readl(regs + SPI_INT_STATUS);
++	unsigned int reg = MX27_CSPICTRL_ENABLE | MX27_CSPICTRL_MASTER;
+ 
+-	if ((status & (SPI_INTEN_RO | SPI_STATUS_RO))
+-			== (SPI_INTEN_RO | SPI_STATUS_RO)) {
+-		writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS);
++	reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, config->speed_hz) <<
++		MX27_CSPICTRL_DR_SHIFT;
++	reg |= config->bpw - 1;
+ 
+-		imx_dma_disable(drv_data->tx_channel);
+-		imx_dma_disable(drv_data->rx_channel);
+-		unmap_dma_buffers(drv_data);
++	if (config->mode & SPI_CPHA)
++		reg |= MX27_CSPICTRL_PHA;
++	if (config->mode & SPI_CPOL)
++		reg |= MX27_CSPICTRL_POL;
++	if (config->mode & SPI_CS_HIGH)
++		reg |= MX27_CSPICTRL_SSPOL;
++	if (config->cs < 0)
++		reg |= (config->cs + 32) << MX27_CSPICTRL_CS_SHIFT;
+ 
+-		flush(drv_data);
++	writel(reg, spi_imx->base + MXC_CSPICTRL);
+ 
+-		dev_warn(&drv_data->pdev->dev,
+-				"dma_transfer - fifo overun\n");
+-
+-		msg->state = ERROR_STATE;
+-		tasklet_schedule(&drv_data->pump_transfers);
+-
+-		return IRQ_HANDLED;
+-	}
+-
+-	if (status & SPI_STATUS_TE) {
+-		writel(status & ~SPI_INTEN_TE, regs + SPI_INT_STATUS);
+-
+-		if (drv_data->rx) {
+-			/* Wait end of transfer before read trailing data */
+-			while (readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH)
+-				cpu_relax();
+-
+-			imx_dma_disable(drv_data->rx_channel);
+-			unmap_dma_buffers(drv_data);
+-
+-			/* Release chip select if requested, transfer delays are
+-			   handled in pump_transfers() */
+-			if (drv_data->cs_change)
+-				drv_data->cs_control(SPI_CS_DEASSERT);
+-
+-			/* Calculate number of trailing data and read them */
+-			dev_dbg(&drv_data->pdev->dev,
+-				"dma_transfer - test = 0x%08X\n",
+-				readl(regs + SPI_TEST));
+-			drv_data->rx = drv_data->rx_end -
+-					((readl(regs + SPI_TEST) &
+-					SPI_TEST_RXCNT) >>
+-					SPI_TEST_RXCNT_LSB)*drv_data->n_bytes;
+-			read(drv_data);
+-		} else {
+-			/* Write only transfer */
+-			unmap_dma_buffers(drv_data);
+-
+-			flush(drv_data);
+-		}
+-
+-		/* End of transfer, update total byte transfered */
+-		msg->actual_length += drv_data->len;
+-
+-		/* Move to next transfer */
+-		msg->state = next_transfer(drv_data);
+-
+-		/* Schedule transfer tasklet */
+-		tasklet_schedule(&drv_data->pump_transfers);
+-
+-		return IRQ_HANDLED;
+-	}
+-
+-	/* Opps problem detected */
+-	return IRQ_NONE;
++	return 0;
+ }
+ 
+-static irqreturn_t interrupt_wronly_transfer(struct driver_data *drv_data)
++static int mx27_rx_available(struct spi_imx_data *spi_imx)
+ {
+-	struct spi_message *msg = drv_data->cur_msg;
+-	void __iomem *regs = drv_data->regs;
+-	u32 status;
+-	irqreturn_t handled = IRQ_NONE;
+-
+-	status = readl(regs + SPI_INT_STATUS);
+-
+-	if (status & SPI_INTEN_TE) {
+-		/* TXFIFO Empty Interrupt on the last transfered word */
+-		writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS);
+-		dev_dbg(&drv_data->pdev->dev,
+-			"interrupt_wronly_transfer - end of tx\n");
+-
+-		flush(drv_data);
++	return readl(spi_imx->base + MXC_CSPIINT) & MX27_INTREG_RR;
++}
+ 
+-		/* Update total byte transfered */
+-		msg->actual_length += drv_data->len;
++#define MX1_INTREG_RR		(1 << 3)
++#define MX1_INTREG_TEEN		(1 << 8)
++#define MX1_INTREG_RREN		(1 << 11)
+ 
+-		/* Move to next transfer */
+-		msg->state = next_transfer(drv_data);
++#define MX1_CSPICTRL_POL	(1 << 4)
++#define MX1_CSPICTRL_PHA	(1 << 5)
++#define MX1_CSPICTRL_XCH	(1 << 8)
++#define MX1_CSPICTRL_ENABLE	(1 << 9)
++#define MX1_CSPICTRL_MASTER	(1 << 10)
++#define MX1_CSPICTRL_DR_SHIFT	13
+ 
+-		/* Schedule transfer tasklet */
+-		tasklet_schedule(&drv_data->pump_transfers);
++static void mx1_intctrl(struct spi_imx_data *spi_imx, int enable)
++{
++	unsigned int val = 0;
+ 
+-		return IRQ_HANDLED;
+-	} else {
+-		while (status & SPI_STATUS_TH) {
+-			dev_dbg(&drv_data->pdev->dev,
+-				"interrupt_wronly_transfer - status = 0x%08X\n",
+-				status);
+-
+-			/* Pump data */
+-			if (write(drv_data)) {
+-				/* End of TXFIFO writes,
+-				   now wait until TXFIFO is empty */
+-				writel(SPI_INTEN_TE, regs + SPI_INT_STATUS);
+-				return IRQ_HANDLED;
+-			}
+-
+-			status = readl(regs + SPI_INT_STATUS);
+-
+-			/* We did something */
+-			handled = IRQ_HANDLED;
+-		}
+-	}
++	if (enable & MXC_INT_TE)
++		val |= MX1_INTREG_TEEN;
++	if (enable & MXC_INT_RR)
++		val |= MX1_INTREG_RREN;
+ 
+-	return handled;
++	writel(val, spi_imx->base + MXC_CSPIINT);
+ }
+ 
+-static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
++static void mx1_trigger(struct spi_imx_data *spi_imx)
+ {
+-	struct spi_message *msg = drv_data->cur_msg;
+-	void __iomem *regs = drv_data->regs;
+-	u32 status, control;
+-	irqreturn_t handled = IRQ_NONE;
+-	unsigned long limit;
+-
+-	status = readl(regs + SPI_INT_STATUS);
+-
+-	if (status & SPI_INTEN_TE) {
+-		/* TXFIFO Empty Interrupt on the last transfered word */
+-		writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS);
+-		dev_dbg(&drv_data->pdev->dev,
+-			"interrupt_transfer - end of tx\n");
+-
+-		if (msg->state == ERROR_STATE) {
+-			/* RXFIFO overrun was detected and message aborted */
+-			flush(drv_data);
+-		} else {
+-			/* Wait for end of transaction */
+-			do {
+-				control = readl(regs + SPI_CONTROL);
+-			} while (control & SPI_CONTROL_XCH);
+-
+-			/* Release chip select if requested, transfer delays are
+-			   handled in pump_transfers */
+-			if (drv_data->cs_change)
+-				drv_data->cs_control(SPI_CS_DEASSERT);
+-
+-			/* Read trailing bytes */
+-			limit = loops_per_jiffy << 1;
+-			while ((read(drv_data) == 0) && --limit)
+-				cpu_relax();
+-
+-			if (limit == 0)
+-				dev_err(&drv_data->pdev->dev,
+-					"interrupt_transfer - "
+-					"trailing byte read failed\n");
+-			else
+-				dev_dbg(&drv_data->pdev->dev,
+-					"interrupt_transfer - end of rx\n");
+-
+-			/* Update total byte transfered */
+-			msg->actual_length += drv_data->len;
+-
+-			/* Move to next transfer */
+-			msg->state = next_transfer(drv_data);
+-		}
+-
+-		/* Schedule transfer tasklet */
+-		tasklet_schedule(&drv_data->pump_transfers);
++	unsigned int reg;
+ 
+-		return IRQ_HANDLED;
+-	} else {
+-		while (status & (SPI_STATUS_TH | SPI_STATUS_RO)) {
+-			dev_dbg(&drv_data->pdev->dev,
+-				"interrupt_transfer - status = 0x%08X\n",
+-				status);
+-
+-			if (status & SPI_STATUS_RO) {
+-				/* RXFIFO overrun, abort message end wait
+-				   until TXFIFO is empty */
+-				writel(SPI_INTEN_TE, regs + SPI_INT_STATUS);
+-
+-				dev_warn(&drv_data->pdev->dev,
+-					"interrupt_transfer - fifo overun\n"
+-					"    data not yet written = %d\n"
+-					"    data not yet read    = %d\n",
+-					data_to_write(drv_data),
+-					data_to_read(drv_data));
+-
+-				msg->state = ERROR_STATE;
+-
+-				return IRQ_HANDLED;
+-			}
+-
+-			/* Pump data */
+-			read(drv_data);
+-			if (write(drv_data)) {
+-				/* End of TXFIFO writes,
+-				   now wait until TXFIFO is empty */
+-				writel(SPI_INTEN_TE, regs + SPI_INT_STATUS);
+-				return IRQ_HANDLED;
+-			}
+-
+-			status = readl(regs + SPI_INT_STATUS);
+-
+-			/* We did something */
+-			handled = IRQ_HANDLED;
+-		}
+-	}
+-
+-	return handled;
++	reg = readl(spi_imx->base + MXC_CSPICTRL);
++	reg |= MX1_CSPICTRL_XCH;
++	writel(reg, spi_imx->base + MXC_CSPICTRL);
+ }
+ 
+-static irqreturn_t spi_int(int irq, void *dev_id)
++static int mx1_config(struct spi_imx_data *spi_imx,
++		struct spi_imx_config *config)
+ {
+-	struct driver_data *drv_data = (struct driver_data *)dev_id;
++	unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_MASTER;
+ 
+-	if (!drv_data->cur_msg) {
+-		dev_err(&drv_data->pdev->dev,
+-			"spi_int - bad message state\n");
+-		/* Never fail */
+-		return IRQ_HANDLED;
+-	}
++	reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) <<
++		MX1_CSPICTRL_DR_SHIFT;
++	reg |= config->bpw - 1;
+ 
+-	return drv_data->transfer_handler(drv_data);
+-}
++	if (config->mode & SPI_CPHA)
++		reg |= MX1_CSPICTRL_PHA;
++	if (config->mode & SPI_CPOL)
++		reg |= MX1_CSPICTRL_POL;
+ 
+-static inline u32 spi_speed_hz(struct driver_data *drv_data, u32 data_rate)
+-{
+-	return clk_get_rate(drv_data->clk) / (4 << ((data_rate) >> 13));
++	writel(reg, spi_imx->base + MXC_CSPICTRL);
++
++	return 0;
+ }
+ 
+-static u32 spi_data_rate(struct driver_data *drv_data, u32 speed_hz)
++static int mx1_rx_available(struct spi_imx_data *spi_imx)
+ {
+-	u32 div;
+-	u32 quantized_hz = clk_get_rate(drv_data->clk) >> 2;
+-
+-	for (div = SPI_PERCLK2_DIV_MIN;
+-		div <= SPI_PERCLK2_DIV_MAX;
+-		div++, quantized_hz >>= 1) {
+-			if (quantized_hz <= speed_hz)
+-				/* Max available speed LEQ required speed */
+-				return div << 13;
+-	}
+-	return SPI_CONTROL_DATARATE_BAD;
++	return readl(spi_imx->base + MXC_CSPIINT) & MX1_INTREG_RR;
+ }
+ 
+-static void pump_transfers(unsigned long data)
++static void spi_imx_chipselect(struct spi_device *spi, int is_active)
+ {
+-	struct driver_data *drv_data = (struct driver_data *)data;
+-	struct spi_message *message;
+-	struct spi_transfer *transfer, *previous;
+-	struct chip_data *chip;
+-	void __iomem *regs;
+-	u32 tmp, control;
+-
+-	dev_dbg(&drv_data->pdev->dev, "pump_transfer\n");
++	struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
++	int gpio = spi_imx->chipselect[spi->chip_select];
++	int active = is_active != BITBANG_CS_INACTIVE;
++	int dev_is_lowactive = !(spi->mode & SPI_CS_HIGH);
+ 
+-	message = drv_data->cur_msg;
+-
+-	/* Handle for abort */
+-	if (message->state == ERROR_STATE) {
+-		message->status = -EIO;
+-		giveback(message, drv_data);
+-		return;
+-	}
+-
+-	/* Handle end of message */
+-	if (message->state == DONE_STATE) {
+-		message->status = 0;
+-		giveback(message, drv_data);
++	if (gpio < 0)
+ 		return;
+-	}
+-
+-	chip = drv_data->cur_chip;
+-
+-	/* Delay if requested at end of transfer*/
+-	transfer = drv_data->cur_transfer;
+-	if (message->state == RUNNING_STATE) {
+-		previous = list_entry(transfer->transfer_list.prev,
+-					struct spi_transfer,
+-					transfer_list);
+-		if (previous->delay_usecs)
+-			udelay(previous->delay_usecs);
+-	} else {
+-		/* START_STATE */
+-		message->state = RUNNING_STATE;
+-		drv_data->cs_control = chip->cs_control;
+-	}
+ 
+-	transfer = drv_data->cur_transfer;
+-	drv_data->tx = (void *)transfer->tx_buf;
+-	drv_data->tx_end = drv_data->tx + transfer->len;
+-	drv_data->rx = transfer->rx_buf;
+-	drv_data->rx_end = drv_data->rx + transfer->len;
+-	drv_data->rx_dma = transfer->rx_dma;
+-	drv_data->tx_dma = transfer->tx_dma;
+-	drv_data->len = transfer->len;
+-	drv_data->cs_change = transfer->cs_change;
+-	drv_data->rd_only = (drv_data->tx == NULL);
+-
+-	regs = drv_data->regs;
+-	control = readl(regs + SPI_CONTROL);
+-
+-	/* Bits per word setup */
+-	tmp = transfer->bits_per_word;
+-	if (tmp == 0) {
+-		/* Use device setup */
+-		tmp = chip->bits_per_word;
+-		drv_data->n_bytes = chip->n_bytes;
+-	} else
+-		/* Use per-transfer setup */
+-		drv_data->n_bytes = (tmp <= 8) ? 1 : 2;
+-	u32_EDIT(control, SPI_CONTROL_BITCOUNT_MASK, tmp - 1);
+-
+-	/* Speed setup (surely valid because already checked) */
+-	tmp = transfer->speed_hz;
+-	if (tmp == 0)
+-		tmp = chip->max_speed_hz;
+-	tmp = spi_data_rate(drv_data, tmp);
+-	u32_EDIT(control, SPI_CONTROL_DATARATE, tmp);
+-
+-	writel(control, regs + SPI_CONTROL);
+-
+-	/* Assert device chip-select */
+-	drv_data->cs_control(SPI_CS_ASSERT);
+-
+-	/* DMA cannot read/write SPI FIFOs other than 16 bits at a time; hence
+-	   if bits_per_word is less or equal 8 PIO transfers are performed.
+-	   Moreover DMA is convinient for transfer length bigger than FIFOs
+-	   byte size. */
+-	if ((drv_data->n_bytes == 2) &&
+-		(drv_data->len > SPI_FIFO_DEPTH*SPI_FIFO_BYTE_WIDTH) &&
+-		(map_dma_buffers(drv_data) == 0)) {
+-		dev_dbg(&drv_data->pdev->dev,
+-			"pump dma transfer\n"
+-			"    tx      = %p\n"
+-			"    tx_dma  = %08X\n"
+-			"    rx      = %p\n"
+-			"    rx_dma  = %08X\n"
+-			"    len     = %d\n",
+-			drv_data->tx,
+-			(unsigned int)drv_data->tx_dma,
+-			drv_data->rx,
+-			(unsigned int)drv_data->rx_dma,
+-			drv_data->len);
+-
+-		/* Ensure we have the correct interrupt handler */
+-		drv_data->transfer_handler = dma_transfer;
+-
+-		/* Trigger transfer */
+-		writel(readl(regs + SPI_CONTROL) | SPI_CONTROL_XCH,
+-			regs + SPI_CONTROL);
+-
+-		/* Setup tx DMA */
+-		if (drv_data->tx)
+-			/* Linear source address */
+-			CCR(drv_data->tx_channel) =
+-				CCR_DMOD_FIFO |
+-				CCR_SMOD_LINEAR |
+-				CCR_SSIZ_32 | CCR_DSIZ_16 |
+-				CCR_REN;
+-		else
+-			/* Read only transfer -> fixed source address for
+-			   dummy write to achive read */
+-			CCR(drv_data->tx_channel) =
+-				CCR_DMOD_FIFO |
+-				CCR_SMOD_FIFO |
+-				CCR_SSIZ_32 | CCR_DSIZ_16 |
+-				CCR_REN;
+-
+-		imx_dma_setup_single(
+-			drv_data->tx_channel,
+-			drv_data->tx_dma,
+-			drv_data->len,
+-			drv_data->rd_data_phys + 4,
+-			DMA_MODE_WRITE);
+-
+-		if (drv_data->rx) {
+-			/* Setup rx DMA for linear destination address */
+-			CCR(drv_data->rx_channel) =
+-				CCR_DMOD_LINEAR |
+-				CCR_SMOD_FIFO |
+-				CCR_DSIZ_32 | CCR_SSIZ_16 |
+-				CCR_REN;
+-			imx_dma_setup_single(
+-				drv_data->rx_channel,
+-				drv_data->rx_dma,
+-				drv_data->len,
+-				drv_data->rd_data_phys,
+-				DMA_MODE_READ);
+-			imx_dma_enable(drv_data->rx_channel);
+-
+-			/* Enable SPI interrupt */
+-			writel(SPI_INTEN_RO, regs + SPI_INT_STATUS);
+-
+-			/* Set SPI to request DMA service on both
+-			   Rx and Tx half fifo watermark */
+-			writel(SPI_DMA_RHDEN | SPI_DMA_THDEN, regs + SPI_DMA);
+-		} else
+-			/* Write only access -> set SPI to request DMA
+-			   service on Tx half fifo watermark */
+-			writel(SPI_DMA_THDEN, regs + SPI_DMA);
+-
+-		imx_dma_enable(drv_data->tx_channel);
+-	} else {
+-		dev_dbg(&drv_data->pdev->dev,
+-			"pump pio transfer\n"
+-			"    tx      = %p\n"
+-			"    rx      = %p\n"
+-			"    len     = %d\n",
+-			drv_data->tx,
+-			drv_data->rx,
+-			drv_data->len);
+-
+-		/* Ensure we have the correct interrupt handler	*/
+-		if (drv_data->rx)
+-			drv_data->transfer_handler = interrupt_transfer;
+-		else
+-			drv_data->transfer_handler = interrupt_wronly_transfer;
+-
+-		/* Enable SPI interrupt */
+-		if (drv_data->rx)
+-			writel(SPI_INTEN_TH | SPI_INTEN_RO,
+-				regs + SPI_INT_STATUS);
+-		else
+-			writel(SPI_INTEN_TH, regs + SPI_INT_STATUS);
+-	}
++	gpio_set_value(gpio, dev_is_lowactive ^ active);
+ }
+ 
+-static void pump_messages(struct work_struct *work)
++static void spi_imx_push(struct spi_imx_data *spi_imx)
+ {
+-	struct driver_data *drv_data =
+-				container_of(work, struct driver_data, work);
+-	unsigned long flags;
+-
+-	/* Lock queue and check for queue work */
+-	spin_lock_irqsave(&drv_data->lock, flags);
+-	if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) {
+-		drv_data->busy = 0;
+-		spin_unlock_irqrestore(&drv_data->lock, flags);
+-		return;
+-	}
+-
+-	/* Make sure we are not already running a message */
+-	if (drv_data->cur_msg) {
+-		spin_unlock_irqrestore(&drv_data->lock, flags);
+-		return;
++	while (spi_imx->txfifo < 8) {
++		if (!spi_imx->count)
++			break;
++		spi_imx->tx(spi_imx);
++		spi_imx->txfifo++;
+ 	}
+ 
+-	/* Extract head of queue */
+-	drv_data->cur_msg = list_entry(drv_data->queue.next,
+-					struct spi_message, queue);
+-	list_del_init(&drv_data->cur_msg->queue);
+-	drv_data->busy = 1;
+-	spin_unlock_irqrestore(&drv_data->lock, flags);
+-
+-	/* Initial message state */
+-	drv_data->cur_msg->state = START_STATE;
+-	drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
+-						struct spi_transfer,
+-						transfer_list);
+-
+-	/* Setup the SPI using the per chip configuration */
+-	drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
+-	restore_state(drv_data);
+-
+-	/* Mark as busy and launch transfers */
+-	tasklet_schedule(&drv_data->pump_transfers);
++	spi_imx->trigger(spi_imx);
+ }
+ 
+-static int transfer(struct spi_device *spi, struct spi_message *msg)
++static irqreturn_t spi_imx_isr(int irq, void *dev_id)
+ {
+-	struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+-	u32 min_speed_hz, max_speed_hz, tmp;
+-	struct spi_transfer *trans;
+-	unsigned long flags;
+-
+-	msg->actual_length = 0;
+-
+-	/* Per transfer setup check */
+-	min_speed_hz = spi_speed_hz(drv_data, SPI_CONTROL_DATARATE_MIN);
+-	max_speed_hz = spi->max_speed_hz;
+-	list_for_each_entry(trans, &msg->transfers, transfer_list) {
+-		tmp = trans->bits_per_word;
+-		if (tmp > 16) {
+-			dev_err(&drv_data->pdev->dev,
+-				"message rejected : "
+-				"invalid transfer bits_per_word (%d bits)\n",
+-				tmp);
+-			goto msg_rejected;
+-		}
+-		tmp = trans->speed_hz;
+-		if (tmp) {
+-			if (tmp < min_speed_hz) {
+-				dev_err(&drv_data->pdev->dev,
+-					"message rejected : "
+-					"device min speed (%d Hz) exceeds "
+-					"required transfer speed (%d Hz)\n",
+-					min_speed_hz,
+-					tmp);
+-				goto msg_rejected;
+-			} else if (tmp > max_speed_hz) {
+-				dev_err(&drv_data->pdev->dev,
+-					"message rejected : "
+-					"transfer speed (%d Hz) exceeds "
+-					"device max speed (%d Hz)\n",
+-					tmp,
+-					max_speed_hz);
+-				goto msg_rejected;
+-			}
+-		}
+-	}
+-
+-	/* Message accepted */
+-	msg->status = -EINPROGRESS;
+-	msg->state = START_STATE;
++	struct spi_imx_data *spi_imx = dev_id;
+ 
+-	spin_lock_irqsave(&drv_data->lock, flags);
+-	if (drv_data->run == QUEUE_STOPPED) {
+-		spin_unlock_irqrestore(&drv_data->lock, flags);
+-		return -ESHUTDOWN;
++	while (spi_imx->rx_available(spi_imx)) {
++		spi_imx->rx(spi_imx);
++		spi_imx->txfifo--;
+ 	}
+ 
+-	list_add_tail(&msg->queue, &drv_data->queue);
+-	if (drv_data->run == QUEUE_RUNNING && !drv_data->busy)
+-		queue_work(drv_data->workqueue, &drv_data->work);
+-
+-	spin_unlock_irqrestore(&drv_data->lock, flags);
+-	return 0;
+-
+-msg_rejected:
+-	/* Message rejected and not queued */
+-	msg->status = -EINVAL;
+-	msg->state = ERROR_STATE;
+-	if (msg->complete)
+-		msg->complete(msg->context);
+-	return -EINVAL;
+-}
+-
+-/* On first setup bad values must free chip_data memory since will cause
+-   spi_new_device to fail. Bad value setup from protocol driver are simply not
+-   applied and notified to the calling driver. */
+-static int setup(struct spi_device *spi)
+-{
+-	struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+-	struct spi_imx_chip *chip_info;
+-	struct chip_data *chip;
+-	int first_setup = 0;
+-	u32 tmp;
+-	int status = 0;
+-
+-	/* Get controller data */
+-	chip_info = spi->controller_data;
+-
+-	/* Get controller_state */
+-	chip = spi_get_ctldata(spi);
+-	if (chip == NULL) {
+-		first_setup = 1;
+-
+-		chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
+-		if (!chip) {
+-			dev_err(&spi->dev,
+-				"setup - cannot allocate controller state\n");
+-			return -ENOMEM;
+-		}
+-		chip->control = SPI_DEFAULT_CONTROL;
+-
+-		if (chip_info == NULL) {
+-			/* spi_board_info.controller_data not is supplied */
+-			chip_info = kzalloc(sizeof(struct spi_imx_chip),
+-						GFP_KERNEL);
+-			if (!chip_info) {
+-				dev_err(&spi->dev,
+-					"setup - "
+-					"cannot allocate controller data\n");
+-				status = -ENOMEM;
+-				goto err_first_setup;
+-			}
+-			/* Set controller data default value */
+-			chip_info->enable_loopback =
+-						SPI_DEFAULT_ENABLE_LOOPBACK;
+-			chip_info->enable_dma = SPI_DEFAULT_ENABLE_DMA;
+-			chip_info->ins_ss_pulse = 1;
+-			chip_info->bclk_wait = SPI_DEFAULT_PERIOD_WAIT;
+-			chip_info->cs_control = null_cs_control;
+-		}
++	if (spi_imx->count) {
++		spi_imx_push(spi_imx);
++		return IRQ_HANDLED;
+ 	}
+ 
+-	/* Now set controller state based on controller data */
+-
+-	if (first_setup) {
+-		/* SPI loopback */
+-		if (chip_info->enable_loopback)
+-			chip->test = SPI_TEST_LBC;
+-		else
+-			chip->test = 0;
+-
+-		/* SPI dma driven */
+-		chip->enable_dma = chip_info->enable_dma;
+-
+-		/* SPI /SS pulse between spi burst */
+-		if (chip_info->ins_ss_pulse)
+-			u32_EDIT(chip->control,
+-				SPI_CONTROL_SSCTL, SPI_CONTROL_SSCTL_1);
+-		else
+-			u32_EDIT(chip->control,
+-				SPI_CONTROL_SSCTL, SPI_CONTROL_SSCTL_0);
+-
+-		/* SPI bclk waits between each bits_per_word spi burst */
+-		if (chip_info->bclk_wait > SPI_PERIOD_MAX_WAIT) {
+-			dev_err(&spi->dev,
+-				"setup - "
+-				"bclk_wait exceeds max allowed (%d)\n",
+-				SPI_PERIOD_MAX_WAIT);
+-			goto err_first_setup;
+-		}
+-		chip->period = SPI_PERIOD_CSRC_BCLK |
+-				(chip_info->bclk_wait & SPI_PERIOD_WAIT);
++	if (spi_imx->txfifo) {
++		/* No data left to push, but still waiting for rx data,
++		 * enable receive data available interrupt.
++		 */
++		spi_imx->intctrl(spi_imx, MXC_INT_RR);
++		return IRQ_HANDLED;
+ 	}
+ 
+-	/* SPI mode */
+-	tmp = spi->mode;
+-	if (tmp & SPI_CS_HIGH) {
+-		u32_EDIT(chip->control,
+-				SPI_CONTROL_SSPOL, SPI_CONTROL_SSPOL_ACT_HIGH);
+-	}
+-	switch (tmp & SPI_MODE_3) {
+-	case SPI_MODE_0:
+-		tmp = 0;
+-		break;
+-	case SPI_MODE_1:
+-		tmp = SPI_CONTROL_PHA_1;
+-		break;
+-	case SPI_MODE_2:
+-		tmp = SPI_CONTROL_POL_ACT_LOW;
+-		break;
+-	default:
+-		/* SPI_MODE_3 */
+-		tmp = SPI_CONTROL_PHA_1 | SPI_CONTROL_POL_ACT_LOW;
+-		break;
+-	}
+-	u32_EDIT(chip->control, SPI_CONTROL_POL | SPI_CONTROL_PHA, tmp);
+-
+-	/* SPI word width */
+-	tmp = spi->bits_per_word;
+-	if (tmp > 16) {
+-		status = -EINVAL;
+-		dev_err(&spi->dev,
+-			"setup - "
+-			"invalid bits_per_word (%d)\n",
+-			tmp);
+-		if (first_setup)
+-			goto err_first_setup;
+-		else {
+-			/* Undo setup using chip as backup copy */
+-			tmp = chip->bits_per_word;
+-			spi->bits_per_word = tmp;
+-		}
+-	}
+-	chip->bits_per_word = tmp;
+-	u32_EDIT(chip->control, SPI_CONTROL_BITCOUNT_MASK, tmp - 1);
+-	chip->n_bytes = (tmp <= 8) ? 1 : 2;
+-
+-	/* SPI datarate */
+-	tmp = spi_data_rate(drv_data, spi->max_speed_hz);
+-	if (tmp == SPI_CONTROL_DATARATE_BAD) {
+-		status = -EINVAL;
+-		dev_err(&spi->dev,
+-			"setup - "
+-			"HW min speed (%d Hz) exceeds required "
+-			"max speed (%d Hz)\n",
+-			spi_speed_hz(drv_data, SPI_CONTROL_DATARATE_MIN),
+-			spi->max_speed_hz);
+-		if (first_setup)
+-			goto err_first_setup;
+-		else
+-			/* Undo setup using chip as backup copy */
+-			spi->max_speed_hz = chip->max_speed_hz;
+-	} else {
+-		u32_EDIT(chip->control, SPI_CONTROL_DATARATE, tmp);
+-		/* Actual rounded max_speed_hz */
+-		tmp = spi_speed_hz(drv_data, tmp);
+-		spi->max_speed_hz = tmp;
+-		chip->max_speed_hz = tmp;
+-	}
++	spi_imx->intctrl(spi_imx, 0);
++	complete(&spi_imx->xfer_done);
+ 
+-	/* SPI chip-select management */
+-	if (chip_info->cs_control)
+-		chip->cs_control = chip_info->cs_control;
+-	else
+-		chip->cs_control = null_cs_control;
+-
+-	/* Save controller_state */
+-	spi_set_ctldata(spi, chip);
+-
+-	/* Summary */
+-	dev_dbg(&spi->dev,
+-		"setup succeded\n"
+-		"    loopback enable   = %s\n"
+-		"    dma enable        = %s\n"
+-		"    insert /ss pulse  = %s\n"
+-		"    period wait       = %d\n"
+-		"    mode              = %d\n"
+-		"    bits per word     = %d\n"
+-		"    min speed         = %d Hz\n"
+-		"    rounded max speed = %d Hz\n",
+-		chip->test & SPI_TEST_LBC ? "Yes" : "No",
+-		chip->enable_dma ? "Yes" : "No",
+-		chip->control & SPI_CONTROL_SSCTL ? "Yes" : "No",
+-		chip->period & SPI_PERIOD_WAIT,
+-		spi->mode,
+-		spi->bits_per_word,
+-		spi_speed_hz(drv_data, SPI_CONTROL_DATARATE_MIN),
+-		spi->max_speed_hz);
+-	return status;
+-
+-err_first_setup:
+-	kfree(chip);
+-	return status;
++	return IRQ_HANDLED;
+ }
+ 
+-static void cleanup(struct spi_device *spi)
++static int spi_imx_setupxfer(struct spi_device *spi,
++				 struct spi_transfer *t)
+ {
+-	kfree(spi_get_ctldata(spi));
+-}
++	struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
++	struct spi_imx_config config;
+ 
+-static int __init init_queue(struct driver_data *drv_data)
+-{
+-	INIT_LIST_HEAD(&drv_data->queue);
+-	spin_lock_init(&drv_data->lock);
++	config.bpw = t ? t->bits_per_word : spi->bits_per_word;
++	config.speed_hz  = t ? t->speed_hz : spi->max_speed_hz;
++	config.mode = spi->mode;
++	config.cs = spi_imx->chipselect[spi->chip_select];
+ 
+-	drv_data->run = QUEUE_STOPPED;
+-	drv_data->busy = 0;
++	if (!config.speed_hz)
++		config.speed_hz = spi->max_speed_hz;
++	if (!config.bpw)
++		config.bpw = spi->bits_per_word;
++	if (!config.speed_hz)
++		config.speed_hz = spi->max_speed_hz;
+ 
+-	tasklet_init(&drv_data->pump_transfers,
+-			pump_transfers,	(unsigned long)drv_data);
++	/* Initialize the functions for transfer */
++	if (config.bpw <= 8) {
++		spi_imx->rx = spi_imx_buf_rx_u8;
++		spi_imx->tx = spi_imx_buf_tx_u8;
++	} else if (config.bpw <= 16) {
++		spi_imx->rx = spi_imx_buf_rx_u16;
++		spi_imx->tx = spi_imx_buf_tx_u16;
++	} else if (config.bpw <= 32) {
++		spi_imx->rx = spi_imx_buf_rx_u32;
++		spi_imx->tx = spi_imx_buf_tx_u32;
++	} else
++		BUG();
+ 
+-	INIT_WORK(&drv_data->work, pump_messages);
+-	drv_data->workqueue = create_singlethread_workqueue(
+-				dev_name(drv_data->master->dev.parent));
+-	if (drv_data->workqueue == NULL)
+-		return -EBUSY;
++	spi_imx->config(spi_imx, &config);
+ 
+ 	return 0;
+ }
+ 
+-static int start_queue(struct driver_data *drv_data)
++static int spi_imx_transfer(struct spi_device *spi,
++				struct spi_transfer *transfer)
+ {
+-	unsigned long flags;
++	struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
+ 
+-	spin_lock_irqsave(&drv_data->lock, flags);
++	spi_imx->tx_buf = transfer->tx_buf;
++	spi_imx->rx_buf = transfer->rx_buf;
++	spi_imx->count = transfer->len;
++	spi_imx->txfifo = 0;
+ 
+-	if (drv_data->run == QUEUE_RUNNING || drv_data->busy) {
+-		spin_unlock_irqrestore(&drv_data->lock, flags);
+-		return -EBUSY;
+-	}
++	init_completion(&spi_imx->xfer_done);
+ 
+-	drv_data->run = QUEUE_RUNNING;
+-	drv_data->cur_msg = NULL;
+-	drv_data->cur_transfer = NULL;
+-	drv_data->cur_chip = NULL;
+-	spin_unlock_irqrestore(&drv_data->lock, flags);
++	spi_imx_push(spi_imx);
+ 
+-	queue_work(drv_data->workqueue, &drv_data->work);
++	spi_imx->intctrl(spi_imx, MXC_INT_TE);
+ 
+-	return 0;
++	wait_for_completion(&spi_imx->xfer_done);
++
++	return transfer->len;
+ }
+ 
+-static int stop_queue(struct driver_data *drv_data)
++static int spi_imx_setup(struct spi_device *spi)
+ {
+-	unsigned long flags;
+-	unsigned limit = 500;
+-	int status = 0;
+-
+-	spin_lock_irqsave(&drv_data->lock, flags);
+-
+-	/* This is a bit lame, but is optimized for the common execution path.
+-	 * A wait_queue on the drv_data->busy could be used, but then the common
+-	 * execution path (pump_messages) would be required to call wake_up or
+-	 * friends on every SPI message. Do this instead */
+-	drv_data->run = QUEUE_STOPPED;
+-	while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) {
+-		spin_unlock_irqrestore(&drv_data->lock, flags);
+-		msleep(10);
+-		spin_lock_irqsave(&drv_data->lock, flags);
+-	}
++	struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
++	int gpio = spi_imx->chipselect[spi->chip_select];
++
++	pr_debug("%s: mode %d, %u bpw, %d hz\n", __func__,
++		 spi->mode, spi->bits_per_word, spi->max_speed_hz);
+ 
+-	if (!list_empty(&drv_data->queue) || drv_data->busy)
+-		status = -EBUSY;
++	if (gpio >= 0)
++		gpio_direction_output(gpio, spi->mode & SPI_CS_HIGH ? 0 : 1);
+ 
+-	spin_unlock_irqrestore(&drv_data->lock, flags);
++	spi_imx_chipselect(spi, BITBANG_CS_INACTIVE);
+ 
+-	return status;
++	return 0;
+ }
+ 
+-static int destroy_queue(struct driver_data *drv_data)
++static void spi_imx_cleanup(struct spi_device *spi)
+ {
+-	int status;
+-
+-	status = stop_queue(drv_data);
+-	if (status != 0)
+-		return status;
+-
+-	if (drv_data->workqueue)
+-		destroy_workqueue(drv_data->workqueue);
+-
+-	return 0;
+ }
+ 
+ static int __init spi_imx_probe(struct platform_device *pdev)
+ {
+-	struct device *dev = &pdev->dev;
+-	struct spi_imx_master *platform_info;
++	struct spi_imx_master *mxc_platform_info;
+ 	struct spi_master *master;
+-	struct driver_data *drv_data;
++	struct spi_imx_data *spi_imx;
+ 	struct resource *res;
+-	int irq, status = 0;
++	int i, ret;
+ 
+-	platform_info = dev->platform_data;
+-	if (platform_info == NULL) {
+-		dev_err(&pdev->dev, "probe - no platform data supplied\n");
+-		status = -ENODEV;
+-		goto err_no_pdata;
++	mxc_platform_info = (struct spi_imx_master *)pdev->dev.platform_data;
++	if (!mxc_platform_info) {
++		dev_err(&pdev->dev, "can't get the platform data\n");
++		return -EINVAL;
+ 	}
+ 
+-	/* Allocate master with space for drv_data */
+-	master = spi_alloc_master(dev, sizeof(struct driver_data));
+-	if (!master) {
+-		dev_err(&pdev->dev, "probe - cannot alloc spi_master\n");
+-		status = -ENOMEM;
+-		goto err_no_mem;
+-	}
+-	drv_data = spi_master_get_devdata(master);
+-	drv_data->master = master;
+-	drv_data->master_info = platform_info;
+-	drv_data->pdev = pdev;
++	master = spi_alloc_master(&pdev->dev, sizeof(struct spi_imx_data));
++	if (!master)
++		return -ENOMEM;
+ 
+-	/* the spi->mode bits understood by this driver: */
+-	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
++	platform_set_drvdata(pdev, master);
+ 
+ 	master->bus_num = pdev->id;
+-	master->num_chipselect = platform_info->num_chipselect;
+-	master->dma_alignment = DMA_ALIGNMENT;
+-	master->cleanup = cleanup;
+-	master->setup = setup;
+-	master->transfer = transfer;
+-
+-	drv_data->dummy_dma_buf = SPI_DUMMY_u32;
+-
+-	drv_data->clk = clk_get(&pdev->dev, "perclk2");
+-	if (IS_ERR(drv_data->clk)) {
+-		dev_err(&pdev->dev, "probe - cannot get clock\n");
+-		status = PTR_ERR(drv_data->clk);
+-		goto err_no_clk;
+-	}
+-	clk_enable(drv_data->clk);
+-
+-	/* Find and map resources */
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	if (!res) {
+-		dev_err(&pdev->dev, "probe - MEM resources not defined\n");
+-		status = -ENODEV;
+-		goto err_no_iores;
+-	}
+-	drv_data->ioarea = request_mem_region(res->start,
+-						res->end - res->start + 1,
+-						pdev->name);
+-	if (drv_data->ioarea == NULL) {
+-		dev_err(&pdev->dev, "probe - cannot reserve region\n");
+-		status = -ENXIO;
+-		goto err_no_iores;
+-	}
+-	drv_data->regs = ioremap(res->start, res->end - res->start + 1);
+-	if (drv_data->regs == NULL) {
+-		dev_err(&pdev->dev, "probe - cannot map IO\n");
+-		status = -ENXIO;
+-		goto err_no_iomap;
+-	}
+-	drv_data->rd_data_phys = (dma_addr_t)res->start;
+-
+-	/* Attach to IRQ */
+-	irq = platform_get_irq(pdev, 0);
+-	if (irq < 0) {
+-		dev_err(&pdev->dev, "probe - IRQ resource not defined\n");
+-		status = -ENODEV;
+-		goto err_no_irqres;
+-	}
+-	status = request_irq(irq, spi_int, IRQF_DISABLED,
+-			     dev_name(dev), drv_data);
+-	if (status < 0) {
+-		dev_err(&pdev->dev, "probe - cannot get IRQ (%d)\n", status);
+-		goto err_no_irqres;
+-	}
+-
+-	/* Setup DMA if requested */
+-	drv_data->tx_channel = -1;
+-	drv_data->rx_channel = -1;
+-	if (platform_info->enable_dma) {
+-		/* Get rx DMA channel */
+-		drv_data->rx_channel = imx_dma_request_by_prio("spi_imx_rx",
+-							       DMA_PRIO_HIGH);
+-		if (drv_data->rx_channel < 0) {
+-			dev_err(dev,
+-				"probe - problem (%d) requesting rx channel\n",
+-				drv_data->rx_channel);
+-			goto err_no_rxdma;
+-		} else
+-			imx_dma_setup_handlers(drv_data->rx_channel, NULL,
+-						dma_err_handler, drv_data);
+-
+-		/* Get tx DMA channel */
+-		drv_data->tx_channel = imx_dma_request_by_prio("spi_imx_tx",
+-							       DMA_PRIO_MEDIUM);
+-		if (drv_data->tx_channel < 0) {
+-			dev_err(dev,
+-				"probe - problem (%d) requesting tx channel\n",
+-				drv_data->tx_channel);
+-			imx_dma_free(drv_data->rx_channel);
+-			goto err_no_txdma;
+-		} else
+-			imx_dma_setup_handlers(drv_data->tx_channel,
+-						dma_tx_handler, dma_err_handler,
+-						drv_data);
+-
+-		/* Set request source and burst length for allocated channels */
+-		switch (drv_data->pdev->id) {
+-		case 1:
+-			/* Using SPI1 */
+-			RSSR(drv_data->rx_channel) = DMA_REQ_SPI1_R;
+-			RSSR(drv_data->tx_channel) = DMA_REQ_SPI1_T;
+-			break;
+-		case 2:
+-			/* Using SPI2 */
+-			RSSR(drv_data->rx_channel) = DMA_REQ_SPI2_R;
+-			RSSR(drv_data->tx_channel) = DMA_REQ_SPI2_T;
+-			break;
+-		default:
+-			dev_err(dev, "probe - bad SPI Id\n");
+-			imx_dma_free(drv_data->rx_channel);
+-			imx_dma_free(drv_data->tx_channel);
+-			status = -ENODEV;
+-			goto err_no_devid;
++	master->num_chipselect = mxc_platform_info->num_chipselect;
++
++	spi_imx = spi_master_get_devdata(master);
++	spi_imx->bitbang.master = spi_master_get(master);
++	spi_imx->chipselect = mxc_platform_info->chipselect;
++
++	for (i = 0; i < master->num_chipselect; i++) {
++		if (spi_imx->chipselect[i] < 0)
++			continue;
++		ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME);
++		if (ret) {
++			i--;
++			while (i > 0)
++				if (spi_imx->chipselect[i] >= 0)
++					gpio_free(spi_imx->chipselect[i--]);
++			dev_err(&pdev->dev, "can't get cs gpios");
++			goto out_master_put;
+ 		}
+-		BLR(drv_data->rx_channel) = SPI_DMA_BLR;
+-		BLR(drv_data->tx_channel) = SPI_DMA_BLR;
+ 	}
+ 
+-	/* Load default SPI configuration */
+-	writel(SPI_RESET_START, drv_data->regs + SPI_RESET);
+-	writel(0, drv_data->regs + SPI_RESET);
+-	writel(SPI_DEFAULT_CONTROL, drv_data->regs + SPI_CONTROL);
++	spi_imx->bitbang.chipselect = spi_imx_chipselect;
++	spi_imx->bitbang.setup_transfer = spi_imx_setupxfer;
++	spi_imx->bitbang.txrx_bufs = spi_imx_transfer;
++	spi_imx->bitbang.master->setup = spi_imx_setup;
++	spi_imx->bitbang.master->cleanup = spi_imx_cleanup;
++	spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ 
+-	/* Initial and start queue */
+-	status = init_queue(drv_data);
+-	if (status != 0) {
+-		dev_err(&pdev->dev, "probe - problem initializing queue\n");
+-		goto err_init_queue;
+-	}
+-	status = start_queue(drv_data);
+-	if (status != 0) {
+-		dev_err(&pdev->dev, "probe - problem starting queue\n");
+-		goto err_start_queue;
+-	}
++	init_completion(&spi_imx->xfer_done);
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		dev_err(&pdev->dev, "can't get platform resource\n");
++		ret = -ENOMEM;
++		goto out_gpio_free;
++	}
++
++	if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
++		dev_err(&pdev->dev, "request_mem_region failed\n");
++		ret = -EBUSY;
++		goto out_gpio_free;
++	}
++
++	spi_imx->base = ioremap(res->start, resource_size(res));
++	if (!spi_imx->base) {
++		ret = -EINVAL;
++		goto out_release_mem;
++	}
++
++	spi_imx->irq = platform_get_irq(pdev, 0);
++	if (!spi_imx->irq) {
++		ret = -EINVAL;
++		goto out_iounmap;
++	}
++
++	ret = request_irq(spi_imx->irq, spi_imx_isr, 0, DRIVER_NAME, spi_imx);
++	if (ret) {
++		dev_err(&pdev->dev, "can't get irq%d: %d\n", spi_imx->irq, ret);
++		goto out_iounmap;
++	}
++
++	if (cpu_is_mx31() || cpu_is_mx35()) {
++		spi_imx->intctrl = mx31_intctrl;
++		spi_imx->config = mx31_config;
++		spi_imx->trigger = mx31_trigger;
++		spi_imx->rx_available = mx31_rx_available;
++	} else  if (cpu_is_mx27() || cpu_is_mx21()) {
++		spi_imx->intctrl = mx27_intctrl;
++		spi_imx->config = mx27_config;
++		spi_imx->trigger = mx27_trigger;
++		spi_imx->rx_available = mx27_rx_available;
++	} else if (cpu_is_mx1()) {
++		spi_imx->intctrl = mx1_intctrl;
++		spi_imx->config = mx1_config;
++		spi_imx->trigger = mx1_trigger;
++		spi_imx->rx_available = mx1_rx_available;
++	} else
++		BUG();
+ 
+-	/* Register with the SPI framework */
+-	platform_set_drvdata(pdev, drv_data);
+-	status = spi_register_master(master);
+-	if (status != 0) {
+-		dev_err(&pdev->dev, "probe - problem registering spi master\n");
+-		goto err_spi_register;
++	spi_imx->clk = clk_get(&pdev->dev, NULL);
++	if (IS_ERR(spi_imx->clk)) {
++		dev_err(&pdev->dev, "unable to get clock\n");
++		ret = PTR_ERR(spi_imx->clk);
++		goto out_free_irq;
+ 	}
+ 
+-	dev_dbg(dev, "probe succeded\n");
+-	return 0;
++	clk_enable(spi_imx->clk);
++	spi_imx->spi_clk = clk_get_rate(spi_imx->clk);
+ 
+-err_init_queue:
+-err_start_queue:
+-err_spi_register:
+-	destroy_queue(drv_data);
++	if (!cpu_is_mx31() || !cpu_is_mx35())
++		writel(1, spi_imx->base + MXC_RESET);
+ 
+-err_no_rxdma:
+-err_no_txdma:
+-err_no_devid:
+-	free_irq(irq, drv_data);
++	spi_imx->intctrl(spi_imx, 0);
+ 
+-err_no_irqres:
+-	iounmap(drv_data->regs);
++	ret = spi_bitbang_start(&spi_imx->bitbang);
++	if (ret) {
++		dev_err(&pdev->dev, "bitbang start failed with %d\n", ret);
++		goto out_clk_put;
++	}
+ 
+-err_no_iomap:
+-	release_resource(drv_data->ioarea);
+-	kfree(drv_data->ioarea);
++	dev_info(&pdev->dev, "probed\n");
+ 
+-err_no_iores:
+-	clk_disable(drv_data->clk);
+-	clk_put(drv_data->clk);
++	return ret;
+ 
+-err_no_clk:
++out_clk_put:
++	clk_disable(spi_imx->clk);
++	clk_put(spi_imx->clk);
++out_free_irq:
++	free_irq(spi_imx->irq, spi_imx);
++out_iounmap:
++	iounmap(spi_imx->base);
++out_release_mem:
++	release_mem_region(res->start, resource_size(res));
++out_gpio_free:
++	for (i = 0; i < master->num_chipselect; i++)
++		if (spi_imx->chipselect[i] >= 0)
++			gpio_free(spi_imx->chipselect[i]);
++out_master_put:
+ 	spi_master_put(master);
+-
+-err_no_pdata:
+-err_no_mem:
+-	return status;
++	kfree(master);
++	platform_set_drvdata(pdev, NULL);
++	return ret;
+ }
+ 
+ static int __exit spi_imx_remove(struct platform_device *pdev)
+ {
+-	struct driver_data *drv_data = platform_get_drvdata(pdev);
+-	int irq;
+-	int status = 0;
+-
+-	if (!drv_data)
+-		return 0;
+-
+-	tasklet_kill(&drv_data->pump_transfers);
++	struct spi_master *master = platform_get_drvdata(pdev);
++	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
++	int i;
+ 
+-	/* Remove the queue */
+-	status = destroy_queue(drv_data);
+-	if (status != 0) {
+-		dev_err(&pdev->dev, "queue remove failed (%d)\n", status);
+-		return status;
+-	}
+-
+-	/* Reset SPI */
+-	writel(SPI_RESET_START, drv_data->regs + SPI_RESET);
+-	writel(0, drv_data->regs + SPI_RESET);
+-
+-	/* Release DMA */
+-	if (drv_data->master_info->enable_dma) {
+-		RSSR(drv_data->rx_channel) = 0;
+-		RSSR(drv_data->tx_channel) = 0;
+-		imx_dma_free(drv_data->tx_channel);
+-		imx_dma_free(drv_data->rx_channel);
+-	}
++	spi_bitbang_stop(&spi_imx->bitbang);
+ 
+-	/* Release IRQ */
+-	irq = platform_get_irq(pdev, 0);
+-	if (irq >= 0)
+-		free_irq(irq, drv_data);
++	writel(0, spi_imx->base + MXC_CSPICTRL);
++	clk_disable(spi_imx->clk);
++	clk_put(spi_imx->clk);
++	free_irq(spi_imx->irq, spi_imx);
++	iounmap(spi_imx->base);
+ 
+-	clk_disable(drv_data->clk);
+-	clk_put(drv_data->clk);
++	for (i = 0; i < master->num_chipselect; i++)
++		if (spi_imx->chipselect[i] >= 0)
++			gpio_free(spi_imx->chipselect[i]);
+ 
+-	/* Release map resources */
+-	iounmap(drv_data->regs);
+-	release_resource(drv_data->ioarea);
+-	kfree(drv_data->ioarea);
++	spi_master_put(master);
+ 
+-	/* Disconnect from the SPI framework */
+-	spi_unregister_master(drv_data->master);
+-	spi_master_put(drv_data->master);
++	release_mem_region(res->start, resource_size(res));
+ 
+-	/* Prevent double remove */
+ 	platform_set_drvdata(pdev, NULL);
+ 
+-	dev_dbg(&pdev->dev, "remove succeded\n");
+-
+ 	return 0;
+ }
+ 
+-static void spi_imx_shutdown(struct platform_device *pdev)
+-{
+-	struct driver_data *drv_data = platform_get_drvdata(pdev);
+-
+-	/* Reset SPI */
+-	writel(SPI_RESET_START, drv_data->regs + SPI_RESET);
+-	writel(0, drv_data->regs + SPI_RESET);
+-
+-	dev_dbg(&pdev->dev, "shutdown succeded\n");
+-}
+-
+-#ifdef CONFIG_PM
+-
+-static int spi_imx_suspend(struct platform_device *pdev, pm_message_t state)
+-{
+-	struct driver_data *drv_data = platform_get_drvdata(pdev);
+-	int status = 0;
+-
+-	status = stop_queue(drv_data);
+-	if (status != 0) {
+-		dev_warn(&pdev->dev, "suspend cannot stop queue\n");
+-		return status;
+-	}
+-
+-	dev_dbg(&pdev->dev, "suspended\n");
+-
+-	return 0;
+-}
+-
+-static int spi_imx_resume(struct platform_device *pdev)
+-{
+-	struct driver_data *drv_data = platform_get_drvdata(pdev);
+-	int status = 0;
+-
+-	/* Start the queue running */
+-	status = start_queue(drv_data);
+-	if (status != 0)
+-		dev_err(&pdev->dev, "problem starting queue (%d)\n", status);
+-	else
+-		dev_dbg(&pdev->dev, "resumed\n");
+-
+-	return status;
+-}
+-#else
+-#define spi_imx_suspend NULL
+-#define spi_imx_resume NULL
+-#endif /* CONFIG_PM */
+-
+-/* work with hotplug and coldplug */
+-MODULE_ALIAS("platform:spi_imx");
+-
+-static struct platform_driver driver = {
++static struct platform_driver spi_imx_driver = {
+ 	.driver = {
+-		.name = "spi_imx",
+-		.owner = THIS_MODULE,
+-	},
++		   .name = DRIVER_NAME,
++		   .owner = THIS_MODULE,
++		   },
++	.probe = spi_imx_probe,
+ 	.remove = __exit_p(spi_imx_remove),
+-	.shutdown = spi_imx_shutdown,
+-	.suspend = spi_imx_suspend,
+-	.resume = spi_imx_resume,
+ };
+ 
+ static int __init spi_imx_init(void)
+ {
+-	return platform_driver_probe(&driver, spi_imx_probe);
++	return platform_driver_register(&spi_imx_driver);
+ }
+-module_init(spi_imx_init);
+ 
+ static void __exit spi_imx_exit(void)
+ {
+-	platform_driver_unregister(&driver);
++	platform_driver_unregister(&spi_imx_driver);
+ }
++
++module_init(spi_imx_init);
+ module_exit(spi_imx_exit);
+ 
+-MODULE_AUTHOR("Andrea Paterniani, <a.paterniani at swapp-eng.it>");
+-MODULE_DESCRIPTION("iMX SPI Controller Driver");
++MODULE_DESCRIPTION("SPI Master Controller driver");
++MODULE_AUTHOR("Sascha Hauer, Pengutronix");
+ MODULE_LICENSE("GPL");
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0002-MXC-NFC-Remove-useless-structure-member.patch b/recipes/linux/linux-2.6.31/pcm043/0002-MXC-NFC-Remove-useless-structure-member.patch
new file mode 100644
index 0000000..1cad5b5
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0002-MXC-NFC-Remove-useless-structure-member.patch
@@ -0,0 +1,45 @@
+From ec0217a98d38662cc058dcc6124c5a1e7a6bc8db Mon Sep 17 00:00:00 2001
+From: Juergen Beisert <j.beisert at pengutronix.de>
+Date: Tue, 29 Sep 2009 13:51:19 +0200
+Subject: [PATCH 02/15] MXC NFC: Remove useless structure member
+
+Remove a local copy of a value always present in other structures.
+
+Signed-off-by: Juergen Beisert <j.beisert at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand_v2.c |    5 +----
+ 1 files changed, 1 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand_v2.c b/drivers/mtd/nand/mxc_nand_v2.c
+index b7ae2e0..3483e7d 100644
+--- a/drivers/mtd/nand/mxc_nand_v2.c
++++ b/drivers/mtd/nand/mxc_nand_v2.c
+@@ -104,7 +104,6 @@ struct mxc_nand_host {
+ 	unsigned int		buf_start;
+ 
+ 	wait_queue_head_t	irq_waitq;
+-	int			g_page_mask;
+ 
+ 	struct clk		*clk;
+ 	int			clk_enabled;
+@@ -473,7 +472,7 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
+ 	struct nand_chip *nand_chip = mtd->priv;
+ 	struct mxc_nand_host *host = nand_chip->priv;
+ 
+-	u32 page_mask = host->g_page_mask;
++	u32 page_mask = nand_chip->pagemask;
+ 
+ 	if (column != -1) {
+ 		send_addr(host, column & 0xFF);
+@@ -790,8 +789,6 @@ static int mxc_nand_scan_bbt(struct mtd_info *mtd)
+ 	struct nand_chip *this = mtd->priv;
+ 	struct mxc_nand_host *host = this->priv;
+ 
+-	host->g_page_mask = this->pagemask;
+-
+ 	if (mtd->writesize == 2048) {
+ 		mxc_set_nfms(mtd, 1 << NFMS_NF_PG_SZ);
+ 		this->ecc.layout = &nand_hw_eccoob_2k;
+-- 
+1.6.1
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0002-mfd-Add-Freescale-MC13783-driver.patch b/recipes/linux/linux-2.6.31/pcm043/0002-mfd-Add-Freescale-MC13783-driver.patch
new file mode 100644
index 0000000..c975666
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0002-mfd-Add-Freescale-MC13783-driver.patch
@@ -0,0 +1,984 @@
+From b7f6a24d9c7f9715845cc910000618f2c658ea27 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Wed, 19 Aug 2009 01:40:28 +0200
+Subject: [PATCH 02/28] mfd: Add Freescale MC13783 driver
+
+This driver provides the core Freescale MC13783 support. It
+registers the client platform_devices and provides access
+to the A/D converter.
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+Signed-off-by: Samuel Ortiz <sameo at linux.intel.com>
+---
+ drivers/mfd/Kconfig                 |   10 +
+ drivers/mfd/Makefile                |    2 +
+ drivers/mfd/mc13783-core.c          |  427 +++++++++++++++++++++++++++++++++++
+ include/linux/mfd/mc13783-private.h |  396 ++++++++++++++++++++++++++++++++
+ include/linux/mfd/mc13783.h         |   84 +++++++
+ 5 files changed, 919 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/mfd/mc13783-core.c
+ create mode 100644 include/linux/mfd/mc13783-private.h
+ create mode 100644 include/linux/mfd/mc13783.h
+
+diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
+index 491ac0f..c9aa085 100644
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -228,6 +228,16 @@ config MFD_PCF50633
+ 	  facilities, and registers devices for the various functions
+ 	  so that function-specific drivers can bind to them.
+ 
++config MFD_MC13783
++	tristate "Support Freescale MC13783"
++	depends on SPI_MASTER
++	select MFD_CORE
++	help
++	  Support for the Freescale (Atlas) MC13783 PMIC and audio CODEC.
++	  This driver provides common support for accessing  the device,
++	  additional drivers must be enabled in order to use the
++	  functionality of the device.
++
+ config PCF50633_ADC
+ 	tristate "Support for NXP PCF50633 ADC"
+ 	depends on MFD_PCF50633
+diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
+index 6f8a9a1..7262822 100644
+--- a/drivers/mfd/Makefile
++++ b/drivers/mfd/Makefile
+@@ -24,6 +24,8 @@ obj-$(CONFIG_MENELAUS)		+= menelaus.o
+ 
+ obj-$(CONFIG_TWL4030_CORE)	+= twl4030-core.o twl4030-irq.o
+ 
++obj-$(CONFIG_MFD_MC13783)	+= mc13783-core.o
++
+ obj-$(CONFIG_MFD_CORE)		+= mfd-core.o
+ 
+ obj-$(CONFIG_EZX_PCAP)		+= ezx-pcap.o
+diff --git a/drivers/mfd/mc13783-core.c b/drivers/mfd/mc13783-core.c
+new file mode 100644
+index 0000000..e354d29
+--- /dev/null
++++ b/drivers/mfd/mc13783-core.c
+@@ -0,0 +1,427 @@
++/*
++ * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer at pengutronix.de>
++ *
++ * This code is in parts based on wm8350-core.c and pcf50633-core.c
++ *
++ * Initial development of this code was funded by
++ * Phytec Messtechnik GmbH, http://www.phytec.de
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/mfd/mc13783-private.h>
++#include <linux/platform_device.h>
++#include <linux/mfd/mc13783.h>
++#include <linux/completion.h>
++#include <linux/interrupt.h>
++#include <linux/mfd/core.h>
++#include <linux/spi/spi.h>
++#include <linux/uaccess.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/irq.h>
++
++#define MC13783_MAX_REG_NUM	0x3f
++#define MC13783_FRAME_MASK	0x00ffffff
++#define MC13783_MAX_REG_NUM	0x3f
++#define MC13783_REG_NUM_SHIFT	0x19
++#define MC13783_WRITE_BIT_SHIFT	31
++
++static inline int spi_rw(struct spi_device *spi, u8 * buf, size_t len)
++{
++	struct spi_transfer t = {
++		.tx_buf = (const void *)buf,
++		.rx_buf = buf,
++		.len = len,
++		.cs_change = 0,
++		.delay_usecs = 0,
++	};
++	struct spi_message m;
++
++	spi_message_init(&m);
++	spi_message_add_tail(&t, &m);
++	if (spi_sync(spi, &m) != 0 || m.status != 0)
++		return -EINVAL;
++	return len - m.actual_length;
++}
++
++static int mc13783_read(struct mc13783 *mc13783, int reg_num, u32 *reg_val)
++{
++	unsigned int frame = 0;
++	int ret = 0;
++
++	if (reg_num > MC13783_MAX_REG_NUM)
++		return -EINVAL;
++
++	frame |= reg_num << MC13783_REG_NUM_SHIFT;
++
++	ret = spi_rw(mc13783->spi_device, (u8 *)&frame, 4);
++
++	*reg_val = frame & MC13783_FRAME_MASK;
++
++	return ret;
++}
++
++static int mc13783_write(struct mc13783 *mc13783, int reg_num, u32 reg_val)
++{
++	unsigned int frame = 0;
++
++	if (reg_num > MC13783_MAX_REG_NUM)
++		return -EINVAL;
++
++	frame |= (1 << MC13783_WRITE_BIT_SHIFT);
++	frame |= reg_num << MC13783_REG_NUM_SHIFT;
++	frame |= reg_val & MC13783_FRAME_MASK;
++
++	return spi_rw(mc13783->spi_device, (u8 *)&frame, 4);
++}
++
++int mc13783_reg_read(struct mc13783 *mc13783, int reg_num, u32 *reg_val)
++{
++	int ret;
++
++	mutex_lock(&mc13783->io_lock);
++	ret = mc13783_read(mc13783, reg_num, reg_val);
++	mutex_unlock(&mc13783->io_lock);
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(mc13783_reg_read);
++
++int mc13783_reg_write(struct mc13783 *mc13783, int reg_num, u32 reg_val)
++{
++	int ret;
++
++	mutex_lock(&mc13783->io_lock);
++	ret = mc13783_write(mc13783, reg_num, reg_val);
++	mutex_unlock(&mc13783->io_lock);
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(mc13783_reg_write);
++
++/**
++ * mc13783_set_bits - Bitmask write
++ *
++ * @mc13783: Pointer to mc13783 control structure
++ * @reg:    Register to access
++ * @mask:   Mask of bits to change
++ * @val:    Value to set for masked bits
++ */
++int mc13783_set_bits(struct mc13783 *mc13783, int reg, u32 mask, u32 val)
++{
++	u32 tmp;
++	int ret;
++
++	mutex_lock(&mc13783->io_lock);
++
++	ret = mc13783_read(mc13783, reg, &tmp);
++	tmp = (tmp & ~mask) | val;
++	if (ret == 0)
++		ret = mc13783_write(mc13783, reg, tmp);
++
++	mutex_unlock(&mc13783->io_lock);
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(mc13783_set_bits);
++
++int mc13783_register_irq(struct mc13783 *mc13783, int irq,
++		void (*handler) (int, void *), void *data)
++{
++	if (irq < 0 || irq > MC13783_NUM_IRQ || !handler)
++		return -EINVAL;
++
++	if (WARN_ON(mc13783->irq_handler[irq].handler))
++		return -EBUSY;
++
++	mutex_lock(&mc13783->io_lock);
++	mc13783->irq_handler[irq].handler = handler;
++	mc13783->irq_handler[irq].data = data;
++	mutex_unlock(&mc13783->io_lock);
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(mc13783_register_irq);
++
++int mc13783_free_irq(struct mc13783 *mc13783, int irq)
++{
++	if (irq < 0 || irq > MC13783_NUM_IRQ)
++		return -EINVAL;
++
++	mutex_lock(&mc13783->io_lock);
++	mc13783->irq_handler[irq].handler = NULL;
++	mutex_unlock(&mc13783->io_lock);
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(mc13783_free_irq);
++
++static void mc13783_irq_work(struct work_struct *work)
++{
++	struct mc13783 *mc13783 = container_of(work, struct mc13783, work);
++	int i;
++	unsigned int adc_sts;
++
++	/* check if the adc has finished any completion */
++	mc13783_reg_read(mc13783, MC13783_REG_INTERRUPT_STATUS_0, &adc_sts);
++	mc13783_reg_write(mc13783, MC13783_REG_INTERRUPT_STATUS_0,
++			adc_sts & MC13783_INT_STAT_ADCDONEI);
++
++	if (adc_sts & MC13783_INT_STAT_ADCDONEI)
++		complete_all(&mc13783->adc_done);
++
++	for (i = 0; i < MC13783_NUM_IRQ; i++)
++		if (mc13783->irq_handler[i].handler)
++			mc13783->irq_handler[i].handler(i,
++					mc13783->irq_handler[i].data);
++	enable_irq(mc13783->irq);
++}
++
++static irqreturn_t mc13783_interrupt(int irq, void *dev_id)
++{
++	struct mc13783 *mc13783 = dev_id;
++
++	disable_irq_nosync(irq);
++
++	schedule_work(&mc13783->work);
++	return IRQ_HANDLED;
++}
++
++/* set adc to ts interrupt mode, which generates touchscreen wakeup interrupt */
++static inline void mc13783_adc_set_ts_irq_mode(struct mc13783 *mc13783)
++{
++	unsigned int reg_adc0, reg_adc1;
++
++	reg_adc0 = MC13783_ADC0_ADREFEN | MC13783_ADC0_ADREFMODE
++			| MC13783_ADC0_TSMOD0;
++	reg_adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN;
++
++	mc13783_reg_write(mc13783, MC13783_REG_ADC_0, reg_adc0);
++	mc13783_reg_write(mc13783, MC13783_REG_ADC_1, reg_adc1);
++}
++
++int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode,
++		unsigned int channel, unsigned int *sample)
++{
++	unsigned int reg_adc0, reg_adc1;
++	int i;
++
++	mutex_lock(&mc13783->adc_conv_lock);
++
++	/* set up auto incrementing anyway to make quick read */
++	reg_adc0 =  MC13783_ADC0_ADINC1 | MC13783_ADC0_ADINC2;
++	/* enable the adc, ignore external triggering and set ASC to trigger
++	 * conversion */
++	reg_adc1 =  MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN
++		| MC13783_ADC1_ASC;
++
++	/* setup channel number */
++	if (channel > 7)
++		reg_adc1 |= MC13783_ADC1_ADSEL;
++
++	switch (mode) {
++	case MC13783_ADC_MODE_TS:
++		/* enables touch screen reference mode and set touchscreen mode
++		 * to position mode */
++		reg_adc0 |= MC13783_ADC0_ADREFEN | MC13783_ADC0_ADREFMODE
++			| MC13783_ADC0_TSMOD0 | MC13783_ADC0_TSMOD1;
++		reg_adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT;
++		break;
++	case MC13783_ADC_MODE_SINGLE_CHAN:
++		reg_adc1 |= (channel & 0x7) << MC13783_ADC1_CHAN0_SHIFT;
++		reg_adc1 |= MC13783_ADC1_RAND;
++		break;
++	case MC13783_ADC_MODE_MULT_CHAN:
++		reg_adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	mc13783_reg_write(mc13783, MC13783_REG_ADC_0, reg_adc0);
++	mc13783_reg_write(mc13783, MC13783_REG_ADC_1, reg_adc1);
++
++	wait_for_completion_interruptible(&mc13783->adc_done);
++
++	for (i = 0; i < 4; i++)
++		mc13783_reg_read(mc13783, MC13783_REG_ADC_2, &sample[i]);
++
++	if (mc13783->ts_active)
++		mc13783_adc_set_ts_irq_mode(mc13783);
++
++	mutex_unlock(&mc13783->adc_conv_lock);
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion);
++
++void mc13783_adc_set_ts_status(struct mc13783 *mc13783, unsigned int status)
++{
++	mc13783->ts_active = status;
++}
++EXPORT_SYMBOL_GPL(mc13783_adc_set_ts_status);
++
++static int mc13783_check_revision(struct mc13783 *mc13783)
++{
++	u32 rev_id, rev1, rev2, finid, icid;
++
++	mc13783_read(mc13783, MC13783_REG_REVISION, &rev_id);
++
++	rev1 = (rev_id & 0x018) >> 3;
++	rev2 = (rev_id & 0x007);
++	icid = (rev_id & 0x01C0) >> 6;
++	finid = (rev_id & 0x01E00) >> 9;
++
++	/* Ver 0.2 is actually 3.2a.  Report as 3.2 */
++	if ((rev1 == 0) && (rev2 == 2))
++		rev1 = 3;
++
++	if (rev1 == 0 || icid != 2) {
++		dev_err(mc13783->dev, "No MC13783 detected.\n");
++		return -ENODEV;
++	}
++
++	mc13783->revision = ((rev1 * 10) + rev2);
++	dev_info(mc13783->dev, "MC13783 Rev %d.%d FinVer %x detected\n", rev1,
++	       rev2, finid);
++
++	return 0;
++}
++
++/*
++ * Register a client device.  This is non-fatal since there is no need to
++ * fail the entire device init due to a single platform device failing.
++ */
++static void mc13783_client_dev_register(struct mc13783 *mc13783,
++				       const char *name)
++{
++	struct mfd_cell cell = {};
++
++	cell.name = name;
++
++	mfd_add_devices(mc13783->dev, -1, &cell, 1, NULL, 0);
++}
++
++static int __devinit mc13783_probe(struct spi_device *spi)
++{
++	struct mc13783 *mc13783;
++	struct mc13783_platform_data *pdata = spi->dev.platform_data;
++	int ret;
++
++	mc13783 = kzalloc(sizeof(struct mc13783), GFP_KERNEL);
++	if (!mc13783)
++		return -ENOMEM;
++
++	dev_set_drvdata(&spi->dev, mc13783);
++	spi->mode = SPI_MODE_0 | SPI_CS_HIGH;
++	spi->bits_per_word = 32;
++	spi_setup(spi);
++
++	mc13783->spi_device = spi;
++	mc13783->dev = &spi->dev;
++	mc13783->irq = spi->irq;
++
++	INIT_WORK(&mc13783->work, mc13783_irq_work);
++	mutex_init(&mc13783->io_lock);
++	mutex_init(&mc13783->adc_conv_lock);
++	init_completion(&mc13783->adc_done);
++
++	if (pdata) {
++		mc13783->flags = pdata->flags;
++		mc13783->regulators = pdata->regulators;
++		mc13783->num_regulators = pdata->num_regulators;
++	}
++
++	if (mc13783_check_revision(mc13783)) {
++		ret = -ENODEV;
++		goto err_out;
++	}
++
++	/* clear and mask all interrupts */
++	mc13783_reg_write(mc13783, MC13783_REG_INTERRUPT_STATUS_0, 0x00ffffff);
++	mc13783_reg_write(mc13783, MC13783_REG_INTERRUPT_MASK_0, 0x00ffffff);
++	mc13783_reg_write(mc13783, MC13783_REG_INTERRUPT_STATUS_1, 0x00ffffff);
++	mc13783_reg_write(mc13783, MC13783_REG_INTERRUPT_MASK_1, 0x00ffffff);
++
++	/* unmask adcdone interrupts */
++	mc13783_set_bits(mc13783, MC13783_REG_INTERRUPT_MASK_0,
++			MC13783_INT_MASK_ADCDONEM, 0);
++
++	ret = request_irq(mc13783->irq, mc13783_interrupt,
++			IRQF_DISABLED | IRQF_TRIGGER_HIGH, "mc13783",
++			mc13783);
++	if (ret)
++		goto err_out;
++
++	if (mc13783->flags & MC13783_USE_CODEC)
++		mc13783_client_dev_register(mc13783, "mc13783-codec");
++	if (mc13783->flags & MC13783_USE_ADC)
++		mc13783_client_dev_register(mc13783, "mc13783-adc");
++	if (mc13783->flags & MC13783_USE_RTC)
++		mc13783_client_dev_register(mc13783, "mc13783-rtc");
++	if (mc13783->flags & MC13783_USE_REGULATOR)
++		mc13783_client_dev_register(mc13783, "mc13783-regulator");
++	if (mc13783->flags & MC13783_USE_TOUCHSCREEN)
++		mc13783_client_dev_register(mc13783, "mc13783-ts");
++
++	return 0;
++
++err_out:
++	kfree(mc13783);
++	return ret;
++}
++
++static int __devexit mc13783_remove(struct spi_device *spi)
++{
++	struct mc13783 *mc13783;
++
++	mc13783 = dev_get_drvdata(&spi->dev);
++
++	free_irq(mc13783->irq, mc13783);
++
++	mfd_remove_devices(&spi->dev);
++
++	return 0;
++}
++
++static struct spi_driver pmic_driver = {
++	.driver = {
++		   .name = "mc13783",
++		   .bus = &spi_bus_type,
++		   .owner = THIS_MODULE,
++	},
++	.probe = mc13783_probe,
++	.remove = __devexit_p(mc13783_remove),
++};
++
++static int __init pmic_init(void)
++{
++	return spi_register_driver(&pmic_driver);
++}
++subsys_initcall(pmic_init);
++
++static void __exit pmic_exit(void)
++{
++	spi_unregister_driver(&pmic_driver);
++}
++module_exit(pmic_exit);
++
++MODULE_DESCRIPTION("Core/Protocol driver for Freescale MC13783 PMIC");
++MODULE_AUTHOR("Sascha Hauer <s.hauer at pengutronix.de>");
++MODULE_LICENSE("GPL");
++
+diff --git a/include/linux/mfd/mc13783-private.h b/include/linux/mfd/mc13783-private.h
+new file mode 100644
+index 0000000..47e698c
+--- /dev/null
++++ b/include/linux/mfd/mc13783-private.h
+@@ -0,0 +1,396 @@
++/*
++ * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer at pengutronix.de>
++ *
++ * Initial development of this code was funded by
++ * Phytec Messtechnik GmbH, http://www.phytec.de
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#ifndef __LINUX_MFD_MC13783_PRIV_H
++#define __LINUX_MFD_MC13783_PRIV_H
++
++#include <linux/platform_device.h>
++#include <linux/mfd/mc13783.h>
++#include <linux/workqueue.h>
++#include <linux/mutex.h>
++
++struct mc13783_irq {
++	void (*handler)(int, void *);
++	void *data;
++};
++
++#define MC13783_NUM_IRQ		2
++#define MC13783_IRQ_TS		0
++#define MC13783_IRQ_REGULATOR	1
++
++#define MC13783_ADC_MODE_TS		1
++#define MC13783_ADC_MODE_SINGLE_CHAN	2
++#define MC13783_ADC_MODE_MULT_CHAN	3
++
++struct mc13783 {
++	int revision;
++	struct device *dev;
++	struct spi_device *spi_device;
++
++	int (*read_dev)(void *data, char reg, int count, u32 *dst);
++	int (*write_dev)(void *data, char reg, int count, const u32 *src);
++
++	struct mutex io_lock;
++	void *io_data;
++	int irq;
++	unsigned int flags;
++
++	struct mc13783_irq irq_handler[MC13783_NUM_IRQ];
++	struct work_struct work;
++	struct completion adc_done;
++	unsigned int ts_active;
++	struct mutex adc_conv_lock;
++
++	struct mc13783_regulator_init_data *regulators;
++	int num_regulators;
++};
++
++int mc13783_reg_read(struct mc13783 *, int reg_num, u32 *);
++int mc13783_reg_write(struct mc13783 *, int, u32);
++int mc13783_set_bits(struct mc13783 *, int, u32, u32);
++int mc13783_free_irq(struct mc13783 *mc13783, int irq);
++int mc13783_register_irq(struct mc13783 *mc13783, int irq,
++		void (*handler) (int, void *), void *data);
++
++#define MC13783_REG_INTERRUPT_STATUS_0		 0
++#define MC13783_REG_INTERRUPT_MASK_0		 1
++#define MC13783_REG_INTERRUPT_SENSE_0		 2
++#define MC13783_REG_INTERRUPT_STATUS_1		 3
++#define MC13783_REG_INTERRUPT_MASK_1		 4
++#define MC13783_REG_INTERRUPT_SENSE_1		 5
++#define MC13783_REG_POWER_UP_MODE_SENSE		 6
++#define MC13783_REG_REVISION			 7
++#define MC13783_REG_SEMAPHORE			 8
++#define MC13783_REG_ARBITRATION_PERIPHERAL_AUDIO 9
++#define MC13783_REG_ARBITRATION_SWITCHERS	10
++#define MC13783_REG_ARBITRATION_REGULATORS_0	11
++#define MC13783_REG_ARBITRATION_REGULATORS_1	12
++#define MC13783_REG_POWER_CONTROL_0		13
++#define MC13783_REG_POWER_CONTROL_1		14
++#define MC13783_REG_POWER_CONTROL_2		15
++#define MC13783_REG_REGEN_ASSIGNMENT		16
++#define MC13783_REG_CONTROL_SPARE		17
++#define MC13783_REG_MEMORY_A			18
++#define MC13783_REG_MEMORY_B			19
++#define MC13783_REG_RTC_TIME			20
++#define MC13783_REG_RTC_ALARM			21
++#define MC13783_REG_RTC_DAY			22
++#define MC13783_REG_RTC_DAY_ALARM		23
++#define MC13783_REG_SWITCHERS_0			24
++#define MC13783_REG_SWITCHERS_1			25
++#define MC13783_REG_SWITCHERS_2			26
++#define MC13783_REG_SWITCHERS_3			27
++#define MC13783_REG_SWITCHERS_4			28
++#define MC13783_REG_SWITCHERS_5			29
++#define MC13783_REG_REGULATOR_SETTING_0		30
++#define MC13783_REG_REGULATOR_SETTING_1		31
++#define MC13783_REG_REGULATOR_MODE_0		32
++#define MC13783_REG_REGULATOR_MODE_1		33
++#define MC13783_REG_POWER_MISCELLANEOUS		34
++#define MC13783_REG_POWER_SPARE			35
++#define MC13783_REG_AUDIO_RX_0			36
++#define MC13783_REG_AUDIO_RX_1			37
++#define MC13783_REG_AUDIO_TX			38
++#define MC13783_REG_AUDIO_SSI_NETWORK		39
++#define MC13783_REG_AUDIO_CODEC			40
++#define MC13783_REG_AUDIO_STEREO_DAC		41
++#define MC13783_REG_AUDIO_SPARE			42
++#define MC13783_REG_ADC_0			43
++#define MC13783_REG_ADC_1			44
++#define MC13783_REG_ADC_2			45
++#define MC13783_REG_ADC_3			46
++#define MC13783_REG_ADC_4			47
++#define MC13783_REG_CHARGER			48
++#define MC13783_REG_USB				49
++#define MC13783_REG_CHARGE_USB_SPARE		50
++#define MC13783_REG_LED_CONTROL_0		51
++#define MC13783_REG_LED_CONTROL_1		52
++#define MC13783_REG_LED_CONTROL_2		53
++#define MC13783_REG_LED_CONTROL_3		54
++#define MC13783_REG_LED_CONTROL_4		55
++#define MC13783_REG_LED_CONTROL_5		56
++#define MC13783_REG_SPARE			57
++#define MC13783_REG_TRIM_0			58
++#define MC13783_REG_TRIM_1			59
++#define MC13783_REG_TEST_0			60
++#define MC13783_REG_TEST_1			61
++#define MC13783_REG_TEST_2			62
++#define MC13783_REG_TEST_3			63
++#define MC13783_REG_NB				64
++
++
++/*
++ * Interrupt Status
++ */
++#define MC13783_INT_STAT_ADCDONEI	(1 << 0)
++#define MC13783_INT_STAT_ADCBISDONEI	(1 << 1)
++#define MC13783_INT_STAT_TSI		(1 << 2)
++#define MC13783_INT_STAT_WHIGHI		(1 << 3)
++#define MC13783_INT_STAT_WLOWI		(1 << 4)
++#define MC13783_INT_STAT_CHGDETI	(1 << 6)
++#define MC13783_INT_STAT_CHGOVI		(1 << 7)
++#define MC13783_INT_STAT_CHGREVI	(1 << 8)
++#define MC13783_INT_STAT_CHGSHORTI	(1 << 9)
++#define MC13783_INT_STAT_CCCVI		(1 << 10)
++#define MC13783_INT_STAT_CHGCURRI	(1 << 11)
++#define MC13783_INT_STAT_BPONI		(1 << 12)
++#define MC13783_INT_STAT_LOBATLI	(1 << 13)
++#define MC13783_INT_STAT_LOBATHI	(1 << 14)
++#define MC13783_INT_STAT_UDPI		(1 << 15)
++#define MC13783_INT_STAT_USBI		(1 << 16)
++#define MC13783_INT_STAT_IDI		(1 << 19)
++#define MC13783_INT_STAT_Unused		(1 << 20)
++#define MC13783_INT_STAT_SE1I		(1 << 21)
++#define MC13783_INT_STAT_CKDETI		(1 << 22)
++#define MC13783_INT_STAT_UDMI		(1 << 23)
++
++/*
++ * Interrupt Mask
++ */
++#define MC13783_INT_MASK_ADCDONEM	(1 << 0)
++#define MC13783_INT_MASK_ADCBISDONEM	(1 << 1)
++#define MC13783_INT_MASK_TSM		(1 << 2)
++#define MC13783_INT_MASK_WHIGHM		(1 << 3)
++#define MC13783_INT_MASK_WLOWM		(1 << 4)
++#define MC13783_INT_MASK_CHGDETM	(1 << 6)
++#define MC13783_INT_MASK_CHGOVM		(1 << 7)
++#define MC13783_INT_MASK_CHGREVM	(1 << 8)
++#define MC13783_INT_MASK_CHGSHORTM	(1 << 9)
++#define MC13783_INT_MASK_CCCVM		(1 << 10)
++#define MC13783_INT_MASK_CHGCURRM	(1 << 11)
++#define MC13783_INT_MASK_BPONM		(1 << 12)
++#define MC13783_INT_MASK_LOBATLM	(1 << 13)
++#define MC13783_INT_MASK_LOBATHM	(1 << 14)
++#define MC13783_INT_MASK_UDPM		(1 << 15)
++#define MC13783_INT_MASK_USBM		(1 << 16)
++#define MC13783_INT_MASK_IDM		(1 << 19)
++#define MC13783_INT_MASK_SE1M		(1 << 21)
++#define MC13783_INT_MASK_CKDETM		(1 << 22)
++
++/*
++ * Reg Regulator Mode 0
++ */
++#define MC13783_REGCTRL_VAUDIO_EN	(1 << 0)
++#define MC13783_REGCTRL_VAUDIO_STBY	(1 << 1)
++#define MC13783_REGCTRL_VAUDIO_MODE	(1 << 2)
++#define MC13783_REGCTRL_VIOHI_EN	(1 << 3)
++#define MC13783_REGCTRL_VIOHI_STBY	(1 << 4)
++#define MC13783_REGCTRL_VIOHI_MODE	(1 << 5)
++#define MC13783_REGCTRL_VIOLO_EN	(1 << 6)
++#define MC13783_REGCTRL_VIOLO_STBY 	(1 << 7)
++#define MC13783_REGCTRL_VIOLO_MODE	(1 << 8)
++#define MC13783_REGCTRL_VDIG_EN		(1 << 9)
++#define MC13783_REGCTRL_VDIG_STBY	(1 << 10)
++#define MC13783_REGCTRL_VDIG_MODE	(1 << 11)
++#define MC13783_REGCTRL_VGEN_EN		(1 << 12)
++#define MC13783_REGCTRL_VGEN_STBY	(1 << 13)
++#define MC13783_REGCTRL_VGEN_MODE	(1 << 14)
++#define MC13783_REGCTRL_VRFDIG_EN	(1 << 15)
++#define MC13783_REGCTRL_VRFDIG_STBY	(1 << 16)
++#define MC13783_REGCTRL_VRFDIG_MODE	(1 << 17)
++#define MC13783_REGCTRL_VRFREF_EN	(1 << 18)
++#define MC13783_REGCTRL_VRFREF_STBY	(1 << 19)
++#define MC13783_REGCTRL_VRFREF_MODE	(1 << 20)
++#define MC13783_REGCTRL_VRFCP_EN	(1 << 21)
++#define MC13783_REGCTRL_VRFCP_STBY	(1 << 22)
++#define MC13783_REGCTRL_VRFCP_MODE	(1 << 23)
++
++/*
++ * Reg Regulator Mode 1
++ */
++#define MC13783_REGCTRL_VSIM_EN		(1 << 0)
++#define MC13783_REGCTRL_VSIM_STBY	(1 << 1)
++#define MC13783_REGCTRL_VSIM_MODE	(1 << 2)
++#define MC13783_REGCTRL_VESIM_EN	(1 << 3)
++#define MC13783_REGCTRL_VESIM_STBY	(1 << 4)
++#define MC13783_REGCTRL_VESIM_MODE	(1 << 5)
++#define MC13783_REGCTRL_VCAM_EN		(1 << 6)
++#define MC13783_REGCTRL_VCAM_STBY	(1 << 7)
++#define MC13783_REGCTRL_VCAM_MODE	(1 << 8)
++#define	MC13783_REGCTRL_VRFBG_EN	(1 << 9)
++#define MC13783_REGCTRL_VRFBG_STBY	(1 << 10)
++#define MC13783_REGCTRL_VVIB_EN		(1 << 11)
++#define MC13783_REGCTRL_VRF1_EN		(1 << 12)
++#define MC13783_REGCTRL_VRF1_STBY	(1 << 13)
++#define MC13783_REGCTRL_VRF1_MODE	(1 << 14)
++#define MC13783_REGCTRL_VRF2_EN		(1 << 15)
++#define MC13783_REGCTRL_VRF2_STBY	(1 << 16)
++#define MC13783_REGCTRL_VRF2_MODE	(1 << 17)
++#define MC13783_REGCTRL_VMMC1_EN	(1 << 18)
++#define MC13783_REGCTRL_VMMC1_STBY	(1 << 19)
++#define MC13783_REGCTRL_VMMC1_MODE	(1 << 20)
++#define MC13783_REGCTRL_VMMC2_EN	(1 << 21)
++#define MC13783_REGCTRL_VMMC2_STBY	(1 << 22)
++#define MC13783_REGCTRL_VMMC2_MODE	(1 << 23)
++
++/*
++ * Reg Regulator Misc.
++ */
++#define MC13783_REGCTRL_GPO1_EN		(1 << 6)
++#define MC13783_REGCTRL_GPO2_EN		(1 << 8)
++#define MC13783_REGCTRL_GPO3_EN		(1 << 10)
++#define MC13783_REGCTRL_GPO4_EN		(1 << 12)
++#define MC13783_REGCTRL_VIBPINCTRL	(1 << 14)
++
++/*
++ * Reg Switcher 4
++ */
++#define MC13783_SWCTRL_SW1A_MODE	(1 << 0)
++#define MC13783_SWCTRL_SW1A_STBY_MODE	(1 << 2)
++#define MC13783_SWCTRL_SW1A_DVS_SPEED	(1 << 6)
++#define MC13783_SWCTRL_SW1A_PANIC_MODE	(1 << 8)
++#define MC13783_SWCTRL_SW1A_SOFTSTART	(1 << 9)
++#define MC13783_SWCTRL_SW1B_MODE	(1 << 10)
++#define MC13783_SWCTRL_SW1B_STBY_MODE	(1 << 12)
++#define MC13783_SWCTRL_SW1B_DVS_SPEED	(1 << 14)
++#define MC13783_SWCTRL_SW1B_PANIC_MODE	(1 << 16)
++#define MC13783_SWCTRL_SW1B_SOFTSTART	(1 << 17)
++#define MC13783_SWCTRL_PLL_EN		(1 << 18)
++#define MC13783_SWCTRL_PLL_FACTOR	(1 << 19)
++
++/*
++ * Reg Switcher 5
++ */
++#define MC13783_SWCTRL_SW2A_MODE	(1 << 0)
++#define MC13783_SWCTRL_SW2A_STBY_MODE	(1 << 2)
++#define MC13783_SWCTRL_SW2A_DVS_SPEED	(1 << 6)
++#define MC13783_SWCTRL_SW2A_PANIC_MODE	(1 << 8)
++#define MC13783_SWCTRL_SW2A_SOFTSTART	(1 << 9)
++#define MC13783_SWCTRL_SW2B_MODE	(1 << 10)
++#define MC13783_SWCTRL_SW2B_STBY_MODE	(1 << 12)
++#define MC13783_SWCTRL_SW2B_DVS_SPEED	(1 << 14)
++#define MC13783_SWCTRL_SW2B_PANIC_MODE	(1 << 16)
++#define MC13783_SWCTRL_SW2B_SOFTSTART	(1 << 17)
++#define MC13783_SWSET_SW3		(1 << 18)
++#define MC13783_SWCTRL_SW3_EN		(1 << 20)
++#define MC13783_SWCTRL_SW3_STBY		(1 << 21)
++#define MC13783_SWCTRL_SW3_MODE		(1 << 22)
++
++/*
++ * ADC/Touch
++ */
++#define MC13783_ADC0_LICELLCON		(1 << 0)
++#define MC13783_ADC0_CHRGICON		(1 << 1)
++#define MC13783_ADC0_BATICON		(1 << 2)
++#define MC13783_ADC0_RTHEN 		(1 << 3)
++#define MC13783_ADC0_DTHEN		(1 << 4)
++#define MC13783_ADC0_UIDEN		(1 << 5)
++#define MC13783_ADC0_ADOUTEN 		(1 << 6)
++#define MC13783_ADC0_ADOUTPER		(1 << 7)
++#define MC13783_ADC0_ADREFEN		(1 << 10)
++#define MC13783_ADC0_ADREFMODE		(1 << 11)
++#define MC13783_ADC0_TSMOD0		(1 << 12)
++#define MC13783_ADC0_TSMOD1		(1 << 13)
++#define MC13783_ADC0_TSMOD2		(1 << 14)
++#define MC13783_ADC0_CHRGRAWDIV		(1 << 15)
++#define MC13783_ADC0_ADINC1		(1 << 16)
++#define MC13783_ADC0_ADINC2		(1 << 17)
++#define MC13783_ADC0_WCOMP		(1 << 18)
++#define MC13783_ADC0_ADCBIS0		(1 << 23)
++
++#define MC13783_ADC1_ADEN		(1 << 0)
++#define MC13783_ADC1_RAND		(1 << 1)
++#define MC13783_ADC1_ADSEL		(1 << 3)
++#define MC13783_ADC1_TRIGMASK		(1 << 4)
++#define MC13783_ADC1_ADA10		(1 << 5)
++#define MC13783_ADC1_ADA11		(1 << 6)
++#define MC13783_ADC1_ADA12		(1 << 7)
++#define MC13783_ADC1_ADA20		(1 << 8)
++#define MC13783_ADC1_ADA21		(1 << 9)
++#define MC13783_ADC1_ADA22		(1 << 10)
++#define MC13783_ADC1_ATO0		(1 << 11)
++#define MC13783_ADC1_ATO1		(1 << 12)
++#define MC13783_ADC1_ATO2		(1 << 13)
++#define MC13783_ADC1_ATO3		(1 << 14)
++#define MC13783_ADC1_ATO4		(1 << 15)
++#define MC13783_ADC1_ATO5		(1 << 16)
++#define MC13783_ADC1_ATO6		(1 << 17)
++#define MC13783_ADC1_ATO7		(1 << 18)
++#define MC13783_ADC1_ATOX		(1 << 19)
++#define MC13783_ADC1_ASC		(1 << 20)
++#define MC13783_ADC1_ADTRIGIGN		(1 << 21)
++#define MC13783_ADC1_ADONESHOT		(1 << 22)
++#define MC13783_ADC1_ADCBIS1		(1 << 23)
++
++#define MC13783_ADC1_CHAN0_SHIFT	5
++#define MC13783_ADC1_CHAN1_SHIFT	8
++
++#define MC13783_ADC2_ADD10		(1 << 2)
++#define MC13783_ADC2_ADD11		(1 << 3)
++#define MC13783_ADC2_ADD12		(1 << 4)
++#define MC13783_ADC2_ADD13		(1 << 5)
++#define MC13783_ADC2_ADD14		(1 << 6)
++#define MC13783_ADC2_ADD15		(1 << 7)
++#define MC13783_ADC2_ADD16		(1 << 8)
++#define MC13783_ADC2_ADD17		(1 << 9)
++#define MC13783_ADC2_ADD18		(1 << 10)
++#define MC13783_ADC2_ADD19		(1 << 11)
++#define MC13783_ADC2_ADD20		(1 << 14)
++#define MC13783_ADC2_ADD21		(1 << 15)
++#define MC13783_ADC2_ADD22		(1 << 16)
++#define MC13783_ADC2_ADD23		(1 << 17)
++#define MC13783_ADC2_ADD24		(1 << 18)
++#define MC13783_ADC2_ADD25		(1 << 19)
++#define MC13783_ADC2_ADD26		(1 << 20)
++#define MC13783_ADC2_ADD27		(1 << 21)
++#define MC13783_ADC2_ADD28		(1 << 22)
++#define MC13783_ADC2_ADD29		(1 << 23)
++
++#define MC13783_ADC3_WHIGH0		(1 << 0)
++#define MC13783_ADC3_WHIGH1		(1 << 1)
++#define MC13783_ADC3_WHIGH2		(1 << 2)
++#define MC13783_ADC3_WHIGH3		(1 << 3)
++#define MC13783_ADC3_WHIGH4		(1 << 4)
++#define MC13783_ADC3_WHIGH5		(1 << 5)
++#define MC13783_ADC3_ICID0		(1 << 6)
++#define MC13783_ADC3_ICID1		(1 << 7)
++#define MC13783_ADC3_ICID2		(1 << 8)
++#define MC13783_ADC3_WLOW0		(1 << 9)
++#define MC13783_ADC3_WLOW1		(1 << 10)
++#define MC13783_ADC3_WLOW2		(1 << 11)
++#define MC13783_ADC3_WLOW3		(1 << 12)
++#define MC13783_ADC3_WLOW4		(1 << 13)
++#define MC13783_ADC3_WLOW5		(1 << 14)
++#define MC13783_ADC3_ADCBIS2		(1 << 23)
++
++#define MC13783_ADC4_ADDBIS10		(1 << 2)
++#define MC13783_ADC4_ADDBIS11		(1 << 3)
++#define MC13783_ADC4_ADDBIS12		(1 << 4)
++#define MC13783_ADC4_ADDBIS13		(1 << 5)
++#define MC13783_ADC4_ADDBIS14		(1 << 6)
++#define MC13783_ADC4_ADDBIS15		(1 << 7)
++#define MC13783_ADC4_ADDBIS16		(1 << 8)
++#define MC13783_ADC4_ADDBIS17		(1 << 9)
++#define MC13783_ADC4_ADDBIS18		(1 << 10)
++#define MC13783_ADC4_ADDBIS19		(1 << 11)
++#define MC13783_ADC4_ADDBIS20		(1 << 14)
++#define MC13783_ADC4_ADDBIS21		(1 << 15)
++#define MC13783_ADC4_ADDBIS22		(1 << 16)
++#define MC13783_ADC4_ADDBIS23		(1 << 17)
++#define MC13783_ADC4_ADDBIS24		(1 << 18)
++#define MC13783_ADC4_ADDBIS25		(1 << 19)
++#define MC13783_ADC4_ADDBIS26		(1 << 20)
++#define MC13783_ADC4_ADDBIS27		(1 << 21)
++#define MC13783_ADC4_ADDBIS28		(1 << 22)
++#define MC13783_ADC4_ADDBIS29		(1 << 23)
++
++#endif /* __LINUX_MFD_MC13783_PRIV_H */
++
+diff --git a/include/linux/mfd/mc13783.h b/include/linux/mfd/mc13783.h
+new file mode 100644
+index 0000000..b3a2a72
+--- /dev/null
++++ b/include/linux/mfd/mc13783.h
+@@ -0,0 +1,84 @@
++/*
++ * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer at pengutronix.de>
++ *
++ * Initial development of this code was funded by
++ * Phytec Messtechnik GmbH, http://www.phytec.de
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#ifndef __INCLUDE_LINUX_MFD_MC13783_H
++#define __INCLUDE_LINUX_MFD_MC13783_H
++
++struct mc13783;
++struct regulator_init_data;
++
++struct mc13783_regulator_init_data {
++	int id;
++	struct regulator_init_data *init_data;
++};
++
++struct mc13783_platform_data {
++	struct mc13783_regulator_init_data *regulators;
++	int num_regulators;
++	unsigned int flags;
++};
++
++/* mc13783_platform_data flags */
++#define MC13783_USE_TOUCHSCREEN (1 << 0)
++#define MC13783_USE_CODEC	(1 << 1)
++#define MC13783_USE_ADC		(1 << 2)
++#define MC13783_USE_RTC		(1 << 3)
++#define MC13783_USE_REGULATOR	(1 << 4)
++
++int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode,
++		unsigned int channel, unsigned int *sample);
++
++void mc13783_adc_set_ts_status(struct mc13783 *mc13783, unsigned int status);
++
++#define	MC13783_SW_SW1A		0
++#define	MC13783_SW_SW1B		1
++#define	MC13783_SW_SW2A		2
++#define	MC13783_SW_SW2B		3
++#define	MC13783_SW_SW3		4
++#define	MC13783_SW_PLL		5
++#define	MC13783_REGU_VAUDIO	6
++#define	MC13783_REGU_VIOHI	7
++#define	MC13783_REGU_VIOLO	8
++#define	MC13783_REGU_VDIG	9
++#define	MC13783_REGU_VGEN	10
++#define	MC13783_REGU_VRFDIG	11
++#define	MC13783_REGU_VRFREF	12
++#define	MC13783_REGU_VRFCP	13
++#define	MC13783_REGU_VSIM	14
++#define	MC13783_REGU_VESIM	15
++#define	MC13783_REGU_VCAM	16
++#define	MC13783_REGU_VRFBG	17
++#define	MC13783_REGU_VVIB	18
++#define	MC13783_REGU_VRF1	19
++#define	MC13783_REGU_VRF2	20
++#define	MC13783_REGU_VMMC1	21
++#define	MC13783_REGU_VMMC2	22
++#define	MC13783_REGU_GPO1	23
++#define	MC13783_REGU_GPO2	24
++#define	MC13783_REGU_GPO3	25
++#define	MC13783_REGU_GPO4	26
++#define	MC13783_REGU_V1		27
++#define	MC13783_REGU_V2		28
++#define	MC13783_REGU_V3		29
++#define	MC13783_REGU_V4		30
++
++#endif /* __INCLUDE_LINUX_MFD_MC13783_H */
++
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0002-mxc_nand-cleanup-eccoob-descriptions.patch b/recipes/linux/linux-2.6.31/pcm043/0002-mxc_nand-cleanup-eccoob-descriptions.patch
new file mode 100644
index 0000000..f8258ac
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0002-mxc_nand-cleanup-eccoob-descriptions.patch
@@ -0,0 +1,111 @@
+From 6092478fe41d7b58212bc20808dd94ce6170f35b Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Wed, 21 Oct 2009 10:22:01 +0200
+Subject: [PATCH] mxc_nand: cleanup eccoob descriptions
+
+The original Freescale driver used to have eccoob descriptions like
+this:
+
+static struct nand_ecclayout nand_hw_eccoob_8 = {
+	.eccbytes = 5,
+	.eccpos = {6, 7, 8, 9, 10},
+	.oobfree = {{0, 5}, {11, 5}}
+};
+
+static struct nand_ecclayout nand_hw_eccoob_16 = {
+	.eccbytes = 5,
+	.eccpos = {6, 7, 8, 9, 10},
+	.oobfree = {{0, 6}, {12, 4}}
+};
+
+The former was used for 8bit flashes and the latter for 16bit flashes.
+They honored the fact that the bad block marker on 8bit flashes is on byte 5
+while on 16bit flashes it is on byte 11.
+In the Kernel driver this was copied wrong and we ended up with two identical
+descriptions.
+
+Change it so that we have only one description which leaves byte 5 and byte
+11 unspecified so that it won't be used by others.
+
+Also, rename the descriptions to nand_hw_eccoob_smallpage and
+nand_hw_eccoob_largepage so that it can't be confused with Nand chip bus
+widths (what actually happened in this driver)
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand.c |   24 +++++++++---------------
+ 1 files changed, 9 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
+index 76beea4..7a34679 100644
+--- a/drivers/mtd/nand/mxc_nand.c
++++ b/drivers/mtd/nand/mxc_nand.c
+@@ -129,19 +129,13 @@ struct mxc_nand_host {
+ #define SPARE_SINGLEBIT_ERROR 0x1
+ 
+ /* OOB placement block for use with hardware ecc generation */
+-static struct nand_ecclayout nand_hw_eccoob_8 = {
++static struct nand_ecclayout nand_hw_eccoob_smallpage = {
+ 	.eccbytes = 5,
+ 	.eccpos = {6, 7, 8, 9, 10},
+-	.oobfree = {{0, 5}, {11, 5}, }
++	.oobfree = {{0, 5}, {12, 4}, }
+ };
+ 
+-static struct nand_ecclayout nand_hw_eccoob_16 = {
+-	.eccbytes = 5,
+-	.eccpos = {6, 7, 8, 9, 10},
+-	.oobfree = {{0, 5}, {11, 5}, }
+-};
+-
+-static struct nand_ecclayout nand_hw_eccoob_64 = {
++static struct nand_ecclayout nand_hw_eccoob_largepage = {
+ 	.eccbytes = 20,
+ 	.eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26,
+ 		   38, 39, 40, 41, 42, 54, 55, 56, 57, 58},
+@@ -940,7 +934,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 	} else {
+ 		this->ecc.size = 512;
+ 		this->ecc.bytes = 3;
+-		this->ecc.layout = &nand_hw_eccoob_8;
++		this->ecc.layout = &nand_hw_eccoob_smallpage;
+ 		this->ecc.mode = NAND_ECC_SOFT;
+ 		tmp = readw(host->regs + NFC_CONFIG1);
+ 		tmp &= ~NFC_ECC_EN;
+@@ -964,7 +958,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 	/* NAND bus width determines access funtions used by upper layer */
+ 	if (pdata->width == 2) {
+ 		this->options |= NAND_BUSWIDTH_16;
+-		this->ecc.layout = &nand_hw_eccoob_16;
++		this->ecc.layout = &nand_hw_eccoob_smallpage;
+ 	}
+ 
+ 	/* first scan to find the device and get the page size */
+@@ -978,20 +972,20 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 	if (this->ecc.mode == NAND_ECC_HW) {
+ 		switch (mtd->oobsize) {
+ 		case 8:
+-			this->ecc.layout = &nand_hw_eccoob_8;
++			this->ecc.layout = &nand_hw_eccoob_smallpage;
+ 			break;
+ 		case 16:
+-			this->ecc.layout = &nand_hw_eccoob_16;
++			this->ecc.layout = &nand_hw_eccoob_smallpage;
+ 			break;
+ 		case 64:
+-			this->ecc.layout = &nand_hw_eccoob_64;
++			this->ecc.layout = &nand_hw_eccoob_largepage;
+ 			break;
+ 		default:
+ 			/* page size not handled by HW ECC */
+ 			/* switching back to soft ECC */
+ 			this->ecc.size = 512;
+ 			this->ecc.bytes = 3;
+-			this->ecc.layout = &nand_hw_eccoob_8;
++			this->ecc.layout = &nand_hw_eccoob_smallpage;
+ 			this->ecc.mode = NAND_ECC_SOFT;
+ 			this->ecc.calculate = NULL;
+ 			this->ecc.correct = NULL;
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0003-MXC-NFC-Add-a-real-NAND-flash-data-width-setup-func.patch b/recipes/linux/linux-2.6.31/pcm043/0003-MXC-NFC-Add-a-real-NAND-flash-data-width-setup-func.patch
new file mode 100644
index 0000000..5a526fa
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0003-MXC-NFC-Add-a-real-NAND-flash-data-width-setup-func.patch
@@ -0,0 +1,51 @@
+From e31e8120d5552c200785a6e2f1958d7f7643a675 Mon Sep 17 00:00:00 2001
+From: Juergen Beisert <j.beisert at pengutronix.de>
+Date: Tue, 29 Sep 2009 14:55:47 +0200
+Subject: [PATCH 03/15] MXC NFC: Add a real NAND flash data width setup function
+
+Provide a real subfunction to setup the NAND flash data width.
+
+Signed-off-by: Juergen Beisert <j.beisert at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand_v2.c |   15 ++++++++++++---
+ 1 files changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand_v2.c b/drivers/mtd/nand/mxc_nand_v2.c
+index 3483e7d..03d1ba4 100644
+--- a/drivers/mtd/nand/mxc_nand_v2.c
++++ b/drivers/mtd/nand/mxc_nand_v2.c
+@@ -830,6 +830,14 @@ static void unlock_addr(struct mxc_nand_host *host, unsigned int start_addr, uns
+ 		BUG();
+ }
+ 
++static void __init mxc_data_width(struct mxc_nand_host *host, unsigned width)
++{
++	if ((width != 8) && (width != 16)) {
++		BUG();
++	}
++	/* TODO */
++}
++
+ static int __init mxcnd_probe(struct platform_device *pdev)
+ {
+ 	struct nand_chip *this;
+@@ -898,12 +906,13 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 	} else
+ 		BUG();
+ 
+-	/* NAND bus width determines access funtions used by upper layer */
++	/* NAND bus width determines access functions used by upper layer */
+ 	if (pdata->width == 2) {
+ 		this->read_byte = mxc_nand_read_byte16;
+ 		this->options |= NAND_BUSWIDTH_16;
+-		mxc_set_nfms(mtd, 1 << NFMS_NF_DWIDTH);
+-	}
++		mxc_data_width(host, 16);
++	} else
++		mxc_data_width(host, 8);
+ 
+ 	init_waitqueue_head(&host->irq_waitq);
+ 
+-- 
+1.6.1
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0003-mx3-Add-SSI-pins-to-iomux-table.patch b/recipes/linux/linux-2.6.31/pcm043/0003-mx3-Add-SSI-pins-to-iomux-table.patch
new file mode 100644
index 0000000..c1e9ab0
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0003-mx3-Add-SSI-pins-to-iomux-table.patch
@@ -0,0 +1,48 @@
+From f1f19d863e177c09ca93ee960aa615701649dc9b Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Thu, 12 Nov 2009 14:02:22 +0100
+Subject: [PATCH 03/28] mx3: Add SSI pins to iomux table
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/plat-mxc/include/mach/iomux-mx3.h |   24 ++++++++++++++++++++++++
+ 1 files changed, 24 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx3.h b/arch/arm/plat-mxc/include/mach/iomux-mx3.h
+index 2eb182f..0fb1ad5 100644
+--- a/arch/arm/plat-mxc/include/mach/iomux-mx3.h
++++ b/arch/arm/plat-mxc/include/mach/iomux-mx3.h
+@@ -669,6 +669,30 @@ enum iomux_pins {
+ #define MX31_PIN_GPIO3_0__GPIO3_0	IOMUX_MODE(MX31_PIN_GPIO3_0, IOMUX_CONFIG_GPIO)
+ #define MX31_PIN_GPIO3_1__GPIO3_1	IOMUX_MODE(MX31_PIN_GPIO3_1, IOMUX_CONFIG_GPIO)
+ #define MX31_PIN_TXD2__GPIO1_28		IOMUX_MODE(MX31_PIN_TXD2, IOMUX_CONFIG_GPIO)
++#define MX31_PIN_GPIO1_0__GPIO1_0	IOMUX_MODE(MX31_PIN_GPIO1_0, IOMUX_CONFIG_GPIO)
++#define MX31_PIN_SVEN0__GPIO2_0		IOMUX_MODE(MX31_PIN_SVEN0, IOMUX_CONFIG_GPIO)
++#define MX31_PIN_STX0__GPIO2_1		IOMUX_MODE(MX31_PIN_STX0, IOMUX_CONFIG_GPIO)
++#define MX31_PIN_SRX0__GPIO2_2		IOMUX_MODE(MX31_PIN_SRX0, IOMUX_CONFIG_GPIO)
++#define MX31_PIN_SIMPD0__GPIO2_3	IOMUX_MODE(MX31_PIN_SIMPD0, IOMUX_CONFIG_GPIO)
++#define MX31_PIN_DTR_DCE1__GPIO2_8	IOMUX_MODE(MX31_PIN_DTR_DCE1, IOMUX_CONFIG_GPIO)
++#define MX31_PIN_DSR_DCE1__GPIO2_9	IOMUX_MODE(MX31_PIN_DSR_DCE1, IOMUX_CONFIG_GPIO)
++#define MX31_PIN_RI_DCE1__GPIO2_10	IOMUX_MODE(MX31_PIN_RI_DCE1, IOMUX_CONFIG_GPIO)
++#define MX31_PIN_DCD_DCE1__GPIO2_11	IOMUX_MODE(MX31_PIN_DCD_DCE1, IOMUX_CONFIG_GPIO)
++#define MX31_PIN_STXD5__GPIO1_21       IOMUX_MODE(MX31_PIN_STXD5, IOMUX_CONFIG_GPIO)
++#define MX31_PIN_SRXD5__GPIO1_22       IOMUX_MODE(MX31_PIN_SRXD5, IOMUX_CONFIG_GPIO)
++#define MX31_PIN_GPIO1_3__GPIO1_3	IOMUX_MODE(MX31_PIN_GPIO1_3, IOMUX_CONFIG_GPIO)
++#define MX31_PIN_CSPI2_SS1__CSPI3_SS1	IOMUX_MODE(MX31_PIN_CSPI2_SS1, IOMUX_CONFIG_ALT1)
++#define MX31_PIN_RTS1__GPIO2_6		IOMUX_MODE(MX31_PIN_RTS1, IOMUX_CONFIG_GPIO)
++#define MX31_PIN_CTS1__GPIO2_7		IOMUX_MODE(MX31_PIN_CTS1, IOMUX_CONFIG_GPIO)
++#define MX31_PIN_LCS0__GPIO3_23		IOMUX_MODE(MX31_PIN_LCS0, IOMUX_CONFIG_GPIO)
++#define MX31_PIN_STXD4__STXD4		IOMUX_MODE(MX31_PIN_STXD4, IOMUX_CONFIG_FUNC)
++#define MX31_PIN_SRXD4__SRXD4		IOMUX_MODE(MX31_PIN_SRXD4, IOMUX_CONFIG_FUNC)
++#define MX31_PIN_SCK4__SCK4		IOMUX_MODE(MX31_PIN_SCK4, IOMUX_CONFIG_FUNC)
++#define MX31_PIN_SFS4__SFS4		IOMUX_MODE(MX31_PIN_SFS4, IOMUX_CONFIG_FUNC)
++#define MX31_PIN_STXD5__STXD5		IOMUX_MODE(MX31_PIN_STXD5, IOMUX_CONFIG_FUNC)
++#define MX31_PIN_SRXD5__SRXD5		IOMUX_MODE(MX31_PIN_SRXD5, IOMUX_CONFIG_FUNC)
++#define MX31_PIN_SCK5__SCK5		IOMUX_MODE(MX31_PIN_SCK5, IOMUX_CONFIG_FUNC)
++#define MX31_PIN_SFS5__SFS5		IOMUX_MODE(MX31_PIN_SFS5, IOMUX_CONFIG_FUNC)
+ 
+ /*XXX: The SS0, SS1, SS2, SS3 lines of spi3 are multiplexed by cspi2_ss0, cspi2_ss1, cspi1_ss0
+  * cspi1_ss1*/
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0003-mxc_nand-cleanup-initialization.patch b/recipes/linux/linux-2.6.31/pcm043/0003-mxc_nand-cleanup-initialization.patch
new file mode 100644
index 0000000..f437724
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0003-mxc_nand-cleanup-initialization.patch
@@ -0,0 +1,124 @@
+From 4521787dcf7e16910e5a0e0ac817283b14e5f11b Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Wed, 21 Oct 2009 10:39:05 +0200
+Subject: [PATCH] mxc_nand: cleanup initialization
+
+The oob layout was initialized several times. Instead, use
+a smallpage layout by default and switch to a largepage
+afterwards if necessary.
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand.c |   72 +++++++++++++-----------------------------
+ 1 files changed, 22 insertions(+), 50 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
+index 7a34679..b28e5f9 100644
+--- a/drivers/mtd/nand/mxc_nand.c
++++ b/drivers/mtd/nand/mxc_nand.c
+@@ -921,45 +921,42 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 	if (err)
+ 		goto eirq;
+ 
++	/* Reset NAND */
++	this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
++
++	/* preset operation */
++	/* Unlock the internal RAM Buffer */
++	writew(0x2, host->regs + NFC_CONFIG);
++
++	/* Blocks to be unlocked */
++	writew(0x0, host->regs + NFC_UNLOCKSTART_BLKADDR);
++	writew(0x4000, host->regs + NFC_UNLOCKEND_BLKADDR);
++
++	/* Unlock Block Command for given address range */
++	writew(0x4, host->regs + NFC_WRPROT);
++
++	this->ecc.size = 512;
++	this->ecc.bytes = 3;
++	this->ecc.layout = &nand_hw_eccoob_smallpage;
++
+ 	if (pdata->hw_ecc) {
+ 		this->ecc.calculate = mxc_nand_calculate_ecc;
+ 		this->ecc.hwctl = mxc_nand_enable_hwecc;
+ 		this->ecc.correct = mxc_nand_correct_data;
+ 		this->ecc.mode = NAND_ECC_HW;
+-		this->ecc.size = 512;
+-		this->ecc.bytes = 3;
+ 		tmp = readw(host->regs + NFC_CONFIG1);
+ 		tmp |= NFC_ECC_EN;
+ 		writew(tmp, host->regs + NFC_CONFIG1);
+ 	} else {
+-		this->ecc.size = 512;
+-		this->ecc.bytes = 3;
+-		this->ecc.layout = &nand_hw_eccoob_smallpage;
+ 		this->ecc.mode = NAND_ECC_SOFT;
+ 		tmp = readw(host->regs + NFC_CONFIG1);
+ 		tmp &= ~NFC_ECC_EN;
+ 		writew(tmp, host->regs + NFC_CONFIG1);
+ 	}
+ 
+-	/* Reset NAND */
+-	this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+-
+-	/* preset operation */
+-	/* Unlock the internal RAM Buffer */
+-	writew(0x2, host->regs + NFC_CONFIG);
+-
+-	/* Blocks to be unlocked */
+-	writew(0x0, host->regs + NFC_UNLOCKSTART_BLKADDR);
+-	writew(0x4000, host->regs + NFC_UNLOCKEND_BLKADDR);
+-
+-	/* Unlock Block Command for given address range */
+-	writew(0x4, host->regs + NFC_WRPROT);
+-
+ 	/* NAND bus width determines access funtions used by upper layer */
+-	if (pdata->width == 2) {
++	if (pdata->width == 2)
+ 		this->options |= NAND_BUSWIDTH_16;
+-		this->ecc.layout = &nand_hw_eccoob_smallpage;
+-	}
+ 
+ 	/* first scan to find the device and get the page size */
+ 	if (nand_scan_ident(mtd, 1)) {
+@@ -967,34 +964,9 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 		goto escan;
+ 	}
+ 
+-	host->pagesize_2k = (mtd->writesize == 2048) ? 1 : 0;
+-
+-	if (this->ecc.mode == NAND_ECC_HW) {
+-		switch (mtd->oobsize) {
+-		case 8:
+-			this->ecc.layout = &nand_hw_eccoob_smallpage;
+-			break;
+-		case 16:
+-			this->ecc.layout = &nand_hw_eccoob_smallpage;
+-			break;
+-		case 64:
+-			this->ecc.layout = &nand_hw_eccoob_largepage;
+-			break;
+-		default:
+-			/* page size not handled by HW ECC */
+-			/* switching back to soft ECC */
+-			this->ecc.size = 512;
+-			this->ecc.bytes = 3;
+-			this->ecc.layout = &nand_hw_eccoob_smallpage;
+-			this->ecc.mode = NAND_ECC_SOFT;
+-			this->ecc.calculate = NULL;
+-			this->ecc.correct = NULL;
+-			this->ecc.hwctl = NULL;
+-			tmp = readw(host->regs + NFC_CONFIG1);
+-			tmp &= ~NFC_ECC_EN;
+-			writew(tmp, host->regs + NFC_CONFIG1);
+-			break;
+-		}
++	if (mtd->writesize == 2048) {
++		host->pagesize_2k = 1;
++		this->ecc.layout = &nand_hw_eccoob_largepage;
+ 	}
+ 
+ 	/* second phase scan */
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0004-MXC-NFC-Use-generic-bad-block-detection.patch b/recipes/linux/linux-2.6.31/pcm043/0004-MXC-NFC-Use-generic-bad-block-detection.patch
new file mode 100644
index 0000000..2c5c37f
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0004-MXC-NFC-Use-generic-bad-block-detection.patch
@@ -0,0 +1,148 @@
+From 344bc7de5f142e95a524fe2019b51344d9aa3ea7 Mon Sep 17 00:00:00 2001
+From: Juergen Beisert <j.beisert at pengutronix.de>
+Date: Tue, 29 Sep 2009 15:04:11 +0200
+Subject: [PATCH 04/15] MXC NFC: Use generic bad block detection
+
+There is no need to provide a local bad block detection. The generic
+one does a correct job. Due to hardware based ECC we must provide
+a local nand_bbt_descr structure, because the generic one conflicts
+with our ECC sum byte locations.
+
+Signed-off-by: Juergen Beisert <j.beisert at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand_v2.c |   98 ++++-----------------------------------
+ 1 files changed, 10 insertions(+), 88 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand_v2.c b/drivers/mtd/nand/mxc_nand_v2.c
+index 03d1ba4..6b1eeb9 100644
+--- a/drivers/mtd/nand/mxc_nand_v2.c
++++ b/drivers/mtd/nand/mxc_nand_v2.c
+@@ -708,26 +708,10 @@ static void mxc_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+ 	memcpy(host->data_buf + mtd->writesize, chip->oob_poi, mtd->oobsize);
+ }
+ 
+-/* Define some generic bad / good block scan pattern which are used
+- * while scanning a device for factory marked good / bad blocks. */
+-static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
+-
+-static struct nand_bbt_descr smallpage_memorybased = {
+-	.options = NAND_BBT_SCAN2NDPAGE,
+-	.offs = 5,
+-	.len = 1,
+-	.pattern = scan_ff_pattern
+-};
+-
+-static struct nand_bbt_descr largepage_memorybased = {
+-	.options = 0,
+-	.offs = 0,
+-	.len = 2,
+-	.pattern = scan_ff_pattern
+-};
+-
+-/* Generic flash bbt decriptors
+-*/
++/*
++ * We must provide a private bbt decriptor, because the settings from
++ * the generic one collide with our ECC hardware.
++ */
+ static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
+ static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' };
+ 
+@@ -751,73 +735,6 @@ static struct nand_bbt_descr bbt_mirror_descr = {
+ 	.pattern = mirror_pattern
+ };
+ 
+-static void mxc_set_nfms_v21(struct mtd_info *mtd, unsigned int val)
+-{
+-	struct nand_chip *this = mtd->priv;
+-	struct mxc_nand_host *host = this->priv;
+-	unsigned int spas, tmp;
+-
+-//	NFMS |= val; /* FIXME */
+-
+-	if (val & (1 << NFMS_NF_PG_SZ)) {
+-		if (mtd->writesize == 2048)
+-			spas = NFC_SPAS_64;
+-		else if (mtd->writesize == 4096)
+-			spas = NFC_SPAS_128;
+-		else
+-			spas = NFC_SPAS_16;
+-
+-		tmp = readw(host->regs + NFC_CONFIG1);
+-		tmp |= NFC_V2_ECC_MODE_4;
+-		writew(tmp, host->regs + NFC_CONFIG1);
+-
+-		tmp = readw(host->regs + NFC_V21_SPAS);
+-		tmp &= NFC_V21_SPAS_MASK;
+-		tmp |= spas << NFC_V21_SPAS_SHIFT;
+-		writew(tmp, host->regs + NFC_V21_SPAS);
+-	}
+-}
+-
+-static void mxc_set_nfms(struct mtd_info *mtd, unsigned int val)
+-{
+-	if (nfc_is_v21())
+-		mxc_set_nfms_v21(mtd, val);
+-}
+-
+-static int mxc_nand_scan_bbt(struct mtd_info *mtd)
+-{
+-	struct nand_chip *this = mtd->priv;
+-	struct mxc_nand_host *host = this->priv;
+-
+-	if (mtd->writesize == 2048) {
+-		mxc_set_nfms(mtd, 1 << NFMS_NF_PG_SZ);
+-		this->ecc.layout = &nand_hw_eccoob_2k;
+-	} else if (mtd->writesize == 4096) {
+-		mxc_set_nfms(mtd, 1 << NFMS_NF_PG_SZ);
+-		this->ecc.layout = &nand_hw_eccoob_4k;
+-	} else {
+-		this->ecc.layout = &nand_hw_eccoob_512;
+-	}
+-
+-	/* propagate ecc.layout to mtd_info */
+-	mtd->ecclayout = this->ecc.layout;
+-
+-	/* use flash based bbt */
+-	this->bbt_td = &bbt_main_descr;
+-	this->bbt_md = &bbt_mirror_descr;
+-
+-	/* update flash based bbt */
+-	this->options |= NAND_USE_FLASH_BBT;
+-
+-	if (!this->badblock_pattern) {
+-		this->badblock_pattern = (mtd->writesize > 512) ?
+-		    &largepage_memorybased : &smallpage_memorybased;
+-	}
+-
+-	/* Build bad block table */
+-	return nand_scan_bbt(mtd, this->badblock_pattern);
+-}
+-
+ static void unlock_addr(struct mxc_nand_host *host, unsigned int start_addr, unsigned int end_addr)
+ {
+ 	if (nfc_is_v21()) {
+@@ -870,7 +787,6 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 	this->write_buf = mxc_nand_write_buf;
+ 	this->read_buf = mxc_nand_read_buf;
+ 	this->verify_buf = mxc_nand_verify_buf;
+-	this->scan_bbt = mxc_nand_scan_bbt;
+ 
+ 	host->clk = clk_get(&pdev->dev, "nfc_clk");
+ 	if (IS_ERR(host->clk)) {
+@@ -958,6 +874,12 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 
+ 	clk_disable(host->clk);
+ 
++	/* use flash based bbt */
++	this->bbt_td = &bbt_main_descr;
++	this->bbt_md = &bbt_mirror_descr;
++	/* update flash based bbt */
++	this->options |= NAND_USE_FLASH_BBT;
++
+ 	/* Scan to find existence of the device */
+ 	if (nand_scan(mtd, 1)) {
+ 		DEBUG(MTD_DEBUG_LEVEL0,
+-- 
+1.6.1
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0004-mxc-iomux-v3-remove-resource-handling.patch b/recipes/linux/linux-2.6.31/pcm043/0004-mxc-iomux-v3-remove-resource-handling.patch
new file mode 100644
index 0000000..5f04c34
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0004-mxc-iomux-v3-remove-resource-handling.patch
@@ -0,0 +1,111 @@
+From 88a85f7b168d6ee042ea2634414f2ffd43a99cff Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Thu, 29 Oct 2009 17:18:02 +0100
+Subject: [PATCH 04/28] mxc: iomux v3: remove resource handling
+
+The current model does not allow to put a pad into different modes
+once a pins is allocated. Remove the resource handling.
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/plat-mxc/include/mach/iomux-v3.h |   17 +-------------
+ arch/arm/plat-mxc/iomux-v3.c              |   35 +---------------------------
+ 2 files changed, 3 insertions(+), 49 deletions(-)
+
+diff --git a/arch/arm/plat-mxc/include/mach/iomux-v3.h b/arch/arm/plat-mxc/include/mach/iomux-v3.h
+index 7cd8454..f23e579 100644
+--- a/arch/arm/plat-mxc/include/mach/iomux-v3.h
++++ b/arch/arm/plat-mxc/include/mach/iomux-v3.h
+@@ -92,9 +92,7 @@ struct pad_desc {
+ #define PAD_CTL_SLEW_RATE_FAST		1
+ 
+ /*
+- * setups a single pad:
+- * 	- reserves the pad so that it is not claimed by another driver
+- * 	- setups the iomux according to the configuration
++ * setups a single pad in the iomuxer
+  */
+ int mxc_iomux_v3_setup_pad(struct pad_desc *pad);
+ 
+@@ -104,18 +102,5 @@ int mxc_iomux_v3_setup_pad(struct pad_desc *pad);
+  */
+ int mxc_iomux_v3_setup_multiple_pads(struct pad_desc *pad_list, unsigned count);
+ 
+-/*
+- * releases a single pad:
+- * 	- make it available for a future use by another driver
+- * 	- DOES NOT reconfigure the IOMUX in its reset state
+- */
+-void mxc_iomux_v3_release_pad(struct pad_desc *pad);
+-
+-/*
+- * releases multiple pads
+- * convenvient way to call the above function with tables
+- */
+-void mxc_iomux_v3_release_multiple_pads(struct pad_desc *pad_list, int count);
+-
+ #endif /* __MACH_IOMUX_V3_H__*/
+ 
+diff --git a/arch/arm/plat-mxc/iomux-v3.c b/arch/arm/plat-mxc/iomux-v3.c
+index 77a078f..4f0e7fc 100644
+--- a/arch/arm/plat-mxc/iomux-v3.c
++++ b/arch/arm/plat-mxc/iomux-v3.c
+@@ -31,19 +31,11 @@
+ 
+ #define IOMUX_BASE	IO_ADDRESS(IOMUXC_BASE_ADDR)
+ 
+-static unsigned long iomux_v3_pad_alloc_map[0x200 / BITS_PER_LONG];
+-
+ /*
+- * setups a single pin:
+- * 	- reserves the pin so that it is not claimed by another driver
+- * 	- setups the iomux according to the configuration
++ * setups a single pad in the iomuxer
+  */
+ int mxc_iomux_v3_setup_pad(struct pad_desc *pad)
+ {
+-	unsigned int pad_ofs = pad->pad_ctrl_ofs;
+-
+-	if (test_and_set_bit(pad_ofs >> 2, iomux_v3_pad_alloc_map))
+-		return -EBUSY;
+ 	if (pad->mux_ctrl_ofs)
+ 		__raw_writel(pad->mux_mode, IOMUX_BASE + pad->mux_ctrl_ofs);
+ 
+@@ -66,33 +58,10 @@ int mxc_iomux_v3_setup_multiple_pads(struct pad_desc *pad_list, unsigned count)
+ 	for (i = 0; i < count; i++) {
+ 		ret = mxc_iomux_v3_setup_pad(p);
+ 		if (ret)
+-			goto setup_error;
++			return ret;
+ 		p++;
+ 	}
+ 	return 0;
+-
+-setup_error:
+-	mxc_iomux_v3_release_multiple_pads(pad_list, i);
+-	return ret;
+ }
+ EXPORT_SYMBOL(mxc_iomux_v3_setup_multiple_pads);
+ 
+-void mxc_iomux_v3_release_pad(struct pad_desc *pad)
+-{
+-	unsigned int pad_ofs = pad->pad_ctrl_ofs;
+-
+-	clear_bit(pad_ofs >> 2, iomux_v3_pad_alloc_map);
+-}
+-EXPORT_SYMBOL(mxc_iomux_v3_release_pad);
+-
+-void mxc_iomux_v3_release_multiple_pads(struct pad_desc *pad_list, int count)
+-{
+-	struct pad_desc *p = pad_list;
+-	int i;
+-
+-	for (i = 0; i < count; i++) {
+-		mxc_iomux_v3_release_pad(p);
+-		p++;
+-	}
+-}
+-EXPORT_SYMBOL(mxc_iomux_v3_release_multiple_pads);
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0004-mxc_nand-merge-send_read_page-and-send_prog_page.patch b/recipes/linux/linux-2.6.31/pcm043/0004-mxc_nand-merge-send_read_page-and-send_prog_page.patch
new file mode 100644
index 0000000..656e680
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0004-mxc_nand-merge-send_read_page-and-send_prog_page.patch
@@ -0,0 +1,104 @@
+From 9d8a47b34ec9f2a75aefa3ea6e6bc3fa70888cda Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Tue, 2 Jun 2009 11:37:53 +0200
+Subject: [PATCH] mxc_nand: merge send_read_page and send_prog_page
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand.c |   54 ++++++++++--------------------------------
+ 1 files changed, 13 insertions(+), 41 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
+index b28e5f9..56db5ac 100644
+--- a/drivers/mtd/nand/mxc_nand.c
++++ b/drivers/mtd/nand/mxc_nand.c
+@@ -226,12 +226,10 @@ static void send_addr(struct mxc_nand_host *host, uint16_t addr, int islast)
+ 	wait_op_done(host, TROP_US_DELAY, addr, islast);
+ }
+ 
+-/* This function requests the NANDFC to initate the transfer
+- * of data currently in the NANDFC RAM buffer to the NAND device. */
+-static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id,
+-			int spare_only)
++static void send_page(struct mxc_nand_host *host, uint8_t buf_id,
++			int spare_only, unsigned int ops)
+ {
+-	DEBUG(MTD_DEBUG_LEVEL3, "send_prog_page (%d)\n", spare_only);
++	DEBUG(MTD_DEBUG_LEVEL3, "send_page (%d)\n", spare_only);
+ 
+ 	/* NANDFC buffer 0 is used for page read/write */
+ 	writew(buf_id, host->regs + NFC_BUF_ADDR);
+@@ -246,33 +244,7 @@ static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id,
+ 		writew(config1, host->regs + NFC_CONFIG1);
+ 	}
+ 
+-	writew(NFC_INPUT, host->regs + NFC_CONFIG2);
+-
+-	/* Wait for operation to complete */
+-	wait_op_done(host, TROP_US_DELAY, spare_only, true);
+-}
+-
+-/* Requests NANDFC to initated the transfer of data from the
+- * NAND device into in the NANDFC ram buffer. */
+-static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id,
+-		int spare_only)
+-{
+-	DEBUG(MTD_DEBUG_LEVEL3, "send_read_page (%d)\n", spare_only);
+-
+-	/* NANDFC buffer 0 is used for page read/write */
+-	writew(buf_id, host->regs + NFC_BUF_ADDR);
+-
+-	/* Configure spare or page+spare access */
+-	if (!host->pagesize_2k) {
+-		uint32_t config1 = readw(host->regs + NFC_CONFIG1);
+-		if (spare_only)
+-			config1 |= NFC_SP_EN;
+-		else
+-			config1 &= ~NFC_SP_EN;
+-		writew(config1, host->regs + NFC_CONFIG1);
+-	}
+-
+-	writew(NFC_OUTPUT, host->regs + NFC_CONFIG2);
++	writew(ops, host->regs + NFC_CONFIG2);
+ 
+ 	/* Wait for operation to complete */
+ 	wait_op_done(host, TROP_US_DELAY, spare_only, true);
+@@ -756,13 +728,13 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ 		break;
+ 
+ 	case NAND_CMD_PAGEPROG:
+-		send_prog_page(host, 0, host->spare_only);
++		send_page(host, 0, host->spare_only, NFC_INPUT);
+ 
+ 		if (host->pagesize_2k) {
+ 			/* data in 4 areas datas */
+-			send_prog_page(host, 1, host->spare_only);
+-			send_prog_page(host, 2, host->spare_only);
+-			send_prog_page(host, 3, host->spare_only);
++			send_page(host, 1, host->spare_only, NFC_INPUT);
++			send_page(host, 2, host->spare_only, NFC_INPUT);
++			send_page(host, 3, host->spare_only, NFC_INPUT);
+ 		}
+ 
+ 		break;
+@@ -827,12 +799,12 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ 			/* send read confirm command */
+ 			send_cmd(host, NAND_CMD_READSTART, true);
+ 			/* read for each AREA */
+-			send_read_page(host, 0, host->spare_only);
+-			send_read_page(host, 1, host->spare_only);
+-			send_read_page(host, 2, host->spare_only);
+-			send_read_page(host, 3, host->spare_only);
++			send_page(host, 0, host->spare_only, NFC_OUTPUT);
++			send_page(host, 1, host->spare_only, NFC_OUTPUT);
++			send_page(host, 2, host->spare_only, NFC_OUTPUT);
++			send_page(host, 3, host->spare_only, NFC_OUTPUT);
+ 		} else
+-			send_read_page(host, 0, host->spare_only);
++			send_page(host, 0, host->spare_only, NFC_OUTPUT);
+ 		break;
+ 
+ 	case NAND_CMD_READID:
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0005-MXC-NFC-Divide-flash-device-detection-into-two-step.patch b/recipes/linux/linux-2.6.31/pcm043/0005-MXC-NFC-Divide-flash-device-detection-into-two-step.patch
new file mode 100644
index 0000000..2a6d110
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0005-MXC-NFC-Divide-flash-device-detection-into-two-step.patch
@@ -0,0 +1,48 @@
+From a3906c7f2019dbcb2aa6b9a356947ea91ade60b8 Mon Sep 17 00:00:00 2001
+From: Juergen Beisert <j.beisert at pengutronix.de>
+Date: Tue, 29 Sep 2009 15:10:03 +0200
+Subject: [PATCH 05/15] MXC NFC: Divide flash device detection into two steps
+
+To be able to setup the NFC hardware in accordance to the connected
+NAND device, we must detect some information about the NAND first.
+After that we are able to setup the NFC in a correct manner. The last
+step is to continue NAND device handling by the framework.
+
+Signed-off-by: Juergen Beisert <j.beisert at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand_v2.c |   13 +++++++++----
+ 1 files changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand_v2.c b/drivers/mtd/nand/mxc_nand_v2.c
+index 6b1eeb9..2ddd6f5 100644
+--- a/drivers/mtd/nand/mxc_nand_v2.c
++++ b/drivers/mtd/nand/mxc_nand_v2.c
+@@ -874,16 +874,21 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 
+ 	clk_disable(host->clk);
+ 
++	/* detect the device data prio setting up the ECC hardware */
++	if (nand_scan_ident(mtd, 1)) {
++		err = -ENXIO;
++		pr_err("Unable to find any NAND device\n");
++		goto escan;
++	}
++
+ 	/* use flash based bbt */
+ 	this->bbt_td = &bbt_main_descr;
+ 	this->bbt_md = &bbt_mirror_descr;
+ 	/* update flash based bbt */
+ 	this->options |= NAND_USE_FLASH_BBT;
+ 
+-	/* Scan to find existence of the device */
+-	if (nand_scan(mtd, 1)) {
+-		DEBUG(MTD_DEBUG_LEVEL0,
+-		      "MXC_ND2: Unable to find any NAND device.\n");
++	/* second phase scan */
++	if (nand_scan_tail(mtd)) {
+ 		err = -ENXIO;
+ 		goto escan;
+ 	}
+-- 
+1.6.1
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0005-i.MX31-clock-rename-SSI-clocks-to-driver-name.patch b/recipes/linux/linux-2.6.31/pcm043/0005-i.MX31-clock-rename-SSI-clocks-to-driver-name.patch
new file mode 100644
index 0000000..dce0282
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0005-i.MX31-clock-rename-SSI-clocks-to-driver-name.patch
@@ -0,0 +1,28 @@
+From 04683e53f18930db4f5a9e40a65fea91b949ce21 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Thu, 12 Nov 2009 14:09:39 +0100
+Subject: [PATCH 05/28] i.MX31 clock: rename SSI clocks to driver name
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/mach-mx3/clock.c |    4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/mach-mx3/clock.c b/arch/arm/mach-mx3/clock.c
+index 8b14239..f25e8be 100644
+--- a/arch/arm/mach-mx3/clock.c
++++ b/arch/arm/mach-mx3/clock.c
+@@ -545,8 +545,8 @@ static struct clk_lookup lookups[] = {
+ 	_REGISTER_CLOCK("mxc_w1.0", NULL, owire_clk)
+ 	_REGISTER_CLOCK("mxc-mmc.0", NULL, sdhc1_clk)
+ 	_REGISTER_CLOCK("mxc-mmc.1", NULL, sdhc2_clk)
+-	_REGISTER_CLOCK(NULL, "ssi", ssi1_clk)
+-	_REGISTER_CLOCK(NULL, "ssi", ssi2_clk)
++	_REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
++	_REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
+ 	_REGISTER_CLOCK(NULL, "firi", firi_clk)
+ 	_REGISTER_CLOCK(NULL, "ata", ata_clk)
+ 	_REGISTER_CLOCK(NULL, "rtic", rtic_clk)
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0005-mxc_nand-introduce-mxc_do_addr_cycle.patch b/recipes/linux/linux-2.6.31/pcm043/0005-mxc_nand-introduce-mxc_do_addr_cycle.patch
new file mode 100644
index 0000000..539408e
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0005-mxc_nand-introduce-mxc_do_addr_cycle.patch
@@ -0,0 +1,122 @@
+From ded30b9d4cee1890d2b76956102828c6fb009b6b Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Tue, 2 Jun 2009 11:47:59 +0200
+Subject: [PATCH] mxc_nand: introduce mxc_do_addr_cycle
+
+This factors the address cycle to a seperate function. This
+becomes useful in a later patch where we can simplify the
+command processing by making use of this function.
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand.c |   87 +++++++++++++++++++++++--------------------
+ 1 files changed, 47 insertions(+), 40 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
+index 56db5ac..325c5be 100644
+--- a/drivers/mtd/nand/mxc_nand.c
++++ b/drivers/mtd/nand/mxc_nand.c
+@@ -658,6 +658,52 @@ static void mxc_nand_select_chip(struct mtd_info *mtd, int chip)
+ 	}
+ }
+ 
++static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
++{
++	struct nand_chip *nand_chip = mtd->priv;
++	struct mxc_nand_host *host = nand_chip->priv;
++
++	/* Write out column address, if necessary */
++	if (column != -1) {
++		/*
++		 * MXC NANDFC can only perform full page+spare or
++		 * spare-only read/write.  When the upper layers
++		 * layers perform a read/write buf operation,
++		 * we will used the saved column adress to index into
++		 * the full page.
++		 */
++		send_addr(host, 0, page_addr == -1);
++		if (host->pagesize_2k)
++			/* another col addr cycle for 2k page */
++			send_addr(host, 0, false);
++	}
++
++	/* Write out page address, if necessary */
++	if (page_addr != -1) {
++		/* paddr_0 - p_addr_7 */
++		send_addr(host, (page_addr & 0xff), false);
++
++		if (host->pagesize_2k) {
++			if (mtd->size >= 0x10000000) {
++				/* paddr_8 - paddr_15 */
++				send_addr(host, (page_addr >> 8) & 0xff, false);
++				send_addr(host, (page_addr >> 16) & 0xff, true);
++			} else
++				/* paddr_8 - paddr_15 */
++				send_addr(host, (page_addr >> 8) & 0xff, true);
++		} else {
++			/* One more address cycle for higher density devices */
++			if (mtd->size >= 0x4000000) {
++				/* paddr_8 - paddr_15 */
++				send_addr(host, (page_addr >> 8) & 0xff, false);
++				send_addr(host, (page_addr >> 16) & 0xff, true);
++			} else
++				/* paddr_8 - paddr_15 */
++				send_addr(host, (page_addr >> 8) & 0xff, true);
++		}
++	}
++}
++
+ /* Used by the upper layer to write command to NAND Flash for
+  * different operations to be carried out on NAND Flash */
+ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+@@ -746,46 +792,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ 
+ 	/* Write out the command to the device. */
+ 	send_cmd(host, command, useirq);
+-
+-	/* Write out column address, if necessary */
+-	if (column != -1) {
+-		/*
+-		 * MXC NANDFC can only perform full page+spare or
+-		 * spare-only read/write.  When the upper layers
+-		 * layers perform a read/write buf operation,
+-		 * we will used the saved column adress to index into
+-		 * the full page.
+-		 */
+-		send_addr(host, 0, page_addr == -1);
+-		if (host->pagesize_2k)
+-			/* another col addr cycle for 2k page */
+-			send_addr(host, 0, false);
+-	}
+-
+-	/* Write out page address, if necessary */
+-	if (page_addr != -1) {
+-		/* paddr_0 - p_addr_7 */
+-		send_addr(host, (page_addr & 0xff), false);
+-
+-		if (host->pagesize_2k) {
+-			if (mtd->size >= 0x10000000) {
+-				/* paddr_8 - paddr_15 */
+-				send_addr(host, (page_addr >> 8) & 0xff, false);
+-				send_addr(host, (page_addr >> 16) & 0xff, true);
+-			} else
+-				/* paddr_8 - paddr_15 */
+-				send_addr(host, (page_addr >> 8) & 0xff, true);
+-		} else {
+-			/* One more address cycle for higher density devices */
+-			if (mtd->size >= 0x4000000) {
+-				/* paddr_8 - paddr_15 */
+-				send_addr(host, (page_addr >> 8) & 0xff, false);
+-				send_addr(host, (page_addr >> 16) & 0xff, true);
+-			} else
+-				/* paddr_8 - paddr_15 */
+-				send_addr(host, (page_addr >> 8) & 0xff, true);
+-		}
+-	}
++	mxc_do_addr_cycle(mtd, column, page_addr);
+ 
+ 	/* Command post-processing step */
+ 	switch (command) {
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0006-MXC-NFC-Reorder-structure-setup-to-use-NAND-informa.patch b/recipes/linux/linux-2.6.31/pcm043/0006-MXC-NFC-Reorder-structure-setup-to-use-NAND-informa.patch
new file mode 100644
index 0000000..ba75986
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0006-MXC-NFC-Reorder-structure-setup-to-use-NAND-informa.patch
@@ -0,0 +1,129 @@
+From 91457e95796520ecf21937c3b2578ccfe21e054f Mon Sep 17 00:00:00 2001
+From: Juergen Beisert <j.beisert at pengutronix.de>
+Date: Tue, 29 Sep 2009 15:21:44 +0200
+Subject: [PATCH 06/15] MXC NFC: Reorder structure setup to use NAND information
+
+Reorder some structure and NFC setup to use detected NAND information.
+
+Signed-off-by: Juergen Beisert <j.beisert at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand_v2.c |   82 +++++++++++++++++++++++++++++++--------
+ 1 files changed, 65 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand_v2.c b/drivers/mtd/nand/mxc_nand_v2.c
+index 2ddd6f5..3b1011c 100644
+--- a/drivers/mtd/nand/mxc_nand_v2.c
++++ b/drivers/mtd/nand/mxc_nand_v2.c
+@@ -84,6 +84,10 @@
+ #define NFC_V21_SPAS_SHIFT		(0)
+ #define NFC_V21_SPAS_MASK	(0xFF00)
+ 
++/* some NFCs are able to handle different ECC sizes */
++#define MXC_SMALL_ECC 0
++#define MXC_BIG_ECC 1
++
+ struct mxc_nand_host {
+ 	struct mtd_info		mtd;
+ 	struct nand_chip	nand;
+@@ -747,6 +751,30 @@ static void unlock_addr(struct mxc_nand_host *host, unsigned int start_addr, uns
+ 		BUG();
+ }
+ 
++static void __init mxc_spare_size(struct mxc_nand_host *host, unsigned size_code)
++{
++	u16 tmp;
++
++	if (nfc_is_v21()) {
++		tmp = readw(host->regs + NFC_V21_SPAS);
++		tmp &= NFC_V21_SPAS_MASK;
++		tmp |= size_code << NFC_V21_SPAS_SHIFT;
++		writew(tmp, host->regs + NFC_V21_SPAS);
++	}
++}
++
++/* ignore mode in a first step */
++static void __init mxc_ecc_mode(struct mxc_nand_host *host, int mode)
++{
++	u16 tmp;
++
++	if (nfc_is_v21()) {
++		tmp = readw(host->regs + NFC_CONFIG1);
++		tmp |= NFC_V2_ECC_MODE_4;
++		writew(tmp, host->regs + NFC_CONFIG1);
++	}
++}
++
+ static void __init mxc_data_width(struct mxc_nand_host *host, unsigned width)
+ {
+ 	if ((width != 8) && (width != 16)) {
+@@ -838,23 +866,6 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 	if (err)
+ 		goto eirq;
+ 
+-	if (pdata->hw_ecc) {
+-		this->ecc.read_page = mxc_nand_read_page;
+-		this->ecc.write_page = mxc_nand_write_page;
+-		this->ecc.read_oob = mxc_nand_read_oob;
+-		this->ecc.layout = &nand_hw_eccoob_512;
+-		this->ecc.calculate = mxc_nand_calculate_ecc;
+-		this->ecc.hwctl = mxc_nand_enable_hwecc;
+-		this->ecc.correct = mxc_nand_correct_data;
+-		this->ecc.mode = NAND_ECC_HW;
+-		this->ecc.size = 512;
+-		this->ecc.bytes = 9;
+-		mxc_nand_hwecc(host, 1);
+-	} else {
+-		this->ecc.mode = NAND_ECC_SOFT;
+-		mxc_nand_hwecc(host, 0);
+-	}
+-
+ 	clk_enable(host->clk);
+ 
+ 	/* Disable interrupt */
+@@ -887,6 +898,43 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 	/* update flash based bbt */
+ 	this->options |= NAND_USE_FLASH_BBT;
+ 
++	this->ecc.mode = NAND_ECC_SOFT;	/* start with a default */
++
++	/* Note: ECC needs at least 16 bytes oob per 512 bytes pagesize */
++	if (pdata->hw_ecc && (mtd->oobsize >= 16)) {
++		if (mtd->writesize == 512) {
++			this->ecc.mode = NAND_ECC_HW;
++			this->ecc.layout = &nand_hw_eccoob_512;
++			mxc_spare_size(host, NFC_SPAS_16);
++		}
++		if ((mtd->writesize == 2048) && (mtd->oobsize >= 64)) {
++			this->ecc.mode = NAND_ECC_HW;
++			this->ecc.layout = &nand_hw_eccoob_2k;
++			mxc_spare_size(host, NFC_SPAS_64);
++		}
++		if ((mtd->writesize == 4096) && (mtd->oobsize >= 128)) {
++			this->ecc.mode = NAND_ECC_HW;
++			this->ecc.layout = &nand_hw_eccoob_4k;
++			mxc_spare_size(host, NFC_SPAS_128);
++		}
++		/* can we use hardware ECC? */
++		if (this->ecc.mode == NAND_ECC_HW) {
++			this->ecc.read_page = mxc_nand_read_page;
++			this->ecc.write_page = mxc_nand_write_page;
++			this->ecc.read_oob = mxc_nand_read_oob;
++			this->ecc.calculate = mxc_nand_calculate_ecc;
++			this->ecc.hwctl = mxc_nand_enable_hwecc;
++			this->ecc.correct = mxc_nand_correct_data;
++			this->ecc.size = 512;
++			this->ecc.bytes = 9;
++			mxc_ecc_mode(host, MXC_SMALL_ECC);
++			mxc_nand_hwecc(host, 1);
++		}
++	}
++
++	if (this->ecc.mode == NAND_ECC_SOFT)
++		mxc_nand_hwecc(host, 0);
++
+ 	/* second phase scan */
+ 	if (nand_scan_tail(mtd)) {
+ 		err = -ENXIO;
+-- 
+1.6.1
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0006-i.MX2-Add-sound-ssi-resources.patch b/recipes/linux/linux-2.6.31/pcm043/0006-i.MX2-Add-sound-ssi-resources.patch
new file mode 100644
index 0000000..9de57cf
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0006-i.MX2-Add-sound-ssi-resources.patch
@@ -0,0 +1,132 @@
+From 4bdc922cba4f392af2adf57c9aa86c0d2241ac88 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Thu, 22 Oct 2009 14:50:33 +0200
+Subject: [PATCH 06/28] i.MX2: Add sound (ssi) resources
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/mach-mx2/clock_imx27.c |    4 +-
+ arch/arm/mach-mx2/devices.c     |   78 +++++++++++++++++++++++++++++++++++++++
+ arch/arm/mach-mx2/devices.h     |    5 ++
+ 3 files changed, 85 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/mach-mx2/clock_imx27.c b/arch/arm/mach-mx2/clock_imx27.c
+index 2c97144..5abb763 100644
+--- a/arch/arm/mach-mx2/clock_imx27.c
++++ b/arch/arm/mach-mx2/clock_imx27.c
+@@ -644,8 +644,8 @@ static struct clk_lookup lookups[] = {
+ 	_REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk)
+ 	_REGISTER_CLOCK(NULL, "csi", csi_clk)
+ 	_REGISTER_CLOCK(NULL, "usb", usb_clk)
+-	_REGISTER_CLOCK(NULL, "ssi1", ssi1_clk)
+-	_REGISTER_CLOCK(NULL, "ssi2", ssi2_clk)
++	_REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
++	_REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
+ 	_REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk)
+ 	_REGISTER_CLOCK(NULL, "vpu", vpu_clk)
+ 	_REGISTER_CLOCK(NULL, "dma", dma_clk)
+diff --git a/arch/arm/mach-mx2/devices.c b/arch/arm/mach-mx2/devices.c
+index a0f1b36..f877baa 100644
+--- a/arch/arm/mach-mx2/devices.c
++++ b/arch/arm/mach-mx2/devices.c
+@@ -407,6 +407,84 @@ struct platform_device mxc_sdhc_device1 = {
+        .resource       = mxc_sdhc2_resources,
+ };
+ 
++static struct resource imx_ssi_resources0[] = {
++	{
++		.start	= SSI1_BASE_ADDR,
++		.end	= SSI1_BASE_ADDR + 0x6F,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= MXC_INT_SSI1,
++		.end	= MXC_INT_SSI1,
++		.flags	= IORESOURCE_IRQ,
++	}, {
++		.name	= "tx0",
++		.start	= DMA_REQ_SSI1_TX0,
++		.end	= DMA_REQ_SSI1_TX0,
++		.flags	= IORESOURCE_DMA,
++	}, {
++		.name	= "rx0",
++		.start	= DMA_REQ_SSI1_RX0,
++		.end	= DMA_REQ_SSI1_RX0,
++		.flags	= IORESOURCE_DMA,
++	}, {
++		.name	= "tx1",
++		.start	= DMA_REQ_SSI1_TX1,
++		.end	= DMA_REQ_SSI1_TX1,
++		.flags	= IORESOURCE_DMA,
++	}, {
++		.name	= "rx1",
++		.start	= DMA_REQ_SSI1_RX1,
++		.end	= DMA_REQ_SSI1_RX1,
++		.flags	= IORESOURCE_DMA,
++	},
++};
++
++static struct resource imx_ssi_resources1[] = {
++	{
++		.start	= SSI2_BASE_ADDR,
++		.end	= SSI2_BASE_ADDR + 0x6F,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= MXC_INT_SSI2,
++		.end	= MXC_INT_SSI2,
++		.flags	= IORESOURCE_IRQ,
++	}, {
++		.name	= "tx0",
++		.start	= DMA_REQ_SSI2_TX0,
++		.end	= DMA_REQ_SSI2_TX0,
++		.flags	= IORESOURCE_DMA,
++	}, {
++		.name	= "rx0",
++		.start	= DMA_REQ_SSI2_RX0,
++		.end	= DMA_REQ_SSI2_RX0,
++		.flags	= IORESOURCE_DMA,
++	}, {
++		.name	= "tx1",
++		.start	= DMA_REQ_SSI2_TX1,
++		.end	= DMA_REQ_SSI2_TX1,
++		.flags	= IORESOURCE_DMA,
++	}, {
++		.name	= "rx1",
++		.start	= DMA_REQ_SSI2_RX1,
++		.end	= DMA_REQ_SSI2_RX1,
++		.flags	= IORESOURCE_DMA,
++	},
++};
++
++struct platform_device imx_ssi_device0 = {
++	.name = "imx-ssi",
++	.id = 0,
++	.num_resources = ARRAY_SIZE(imx_ssi_resources0),
++	.resource = imx_ssi_resources0,
++};
++
++struct platform_device imx_ssi_device1 = {
++	.name = "imx-ssi",
++	.id = 1,
++	.num_resources = ARRAY_SIZE(imx_ssi_resources1),
++	.resource = imx_ssi_resources1,
++};
++
+ /* GPIO port description */
+ static struct mxc_gpio_port imx_gpio_ports[] = {
+ 	[0] = {
+diff --git a/arch/arm/mach-mx2/devices.h b/arch/arm/mach-mx2/devices.h
+index 049005b..0c1f14d 100644
+--- a/arch/arm/mach-mx2/devices.h
++++ b/arch/arm/mach-mx2/devices.h
+@@ -20,3 +20,8 @@ extern struct platform_device mxc_i2c_device0;
+ extern struct platform_device mxc_i2c_device1;
+ extern struct platform_device mxc_sdhc_device0;
+ extern struct platform_device mxc_sdhc_device1;
++extern struct platform_device mxc_spi_device0;
++extern struct platform_device mxc_spi_device1;
++extern struct platform_device mxc_spi_device2;
++extern struct platform_device imx_ssi_device0;
++extern struct platform_device imx_ssi_device1;
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0006-mxc-nand-remove-debug-param.patch b/recipes/linux/linux-2.6.31/pcm043/0006-mxc-nand-remove-debug-param.patch
new file mode 100644
index 0000000..0829ae0
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0006-mxc-nand-remove-debug-param.patch
@@ -0,0 +1,82 @@
+From 74689944a8d49bcfd0acdaabe1952d368a889eae Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Thu, 4 Jun 2009 15:57:20 +0200
+Subject: [PATCH] mxc nand: remove debug param
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand.c |   16 ++++++++--------
+ 1 files changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
+index 325c5be..cd09196 100644
+--- a/drivers/mtd/nand/mxc_nand.c
++++ b/drivers/mtd/nand/mxc_nand.c
+@@ -165,7 +165,7 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
+  * complete by checking the INT bit of config2 register.
+  */
+ static void wait_op_done(struct mxc_nand_host *host, int max_retries,
+-				uint16_t param, int useirq)
++				int useirq)
+ {
+ 	uint32_t tmp;
+ 
+@@ -194,8 +194,8 @@ static void wait_op_done(struct mxc_nand_host *host, int max_retries,
+ 			udelay(1);
+ 		}
+ 		if (max_retries < 0)
+-			DEBUG(MTD_DEBUG_LEVEL0, "%s(%d): INT not set\n",
+-			      __func__, param);
++			DEBUG(MTD_DEBUG_LEVEL0, "%s: INT not set\n",
++			      __func__);
+ 	}
+ }
+ 
+@@ -209,7 +209,7 @@ static void send_cmd(struct mxc_nand_host *host, uint16_t cmd, int useirq)
+ 	writew(NFC_CMD, host->regs + NFC_CONFIG2);
+ 
+ 	/* Wait for operation to complete */
+-	wait_op_done(host, TROP_US_DELAY, cmd, useirq);
++	wait_op_done(host, TROP_US_DELAY, useirq);
+ }
+ 
+ /* This function sends an address (or partial address) to the
+@@ -223,7 +223,7 @@ static void send_addr(struct mxc_nand_host *host, uint16_t addr, int islast)
+ 	writew(NFC_ADDR, host->regs + NFC_CONFIG2);
+ 
+ 	/* Wait for operation to complete */
+-	wait_op_done(host, TROP_US_DELAY, addr, islast);
++	wait_op_done(host, TROP_US_DELAY, islast);
+ }
+ 
+ static void send_page(struct mxc_nand_host *host, uint8_t buf_id,
+@@ -247,7 +247,7 @@ static void send_page(struct mxc_nand_host *host, uint8_t buf_id,
+ 	writew(ops, host->regs + NFC_CONFIG2);
+ 
+ 	/* Wait for operation to complete */
+-	wait_op_done(host, TROP_US_DELAY, spare_only, true);
++	wait_op_done(host, TROP_US_DELAY, true);
+ }
+ 
+ /* Request the NANDFC to perform a read of the NAND device ID. */
+@@ -267,7 +267,7 @@ static void send_read_id(struct mxc_nand_host *host)
+ 	writew(NFC_ID, host->regs + NFC_CONFIG2);
+ 
+ 	/* Wait for operation to complete */
+-	wait_op_done(host, TROP_US_DELAY, 0, true);
++	wait_op_done(host, TROP_US_DELAY, true);
+ 
+ 	if (this->options & NAND_BUSWIDTH_16) {
+ 		void __iomem *main_buf = host->regs + MAIN_AREA0;
+@@ -303,7 +303,7 @@ static uint16_t get_dev_status(struct mxc_nand_host *host)
+ 	writew(NFC_STATUS, host->regs + NFC_CONFIG2);
+ 
+ 	/* Wait for operation to complete */
+-	wait_op_done(host, TROP_US_DELAY, 0, true);
++	wait_op_done(host, TROP_US_DELAY, true);
+ 
+ 	/* Status is placed in first word of main buffer */
+ 	/* get status, then recovery area 1 data */
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0007-MXC-NFC-Fix-OOB-layout.patch b/recipes/linux/linux-2.6.31/pcm043/0007-MXC-NFC-Fix-OOB-layout.patch
new file mode 100644
index 0000000..0aa5cc6
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0007-MXC-NFC-Fix-OOB-layout.patch
@@ -0,0 +1,104 @@
+From 1b05f0fbf96df288d1ee6d0bf4175e99b7d04730 Mon Sep 17 00:00:00 2001
+From: Juergen Beisert <j.beisert at pengutronix.de>
+Date: Tue, 29 Sep 2009 15:28:21 +0200
+Subject: [PATCH 07/15] MXC NFC: Fix OOB layout
+
+This data is not from the datasheet because the datasheet conceals these
+facts. Its collected from other sources and some hints from the datasheet.
+Hope its documentation is useful.
+
+Signed-off-by: Juergen Beisert <j.beisert at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand_v2.c |   68 ++++++++++++++++++++++++++++++++-------
+ 1 files changed, 55 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand_v2.c b/drivers/mtd/nand/mxc_nand_v2.c
+index 3b1011c..c1cbb05 100644
+--- a/drivers/mtd/nand/mxc_nand_v2.c
++++ b/drivers/mtd/nand/mxc_nand_v2.c
+@@ -121,27 +121,69 @@ struct mxc_nand_host {
+ #define TROP_US_DELAY   2000
+ 
+ /*
+- * OOB placement block for use with hardware ecc generation
++ * ECC data seems organized in 16 byte planes in this hardware.
++ * 7 bytes can be used for user's purpose, and 9 bytes are used
++ * for the ECC sum.
++ *
++ *  0 1 2 3 4 5 6 7 8 9 A B C D E F
++ *  |<----------->|<------------->|
++ *      User             ECC
++ *
++ * For pages larger than 512 bytes, n structures of this type will be used.
+  */
++
++/* OOB description for 512 byte pages with 16 byte OOB */
+ static struct nand_ecclayout nand_hw_eccoob_512 = {
+-	.eccbytes = 9,
+-	.eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15},
+-	.oobavail = 4,
+-	.oobfree = {{0, 4}}
++	.eccbytes = 1 * 9,
++	.eccpos = {
++		 7,  8,  9, 10, 11, 12, 13, 14, 15
++	},
++	.oobfree = {
++		{.offset = 0, .length = 7}
++	}
+ };
+ 
++/* OOB description for 2048 byte pages with 64 byte OOB */
+ static struct nand_ecclayout nand_hw_eccoob_2k = {
+-	.eccbytes = 9,
+-	.eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15},
+-	.oobavail = 4,
+-	.oobfree = {{2, 4}}
++	.eccbytes = 4 * 9,
++	.eccpos = {
++		 7,  8,  9, 10, 11, 12, 13, 14, 15,
++		23, 24, 25, 26, 27, 28, 29, 30, 31,
++		39, 40, 41, 42, 43, 44, 45, 46, 47,
++		55, 56, 57, 58, 59, 60, 61, 62, 63
++	},
++	.oobfree = {
++		{.offset = 0, .length = 7},
++		{.offset = 16, .length = 7},
++		{.offset = 32, .length = 7},
++		{.offset = 48, .length = 7}
++	}
+ };
+ 
++/* OOB description for 4096 byte pages with 128 byte OOB */
+ static struct nand_ecclayout nand_hw_eccoob_4k = {
+-	.eccbytes = 9,
+-	.eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15},
+-	.oobavail = 4,
+-	.oobfree = {{2, 4}}
++	.eccbytes = 8 * 9,
++	.eccpos = {
++		 7,  8,  9, 10, 11, 12, 13, 14, 15,
++		23, 24, 25, 26, 27, 28, 29, 30, 31,
++		39, 40, 41, 42, 43, 44, 45, 46, 47,
++		55, 56, 57, 58, 59, 60, 61, 62, 63,
++		71, 72, 73, 74, 75, 76, 77, 78, 79,
++		87, 88, 89, 90, 91, 92, 93, 94, 95,
++		103, 104, 105, 106, 107, 108, 109, 110, 111,
++/* ouch, only 64 entries allowed */
++/*		119, 120, 121, 122, 123, 124, 125, 126, 127 */
++	},
++	.oobfree = {
++		{.offset = 0, .length = 7},
++		{.offset = 16, .length = 7},
++		{.offset = 32, .length = 7},
++		{.offset = 48, .length = 7},
++		{.offset = 64, .length = 7},
++		{.offset = 80, .length = 7},
++		{.offset = 96, .length = 7},
++		{.offset = 112, .length = 7}
++	}
+ };
+ 
+ #ifdef CONFIG_MTD_PARTITIONS
+-- 
+1.6.1
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0007-i.MX3-Add-sound-ssi-resources.patch b/recipes/linux/linux-2.6.31/pcm043/0007-i.MX3-Add-sound-ssi-resources.patch
new file mode 100644
index 0000000..10eb2dc
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0007-i.MX3-Add-sound-ssi-resources.patch
@@ -0,0 +1,101 @@
+From cd733f49a7e0fd82164138933157bbdbb9937f2c Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Thu, 29 Oct 2009 17:17:42 +0100
+Subject: [PATCH 07/28] i.MX3: Add sound (ssi) resources
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/mach-mx3/clock-imx35.c |    4 +-
+ arch/arm/mach-mx3/devices.c     |   42 +++++++++++++++++++++++++++++++++++++++
+ arch/arm/mach-mx3/devices.h     |    3 +-
+ 3 files changed, 46 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/mach-mx3/clock-imx35.c b/arch/arm/mach-mx3/clock-imx35.c
+index 577ee83..02b2507 100644
+--- a/arch/arm/mach-mx3/clock-imx35.c
++++ b/arch/arm/mach-mx3/clock-imx35.c
+@@ -421,8 +421,8 @@ static struct clk_lookup lookups[] = {
+ 	_REGISTER_CLOCK(NULL, "sdma", sdma_clk)
+ 	_REGISTER_CLOCK(NULL, "spba", spba_clk)
+ 	_REGISTER_CLOCK(NULL, "spdif", spdif_clk)
+-	_REGISTER_CLOCK(NULL, "ssi", ssi1_clk)
+-	_REGISTER_CLOCK(NULL, "ssi", ssi2_clk)
++	_REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
++	_REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
+ 	_REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
+ 	_REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
+ 	_REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
+diff --git a/arch/arm/mach-mx3/devices.c b/arch/arm/mach-mx3/devices.c
+index 9e87e08..06dab5f 100644
+--- a/arch/arm/mach-mx3/devices.c
++++ b/arch/arm/mach-mx3/devices.c
+@@ -416,6 +416,44 @@ struct platform_device mxc_fec_device = {
+ };
+ #endif
+ 
++static struct resource imx_ssi_resources0[] = {
++	{
++		.start	= SSI1_BASE_ADDR,
++		.end	= SSI1_BASE_ADDR + 0xfff,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= MX31_INT_SSI1,
++		.end	= MX31_INT_SSI1,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct resource imx_ssi_resources1[] = {
++	{
++		.start	= SSI2_BASE_ADDR,
++		.end	= SSI2_BASE_ADDR + 0xfff,
++		.flags	= IORESOURCE_MEM
++	}, {
++		.start	= MX31_INT_SSI2,
++		.end	= MX31_INT_SSI2,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++struct platform_device imx_ssi_device0 = {
++	.name = "imx-ssi",
++	.id = 0,
++	.num_resources = ARRAY_SIZE(imx_ssi_resources0),
++	.resource = imx_ssi_resources0,
++};
++
++struct platform_device imx_ssi_device1 = {
++	.name = "imx-ssi",
++	.id = 1,
++	.num_resources = ARRAY_SIZE(imx_ssi_resources1),
++	.resource = imx_ssi_resources1,
++};
++
+ static int mx3_devices_init(void)
+ {
+ 	if (cpu_is_mx31()) {
+@@ -426,6 +464,10 @@ static int mx3_devices_init(void)
+ 	if (cpu_is_mx35()) {
+ 		mxc_nand_resources[0].start = MX35_NFC_BASE_ADDR;
+ 		mxc_nand_resources[0].end = MX35_NFC_BASE_ADDR + 0xfff;
++		imx_ssi_resources0[1].start = MX35_INT_SSI1;
++		imx_ssi_resources0[1].end = MX35_INT_SSI1;
++		imx_ssi_resources1[1].start = MX35_INT_SSI2;
++		imx_ssi_resources1[1].end = MX35_INT_SSI2;
+ 	}
+ 
+ 	return 0;
+diff --git a/arch/arm/mach-mx3/devices.h b/arch/arm/mach-mx3/devices.h
+index ffd494d..224c2eb 100644
+--- a/arch/arm/mach-mx3/devices.h
++++ b/arch/arm/mach-mx3/devices.h
+@@ -17,4 +17,5 @@ extern struct platform_device mxcsdhc_device0;
+ extern struct platform_device mxcsdhc_device1;
+ extern struct platform_device mxc_otg_udc_device;
+ extern struct platform_device mxc_rnga_device;
+-
++extern struct platform_device imx_ssi_device0;
++extern struct platform_device imx_ssi_device1;
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0007-mxc-nand-remove-dead-code.patch b/recipes/linux/linux-2.6.31/pcm043/0007-mxc-nand-remove-dead-code.patch
new file mode 100644
index 0000000..218b103
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0007-mxc-nand-remove-dead-code.patch
@@ -0,0 +1,41 @@
+From 406ec8e7472d4435f6f862cd2e8179ee8dddb57e Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Thu, 4 Jun 2009 16:12:40 +0200
+Subject: [PATCH] mxc nand: remove dead code
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand.c |   17 -----------------
+ 1 files changed, 0 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
+index cd09196..74c5dbc 100644
+--- a/drivers/mtd/nand/mxc_nand.c
++++ b/drivers/mtd/nand/mxc_nand.c
+@@ -620,23 +620,6 @@ static void mxc_nand_select_chip(struct mtd_info *mtd, int chip)
+ 	struct nand_chip *nand_chip = mtd->priv;
+ 	struct mxc_nand_host *host = nand_chip->priv;
+ 
+-#ifdef CONFIG_MTD_NAND_MXC_FORCE_CE
+-	if (chip > 0) {
+-		DEBUG(MTD_DEBUG_LEVEL0,
+-		      "ERROR:  Illegal chip select (chip = %d)\n", chip);
+-		return;
+-	}
+-
+-	if (chip == -1) {
+-		writew(readw(host->regs + NFC_CONFIG1) & ~NFC_CE,
+-				host->regs + NFC_CONFIG1);
+-		return;
+-	}
+-
+-	writew(readw(host->regs + NFC_CONFIG1) | NFC_CE,
+-			host->regs + NFC_CONFIG1);
+-#endif
+-
+ 	switch (chip) {
+ 	case -1:
+ 		/* Disable the NFC clock */
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0008-MXC-Add-a-digital-audio-multiplexer-driver.patch b/recipes/linux/linux-2.6.31/pcm043/0008-MXC-Add-a-digital-audio-multiplexer-driver.patch
new file mode 100644
index 0000000..65c7339
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0008-MXC-Add-a-digital-audio-multiplexer-driver.patch
@@ -0,0 +1,281 @@
+From 2ff993c8bed5670aab72ef1d7901fe87e753aa54 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Thu, 29 Oct 2009 17:12:39 +0100
+Subject: [PATCH 08/28] MXC: Add a digital audio multiplexer driver
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/mach-mx2/Kconfig               |    2 +
+ arch/arm/mach-mx3/Kconfig               |    2 +
+ arch/arm/plat-mxc/Kconfig               |    7 +++
+ arch/arm/plat-mxc/Makefile              |    2 +
+ arch/arm/plat-mxc/audmux-v1.c           |   53 ++++++++++++++++++++++
+ arch/arm/plat-mxc/audmux-v2.c           |   74 +++++++++++++++++++++++++++++++
+ arch/arm/plat-mxc/include/mach/audmux.h |   52 +++++++++++++++++++++
+ 7 files changed, 192 insertions(+), 0 deletions(-)
+ create mode 100644 arch/arm/plat-mxc/audmux-v1.c
+ create mode 100644 arch/arm/plat-mxc/audmux-v2.c
+ create mode 100644 arch/arm/plat-mxc/include/mach/audmux.h
+
+diff --git a/arch/arm/mach-mx2/Kconfig b/arch/arm/mach-mx2/Kconfig
+index c77da58..0d08c34 100644
+--- a/arch/arm/mach-mx2/Kconfig
++++ b/arch/arm/mach-mx2/Kconfig
+@@ -6,11 +6,13 @@ choice
+ 
+ config MACH_MX21
+ 	bool "i.MX21 support"
++	select ARCH_MXC_AUDMUX_V1
+ 	help
+ 	  This enables support for Freescale's MX2 based i.MX21 processor.
+ 
+ config MACH_MX27
+ 	bool "i.MX27 support"
++	select ARCH_MXC_AUDMUX_V1
+ 	help
+ 	  This enables support for Freescale's MX2 based i.MX27 processor.
+ 
+diff --git a/arch/arm/mach-mx3/Kconfig b/arch/arm/mach-mx3/Kconfig
+index 851f245..ffdd211 100644
+--- a/arch/arm/mach-mx3/Kconfig
++++ b/arch/arm/mach-mx3/Kconfig
+@@ -2,11 +2,13 @@ if ARCH_MX3
+ 
+ config ARCH_MX31
+ 	select ARCH_HAS_RNGA
++	select ARCH_MXC_AUDMUX_V2
+ 	bool
+ 
+ config ARCH_MX35
+ 	bool
+ 	select ARCH_MXC_IOMUX_V3
++	select ARCH_MXC_AUDMUX_V2
+ 
+ comment "MX3 platforms:"
+ 
+diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig
+index 8986b74..995c357 100644
+--- a/arch/arm/plat-mxc/Kconfig
++++ b/arch/arm/plat-mxc/Kconfig
+@@ -58,4 +58,11 @@ config ARCH_HAS_RNGA
+ 
+ config ARCH_MXC_IOMUX_V3
+ 	bool
++
++config ARCH_MXC_AUDMUX_V1
++	bool
++
++config ARCH_MXC_AUDMUX_V2
++	bool
++
+ endif
+diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile
+index e3212c8..92fc8b2 100644
+--- a/arch/arm/plat-mxc/Makefile
++++ b/arch/arm/plat-mxc/Makefile
+@@ -9,3 +9,5 @@ obj-$(CONFIG_ARCH_MX1) += iomux-mx1-mx2.o dma-mx1-mx2.o
+ obj-$(CONFIG_ARCH_MX2) += iomux-mx1-mx2.o dma-mx1-mx2.o
+ obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o
+ obj-$(CONFIG_MXC_PWM)  += pwm.o
++obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o
++obj-$(CONFIG_ARCH_MXC_AUDMUX_V2) += audmux-v2.o
+diff --git a/arch/arm/plat-mxc/audmux-v1.c b/arch/arm/plat-mxc/audmux-v1.c
+new file mode 100644
+index 0000000..70ab5af
+--- /dev/null
++++ b/arch/arm/plat-mxc/audmux-v1.c
+@@ -0,0 +1,53 @@
++/*
++ * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer at pengutronix.de>
++ *
++ * Initial development of this code was funded by
++ * Phytec Messtechnik GmbH, http://www.phytec.de
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/module.h>
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/clk.h>
++#include <mach/audmux.h>
++#include <mach/hardware.h>
++
++static void __iomem *audmux_base;
++
++#define MXC_AUDMUX_V1_PCR(x)	((x) * 4)
++
++int mxc_audmux_v1_configure_port(unsigned int port, unsigned int pcr)
++{
++	if (!audmux_base) {
++		printk("%s: not configured\n", __func__);
++		return -ENOSYS;
++	}
++
++	writel(pcr, audmux_base + MXC_AUDMUX_V1_PCR(port));
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(mxc_audmux_v1_configure_port);
++
++static int mxc_audmux_v1_init(void)
++{
++	if (cpu_is_mx27() || cpu_is_mx21())
++		audmux_base = IO_ADDRESS(AUDMUX_BASE_ADDR);
++	return 0;
++}
++
++postcore_initcall(mxc_audmux_v1_init);
+diff --git a/arch/arm/plat-mxc/audmux-v2.c b/arch/arm/plat-mxc/audmux-v2.c
+new file mode 100644
+index 0000000..6f21096
+--- /dev/null
++++ b/arch/arm/plat-mxc/audmux-v2.c
+@@ -0,0 +1,74 @@
++/*
++ * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer at pengutronix.de>
++ *
++ * Initial development of this code was funded by
++ * Phytec Messtechnik GmbH, http://www.phytec.de
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/module.h>
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/clk.h>
++#include <mach/audmux.h>
++#include <mach/hardware.h>
++
++static struct clk *audmux_clk;
++static void __iomem *audmux_base;
++
++#define MXC_AUDMUX_V2_PTCR(x)		((x) * 8)
++#define MXC_AUDMUX_V2_PDCR(x)		((x) * 8 + 4)
++
++int mxc_audmux_v2_configure_port(unsigned int port, unsigned int ptcr,
++		unsigned int pdcr)
++{
++	if (!audmux_base)
++		return -ENOSYS;
++
++	if (audmux_clk)
++		clk_enable(audmux_clk);
++
++	writel(ptcr, audmux_base + MXC_AUDMUX_V2_PTCR(port));
++	writel(pdcr, audmux_base + MXC_AUDMUX_V2_PDCR(port));
++
++	if (audmux_clk)
++		clk_disable(audmux_clk);
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(mxc_audmux_v2_configure_port);
++
++static int mxc_audmux_v2_init(void)
++{
++	int ret;
++
++	if (cpu_is_mx35()) {
++		audmux_clk = clk_get(NULL, "audmux");
++		if (IS_ERR(audmux_clk)) {
++			ret = PTR_ERR(audmux_clk);
++			printk(KERN_ERR "%s: cannot get clock: %d\n", __func__,
++					ret);
++			return ret;
++		}
++	}
++
++	if (cpu_is_mx31() || cpu_is_mx35())
++		audmux_base = IO_ADDRESS(AUDMUX_BASE_ADDR);
++
++	return 0;
++}
++
++postcore_initcall(mxc_audmux_v2_init);
+diff --git a/arch/arm/plat-mxc/include/mach/audmux.h b/arch/arm/plat-mxc/include/mach/audmux.h
+new file mode 100644
+index 0000000..5cd6466
+--- /dev/null
++++ b/arch/arm/plat-mxc/include/mach/audmux.h
+@@ -0,0 +1,52 @@
++#ifndef __MACH_AUDMUX_H
++#define __MACH_AUDMUX_H
++
++#define MX27_AUDMUX_HPCR1_SSI0		0
++#define MX27_AUDMUX_HPCR2_SSI1		1
++#define MX27_AUDMUX_HPCR3_SSI_PINS_4	2
++#define MX27_AUDMUX_PPCR1_SSI_PINS_1	3
++#define MX27_AUDMUX_PPCR2_SSI_PINS_2	4
++#define MX27_AUDMUX_PPCR3_SSI_PINS_3	5
++
++#define MX31_AUDMUX_PORT1_SSI0		0
++#define MX31_AUDMUX_PORT2_SSI1		1
++#define MX31_AUDMUX_PORT3_SSI_PINS_3	2
++#define MX31_AUDMUX_PORT4_SSI_PINS_4	3
++#define MX31_AUDMUX_PORT5_SSI_PINS_5	4
++#define MX31_AUDMUX_PORT6_SSI_PINS_6	5
++
++/* Register definitions for the i.MX21/27 Digital Audio Multiplexer */
++#define MXC_AUDMUX_V1_PCR_INMMASK(x)	((x) & 0xff)
++#define MXC_AUDMUX_V1_PCR_INMEN		(1 << 8)
++#define MXC_AUDMUX_V1_PCR_TXRXEN	(1 << 10)
++#define MXC_AUDMUX_V1_PCR_SYN		(1 << 12)
++#define MXC_AUDMUX_V1_PCR_RXDSEL(x)	(((x) & 0x7) << 13)
++#define MXC_AUDMUX_V1_PCR_RFCSEL(x)	(((x) & 0xf) << 20)
++#define MXC_AUDMUX_V1_PCR_RCLKDIR	(1 << 24)
++#define MXC_AUDMUX_V1_PCR_RFSDIR	(1 << 25)
++#define MXC_AUDMUX_V1_PCR_TFCSEL(x)	(((x) & 0xf) << 26)
++#define MXC_AUDMUX_V1_PCR_TCLKDIR	(1 << 30)
++#define MXC_AUDMUX_V1_PCR_TFSDIR	(1 << 31)
++
++/* Register definitions for the i.MX25/31/35 Digital Audio Multiplexer */
++#define MXC_AUDMUX_V2_PTCR_TFSDIR	(1 << 31)
++#define MXC_AUDMUX_V2_PTCR_TFSEL(x)	(((x) & 0xf) << 27)
++#define MXC_AUDMUX_V2_PTCR_TCLKDIR	(1 << 26)
++#define MXC_AUDMUX_V2_PTCR_TCSEL(x)	(((x) & 0xf) << 22)
++#define MXC_AUDMUX_V2_PTCR_RFSDIR	(1 << 21)
++#define MXC_AUDMUX_V2_PTCR_RFSEL(x)	(((x) & 0xf) << 17)
++#define MXC_AUDMUX_V2_PTCR_RCLKDIR	(1 << 16)
++#define MXC_AUDMUX_V2_PTCR_RCSEL(x)	(((x) & 0xf) << 12)
++#define MXC_AUDMUX_V2_PTCR_SYN		(1 << 11)
++
++#define MXC_AUDMUX_V2_PDCR_RXDSEL(x)	(((x) & 0x7) << 13)
++#define MXC_AUDMUX_V2_PDCR_TXRXEN	(1 << 12)
++#define MXC_AUDMUX_V2_PDCR_MODE(x)	(((x) & 0x3) << 8)
++#define MXC_AUDMUX_V2_PDCR_INMMASK(x)	((x) & 0xff)
++
++int mxc_audmux_v1_configure_port(unsigned int port, unsigned int pcr);
++
++int mxc_audmux_v2_configure_port(unsigned int port, unsigned int ptcr,
++		unsigned int pdcr);
++
++#endif /* __MACH_AUDMUX_H */
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0008-MXC-NFC-The-i.MX35-CPU-also-uses-a-V2.1-NFC.patch b/recipes/linux/linux-2.6.31/pcm043/0008-MXC-NFC-The-i.MX35-CPU-also-uses-a-V2.1-NFC.patch
new file mode 100644
index 0000000..8d2a3c7
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0008-MXC-NFC-The-i.MX35-CPU-also-uses-a-V2.1-NFC.patch
@@ -0,0 +1,26 @@
+From b319bc5f9a9733e534a57b6725b94f438a1e406e Mon Sep 17 00:00:00 2001
+From: Juergen Beisert <j.beisert at pengutronix.de>
+Date: Tue, 29 Sep 2009 15:31:18 +0200
+Subject: [PATCH 08/15] MXC NFC: The i.MX35 CPU also uses a V2.1 NFC
+
+Signed-off-by: Juergen Beisert <j.beisert at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand_v2.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand_v2.c b/drivers/mtd/nand/mxc_nand_v2.c
+index c1cbb05..3891d9a 100644
+--- a/drivers/mtd/nand/mxc_nand_v2.c
++++ b/drivers/mtd/nand/mxc_nand_v2.c
+@@ -51,7 +51,7 @@
+ #define NFC_V1_UNLOCKSTART_BLKADDR  	0xe14
+ #define NFC_V1_UNLOCKEND_BLKADDR    	0xe16
+ 
+-#define nfc_is_v21()		cpu_is_mx25()
++#define nfc_is_v21()		(cpu_is_mx25() || cpu_is_mx35())
+ #define nfc_is_v2x()		cpu_is_mx31()
+ 
+ #define NFC_ECC_EN          		(1 << 3)
+-- 
+1.6.1
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0008-mxc-nand-use-resource_size.patch b/recipes/linux/linux-2.6.31/pcm043/0008-mxc-nand-use-resource_size.patch
new file mode 100644
index 0000000..ab3b1a3
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0008-mxc-nand-use-resource_size.patch
@@ -0,0 +1,26 @@
+From de6d94479735ef944c1463f42ed6192b1b226395 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Thu, 4 Jun 2009 16:16:01 +0200
+Subject: [PATCH] mxc nand: use resource_size()
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
+index 74c5dbc..127e0b7 100644
+--- a/drivers/mtd/nand/mxc_nand.c
++++ b/drivers/mtd/nand/mxc_nand.c
+@@ -865,7 +865,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 		goto eres;
+ 	}
+ 
+-	host->regs = ioremap(res->start, res->end - res->start + 1);
++	host->regs = ioremap(res->start, resource_size(res));
+ 	if (!host->regs) {
+ 		err = -ENOMEM;
+ 		goto eres;
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0009-MX31-Fix-spi-clock-names.patch b/recipes/linux/linux-2.6.31/pcm043/0009-MX31-Fix-spi-clock-names.patch
new file mode 100644
index 0000000..f59d127
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0009-MX31-Fix-spi-clock-names.patch
@@ -0,0 +1,32 @@
+From 6e58f781f2d5bedae9ff6991ac378212a392b723 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Fri, 20 Mar 2009 19:25:01 +0100
+Subject: [PATCH 09/28] MX31 Fix spi clock names
+
+Fix the SPI clock names to match the device names.
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/mach-mx3/clock.c |    6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/mach-mx3/clock.c b/arch/arm/mach-mx3/clock.c
+index f25e8be..664148c 100644
+--- a/arch/arm/mach-mx3/clock.c
++++ b/arch/arm/mach-mx3/clock.c
+@@ -518,9 +518,9 @@ DEFINE_CLOCK(ipg_clk,     0, NULL,          0, ipg_get_rate, NULL, &ahb_clk);
+ 
+ static struct clk_lookup lookups[] = {
+ 	_REGISTER_CLOCK(NULL, "emi", emi_clk)
+-	_REGISTER_CLOCK(NULL, "cspi", cspi1_clk)
+-	_REGISTER_CLOCK(NULL, "cspi", cspi2_clk)
+-	_REGISTER_CLOCK(NULL, "cspi", cspi3_clk)
++	_REGISTER_CLOCK("spi_imx.0", NULL, cspi1_clk)
++	_REGISTER_CLOCK("spi_imx.1", NULL, cspi2_clk)
++	_REGISTER_CLOCK("spi_imx.2", NULL, cspi3_clk)
+ 	_REGISTER_CLOCK(NULL, "gpt", gpt_clk)
+ 	_REGISTER_CLOCK(NULL, "pwm", pwm_clk)
+ 	_REGISTER_CLOCK(NULL, "wdog", wdog_clk)
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0009-MXC-NFC-Fix-NFC-s-address-area-on-i.MX35.patch b/recipes/linux/linux-2.6.31/pcm043/0009-MXC-NFC-Fix-NFC-s-address-area-on-i.MX35.patch
new file mode 100644
index 0000000..18096a4
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0009-MXC-NFC-Fix-NFC-s-address-area-on-i.MX35.patch
@@ -0,0 +1,28 @@
+From aa20693d5b25d2ed31a31265687a66b29d51737b Mon Sep 17 00:00:00 2001
+From: Juergen Beisert <j.beisert at pengutronix.de>
+Date: Tue, 29 Sep 2009 15:37:47 +0200
+Subject: [PATCH 09/15] MXC NFC: Fix NFC's address area on i.MX35
+
+The address area of the NFS in the i.MX35 silicon is much larger than 4k.
+
+Signed-off-by: Juergen Beisert <j.beisert at pengutronix.de>
+
+rebased to  2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel at phytec.de>
+---
+ arch/arm/mach-mx3/devices.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+Index: arch/arm/mach-mx3/devices.c
+===================================================================
+--- arch/arm/mach-mx3/devices.c.orig	2009-12-10 13:38:53.334702610 +0100
++++ arch/arm/mach-mx3/devices.c	2009-12-10 13:39:18.186144277 +0100
+@@ -585,7 +585,7 @@
+ 	}
+ 	if (cpu_is_mx35()) {
+ 		mxc_nand_resources[0].start = MX35_NFC_BASE_ADDR;
+-		mxc_nand_resources[0].end = MX35_NFC_BASE_ADDR + 0xfff;
++		mxc_nand_resources[0].end = MX35_NFC_BASE_ADDR + 0x1fff;
+ 		otg_resources[0].start = MX35_OTG_BASE_ADDR;
+ 		otg_resources[0].end = MX35_OTG_BASE_ADDR + 0x1ff;
+ 		otg_resources[1].start = MXC_INT_USBOTG;
diff --git a/recipes/linux/linux-2.6.31/pcm043/0009-mxc-nand-use-buffers.patch b/recipes/linux/linux-2.6.31/pcm043/0009-mxc-nand-use-buffers.patch
new file mode 100644
index 0000000..e48ff64
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0009-mxc-nand-use-buffers.patch
@@ -0,0 +1,473 @@
+From 714bcc0f142a1f44fb6e15ad7505b9d234e8f914 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Thu, 4 Jun 2009 17:12:26 +0200
+Subject: [PATCH] mxc nand: use buffers
+
+The NAND controller has some limitations how to access the
+internal buffers. It only allows 32 bit accesses. The driver
+used to work around this by having special alignment aware
+copy routines.
+We now copy the whole page to a buffer in memory and let the
+access functions use this buffer. This simplifies the driver.
+A bonnie++ test showed that this has no negative performance
+impact on the driver.
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand.c |  310 +++++++++++--------------------------------
+ 1 files changed, 77 insertions(+), 233 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
+index 127e0b7..4c338ae 100644
+--- a/drivers/mtd/nand/mxc_nand.c
++++ b/drivers/mtd/nand/mxc_nand.c
+@@ -107,15 +107,17 @@ struct mxc_nand_host {
+ 	struct device		*dev;
+ 
+ 	void __iomem		*regs;
+-	int			spare_only;
+ 	int			status_request;
+ 	int			pagesize_2k;
+-	uint16_t		col_addr;
+ 	struct clk		*clk;
+ 	int			clk_act;
+ 	int			irq;
+ 
+ 	wait_queue_head_t	irq_waitq;
++
++	uint8_t			*data_buf;
++	unsigned int		buf_start;
++	int			spare_len;
+ };
+ 
+ /* Define delays in microsec for NAND device operations */
+@@ -227,23 +229,11 @@ static void send_addr(struct mxc_nand_host *host, uint16_t addr, int islast)
+ }
+ 
+ static void send_page(struct mxc_nand_host *host, uint8_t buf_id,
+-			int spare_only, unsigned int ops)
++		unsigned int ops)
+ {
+-	DEBUG(MTD_DEBUG_LEVEL3, "send_page (%d)\n", spare_only);
+-
+ 	/* NANDFC buffer 0 is used for page read/write */
+ 	writew(buf_id, host->regs + NFC_BUF_ADDR);
+ 
+-	/* Configure spare or page+spare access */
+-	if (!host->pagesize_2k) {
+-		uint16_t config1 = readw(host->regs + NFC_CONFIG1);
+-		if (spare_only)
+-			config1 |= NFC_SP_EN;
+-		else
+-			config1 &= ~(NFC_SP_EN);
+-		writew(config1, host->regs + NFC_CONFIG1);
+-	}
+-
+ 	writew(ops, host->regs + NFC_CONFIG2);
+ 
+ 	/* Wait for operation to complete */
+@@ -278,6 +268,7 @@ static void send_read_id(struct mxc_nand_host *host)
+ 		writeb(readb(main_buf + 8), main_buf + 4);
+ 		writeb(readb(main_buf + 10), main_buf + 5);
+ 	}
++	memcpy(host->data_buf, host->regs + MAIN_AREA0, 16);
+ }
+ 
+ /* This function requests the NANDFC to perform a read of the
+@@ -363,32 +354,14 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd)
+ {
+ 	struct nand_chip *nand_chip = mtd->priv;
+ 	struct mxc_nand_host *host = nand_chip->priv;
+-	uint8_t ret = 0;
+-	uint16_t col, rd_word;
+-	uint16_t __iomem *main_buf = host->regs + MAIN_AREA0;
+-	uint16_t __iomem *spare_buf = host->regs + SPARE_AREA0;
++	uint8_t ret;
+ 
+ 	/* Check for status request */
+ 	if (host->status_request)
+ 		return get_dev_status(host) & 0xFF;
+ 
+-	/* Get column for 16-bit access */
+-	col = host->col_addr >> 1;
+-
+-	/* If we are accessing the spare region */
+-	if (host->spare_only)
+-		rd_word = readw(&spare_buf[col]);
+-	else
+-		rd_word = readw(&main_buf[col]);
+-
+-	/* Pick upper/lower byte of word from RAM buffer */
+-	if (host->col_addr & 0x1)
+-		ret = (rd_word >> 8) & 0xFF;
+-	else
+-		ret = rd_word & 0xFF;
+-
+-	/* Update saved column address */
+-	host->col_addr++;
++	ret = *(uint8_t *)(host->data_buf + host->buf_start);
++	host->buf_start++;
+ 
+ 	return ret;
+ }
+@@ -397,33 +370,10 @@ static uint16_t mxc_nand_read_word(struct mtd_info *mtd)
+ {
+ 	struct nand_chip *nand_chip = mtd->priv;
+ 	struct mxc_nand_host *host = nand_chip->priv;
+-	uint16_t col, rd_word, ret;
+-	uint16_t __iomem *p;
++	uint16_t ret;
+ 
+-	DEBUG(MTD_DEBUG_LEVEL3,
+-	      "mxc_nand_read_word(col = %d)\n", host->col_addr);
+-
+-	col = host->col_addr;
+-	/* Adjust saved column address */
+-	if (col < mtd->writesize && host->spare_only)
+-		col += mtd->writesize;
+-
+-	if (col < mtd->writesize)
+-		p = (host->regs + MAIN_AREA0) + (col >> 1);
+-	else
+-		p = (host->regs + SPARE_AREA0) + ((col - mtd->writesize) >> 1);
+-
+-	if (col & 1) {
+-		rd_word = readw(p);
+-		ret = (rd_word >> 8) & 0xff;
+-		rd_word = readw(&p[1]);
+-		ret |= (rd_word << 8) & 0xff00;
+-
+-	} else
+-		ret = readw(p);
+-
+-	/* Update saved column address */
+-	host->col_addr = col + 2;
++	ret = *(uint16_t *)(host->data_buf + host->buf_start);
++	host->buf_start += 2;
+ 
+ 	return ret;
+ }
+@@ -436,94 +386,14 @@ static void mxc_nand_write_buf(struct mtd_info *mtd,
+ {
+ 	struct nand_chip *nand_chip = mtd->priv;
+ 	struct mxc_nand_host *host = nand_chip->priv;
+-	int n, col, i = 0;
+-
+-	DEBUG(MTD_DEBUG_LEVEL3,
+-	      "mxc_nand_write_buf(col = %d, len = %d)\n", host->col_addr,
+-	      len);
+-
+-	col = host->col_addr;
+-
+-	/* Adjust saved column address */
+-	if (col < mtd->writesize && host->spare_only)
+-		col += mtd->writesize;
+-
+-	n = mtd->writesize + mtd->oobsize - col;
+-	n = min(len, n);
+-
+-	DEBUG(MTD_DEBUG_LEVEL3,
+-	      "%s:%d: col = %d, n = %d\n", __func__, __LINE__, col, n);
+-
+-	while (n) {
+-		void __iomem *p;
+-
+-		if (col < mtd->writesize)
+-			p = host->regs + MAIN_AREA0 + (col & ~3);
+-		else
+-			p = host->regs + SPARE_AREA0 -
+-						mtd->writesize + (col & ~3);
+-
+-		DEBUG(MTD_DEBUG_LEVEL3, "%s:%d: p = %p\n", __func__,
+-		      __LINE__, p);
+-
+-		if (((col | (int)&buf[i]) & 3) || n < 16) {
+-			uint32_t data = 0;
+-
+-			if (col & 3 || n < 4)
+-				data = readl(p);
+-
+-			switch (col & 3) {
+-			case 0:
+-				if (n) {
+-					data = (data & 0xffffff00) |
+-					    (buf[i++] << 0);
+-					n--;
+-					col++;
+-				}
+-			case 1:
+-				if (n) {
+-					data = (data & 0xffff00ff) |
+-					    (buf[i++] << 8);
+-					n--;
+-					col++;
+-				}
+-			case 2:
+-				if (n) {
+-					data = (data & 0xff00ffff) |
+-					    (buf[i++] << 16);
+-					n--;
+-					col++;
+-				}
+-			case 3:
+-				if (n) {
+-					data = (data & 0x00ffffff) |
+-					    (buf[i++] << 24);
+-					n--;
+-					col++;
+-				}
+-			}
+-
+-			writel(data, p);
+-		} else {
+-			int m = mtd->writesize - col;
++	u16 col = host->buf_start;
++	int n = mtd->oobsize + mtd->writesize - col;
+ 
+-			if (col >= mtd->writesize)
+-				m += mtd->oobsize;
++	n = min(n, len);
+ 
+-			m = min(n, m) & ~3;
++	memcpy(host->data_buf + col, buf, n);
+ 
+-			DEBUG(MTD_DEBUG_LEVEL3,
+-			      "%s:%d: n = %d, m = %d, i = %d, col = %d\n",
+-			      __func__,  __LINE__, n, m, i, col);
+-
+-			memcpy(p, &buf[i], m);
+-			col += m;
+-			i += m;
+-			n -= m;
+-		}
+-	}
+-	/* Update saved column address */
+-	host->col_addr = col;
++	host->buf_start += n;
+ }
+ 
+ /* Read the data buffer from the NAND Flash. To read the data from NAND
+@@ -534,75 +404,14 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+ {
+ 	struct nand_chip *nand_chip = mtd->priv;
+ 	struct mxc_nand_host *host = nand_chip->priv;
+-	int n, col, i = 0;
++	u16 col = host->buf_start;
++	int n = mtd->oobsize + mtd->writesize - col;
+ 
+-	DEBUG(MTD_DEBUG_LEVEL3,
+-	      "mxc_nand_read_buf(col = %d, len = %d)\n", host->col_addr, len);
+-
+-	col = host->col_addr;
+-
+-	/* Adjust saved column address */
+-	if (col < mtd->writesize && host->spare_only)
+-		col += mtd->writesize;
+-
+-	n = mtd->writesize + mtd->oobsize - col;
+-	n = min(len, n);
+-
+-	while (n) {
+-		void __iomem *p;
+-
+-		if (col < mtd->writesize)
+-			p = host->regs + MAIN_AREA0 + (col & ~3);
+-		else
+-			p = host->regs + SPARE_AREA0 -
+-					mtd->writesize + (col & ~3);
+-
+-		if (((col | (int)&buf[i]) & 3) || n < 16) {
+-			uint32_t data;
+-
+-			data = readl(p);
+-			switch (col & 3) {
+-			case 0:
+-				if (n) {
+-					buf[i++] = (uint8_t) (data);
+-					n--;
+-					col++;
+-				}
+-			case 1:
+-				if (n) {
+-					buf[i++] = (uint8_t) (data >> 8);
+-					n--;
+-					col++;
+-				}
+-			case 2:
+-				if (n) {
+-					buf[i++] = (uint8_t) (data >> 16);
+-					n--;
+-					col++;
+-				}
+-			case 3:
+-				if (n) {
+-					buf[i++] = (uint8_t) (data >> 24);
+-					n--;
+-					col++;
+-				}
+-			}
+-		} else {
+-			int m = mtd->writesize - col;
++	n = min(n, len);
+ 
+-			if (col >= mtd->writesize)
+-				m += mtd->oobsize;
+-
+-			m = min(n, m) & ~3;
+-			memcpy(&buf[i], p, m);
+-			col += m;
+-			i += m;
+-			n -= m;
+-		}
+-	}
+-	/* Update saved column address */
+-	host->col_addr = col;
++	memcpy(buf, host->data_buf + col, len);
+ 
++	host->buf_start += len;
+ }
+ 
+ /* Used by the upper layer to verify the data in NAND Flash
+@@ -641,6 +450,36 @@ static void mxc_nand_select_chip(struct mtd_info *mtd, int chip)
+ 	}
+ }
+ 
++/*
++ * Function to transfer data to/from spare area.
++ */
++static void copy_spare(struct mtd_info *mtd, bool bfrom)
++{
++	struct nand_chip *this = mtd->priv;
++	struct mxc_nand_host *host = this->priv;
++	u16 i, j;
++	u16 n = mtd->writesize >> 9;
++	u8 *d = host->data_buf + mtd->writesize;
++	u8 *s = host->regs + SPARE_AREA0;
++	u16 t = host->spare_len;
++
++	j = (mtd->oobsize / n >> 1) << 1;
++
++	if (bfrom) {
++		for (i = 0; i < n - 1; i++)
++			memcpy(d + i * j, s + i * t, j);
++
++		/* the last section */
++		memcpy(d + i * j, s + i * t, mtd->oobsize - i * j);
++	} else {
++		for (i = 0; i < n - 1; i++)
++			memcpy(&s[i * t], &d[i * j], j);
++
++		/* the last section */
++		memcpy(&s[i * t], &d[i * j], mtd->oobsize - i * j);
++	}
++}
++
+ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
+ {
+ 	struct nand_chip *nand_chip = mtd->priv;
+@@ -707,19 +546,18 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ 	switch (command) {
+ 
+ 	case NAND_CMD_STATUS:
+-		host->col_addr = 0;
++		host->buf_start = 0;
+ 		host->status_request = true;
+ 		break;
+ 
+ 	case NAND_CMD_READ0:
+-		host->col_addr = column;
+-		host->spare_only = false;
++		host->buf_start = column;
+ 		useirq = false;
+ 		break;
+ 
+ 	case NAND_CMD_READOOB:
+-		host->col_addr = column;
+-		host->spare_only = true;
++		host->buf_start = column + mtd->writesize;
++
+ 		useirq = false;
+ 		if (host->pagesize_2k)
+ 			command = NAND_CMD_READ0; /* only READ0 is valid */
+@@ -739,15 +577,13 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ 				mxc_nand_command(mtd, NAND_CMD_READ0, 0,
+ 						page_addr);
+ 
+-			host->col_addr = column - mtd->writesize;
+-			host->spare_only = true;
++			host->buf_start = column;
+ 
+ 			/* Set program pointer to spare region */
+ 			if (!host->pagesize_2k)
+ 				send_cmd(host, NAND_CMD_READOOB, false);
+ 		} else {
+-			host->spare_only = false;
+-			host->col_addr = column;
++			host->buf_start = column;
+ 
+ 			/* Set program pointer to page start */
+ 			if (!host->pagesize_2k)
+@@ -757,13 +593,15 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ 		break;
+ 
+ 	case NAND_CMD_PAGEPROG:
+-		send_page(host, 0, host->spare_only, NFC_INPUT);
++		memcpy(host->regs + MAIN_AREA0, host->data_buf, mtd->writesize);
++		copy_spare(mtd, false);
++		send_page(host, 0, NFC_INPUT);
+ 
+ 		if (host->pagesize_2k) {
+ 			/* data in 4 areas datas */
+-			send_page(host, 1, host->spare_only, NFC_INPUT);
+-			send_page(host, 2, host->spare_only, NFC_INPUT);
+-			send_page(host, 3, host->spare_only, NFC_INPUT);
++			send_page(host, 1, NFC_INPUT);
++			send_page(host, 2, NFC_INPUT);
++			send_page(host, 3, NFC_INPUT);
+ 		}
+ 
+ 		break;
+@@ -789,16 +627,18 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ 			/* send read confirm command */
+ 			send_cmd(host, NAND_CMD_READSTART, true);
+ 			/* read for each AREA */
+-			send_page(host, 0, host->spare_only, NFC_OUTPUT);
+-			send_page(host, 1, host->spare_only, NFC_OUTPUT);
+-			send_page(host, 2, host->spare_only, NFC_OUTPUT);
+-			send_page(host, 3, host->spare_only, NFC_OUTPUT);
++			send_page(host, 0, NFC_OUTPUT);
++			send_page(host, 1, NFC_OUTPUT);
++			send_page(host, 2, NFC_OUTPUT);
++			send_page(host, 3, NFC_OUTPUT);
+ 		} else
+-			send_page(host, 0, host->spare_only, NFC_OUTPUT);
++			send_page(host, 0, NFC_OUTPUT);
++
++		memcpy(host->data_buf, host->regs + MAIN_AREA0, mtd->writesize);
++		copy_spare(mtd, true);
+ 		break;
+ 
+ 	case NAND_CMD_READID:
+-		host->col_addr = 0;
+ 		send_read_id(host);
+ 		break;
+ 
+@@ -824,10 +664,14 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 	int err = 0, nr_parts = 0;
+ 
+ 	/* Allocate memory for MTD device structure and private data */
+-	host = kzalloc(sizeof(struct mxc_nand_host), GFP_KERNEL);
++	host = kzalloc(sizeof(struct mxc_nand_host) + NAND_MAX_PAGESIZE +
++			NAND_MAX_OOBSIZE, GFP_KERNEL);
+ 	if (!host)
+ 		return -ENOMEM;
+ 
++	host->data_buf = (uint8_t *)(host + 1);
++	host->spare_len = 16;
++
+ 	host->dev = &pdev->dev;
+ 	/* structures must be linked */
+ 	this = &host->nand;
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0010-MXC-NFC-Add-the-clock-resource-to-support-NFC-in-i.patch b/recipes/linux/linux-2.6.31/pcm043/0010-MXC-NFC-Add-the-clock-resource-to-support-NFC-in-i.patch
new file mode 100644
index 0000000..294acbc
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0010-MXC-NFC-Add-the-clock-resource-to-support-NFC-in-i.patch
@@ -0,0 +1,61 @@
+From db1d93750d22c87b588ade0c8e083f8d94ddf88b Mon Sep 17 00:00:00 2001
+From: Juergen Beisert <j.beisert at pengutronix.de>
+Date: Tue, 29 Sep 2009 15:44:00 +0200
+Subject: [PATCH 10/15] MXC NFC: Add the clock resource to support NFC in i.MX35
+
+Signed-off-by: Juergen Beisert <j.beisert at pengutronix.de>
+
+rebased to  2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel at phytec.de>
+---
+ arch/arm/mach-mx3/clock-imx35.c |   30 ++++++++++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+
+Index: arch/arm/mach-mx3/clock-imx35.c
+===================================================================
+--- arch/arm/mach-mx3/clock-imx35.c.orig	2009-12-08 11:03:44.248614597 +0100
++++ arch/arm/mach-mx3/clock-imx35.c	2009-12-08 11:04:48.958686514 +0100
+@@ -387,6 +387,35 @@
+ DEFINE_CLOCK(iim_clk,    0, CCM_CGR3,  2, NULL, NULL);
+ DEFINE_CLOCK(gpu2d_clk,  0, CCM_CGR3,  4, NULL, NULL);
+ 
++static int clk_dummy_enable(struct clk *clk)
++{
++	return 0;
++}
++
++static void clk_dummy_disable(struct clk *clk)
++{
++}
++
++static unsigned long get_rate_nfc(struct clk *clk)
++{
++	unsigned long div1;
++
++	div1 = (__raw_readl(CCM_BASE + CCM_PDR4) >> 28) + 1;
++
++	return get_rate_ahb(NULL) / div1;
++}
++
++/* NAND Controller: It seems it can't be disabled */
++static struct clk nfc_clk = {
++	.id		= 0,
++	.enable_reg	= 0,
++	.enable_shift	= 0,
++	.get_rate	= get_rate_nfc,
++	.set_rate	= NULL, /* set_rate_nfc, */
++	.enable		= clk_dummy_enable,
++	.disable	= clk_dummy_disable
++};
++
+ #define _REGISTER_CLOCK(d, n, c)	\
+ 	{				\
+ 		.dev_id = d,		\
+@@ -448,6 +477,7 @@
+ 	_REGISTER_CLOCK(NULL, "csi", csi_clk)
+ 	_REGISTER_CLOCK(NULL, "iim", iim_clk)
+ 	_REGISTER_CLOCK(NULL, "gpu2d", gpu2d_clk)
++	_REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk)
+ };
+ 
+ int __init mx35_clocks_init()
diff --git a/recipes/linux/linux-2.6.31/pcm043/0010-i.MX35-Fix-audmux-clock.patch b/recipes/linux/linux-2.6.31/pcm043/0010-i.MX35-Fix-audmux-clock.patch
new file mode 100644
index 0000000..765c783
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0010-i.MX35-Fix-audmux-clock.patch
@@ -0,0 +1,52 @@
+From 4e3f4ad37028ae59f910cff4cf9ce2f1acc62d66 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Mon, 2 Nov 2009 09:49:41 +0100
+Subject: [PATCH 10/28] i.MX35: Fix audmux clock
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/mach-mx3/clock-imx35.c |    7 +++----
+ 1 files changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/arch/arm/mach-mx3/clock-imx35.c b/arch/arm/mach-mx3/clock-imx35.c
+index 02b2507..9c0ec17 100644
+--- a/arch/arm/mach-mx3/clock-imx35.c
++++ b/arch/arm/mach-mx3/clock-imx35.c
+@@ -322,7 +322,7 @@ static void clk_cgr_disable(struct clk *clk)
+ 
+ DEFINE_CLOCK(asrc_clk,   0, CCM_CGR0,  0, NULL, NULL);
+ DEFINE_CLOCK(ata_clk,    0, CCM_CGR0,  2, get_rate_ipg, NULL);
+-DEFINE_CLOCK(audmux_clk, 0, CCM_CGR0,  4, NULL, NULL);
++/* DEFINE_CLOCK(audmux_clk, 0, CCM_CGR0,  4, NULL, NULL); */
+ DEFINE_CLOCK(can1_clk,   0, CCM_CGR0,  6, get_rate_ipg, NULL);
+ DEFINE_CLOCK(can2_clk,   1, CCM_CGR0,  8, get_rate_ipg, NULL);
+ DEFINE_CLOCK(cspi1_clk,  0, CCM_CGR0, 10, get_rate_ipg, NULL);
+@@ -368,7 +368,7 @@ DEFINE_CLOCK(uart3_clk,  2, CCM_CGR2, 20, get_rate_uart, NULL);
+ DEFINE_CLOCK(usbotg_clk, 0, CCM_CGR2, 22, NULL, NULL);
+ DEFINE_CLOCK(wdog_clk,   0, CCM_CGR2, 24, NULL, NULL);
+ DEFINE_CLOCK(max_clk,    0, CCM_CGR2, 26, NULL, NULL);
+-DEFINE_CLOCK(admux_clk,  0, CCM_CGR2, 30, NULL, NULL);
++DEFINE_CLOCK(audmux_clk, 0, CCM_CGR2, 30, NULL, NULL);
+ 
+ DEFINE_CLOCK(csi_clk,    0, CCM_CGR3,  0, get_rate_csi, NULL);
+ DEFINE_CLOCK(iim_clk,    0, CCM_CGR3,  2, NULL, NULL);
+@@ -384,7 +384,6 @@ DEFINE_CLOCK(gpu2d_clk,  0, CCM_CGR3,  4, NULL, NULL);
+ static struct clk_lookup lookups[] = {
+ 	_REGISTER_CLOCK(NULL, "asrc", asrc_clk)
+ 	_REGISTER_CLOCK(NULL, "ata", ata_clk)
+-	_REGISTER_CLOCK(NULL, "audmux", audmux_clk)
+ 	_REGISTER_CLOCK(NULL, "can", can1_clk)
+ 	_REGISTER_CLOCK(NULL, "can", can2_clk)
+ 	_REGISTER_CLOCK("spi_imx.0", NULL, cspi1_clk)
+@@ -429,7 +428,7 @@ static struct clk_lookup lookups[] = {
+ 	_REGISTER_CLOCK(NULL, "usbotg", usbotg_clk)
+ 	_REGISTER_CLOCK("mxc_wdt.0", NULL, wdog_clk)
+ 	_REGISTER_CLOCK(NULL, "max", max_clk)
+-	_REGISTER_CLOCK(NULL, "admux", admux_clk)
++	_REGISTER_CLOCK(NULL, "audmux", audmux_clk)
+ 	_REGISTER_CLOCK(NULL, "csi", csi_clk)
+ 	_REGISTER_CLOCK(NULL, "iim", iim_clk)
+ 	_REGISTER_CLOCK(NULL, "gpu2d", gpu2d_clk)
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0010-mxc-nand-simplify-command-processing.patch b/recipes/linux/linux-2.6.31/pcm043/0010-mxc-nand-simplify-command-processing.patch
new file mode 100644
index 0000000..a7d5cda
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0010-mxc-nand-simplify-command-processing.patch
@@ -0,0 +1,143 @@
+From c1aef45fdb7e5281904ea25c035025d6cc19eff6 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Thu, 4 Jun 2009 17:18:01 +0200
+Subject: [PATCH] mxc nand: simplify command processing
+
+Instead of having two switch/case with other operations
+in between, use only one switch/case
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand.c |   81 ++++++++++++++++++------------------------
+ 1 files changed, 35 insertions(+), 46 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
+index 4c338ae..e5de71a 100644
+--- a/drivers/mtd/nand/mxc_nand.c
++++ b/drivers/mtd/nand/mxc_nand.c
+@@ -533,7 +533,6 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ {
+ 	struct nand_chip *nand_chip = mtd->priv;
+ 	struct mxc_nand_host *host = nand_chip->priv;
+-	int useirq = true;
+ 
+ 	DEBUG(MTD_DEBUG_LEVEL3,
+ 	      "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",
+@@ -548,19 +547,37 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ 	case NAND_CMD_STATUS:
+ 		host->buf_start = 0;
+ 		host->status_request = true;
+-		break;
+ 
+-	case NAND_CMD_READ0:
+-		host->buf_start = column;
+-		useirq = false;
++		send_cmd(host, command, true);
++		mxc_do_addr_cycle(mtd, column, page_addr);
+ 		break;
+ 
++	case NAND_CMD_READ0:
+ 	case NAND_CMD_READOOB:
+-		host->buf_start = column + mtd->writesize;
++		if (command == NAND_CMD_READ0)
++			host->buf_start = column;
++		else
++			host->buf_start = column + mtd->writesize;
+ 
+-		useirq = false;
+ 		if (host->pagesize_2k)
+ 			command = NAND_CMD_READ0; /* only READ0 is valid */
++
++		send_cmd(host, command, false);
++		mxc_do_addr_cycle(mtd, column, page_addr);
++
++		if (host->pagesize_2k) {
++			/* send read confirm command */
++			send_cmd(host, NAND_CMD_READSTART, true);
++			/* read for each AREA */
++			send_page(host, 0, NFC_OUTPUT);
++			send_page(host, 1, NFC_OUTPUT);
++			send_page(host, 2, NFC_OUTPUT);
++			send_page(host, 3, NFC_OUTPUT);
++		} else
++			send_page(host, 0, NFC_OUTPUT);
++
++		memcpy(host->data_buf, host->regs + MAIN_AREA0, mtd->writesize);
++		copy_spare(mtd, true);
+ 		break;
+ 
+ 	case NAND_CMD_SEQIN:
+@@ -589,7 +606,9 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ 			if (!host->pagesize_2k)
+ 				send_cmd(host, NAND_CMD_READ0, false);
+ 		}
+-		useirq = false;
++
++		send_cmd(host, command, false);
++		mxc_do_addr_cycle(mtd, column, page_addr);
+ 		break;
+ 
+ 	case NAND_CMD_PAGEPROG:
+@@ -604,51 +623,21 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ 			send_page(host, 3, NFC_INPUT);
+ 		}
+ 
+-		break;
+-
+-	case NAND_CMD_ERASE1:
+-		useirq = false;
+-		break;
+-	}
+-
+-	/* Write out the command to the device. */
+-	send_cmd(host, command, useirq);
+-	mxc_do_addr_cycle(mtd, column, page_addr);
+-
+-	/* Command post-processing step */
+-	switch (command) {
+-
+-	case NAND_CMD_RESET:
+-		break;
+-
+-	case NAND_CMD_READOOB:
+-	case NAND_CMD_READ0:
+-		if (host->pagesize_2k) {
+-			/* send read confirm command */
+-			send_cmd(host, NAND_CMD_READSTART, true);
+-			/* read for each AREA */
+-			send_page(host, 0, NFC_OUTPUT);
+-			send_page(host, 1, NFC_OUTPUT);
+-			send_page(host, 2, NFC_OUTPUT);
+-			send_page(host, 3, NFC_OUTPUT);
+-		} else
+-			send_page(host, 0, NFC_OUTPUT);
+-
+-		memcpy(host->data_buf, host->regs + MAIN_AREA0, mtd->writesize);
+-		copy_spare(mtd, true);
++		send_cmd(host, command, true);
++		mxc_do_addr_cycle(mtd, column, page_addr);
+ 		break;
+ 
+ 	case NAND_CMD_READID:
++		send_cmd(host, command, true);
++		mxc_do_addr_cycle(mtd, column, page_addr);
+ 		send_read_id(host);
+ 		break;
+ 
+-	case NAND_CMD_PAGEPROG:
+-		break;
+-
+-	case NAND_CMD_STATUS:
+-		break;
+-
++	case NAND_CMD_ERASE1:
+ 	case NAND_CMD_ERASE2:
++		send_cmd(host, command, false);
++		mxc_do_addr_cycle(mtd, column, page_addr);
++
+ 		break;
+ 	}
+ }
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0011-MX31-add-spi-controller-devices-resources.patch b/recipes/linux/linux-2.6.31/pcm043/0011-MX31-add-spi-controller-devices-resources.patch
new file mode 100644
index 0000000..66e425b
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0011-MX31-add-spi-controller-devices-resources.patch
@@ -0,0 +1,97 @@
+From 5a3ba6a98a5822698ad4552a4af47b3230807952 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Fri, 19 Dec 2008 14:32:15 +0100
+Subject: [PATCH 11/28] MX31: add spi controller devices/resources
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/mach-mx3/devices.c |   61 +++++++++++++++++++++++++++++++++++++++++++
+ arch/arm/mach-mx3/devices.h |    3 ++
+ 2 files changed, 64 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-mx3/devices.c b/arch/arm/mach-mx3/devices.c
+index 06dab5f..c32049a 100644
+--- a/arch/arm/mach-mx3/devices.c
++++ b/arch/arm/mach-mx3/devices.c
+@@ -454,6 +454,67 @@ struct platform_device imx_ssi_device1 = {
+ 	.resource = imx_ssi_resources1,
+ };
+ 
++/*
++ * SPI master controller
++ * 3 channels
++ */
++static struct resource imx_spi_0_resources[] = {
++	{
++	       .start = CSPI1_BASE_ADDR,
++	       .end = CSPI1_BASE_ADDR + SZ_4K - 1,
++	       .flags = IORESOURCE_MEM,
++	}, {
++	       .start = MXC_INT_CSPI1,
++	       .end = MXC_INT_CSPI1,
++	       .flags = IORESOURCE_IRQ,
++	},
++};
++
++static struct resource imx_spi_1_resources[] = {
++	{
++		.start = CSPI2_BASE_ADDR,
++		.end = CSPI2_BASE_ADDR + SZ_4K - 1,
++		.flags = IORESOURCE_MEM,
++	}, {
++		.start = MXC_INT_CSPI2,
++		.end = MXC_INT_CSPI2,
++		.flags = IORESOURCE_IRQ,
++	},
++};
++
++static struct resource imx_spi_2_resources[] = {
++	{
++		.start = CSPI3_BASE_ADDR,
++		.end = CSPI3_BASE_ADDR + SZ_4K - 1,
++		.flags = IORESOURCE_MEM,
++	}, {
++		.start = MXC_INT_CSPI3,
++		.end = MXC_INT_CSPI3,
++		.flags = IORESOURCE_IRQ,
++	},
++};
++
++struct platform_device imx_spi_device0 = {
++	.name = "spi_imx",
++	.id = 0,
++	.num_resources = ARRAY_SIZE(imx_spi_0_resources),
++	.resource = imx_spi_0_resources,
++};
++
++struct platform_device imx_spi_device1 = {
++	.name = "spi_imx",
++	.id = 1,
++	.num_resources = ARRAY_SIZE(imx_spi_1_resources),
++	.resource = imx_spi_1_resources,
++};
++
++struct platform_device imx_spi_device2 = {
++	.name = "spi_imx",
++	.id = 2,
++	.num_resources = ARRAY_SIZE(imx_spi_2_resources),
++	.resource = imx_spi_2_resources,
++};
++
+ static int mx3_devices_init(void)
+ {
+ 	if (cpu_is_mx31()) {
+diff --git a/arch/arm/mach-mx3/devices.h b/arch/arm/mach-mx3/devices.h
+index 224c2eb..402b60e 100644
+--- a/arch/arm/mach-mx3/devices.h
++++ b/arch/arm/mach-mx3/devices.h
+@@ -19,3 +19,6 @@ extern struct platform_device mxc_otg_udc_device;
+ extern struct platform_device mxc_rnga_device;
+ extern struct platform_device imx_ssi_device0;
+ extern struct platform_device imx_ssi_device1;
++extern struct platform_device imx_spi_device0;
++extern struct platform_device imx_spi_device1;
++extern struct platform_device imx_spi_device2;
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0011-MXC-NFC-Fix-NFC-s-clock-name.patch b/recipes/linux/linux-2.6.31/pcm043/0011-MXC-NFC-Fix-NFC-s-clock-name.patch
new file mode 100644
index 0000000..a2e1d28
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0011-MXC-NFC-Fix-NFC-s-clock-name.patch
@@ -0,0 +1,28 @@
+From 3a28735748fbdeb6c8036f8f64998a4d44ab9228 Mon Sep 17 00:00:00 2001
+From: Juergen Beisert <j.beisert at pengutronix.de>
+Date: Tue, 29 Sep 2009 15:47:34 +0200
+Subject: [PATCH 11/15] MXC NFC: Fix NFC's clock name
+
+Use a name in a style like all other clocks.
+
+Signed-off-by: Juergen Beisert <j.beisert at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand_v2.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand_v2.c b/drivers/mtd/nand/mxc_nand_v2.c
+index 3891d9a..bab3712 100644
+--- a/drivers/mtd/nand/mxc_nand_v2.c
++++ b/drivers/mtd/nand/mxc_nand_v2.c
+@@ -858,7 +858,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 	this->read_buf = mxc_nand_read_buf;
+ 	this->verify_buf = mxc_nand_verify_buf;
+ 
+-	host->clk = clk_get(&pdev->dev, "nfc_clk");
++	host->clk = clk_get(&pdev->dev, NULL);
+ 	if (IS_ERR(host->clk)) {
+ 		err = PTR_ERR(host->clk);
+ 		goto eclk;
+-- 
+1.6.1
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0011-mxc-nand-modify-send_page-to-send-all-pages-not-on.patch b/recipes/linux/linux-2.6.31/pcm043/0011-mxc-nand-modify-send_page-to-send-all-pages-not-on.patch
new file mode 100644
index 0000000..80979a8
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0011-mxc-nand-modify-send_page-to-send-all-pages-not-on.patch
@@ -0,0 +1,87 @@
+From 19cd65a26dafcb725b0b3c99b0a0d79534c8c460 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Thu, 4 Jun 2009 17:25:53 +0200
+Subject: [PATCH] mxc nand: modify send_page to send all pages, not only one
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand.c |   45 +++++++++++++++++++-----------------------
+ 1 files changed, 20 insertions(+), 25 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
+index e5de71a..04b2bf2 100644
+--- a/drivers/mtd/nand/mxc_nand.c
++++ b/drivers/mtd/nand/mxc_nand.c
+@@ -228,16 +228,25 @@ static void send_addr(struct mxc_nand_host *host, uint16_t addr, int islast)
+ 	wait_op_done(host, TROP_US_DELAY, islast);
+ }
+ 
+-static void send_page(struct mxc_nand_host *host, uint8_t buf_id,
+-		unsigned int ops)
++static void send_page(struct mxc_nand_host *host, unsigned int ops)
+ {
+-	/* NANDFC buffer 0 is used for page read/write */
+-	writew(buf_id, host->regs + NFC_BUF_ADDR);
++	int bufs, i;
+ 
+-	writew(ops, host->regs + NFC_CONFIG2);
++	if (host->pagesize_2k)
++		bufs = 4;
++	else
++		bufs = 1;
+ 
+-	/* Wait for operation to complete */
+-	wait_op_done(host, TROP_US_DELAY, true);
++	for (i = 0; i < bufs; i++) {
++
++		/* NANDFC buffer 0 is used for page read/write */
++		writew(i, host->regs + NFC_BUF_ADDR);
++
++		writew(ops, host->regs + NFC_CONFIG2);
++
++		/* Wait for operation to complete */
++		wait_op_done(host, TROP_US_DELAY, true);
++	}
+ }
+ 
+ /* Request the NANDFC to perform a read of the NAND device ID. */
+@@ -565,16 +574,10 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ 		send_cmd(host, command, false);
+ 		mxc_do_addr_cycle(mtd, column, page_addr);
+ 
+-		if (host->pagesize_2k) {
+-			/* send read confirm command */
++		if (host->pagesize_2k)
+ 			send_cmd(host, NAND_CMD_READSTART, true);
+-			/* read for each AREA */
+-			send_page(host, 0, NFC_OUTPUT);
+-			send_page(host, 1, NFC_OUTPUT);
+-			send_page(host, 2, NFC_OUTPUT);
+-			send_page(host, 3, NFC_OUTPUT);
+-		} else
+-			send_page(host, 0, NFC_OUTPUT);
++
++		send_page(host, NFC_OUTPUT);
+ 
+ 		memcpy(host->data_buf, host->regs + MAIN_AREA0, mtd->writesize);
+ 		copy_spare(mtd, true);
+@@ -614,15 +617,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ 	case NAND_CMD_PAGEPROG:
+ 		memcpy(host->regs + MAIN_AREA0, host->data_buf, mtd->writesize);
+ 		copy_spare(mtd, false);
+-		send_page(host, 0, NFC_INPUT);
+-
+-		if (host->pagesize_2k) {
+-			/* data in 4 areas datas */
+-			send_page(host, 1, NFC_INPUT);
+-			send_page(host, 2, NFC_INPUT);
+-			send_page(host, 3, NFC_INPUT);
+-		}
+-
++		send_page(host, NFC_INPUT);
+ 		send_cmd(host, command, true);
+ 		mxc_do_addr_cycle(mtd, column, page_addr);
+ 		break;
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0012-MXC-NFC-i.MX35-can-work-with-the-v2-not-with-v1-of.patch b/recipes/linux/linux-2.6.31/pcm043/0012-MXC-NFC-i.MX35-can-work-with-the-v2-not-with-v1-of.patch
new file mode 100644
index 0000000..9a88af0
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0012-MXC-NFC-i.MX35-can-work-with-the-v2-not-with-v1-of.patch
@@ -0,0 +1,34 @@
+From 0013249e16bc7527bf63b483486ead97ea59839e Mon Sep 17 00:00:00 2001
+From: Juergen Beisert <j.beisert at pengutronix.de>
+Date: Tue, 29 Sep 2009 15:49:52 +0200
+Subject: [PATCH 12/15] MXC NFC: i.MX35 can work with the v2, not with v1 of this driver
+
+Signed-off-by: Juergen Beisert <j.beisert at pengutronix.de>
+
+rebased to  2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel at phytec.de>
+---
+ drivers/mtd/nand/Kconfig |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+Index: drivers/mtd/nand/Kconfig
+===================================================================
+--- drivers/mtd/nand/Kconfig.orig	2009-12-08 10:02:59.468654404 +0100
++++ drivers/mtd/nand/Kconfig	2009-12-08 10:03:38.130073936 +0100
+@@ -421,14 +421,14 @@
+ 
+ config MTD_NAND_MXC
+ 	tristate "MXC NAND support"
+-	depends on ARCH_MX2 || ARCH_MX3
++	depends on ARCH_MX2 || (ARCH_MX3 && !ARCH_MX35)
+ 	help
+ 	  This enables the driver for the NAND flash controller on the
+ 	  MXC processors.
+ 
+ config MTD_NAND_MXC_V2
+ 	tristate "MXC NAND support"
+-	depends on ARCH_MX25
++	depends on ARCH_MX25 || ARCH_MX35
+ 	help
+ 	  This enables the driver for the NAND flash controller on the
+ 	  MXC processors.
diff --git a/recipes/linux/linux-2.6.31/pcm043/0012-i.MX27-clock-rename-spi-clocks-to-match-device.patch b/recipes/linux/linux-2.6.31/pcm043/0012-i.MX27-clock-rename-spi-clocks-to-match-device.patch
new file mode 100644
index 0000000..db2474c
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0012-i.MX27-clock-rename-spi-clocks-to-match-device.patch
@@ -0,0 +1,30 @@
+From 3e3ef3c8c617d291bb674488cd2920ad9088451e Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Thu, 24 Sep 2009 09:58:52 +0200
+Subject: [PATCH 12/28] i.MX27 clock: rename spi clocks to match device
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/mach-mx2/clock_imx27.c |    6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/mach-mx2/clock_imx27.c b/arch/arm/mach-mx2/clock_imx27.c
+index 5abb763..1e9d608 100644
+--- a/arch/arm/mach-mx2/clock_imx27.c
++++ b/arch/arm/mach-mx2/clock_imx27.c
+@@ -638,9 +638,9 @@ static struct clk_lookup lookups[] = {
+ 	_REGISTER_CLOCK("mxc-mmc.0", NULL, sdhc1_clk)
+ 	_REGISTER_CLOCK("mxc-mmc.1", NULL, sdhc2_clk)
+ 	_REGISTER_CLOCK("mxc-mmc.2", NULL, sdhc3_clk)
+-	_REGISTER_CLOCK(NULL, "cspi1", cspi1_clk)
+-	_REGISTER_CLOCK(NULL, "cspi2", cspi2_clk)
+-	_REGISTER_CLOCK(NULL, "cspi3", cspi3_clk)
++	_REGISTER_CLOCK("spi_imx.0", NULL, cspi1_clk)
++	_REGISTER_CLOCK("spi_imx.1", NULL, cspi2_clk)
++	_REGISTER_CLOCK("spi_imx.2", NULL, cspi3_clk)
+ 	_REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk)
+ 	_REGISTER_CLOCK(NULL, "csi", csi_clk)
+ 	_REGISTER_CLOCK(NULL, "usb", usb_clk)
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0012-mxc_nand-remove-unused-defines.patch b/recipes/linux/linux-2.6.31/pcm043/0012-mxc_nand-remove-unused-defines.patch
new file mode 100644
index 0000000..8b4a438
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0012-mxc_nand-remove-unused-defines.patch
@@ -0,0 +1,31 @@
+From cf903eff4c30f2eca4a67951f5b66e961f0ba542 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Fri, 5 Jun 2009 10:55:32 +0200
+Subject: [PATCH] mxc_nand: remove unused defines
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand.c |    7 -------
+ 1 files changed, 0 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
+index 04b2bf2..2988f1d 100644
+--- a/drivers/mtd/nand/mxc_nand.c
++++ b/drivers/mtd/nand/mxc_nand.c
+@@ -122,13 +122,6 @@ struct mxc_nand_host {
+ 
+ /* Define delays in microsec for NAND device operations */
+ #define TROP_US_DELAY   2000
+-/* Macros to get byte and bit positions of ECC */
+-#define COLPOS(x)  ((x) >> 3)
+-#define BITPOS(x) ((x) & 0xf)
+-
+-/* Define single bit Error positions in Main & Spare area */
+-#define MAIN_SINGLEBIT_ERROR 0x4
+-#define SPARE_SINGLEBIT_ERROR 0x1
+ 
+ /* OOB placement block for use with hardware ecc generation */
+ static struct nand_ecclayout nand_hw_eccoob_smallpage = {
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0013-MXC-NFC-Add-the-cpu_is_mx25-macro.patch b/recipes/linux/linux-2.6.31/pcm043/0013-MXC-NFC-Add-the-cpu_is_mx25-macro.patch
new file mode 100644
index 0000000..9fec47b
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0013-MXC-NFC-Add-the-cpu_is_mx25-macro.patch
@@ -0,0 +1,38 @@
+From 6b82a298e085e6bc47d1c241871578d66208ee0f Mon Sep 17 00:00:00 2001
+From: Juergen Beisert <j.beisert at pengutronix.de>
+Date: Tue, 29 Sep 2009 16:10:55 +0200
+Subject: [PATCH 13/15] MXC NFC: Add the cpu_is_mx25 macro
+
+To be able to compile this NFC driver we need all CPU macros to
+distinguish the different revisions of the NFC.
+Note: This macro is untested for the i.MX25 case. Tested for a
+i.MX35 case only.
+
+Signed-off-by: Juergen Beisert <j.beisert at pengutronix.de>
+---
+ arch/arm/plat-mxc/include/mach/mxc.h |   12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+Index: arch/arm/plat-mxc/include/mach/mxc.h
+===================================================================
+--- arch/arm/plat-mxc/include/mach/mxc.h.orig
++++ arch/arm/plat-mxc/include/mach/mxc.h
+@@ -58,6 +58,18 @@ extern unsigned int __mxc_cpu_type;
+ # define cpu_is_mx21()		(0)
+ #endif
+ 
++#ifdef CONFIG_MACH_MX25
++# ifdef mxc_cpu_type
++#  undef mxc_cpu_type
++#  define mxc_cpu_type __mxc_cpu_type
++# else
++#  define mxc_cpu_type MXC_CPU_MX25
++# endif
++# define cpu_is_mx25()		(mxc_cpu_type == MXC_CPU_MX25)
++#else
++# define cpu_is_mx25()		(0)
++#endif
++
+ #ifdef CONFIG_MACH_MX27
+ # ifdef mxc_cpu_type
+ #  undef mxc_cpu_type
diff --git a/recipes/linux/linux-2.6.31/pcm043/0013-add-a-mc13783-codec-driver.patch b/recipes/linux/linux-2.6.31/pcm043/0013-add-a-mc13783-codec-driver.patch
new file mode 100644
index 0000000..c89b83d
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0013-add-a-mc13783-codec-driver.patch
@@ -0,0 +1,834 @@
+From a0437114fe666815acb9f7573acdcdc36dc45203 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Thu, 22 Oct 2009 14:10:14 +0200
+Subject: [PATCH 13/28] add a mc13783 codec driver
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ sound/soc/codecs/Kconfig   |    4 +
+ sound/soc/codecs/Makefile  |    2 +
+ sound/soc/codecs/mc13783.c |  730 ++++++++++++++++++++++++++++++++++++++++++++
+ sound/soc/codecs/mc13783.h |   32 ++
+ 4 files changed, 768 insertions(+), 0 deletions(-)
+ create mode 100644 sound/soc/codecs/mc13783.c
+ create mode 100644 sound/soc/codecs/mc13783.h
+
+diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
+index bbc97fd..34f5c94 100644
+--- a/sound/soc/codecs/Kconfig
++++ b/sound/soc/codecs/Kconfig
+@@ -17,6 +17,7 @@ config SND_SOC_ALL_CODECS
+ 	select SND_SOC_AK4104 if SPI_MASTER
+ 	select SND_SOC_AK4535 if I2C
+ 	select SND_SOC_CS4270 if I2C
++	select SND_SOC_MC13783 if SPI
+ 	select SND_SOC_PCM3008
+ 	select SND_SOC_SPDIF
+ 	select SND_SOC_SSM2602 if I2C
+@@ -89,6 +90,9 @@ config SND_SOC_CS4270_VD33_ERRATA
+ config SND_SOC_L3
+        tristate
+ 
++config SND_SOC_MC13783
++	tristate
++
+ config SND_SOC_PCM3008
+        tristate
+ 
+diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
+index 8b75305..0d3dbc7 100644
+--- a/sound/soc/codecs/Makefile
++++ b/sound/soc/codecs/Makefile
+@@ -5,6 +5,7 @@ snd-soc-ak4104-objs := ak4104.o
+ snd-soc-ak4535-objs := ak4535.o
+ snd-soc-cs4270-objs := cs4270.o
+ snd-soc-l3-objs := l3.o
++snd-soc-mc13783-objs := mc13783.o
+ snd-soc-pcm3008-objs := pcm3008.o
+ snd-soc-spdif-objs := spdif_transciever.o
+ snd-soc-ssm2602-objs := ssm2602.o
+@@ -42,6 +43,7 @@ obj-$(CONFIG_SND_SOC_AK4104)	+= snd-soc-ak4104.o
+ obj-$(CONFIG_SND_SOC_AK4535)	+= snd-soc-ak4535.o
+ obj-$(CONFIG_SND_SOC_CS4270)	+= snd-soc-cs4270.o
+ obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
++obj-$(CONFIG_SND_SOC_MC13783)	+= snd-soc-mc13783.o
+ obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
+ obj-$(CONFIG_SND_SOC_SPDIF)	+= snd-soc-spdif.o
+ obj-$(CONFIG_SND_SOC_SSM2602)	+= snd-soc-ssm2602.o
+diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c
+new file mode 100644
+index 0000000..5a7b4e9
+--- /dev/null
++++ b/sound/soc/codecs/mc13783.c
+@@ -0,0 +1,730 @@
++/*
++ * Copyright 2008 Juergen Beisert, kernel at pengutronix.de
++ * Copyright 2009 Sascha Hauer, s.hauer at pengutronix.de
++ *
++ * Initial development of this code was funded by
++ * Phytec Messtechnik GmbH, http://www.phytec.de
++ *
++ * 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., 51 Franklin Street, Fifth Floor, Boston,
++ * MA  02110-1301, USA.
++ */
++#include <linux/device.h>
++#include <linux/mfd/mc13783-private.h>
++#include <sound/core.h>
++#include <sound/control.h>
++#include <sound/pcm.h>
++#include <sound/soc.h>
++#include <sound/initval.h>
++#include <sound/soc-dapm.h>
++
++#include "mc13783.h"
++
++#define PMIC_AUDIO_RX_0		36
++#define PMIC_AUDIO_RX_1		37
++#define PMIC_AUDIO_TX		38
++#define PMIC_SSI_NETWORK	39
++#define PMIC_AUDIO_CODEC	40
++#define PMIC_AUDIO_DAC		41
++
++#define SSI_NETWORK_CDCTXRXSLOT(x)	(((x) & 0x3) << 2)
++#define SSI_NETWORK_CDCTXSECSLOT(x)	(((x) & 0x3) << 4)
++#define SSI_NETWORK_CDCRXSECSLOT(x)	(((x) & 0x3) << 6)
++#define SSI_NETWORK_CDCRXSECGAIN(x)	(((x) & 0x3) << 8)
++#define SSI_NETWORK_CDCSUMGAIN(x)	(1 << 10)
++#define SSI_NETWORK_CDCFSDLY(x)		(1 << 11)
++#define SSI_NETWORK_STDCSLOT(x)		(((x) & 0x3) << 12)
++#define SSI_NETWORK_STDCRXSLOT(x)	(((x) & 0x3) << 14)
++#define SSI_NETWORK_STDCRXSECSLOT(x)	(((x) & 0x3) << 16)
++#define SSI_NETWORK_STDCRXSECGAIN(x)	(((x) & 0x3) << 18)
++#define SSI_NETWORK_STDCSUMGAIN		(1 << 20)
++
++#define STEREO_DAC_STD_SSI_SEL		(1 << 0)
++#define STEREO_DAC_STD_CLK_SEL		(1 << 1)
++#define STEREO_DAC_STD_CSM		(1 << 2)
++#define STEREO_DAC_STD_BCL_INV		(1 << 3)
++#define STEREO_DAC_STD_CFS_INV		(1 << 4)
++#define STEREO_DAC_STD_CFS(x)		(((x) & 0x3) << 5)
++#define STEREO_DAC_STD_CLK(x)		(((x) & 0x7) << 7)
++#define STEREO_DAC_STD_CFS_DLY_B	(1 << 10)
++#define STEREO_DAC_STD_C_EN		(1 << 11)
++#define STEREO_DAC_STD_C_CLK_EN		(1 << 12)
++#define STEREO_DAC_STD_C_RESET		(1 << 15)
++#define STEREO_DAC_SPDIF		(1 << 16)
++#define STEREO_DAC_SR(x)		(((x) & 0xf) << 17)
++
++static struct mc13783 *mc13783;
++
++struct mc13783_priv {
++	struct snd_soc_codec codec;
++
++	u32 reg_cache[42];
++
++	int mc13783_asp_val;
++	int mc13783_alsp_val;
++};
++
++static unsigned int mc13783_read(struct snd_soc_codec *codec,
++	unsigned int reg)
++{
++	struct mc13783_priv *priv = codec->private_data;
++
++	return priv->reg_cache[reg];
++}
++
++static int mc13783_write(struct snd_soc_codec *codec,
++	unsigned int reg, unsigned int value)
++{
++	struct mc13783_priv *priv = codec->private_data;
++
++	priv->reg_cache[reg] = value;
++
++	return mc13783_reg_write(mc13783, reg, value);
++}
++
++/* Mapping between sample rates and register value */
++static unsigned int mc13783_rates[] = {
++	8000, 11025, 12000, 16000,
++	22050, 24000, 32000, 44100,
++	48000, 64000, 96000
++};
++
++static int mc13783_pcm_hw_params(struct snd_pcm_substream *substream,
++				struct snd_pcm_hw_params *params,
++				struct snd_soc_dai *dai)
++{
++	struct snd_soc_pcm_runtime *rtd = substream->private_data;
++	struct snd_soc_device *socdev = rtd->socdev;
++	struct snd_soc_codec *codec = socdev->card->codec;
++	unsigned int rate = params_rate(params);
++	int i;
++	unsigned int reg;
++
++	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++		for (i = 0; i < ARRAY_SIZE(mc13783_rates); i++) {
++			if (rate == mc13783_rates[i]) {
++				snd_soc_update_bits(codec, PMIC_AUDIO_DAC,
++						0xf << 17, i << 17);
++				return 0;
++			}
++		}
++	} else {
++		if (rate == 8000)
++			reg = 0;
++		else
++			reg = (1 << 10);
++
++		snd_soc_update_bits(codec, PMIC_AUDIO_CODEC,
++				0x1 << 10, reg);
++
++		return 0;
++	}
++
++	return -EINVAL;
++}
++
++static int mc13783_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
++{
++	struct snd_soc_codec *codec = dai->codec;
++	unsigned int reg;
++
++	if (dai->id == MC13783_ID_STEREO_DAC)
++		reg = mc13783_read(codec, PMIC_AUDIO_DAC);
++	else
++		reg = mc13783_read(codec, PMIC_AUDIO_CODEC);
++
++	reg &= ~STEREO_DAC_STD_CFS(3);
++	reg &= ~STEREO_DAC_STD_BCL_INV;
++	reg &= ~STEREO_DAC_STD_CFS_INV;
++	reg &= ~STEREO_DAC_STD_CSM;
++	reg &= ~STEREO_DAC_STD_C_CLK_EN;
++
++	/* DAI mode */
++	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
++	case SND_SOC_DAIFMT_I2S:
++		reg |= STEREO_DAC_STD_CFS(2);
++		break;
++	case SND_SOC_DAIFMT_DSP_A:
++		reg |= STEREO_DAC_STD_CFS(1);
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	/* DAI clock inversion */
++	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
++	case SND_SOC_DAIFMT_NB_NF:
++		reg |= STEREO_DAC_STD_BCL_INV;
++		break;
++	case SND_SOC_DAIFMT_NB_IF:
++		reg |= STEREO_DAC_STD_BCL_INV;
++		reg |= STEREO_DAC_STD_CFS_INV;
++		break;
++	case SND_SOC_DAIFMT_IB_NF:
++		break;
++	case SND_SOC_DAIFMT_IB_IF:
++		reg |= STEREO_DAC_STD_CFS_INV;
++		break;
++	}
++
++	/* DAI clock master masks */
++	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
++	case SND_SOC_DAIFMT_CBM_CFM:
++		reg |= STEREO_DAC_STD_C_CLK_EN;
++		break;
++	case SND_SOC_DAIFMT_CBS_CFS:
++		reg |= STEREO_DAC_STD_CSM;
++	case SND_SOC_DAIFMT_CBM_CFS:
++	case SND_SOC_DAIFMT_CBS_CFM:
++		return -EINVAL;
++	}
++
++	reg |= STEREO_DAC_STD_C_EN;	/* DAC power up */
++	reg |= STEREO_DAC_STD_C_RESET;	/* reset filter */
++
++	if (dai->id == MC13783_ID_STEREO_DAC)
++		mc13783_write(codec, PMIC_AUDIO_DAC, reg);
++	else
++		mc13783_write(codec, PMIC_AUDIO_CODEC, reg);
++
++	return 0;
++}
++
++static int mc13783_set_sysclk(struct snd_soc_dai *dai,
++				  int clk_id, unsigned int freq, int dir)
++{
++	struct snd_soc_codec *codec = dai->codec;
++	int clk;
++	unsigned int reg;
++
++	if (dai->id == MC13783_ID_STEREO_DAC)
++		reg = mc13783_read(codec, PMIC_AUDIO_DAC);
++	else
++		reg = mc13783_read(codec, PMIC_AUDIO_CODEC);
++
++	reg &= ~STEREO_DAC_STD_CLK(0x7);
++	reg &= ~STEREO_DAC_STD_CLK_SEL;
++
++	switch (freq) {
++	case 13000000:
++		clk = 0;
++		break;
++	case 15360000:
++		clk = 1;
++		break;
++	case 16800000:
++		clk = 2;
++		break;
++	case 26000000:
++		clk = 4;
++		break;
++	case 12000000:
++		clk = 5;
++		break;
++	case  3686400:
++		clk = 6;
++		break;
++	case 33600000:
++		clk = 7;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	if (clk_id == MC13783_CLK_CLIB)
++		reg |= STEREO_DAC_STD_CLK_SEL;
++
++	reg |= STEREO_DAC_STD_CLK(clk);
++
++	if (dai->id == MC13783_ID_STEREO_DAC)
++		mc13783_write(codec, PMIC_AUDIO_DAC, reg);
++	else
++		mc13783_write(codec, PMIC_AUDIO_CODEC, reg);
++
++	return 0;
++}
++
++static int mc13783_set_tdm_slot_codec(struct snd_soc_dai *dai,
++	unsigned int mask, int slots)
++{
++	struct snd_soc_codec *codec = dai->codec;
++	unsigned int reg;
++
++	if (slots != 4)
++		return -EINVAL;
++
++	reg = mc13783_read(codec, PMIC_SSI_NETWORK);
++
++	reg &= ~(0xfff << 0);
++	reg |= (0x00 << 2);	/* primary timeslot RX/TX(?) is 0 */
++	reg |= (0x01 << 4);	/* secondary timeslot TX is 1 */
++	reg |= (0x01 << 6);	/* secondary timeslot RX is 1 */
++
++	mc13783_write(codec, PMIC_SSI_NETWORK, reg);
++
++	return 0;
++}
++
++static int mc13783_get_alsp(struct snd_kcontrol *kcontrol,
++	struct snd_ctl_elem_value *ucontrol)
++{
++	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
++	struct mc13783_priv *priv = codec->private_data;
++
++	ucontrol->value.integer.value[0] = priv->mc13783_alsp_val;
++
++	return 0;
++}
++
++static int mc13783_put_alsp(struct snd_kcontrol *kcontrol,
++	struct snd_ctl_elem_value *ucontrol)
++{
++	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
++	struct mc13783_priv *priv = codec->private_data;
++	unsigned int reg;
++
++	priv->mc13783_alsp_val = ucontrol->value.integer.value[0];
++
++	reg = mc13783_read(codec, PMIC_AUDIO_RX_0);
++
++	reg &= ~((1 << 5) | (1 << 7));
++
++	if (priv->mc13783_alsp_val)
++		reg |= 1 << 5;
++
++	if (priv->mc13783_alsp_val == 2)
++		reg |= 1 << 7;
++
++	mc13783_write(codec, PMIC_AUDIO_RX_0, reg);
++
++	return 0;
++}
++
++static int mc13783_pcm_get(struct snd_kcontrol *kcontrol,
++	struct snd_ctl_elem_value *ucontrol)
++{
++	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
++	int val;
++
++	val = mc13783_read(codec, PMIC_AUDIO_RX_0);
++	ucontrol->value.enumerated.item[0] = (val >> 22) & 1;
++
++	return 0;
++}
++
++static int mc13783_pcm_put(struct snd_kcontrol *kcontrol,
++	struct snd_ctl_elem_value *ucontrol)
++{
++	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
++	unsigned int r36, r37;
++
++	r36 = mc13783_read(codec, PMIC_AUDIO_RX_0);
++	r37 = mc13783_read(codec, PMIC_AUDIO_RX_1);
++
++	r36 &= ~(1 << 22);
++	r37 &= ~(1 << 5);
++
++	if (ucontrol->value.enumerated.item[0]) {
++		r36 |= (1 << 22);
++		r37 |= (1 << 5);
++	} else {
++		r36 &= ~(1 << 22);
++		r37 &= ~(1 << 5);
++	}
++
++	mc13783_write(codec, PMIC_AUDIO_RX_0, r36);
++	mc13783_write(codec, PMIC_AUDIO_RX_1, r37);
++
++	return 0;
++}
++
++static int mc13783_linein_get(struct snd_kcontrol *kcontrol,
++	struct snd_ctl_elem_value *ucontrol)
++{
++	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
++	int val;
++
++	val = mc13783_read(codec, PMIC_AUDIO_RX_0);
++	ucontrol->value.enumerated.item[0] = (val >> 23) & 1;
++
++	return 0;
++}
++
++static int mc13783_linein_put(struct snd_kcontrol *kcontrol,
++	struct snd_ctl_elem_value *ucontrol)
++{
++	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
++	unsigned int r36, r37;
++
++	r36 = mc13783_read(codec, PMIC_AUDIO_RX_0);
++	r37 = mc13783_read(codec, PMIC_AUDIO_RX_1);
++
++	r36 &= ~(1 << 23);
++	r37 &= ~(1 << 10);
++
++	if (ucontrol->value.enumerated.item[0]) {
++		r36 |= (1 << 23);
++		r37 |= (1 << 10);
++	} else {
++		r36 &= ~(1 << 23);
++		r37 &= ~(1 << 10);
++	}
++
++	mc13783_write(codec, PMIC_AUDIO_RX_0, r36);
++	mc13783_write(codec, PMIC_AUDIO_RX_1, r37);
++
++	return 0;
++}
++
++static int mc13783_capure_cache;
++
++static int mc13783_get_capture(struct snd_kcontrol *kcontrol,
++	struct snd_ctl_elem_value *ucontrol)
++{
++	ucontrol->value.enumerated.item[0] = mc13783_capure_cache;
++	return 0;
++}
++
++#define AMC1REN (1 << 5)
++#define AMC2EN  (1 << 9)
++#define ATXINEN (1 << 11)
++#define RXINREC (1 << 13)
++#define AMC1LEN (1 << 7)
++
++static int mc13783_put_capture(struct snd_kcontrol *kcontrol,
++	struct snd_ctl_elem_value *ucontrol)
++{
++	struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
++	unsigned int r38, change;
++
++	r38 = mc13783_read(codec, PMIC_AUDIO_TX);
++
++	change = (mc13783_capure_cache != ucontrol->value.enumerated.item[0]);
++	mc13783_capure_cache = ucontrol->value.enumerated.item[0];
++	r38 &= ~(AMC1REN | AMC2EN | ATXINEN | RXINREC | AMC1LEN);
++
++	switch (mc13783_capure_cache) {
++	case 0:
++		break;
++	case 1:
++		r38 |= RXINREC;
++		break;
++	case 2:
++		r38 |= AMC1REN | AMC1LEN;
++		break;
++	case 3:
++		r38 |= AMC1REN;
++		break;
++	case 4:
++		r38 |= AMC2EN;
++		break;
++	case 5:
++		r38 |= AMC1LEN | AMC2EN;
++		break;
++	case 6:
++		r38 |= ATXINEN;
++		break;
++	case 7:
++		r38 |= AMC1LEN | ATXINEN;
++		break;
++	case 8:
++		r38 |= AMC1LEN | RXINREC;
++		break;
++	case 9:
++		r38 |= AMC1LEN;
++		break;
++	default:
++		break;
++	}
++
++	mc13783_write(codec, PMIC_AUDIO_TX, r38);
++
++	return change;
++}
++
++static const char *mc13783_asp[] = {"Off", "Codec", "Right"};
++static const char *mc13783_alsp[] = {"Off", "Codec", "Right"};
++
++static const char *mc13783_ahs[] = {"Codec", "Mixer"};
++
++static const char *mc13783_arxout[] = {"Codec", "Mixer"};
++
++static const char *mc13783_capture[] = {"off/off", "rxinl/rxinr",
++	"mc1lin/mc1rin", "off/mc1rin", "off/mc2in", "mc1lin/mc2in",
++	"off/txin", "mc1lin/txin", "mc1lin/rxinr", "mc1lin/off"};
++
++static const char *mc13783_3d_mixer[] =	{"Stereo", "Phase Mix",
++	"Mono", "Mono Mix"};
++
++static const struct soc_enum mc13783_enum_asp =
++	SOC_ENUM_SINGLE(PMIC_AUDIO_RX_0, 3, ARRAY_SIZE(mc13783_asp), mc13783_asp);
++
++static const struct soc_enum mc13783_enum_alsp =
++	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mc13783_alsp), mc13783_alsp);
++
++static const struct soc_enum mc13783_enum_ahs =
++	SOC_ENUM_SINGLE(PMIC_AUDIO_RX_0, 11, ARRAY_SIZE(mc13783_ahs),
++			mc13783_ahs);
++
++static const struct soc_enum mc13783_enum_arxout =
++	SOC_ENUM_SINGLE(PMIC_AUDIO_RX_0, 17, ARRAY_SIZE(mc13783_arxout),
++			mc13783_arxout);
++
++static const struct soc_enum mc13783_enum_capture =
++	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mc13783_capture), mc13783_capture);
++
++static const struct soc_enum mc13783_enum_3d_mixer =
++	SOC_ENUM_SINGLE(PMIC_AUDIO_RX_1, 16, ARRAY_SIZE(mc13783_3d_mixer),
++			mc13783_3d_mixer);
++
++static struct snd_kcontrol_new mc13783_control_list[] = {
++	/* Output Routing */
++	SOC_ENUM("Asp Source", mc13783_enum_asp),
++	SOC_ENUM_EXT("Alsp Source", mc13783_enum_alsp, mc13783_get_alsp,
++			mc13783_put_alsp),
++	SOC_ENUM("Ahs Source", mc13783_enum_ahs),
++	SOC_SINGLE("Ahsr enable", PMIC_AUDIO_RX_0, 9, 1, 0),
++	SOC_SINGLE("Ahsl enable", PMIC_AUDIO_RX_0, 10, 1, 0),
++	SOC_ENUM("Arxout Source", mc13783_enum_arxout),
++	SOC_SINGLE("ArxoutR enable", PMIC_AUDIO_RX_0, 16, 1, 0),
++	SOC_SINGLE("ArxoutL enable", PMIC_AUDIO_RX_0, 15, 1, 0),
++	SOC_SINGLE_EXT("PCM Playback Switch", 0, 0, 1, 0, mc13783_pcm_get,
++			mc13783_pcm_put),
++	SOC_SINGLE("PCM Playback Volume", PMIC_AUDIO_RX_1, 6, 15, 0),
++	SOC_SINGLE_EXT("Line in Switch", 0, 0, 1, 0, mc13783_linein_get,
++			mc13783_linein_put),
++	SOC_SINGLE("Line in Volume", PMIC_AUDIO_RX_1, 12, 15, 0),
++	SOC_ENUM_EXT("Capture Source", mc13783_enum_capture, mc13783_get_capture,
++			mc13783_put_capture),
++	SOC_DOUBLE("PCM Capture Volume", PMIC_AUDIO_TX, 19, 14, 31, 0),
++	SOC_ENUM("3D Control", mc13783_enum_3d_mixer),
++};
++
++static struct snd_soc_codec *mc13783_codec;
++
++static int mc13783_probe(struct platform_device *pdev)
++{
++	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
++	struct snd_soc_codec *codec = mc13783_codec;
++	struct mc13783_priv *priv = codec->private_data;
++	int i, ret = 0;
++
++	if (!mc13783_codec) {
++		dev_err(&pdev->dev, "Codec device not registered\n");
++		return -ENODEV;
++	}
++
++	/* these are the reset values */
++	priv->reg_cache[PMIC_AUDIO_RX_0]  = 0x001000;
++	priv->reg_cache[PMIC_AUDIO_RX_1]  = 0x00d35A;
++	priv->reg_cache[PMIC_AUDIO_TX]    = 0x420000;
++	priv->reg_cache[PMIC_SSI_NETWORK] = 0x013060;
++	priv->reg_cache[PMIC_AUDIO_CODEC] = 0x180027;
++	priv->reg_cache[PMIC_AUDIO_DAC]   = 0x0e0004;
++
++	/* VAUDIOON -> supply audio part, BIAS enable */
++	priv->reg_cache[PMIC_AUDIO_RX_0] |= 0x3;
++
++	for (i = 36; i < 42; i++)
++		mc13783_write(codec, i, priv->reg_cache[i]);
++
++	socdev->card->codec = mc13783_codec;
++
++	/* register pcms */
++	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
++	if (ret < 0) {
++		dev_err(codec->dev, "failed to create pcms: %d\n", ret);
++		goto pcm_err;
++	}
++
++	snd_soc_add_controls(codec, mc13783_control_list,
++			     ARRAY_SIZE(mc13783_control_list));
++	ret = snd_soc_init_card(socdev);
++	if (ret < 0) {
++		dev_err(codec->dev, "failed to register card: %d\n", ret);
++		goto card_err;
++	}
++
++	return ret;
++
++card_err:
++	snd_soc_free_pcms(socdev);
++	snd_soc_dapm_free(socdev);
++pcm_err:
++	return ret;
++}
++
++static int mc13783_remove(struct platform_device *pdev)
++{
++	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
++	struct snd_soc_codec *codec = mc13783_codec;
++	unsigned int reg;
++
++	reg = mc13783_read(codec, PMIC_AUDIO_RX_0);
++
++	/* VAUDIOON -> switch off audio part, BIAS disable */
++	reg &= ~0x3;
++
++	mc13783_write(codec, PMIC_AUDIO_RX_0, reg);
++
++	snd_soc_free_pcms(socdev);
++	snd_soc_dapm_free(socdev);
++
++	return 0;
++}
++
++#define MC13783_RATES_RECORD (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000)
++
++#define MC13783_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
++	SNDRV_PCM_FMTBIT_S24_LE)
++
++static struct snd_soc_dai_ops mc13783_ops_dac = {
++	.hw_params	= mc13783_pcm_hw_params,
++	.set_fmt	= mc13783_set_fmt,
++	.set_sysclk	= mc13783_set_sysclk,
++};
++
++static struct snd_soc_dai_ops mc13783_ops_voice_codec = {
++	.hw_params	= mc13783_pcm_hw_params,
++	.set_fmt	= mc13783_set_fmt,
++	.set_sysclk	= mc13783_set_sysclk,
++	.set_tdm_slot	= mc13783_set_tdm_slot_codec,
++};
++
++struct snd_soc_dai mc13783_dai[] = {
++	{
++		.name	= "MC13783 Playback",
++		.id	= MC13783_ID_STEREO_DAC,
++		.playback = {
++			.stream_name	= "Playback",
++			.channels_min	= 1,
++			.channels_max	= 2,
++			.rates		= SNDRV_PCM_RATE_8000_96000,
++			.formats	= MC13783_FORMATS,
++		},
++		.ops	= &mc13783_ops_dac,
++	}, {
++		.name	= "MC13783 Capture",
++		.id	= MC13783_ID_STEREO_CODEC,
++		.capture = {
++			.stream_name	= "Capture",
++			.channels_min	= 1,
++			.channels_max	= 2,
++			.rates		= MC13783_RATES_RECORD,
++			.formats	= MC13783_FORMATS,
++		},
++		.ops	= &mc13783_ops_voice_codec,
++	},
++};
++EXPORT_SYMBOL_GPL(mc13783_dai);
++
++struct snd_soc_codec_device soc_codec_dev_mc13783 = {
++	.probe = 	mc13783_probe,
++	.remove = 	mc13783_remove,
++};
++EXPORT_SYMBOL_GPL(soc_codec_dev_mc13783);
++
++/*
++ * OK, this stinks. We currently only can support one MC13783.
++ * Lets take it as an intermediate to turn this stuff into SoC
++ * Audio.
++ */
++static int mc13783_codec_probe(struct platform_device *pdev)
++{
++	struct mc13783_priv *priv;
++	struct snd_soc_codec *codec;
++	int ret;
++
++	if (mc13783)
++		return -EBUSY;
++
++	mc13783 = dev_get_drvdata(pdev->dev.parent);
++
++	priv = kzalloc(sizeof(struct mc13783_priv), GFP_KERNEL);
++	if (priv == NULL)
++		return -ENOMEM;
++
++	codec = &priv->codec;
++	codec->private_data = priv;
++	mc13783_codec = codec;
++
++	mutex_init(&codec->mutex);
++	INIT_LIST_HEAD(&codec->dapm_widgets);
++	INIT_LIST_HEAD(&codec->dapm_paths);
++
++	codec->name = "mc13783";
++	codec->owner = THIS_MODULE;
++	codec->read = mc13783_read;
++	codec->write = mc13783_write;
++	codec->dai = mc13783_dai;
++	codec->num_dai = ARRAY_SIZE(mc13783_dai);
++	codec->control_data = priv;
++	codec->dev = &pdev->dev;
++
++	mc13783_dai[0].dev = codec->dev;
++	mc13783_dai[1].dev = codec->dev;
++
++	ret = snd_soc_register_codec(codec);
++	if (ret)
++		goto err_register_codec;
++
++	ret = snd_soc_register_dais(mc13783_dai, ARRAY_SIZE(mc13783_dai));
++	if (ret)
++		goto err_register_dais;
++
++	return 0;
++
++err_register_dais:
++	snd_soc_unregister_codec(codec);
++err_register_codec:
++	dev_err(&pdev->dev, "register codec failed with %d\n", ret);
++	kfree(priv);
++
++	return ret;
++}
++
++static int mc13783_codec_remove(struct platform_device *pdev)
++{
++	snd_soc_unregister_codec(mc13783_codec);
++	snd_soc_unregister_dais(mc13783_dai, ARRAY_SIZE(mc13783_dai));
++
++	mc13783 = NULL;
++
++	return 0;
++}
++
++static struct platform_driver mc13783_codec_driver = {
++	.driver = {
++		   .name = "mc13783-codec",
++		   .owner = THIS_MODULE,
++		   },
++	.probe = mc13783_codec_probe,
++	.remove = __devexit_p(mc13783_codec_remove),
++};
++
++static __init int mc13783_init(void)
++{
++	return platform_driver_register(&mc13783_codec_driver);
++}
++
++static __exit void mc13783_exit(void)
++{
++	platform_driver_unregister(&mc13783_codec_driver);
++}
++
++module_init(mc13783_init);
++module_exit(mc13783_exit);
++
++MODULE_DESCRIPTION("ASoC MC13783 driver");
++MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer at pengutronix.de>");
++MODULE_LICENSE("GPL");
+diff --git a/sound/soc/codecs/mc13783.h b/sound/soc/codecs/mc13783.h
+new file mode 100644
+index 0000000..b28dbef
+--- /dev/null
++++ b/sound/soc/codecs/mc13783.h
+@@ -0,0 +1,32 @@
++/*
++ * Copyright 2008 Juergen Beisert, kernel at pengutronix.de
++ *
++ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#ifndef MC13783_MIXER_H
++#define MC13783_MIXER_H
++
++extern int mc13783_add_ctl(struct snd_card*, void *);
++
++extern struct snd_soc_dai mc13783_dai[];
++extern struct snd_soc_codec_device soc_codec_dev_mc13783;
++
++#define MC13783_CLK_CLIA	1
++#define MC13783_CLK_CLIB	2
++
++#define MC13783_ID_STEREO_DAC	1
++#define MC13783_ID_STEREO_CODEC	2
++
++#endif /* MC13783_MIXER_H */
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0013-mxc_nand-Make-main-spare-areas-runtime-configurable.patch b/recipes/linux/linux-2.6.31/pcm043/0013-mxc_nand-Make-main-spare-areas-runtime-configurable.patch
new file mode 100644
index 0000000..96d2586
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0013-mxc_nand-Make-main-spare-areas-runtime-configurable.patch
@@ -0,0 +1,142 @@
+From cd3ee0eef0eba058bc5a7a6d42536bc35059ecf9 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Mon, 5 Oct 2009 11:14:35 +0200
+Subject: [PATCH] mxc_nand: Make main/spare areas runtime configurable
+
+The main/spare areas are on different addresses on later versions
+of the controller, so make them configurable.
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand.c |   42 ++++++++++++++++++++----------------------
+ 1 files changed, 20 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
+index 2988f1d..450db4e 100644
+--- a/drivers/mtd/nand/mxc_nand.c
++++ b/drivers/mtd/nand/mxc_nand.c
+@@ -52,18 +52,6 @@
+ #define NFC_CONFIG1		0xE1A
+ #define NFC_CONFIG2		0xE1C
+ 
+-/* Addresses for NFC RAM BUFFER Main area 0 */
+-#define MAIN_AREA0		0x000
+-#define MAIN_AREA1		0x200
+-#define MAIN_AREA2		0x400
+-#define MAIN_AREA3		0x600
+-
+-/* Addresses for NFC SPARE BUFFER Spare area 0 */
+-#define SPARE_AREA0		0x800
+-#define SPARE_AREA1		0x810
+-#define SPARE_AREA2		0x820
+-#define SPARE_AREA3		0x830
+-
+ /* Set INT to 0, FCMD to 1, rest to 0 in NFC_CONFIG2 Register
+  * for Command operation */
+ #define NFC_CMD            0x1
+@@ -106,6 +94,11 @@ struct mxc_nand_host {
+ 	struct mtd_partition	*parts;
+ 	struct device		*dev;
+ 
++	void			*spare0;
++	void			*main_area0;
++	void			*main_area1;
++
++	void __iomem		*base;
+ 	void __iomem		*regs;
+ 	int			status_request;
+ 	int			pagesize_2k;
+@@ -262,7 +255,7 @@ static void send_read_id(struct mxc_nand_host *host)
+ 	wait_op_done(host, TROP_US_DELAY, true);
+ 
+ 	if (this->options & NAND_BUSWIDTH_16) {
+-		void __iomem *main_buf = host->regs + MAIN_AREA0;
++		void __iomem *main_buf = host->main_area0;
+ 		/* compress the ID info */
+ 		writeb(readb(main_buf + 2), main_buf + 1);
+ 		writeb(readb(main_buf + 4), main_buf + 2);
+@@ -270,14 +263,14 @@ static void send_read_id(struct mxc_nand_host *host)
+ 		writeb(readb(main_buf + 8), main_buf + 4);
+ 		writeb(readb(main_buf + 10), main_buf + 5);
+ 	}
+-	memcpy(host->data_buf, host->regs + MAIN_AREA0, 16);
++	memcpy(host->data_buf, host->main_area0, 16);
+ }
+ 
+ /* This function requests the NANDFC to perform a read of the
+  * NAND device status and returns the current status. */
+ static uint16_t get_dev_status(struct mxc_nand_host *host)
+ {
+-	void __iomem *main_buf = host->regs + MAIN_AREA1;
++	void __iomem *main_buf = host->main_area1;
+ 	uint32_t store;
+ 	uint16_t ret, tmp;
+ 	/* Issue status request to NAND device */
+@@ -462,7 +455,7 @@ static void copy_spare(struct mtd_info *mtd, bool bfrom)
+ 	u16 i, j;
+ 	u16 n = mtd->writesize >> 9;
+ 	u8 *d = host->data_buf + mtd->writesize;
+-	u8 *s = host->regs + SPARE_AREA0;
++	u8 *s = host->spare0;
+ 	u16 t = host->spare_len;
+ 
+ 	j = (mtd->oobsize / n >> 1) << 1;
+@@ -572,7 +565,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ 
+ 		send_page(host, NFC_OUTPUT);
+ 
+-		memcpy(host->data_buf, host->regs + MAIN_AREA0, mtd->writesize);
++		memcpy(host->data_buf, host->main_area0, mtd->writesize);
+ 		copy_spare(mtd, true);
+ 		break;
+ 
+@@ -608,7 +601,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ 		break;
+ 
+ 	case NAND_CMD_PAGEPROG:
+-		memcpy(host->regs + MAIN_AREA0, host->data_buf, mtd->writesize);
++		memcpy(host->main_area0, host->data_buf, mtd->writesize);
+ 		copy_spare(mtd, false);
+ 		send_page(host, NFC_INPUT);
+ 		send_cmd(host, command, true);
+@@ -686,12 +679,17 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 		goto eres;
+ 	}
+ 
+-	host->regs = ioremap(res->start, resource_size(res));
+-	if (!host->regs) {
++	host->base = ioremap(res->start, resource_size(res));
++	if (!host->base) {
+ 		err = -ENOMEM;
+ 		goto eres;
+ 	}
+ 
++	host->regs = host->base;
++	host->main_area0 = host->base;
++	host->main_area1 = host->base + 0x200;
++	host->spare0 = host->base + 0x800;
++
+ 	tmp = readw(host->regs + NFC_CONFIG1);
+ 	tmp |= NFC_INT_MSK;
+ 	writew(tmp, host->regs + NFC_CONFIG1);
+@@ -778,7 +776,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ escan:
+ 	free_irq(host->irq, host);
+ eirq:
+-	iounmap(host->regs);
++	iounmap(host->base);
+ eres:
+ 	clk_put(host->clk);
+ eclk:
+@@ -797,7 +795,7 @@ static int __devexit mxcnd_remove(struct platform_device *pdev)
+ 
+ 	nand_release(&host->mtd);
+ 	free_irq(host->irq, host);
+-	iounmap(host->regs);
++	iounmap(host->base);
+ 	kfree(host);
+ 
+ 	return 0;
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0014-MXC-NFC-Add-NAND-device-to-the-pcm043-platform.patch b/recipes/linux/linux-2.6.31/pcm043/0014-MXC-NFC-Add-NAND-device-to-the-pcm043-platform.patch
new file mode 100644
index 0000000..967b3ba
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0014-MXC-NFC-Add-NAND-device-to-the-pcm043-platform.patch
@@ -0,0 +1,47 @@
+From cb9f37d106e5ac9672291f0ce5df5dd955d61d5d Mon Sep 17 00:00:00 2001
+From: Juergen Beisert <j.beisert at pengutronix.de>
+Date: Tue, 29 Sep 2009 17:00:18 +0200
+Subject: [PATCH 14/15] MXC NFC: Add NAND device to the pcm043 platform
+
+Phytec's PCM043 is equipped with a 1 GiB NAND.
+
+Signed-off-by: Juergen Beisert <j.beisert at pengutronix.de>
+
+rebased to  2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel at phytec.de>
+---
+ arch/arm/mach-mx3/pcm043.c |    7 +++++++
+ 1 file changed, 7 insertions(+)
+
+Index: arch/arm/mach-mx3/pcm043.c
+===================================================================
+--- arch/arm/mach-mx3/pcm043.c.orig	2009-12-10 11:34:30.754671808 +0100
++++ arch/arm/mach-mx3/pcm043.c	2009-12-10 11:34:35.157145682 +0100
+@@ -48,6 +48,7 @@
+ #include <mach/mxc_ehci.h>
+ #include <mach/audmux.h>
+ #include <mach/ssi.h>
++#include <mach/mxc_nand.h>
+ 
+ #include "devices.h"
+ 
+@@ -359,6 +360,11 @@
+ 	.flags = IMX_SSI_USE_AC97,
+ };
+ 
++static struct mxc_nand_platform_data pcm043_nand_board_info = {
++	.width = 1,
++	.hw_ecc = 1,
++};
++
+ /*
+  * Board specific initialization.
+  */
+@@ -394,6 +400,7 @@
+ 	mxc_register_device(&mxc_i2c_device0, &pcm043_i2c_1_data);
+ #endif
+ 
++	mxc_register_device(&mxc_nand_device, &pcm043_nand_board_info);
+ 	mxc_register_device(&mx3_ipu, &mx3_ipu_data);
+ 	mxc_register_device(&mx3_fb, &mx3fb_pdata);
+ 
diff --git a/recipes/linux/linux-2.6.31/pcm043/0014-imx-ssi-sound-driver.patch b/recipes/linux/linux-2.6.31/pcm043/0014-imx-ssi-sound-driver.patch
new file mode 100644
index 0000000..3b935c9
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0014-imx-ssi-sound-driver.patch
@@ -0,0 +1,1911 @@
+From 7947679ebf067e88b61b9185c19d625d975e315c Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Thu, 12 Nov 2009 15:00:08 +0100
+Subject: [PATCH 14/28] imx-ssi sound driver
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/plat-mxc/Makefile           |    4 +
+ arch/arm/plat-mxc/include/mach/ssi.h |   17 +
+ arch/arm/plat-mxc/ssi-fiq-ksym.c     |   20 +
+ arch/arm/plat-mxc/ssi-fiq.S          |  134 ++++++
+ sound/soc/Kconfig                    |    1 +
+ sound/soc/Makefile                   |    1 +
+ sound/soc/imx/Kconfig                |   13 +
+ sound/soc/imx/Makefile               |   10 +
+ sound/soc/imx/imx-pcm-dma-mx2.c      |  313 ++++++++++++++
+ sound/soc/imx/imx-pcm-fiq.c          |  277 ++++++++++++
+ sound/soc/imx/imx-ssi.c              |  766 ++++++++++++++++++++++++++++++++++
+ sound/soc/imx/imx-ssi.h              |  238 +++++++++++
+ 12 files changed, 1794 insertions(+), 0 deletions(-)
+ create mode 100644 arch/arm/plat-mxc/include/mach/ssi.h
+ create mode 100644 arch/arm/plat-mxc/ssi-fiq-ksym.c
+ create mode 100644 arch/arm/plat-mxc/ssi-fiq.S
+ create mode 100644 sound/soc/imx/Kconfig
+ create mode 100644 sound/soc/imx/Makefile
+ create mode 100644 sound/soc/imx/imx-pcm-dma-mx2.c
+ create mode 100644 sound/soc/imx/imx-pcm-fiq.c
+ create mode 100644 sound/soc/imx/imx-ssi.c
+ create mode 100644 sound/soc/imx/imx-ssi.h
+
+diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile
+index 92fc8b2..b0b9fc3 100644
+--- a/arch/arm/plat-mxc/Makefile
++++ b/arch/arm/plat-mxc/Makefile
+@@ -11,3 +11,7 @@ obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o
+ obj-$(CONFIG_MXC_PWM)  += pwm.o
+ obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o
+ obj-$(CONFIG_ARCH_MXC_AUDMUX_V2) += audmux-v2.o
++ifdef CONFIG_SND_IMX_SOC
++obj-y += ssi-fiq.o
++obj-y += ssi-fiq-ksym.o
++endif
+diff --git a/arch/arm/plat-mxc/include/mach/ssi.h b/arch/arm/plat-mxc/include/mach/ssi.h
+new file mode 100644
+index 0000000..144a2ac
+--- /dev/null
++++ b/arch/arm/plat-mxc/include/mach/ssi.h
+@@ -0,0 +1,17 @@
++#ifndef __MACH_SSI_H
++#define __MACH_SSI_H
++
++struct snd_ac97;
++
++extern unsigned char imx_ssi_fiq_start, imx_ssi_fiq_end;
++extern unsigned long imx_ssi_fiq_base, imx_ssi_fiq_tx_buffer, imx_ssi_fiq_rx_buffer;
++
++struct imx_ssi_platform_data {
++	unsigned int flags;
++#define IMX_SSI_DMA		(1 << 0)
++#define IMX_SSI_USE_AC97	(1 << 1)
++	void (*ac97_reset) (struct snd_ac97 *ac97);
++	void (*ac97_warm_reset)(struct snd_ac97 *ac97);
++};
++
++#endif /* __MACH_SSI_H */
+diff --git a/arch/arm/plat-mxc/ssi-fiq-ksym.c b/arch/arm/plat-mxc/ssi-fiq-ksym.c
+new file mode 100644
+index 0000000..b5fad45
+--- /dev/null
++++ b/arch/arm/plat-mxc/ssi-fiq-ksym.c
+@@ -0,0 +1,20 @@
++/*
++ * Exported ksyms for the SSI FIQ handler
++ *
++ * Copyright (C) 2009, Sascha Hauer <s.hauer at 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.
++ */
++
++#include <linux/module.h>
++
++#include <mach/ssi.h>
++
++EXPORT_SYMBOL(imx_ssi_fiq_tx_buffer);
++EXPORT_SYMBOL(imx_ssi_fiq_rx_buffer);
++EXPORT_SYMBOL(imx_ssi_fiq_start);
++EXPORT_SYMBOL(imx_ssi_fiq_end);
++EXPORT_SYMBOL(imx_ssi_fiq_base);
++
+diff --git a/arch/arm/plat-mxc/ssi-fiq.S b/arch/arm/plat-mxc/ssi-fiq.S
+new file mode 100644
+index 0000000..4ddce56
+--- /dev/null
++++ b/arch/arm/plat-mxc/ssi-fiq.S
+@@ -0,0 +1,134 @@
++/*
++ *  Copyright (C) 2009 Sascha Hauer <s.hauer at 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.
++ */
++
++#include <linux/linkage.h>
++#include <asm/assembler.h>
++
++/*
++ * r8  = bit 0-15: tx offset, bit 16-31: tx buffer size
++ * r9  = bit 0-15: rx offset, bit 16-31: rx buffer size
++ */
++
++#define SSI_STX0	0x00
++#define SSI_SRX0	0x08
++#define SSI_SISR	0x14
++#define SSI_SIER	0x18
++#define SSI_SACNT	0x38
++
++#define SSI_SACNT_AC97EN	(1 << 0)
++
++#define SSI_SIER_TFE0_EN	(1 << 0)
++#define SSI_SISR_TFE0		(1 << 0)
++#define SSI_SISR_RFF0		(1 << 2)
++#define SSI_SIER_RFF0_EN	(1 << 2)
++
++		.text
++		.global	imx_ssi_fiq_start
++		.global	imx_ssi_fiq_end
++		.global imx_ssi_fiq_base
++		.global imx_ssi_fiq_rx_buffer
++		.global imx_ssi_fiq_tx_buffer
++
++imx_ssi_fiq_start:
++		ldr r12, imx_ssi_fiq_base
++
++		/* TX */
++		ldr r11, imx_ssi_fiq_tx_buffer
++
++		/* shall we send? */
++		ldr r13, [r12, #SSI_SIER]
++		tst r13, #SSI_SIER_TFE0_EN
++		beq 1f
++
++		/* TX FIFO empty? */
++		ldr r13, [r12, #SSI_SISR]
++		tst r13, #SSI_SISR_TFE0
++		beq 1f
++
++		mov r10, #0x10000
++		sub r10, #1
++		and r10, r10, r8	/* r10: current buffer offset */
++
++		add r11, r11, r10
++
++		ldrh r13, [r11]
++		strh r13, [r12, #SSI_STX0]
++
++		ldrh r13, [r11, #2]
++		strh r13, [r12, #SSI_STX0]
++
++		ldrh r13, [r11, #4]
++		strh r13, [r12, #SSI_STX0]
++
++		ldrh r13, [r11, #6]
++		strh r13, [r12, #SSI_STX0]
++
++		add r10, #8
++		lsr r13, r8, #16	/* r13: buffer size */
++		cmp r10, r13
++		lslgt r8, r13, #16
++		addle r8, #8
++1:
++		/* RX */
++
++		/* shall we receive? */
++		ldr r13, [r12, #SSI_SIER]
++		tst r13, #SSI_SIER_RFF0_EN
++		beq 1f
++
++		/* RX FIFO full? */
++		ldr r13, [r12, #SSI_SISR]
++		tst r13, #SSI_SISR_RFF0
++		beq 1f
++
++		ldr r11, imx_ssi_fiq_rx_buffer
++
++		mov r10, #0x10000
++		sub r10, #1
++		and r10, r10, r9	/* r10: current buffer offset */
++
++		add r11, r11, r10
++
++		ldr r13, [r12, #SSI_SACNT]
++		tst r13, #SSI_SACNT_AC97EN
++
++		ldr r13, [r12, #SSI_SRX0]
++		strh r13, [r11]
++
++		ldr r13, [r12, #SSI_SRX0]
++		strh r13, [r11, #2]
++
++		/* dummy read to skip slot 12 */
++		ldrne r13, [r12, #SSI_SRX0]
++
++		ldr r13, [r12, #SSI_SRX0]
++		strh r13, [r11, #4]
++
++		ldr r13, [r12, #SSI_SRX0]
++		strh r13, [r11, #6]
++
++		/* dummy read to skip slot 12 */
++		ldrne r13, [r12, #SSI_SRX0]
++
++		add r10, #8
++		lsr r13, r9, #16	/* r13: buffer size */
++		cmp r10, r13
++		lslgt r9, r13, #16
++		addle r9, #8
++
++1:
++		@ return from FIQ
++		subs	pc, lr, #4
++imx_ssi_fiq_base:
++		.word 0x0
++imx_ssi_fiq_rx_buffer:
++		.word 0x0
++imx_ssi_fiq_tx_buffer:
++		.word 0x0
++imx_ssi_fiq_end:
++
+diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
+index d3e786a..d57e571 100644
+--- a/sound/soc/Kconfig
++++ b/sound/soc/Kconfig
+@@ -35,6 +35,7 @@ source "sound/soc/s3c24xx/Kconfig"
+ source "sound/soc/s6000/Kconfig"
+ source "sound/soc/sh/Kconfig"
+ source "sound/soc/txx9/Kconfig"
++source "sound/soc/imx/Kconfig"
+ 
+ # Supported codecs
+ source "sound/soc/codecs/Kconfig"
+diff --git a/sound/soc/Makefile b/sound/soc/Makefile
+index 6f1e28d..6bcb7f7 100644
+--- a/sound/soc/Makefile
++++ b/sound/soc/Makefile
+@@ -8,6 +8,7 @@ obj-$(CONFIG_SND_SOC)	+= blackfin/
+ obj-$(CONFIG_SND_SOC)	+= davinci/
+ obj-$(CONFIG_SND_SOC)	+= fsl/
+ obj-$(CONFIG_SND_SOC)	+= omap/
++obj-$(CONFIG_SND_SOC)	+= imx/
+ obj-$(CONFIG_SND_SOC)	+= pxa/
+ obj-$(CONFIG_SND_SOC)	+= s3c24xx/
+ obj-$(CONFIG_SND_SOC)	+= s6000/
+diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
+new file mode 100644
+index 0000000..84a25e6
+--- /dev/null
++++ b/sound/soc/imx/Kconfig
+@@ -0,0 +1,13 @@
++config SND_IMX_SOC
++	tristate "SoC Audio for Freecale i.MX CPUs"
++	depends on ARCH_MXC
++	select SND_PCM
++	select FIQ
++	select SND_SOC_AC97_BUS
++	help
++	  Say Y or M if you want to add support for codecs attached to
++	  the i.MX SSI interface.
++
++config SND_MXC_SOC_SSI
++	tristate
++
+diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
+new file mode 100644
+index 0000000..d05cc95
+--- /dev/null
++++ b/sound/soc/imx/Makefile
+@@ -0,0 +1,10 @@
++# i.MX Platform Support
++snd-soc-imx-objs := imx-ssi.o imx-pcm-fiq.o
++
++ifdef CONFIG_MACH_MX27
++snd-soc-imx-objs += imx-pcm-dma-mx2.o
++endif
++
++obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o
++
++# i.MX Machine Support
+diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/imx/imx-pcm-dma-mx2.c
+new file mode 100644
+index 0000000..19452e4
+--- /dev/null
++++ b/sound/soc/imx/imx-pcm-dma-mx2.c
+@@ -0,0 +1,313 @@
++/*
++ * imx-pcm-dma-mx2.c  --  ALSA Soc Audio Layer
++ *
++ * Copyright 2009 Sascha Hauer <s.hauer at pengutronix.de>
++ *
++ * This code is based on code copyrighted by Freescale,
++ * Liam Girdwood, Javier Martin and probably others.
++ *
++ *  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/delay.h>
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <sound/core.h>
++#include <sound/initval.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++
++#include <mach/dma-mx1-mx2.h>
++
++#include "imx-ssi.h"
++
++struct imx_pcm_runtime_data {
++	int sg_count;
++	struct scatterlist *sg_list;
++	int period;
++	int periods;
++	unsigned long dma_addr;
++	int dma;
++	struct snd_pcm_substream *substream;
++	unsigned long offset;
++	unsigned long size;
++	unsigned long period_cnt;
++	void *buf;
++	int period_time;
++};
++
++/* Called by the DMA framework when a period has elapsed */
++static void imx_ssi_dma_progression(int channel, void *data,
++					struct scatterlist *sg)
++{
++	struct snd_pcm_substream *substream = data;
++	struct snd_pcm_runtime *runtime = substream->runtime;
++	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
++
++	if (!sg)
++		return;
++
++	runtime = iprtd->substream->runtime;
++
++	iprtd->offset = sg->dma_address - runtime->dma_addr;
++
++	snd_pcm_period_elapsed(iprtd->substream);
++}
++
++static void imx_ssi_dma_callback(int channel, void *data)
++{
++	pr_err("%s shouldn't be called\n", __func__);
++}
++
++static void snd_imx_dma_err_callback(int channel, void *data, int err)
++{
++	pr_err("DMA error callback called\n");
++
++	pr_err("DMA timeout on channel %d -%s%s%s%s\n",
++		 channel,
++		 err & IMX_DMA_ERR_BURST ?    " burst" : "",
++		 err & IMX_DMA_ERR_REQUEST ?  " request" : "",
++		 err & IMX_DMA_ERR_TRANSFER ? " transfer" : "",
++		 err & IMX_DMA_ERR_BUFFER ?   " buffer" : "");
++}
++
++static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream)
++{
++	struct snd_soc_pcm_runtime *rtd = substream->private_data;
++	struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data;
++	struct snd_pcm_runtime *runtime = substream->runtime;
++	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
++	int ret;
++
++	iprtd->dma = imx_dma_request_by_prio(DRV_NAME, DMA_PRIO_HIGH);
++	if (iprtd->dma < 0) {
++		pr_err("Failed to claim the audio DMA\n");
++		return -ENODEV;
++	}
++
++	ret = imx_dma_setup_handlers(iprtd->dma,
++				imx_ssi_dma_callback,
++				snd_imx_dma_err_callback, substream);
++	if (ret)
++		goto out;
++
++	ret = imx_dma_setup_progression_handler(iprtd->dma,
++			imx_ssi_dma_progression);
++	if (ret) {
++		pr_err("Failed to setup the DMA handler\n");
++		goto out;
++	}
++
++	ret = imx_dma_config_channel(iprtd->dma,
++			IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
++			IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
++			dma_params->dma, 1);
++	if (ret < 0) {
++		pr_err("Cannot configure DMA channel: %d\n", ret);
++		goto out;
++	}
++
++	imx_dma_config_burstlen(iprtd->dma, dma_params->burstsize * 2);
++
++	return 0;
++out:
++	imx_dma_free(iprtd->dma);
++	return ret;
++}
++
++static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
++				struct snd_pcm_hw_params *params)
++{
++	struct snd_pcm_runtime *runtime = substream->runtime;
++	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
++	int i;
++	unsigned long dma_addr;
++
++	imx_ssi_dma_alloc(substream);
++
++	iprtd->size = params_buffer_bytes(params);
++	iprtd->periods = params_periods(params);
++	iprtd->period = params_period_bytes(params);
++	iprtd->offset = 0;
++	iprtd->period_time = HZ / (params_rate(params) /
++			params_period_size(params));
++
++	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
++
++	if (iprtd->sg_count != iprtd->periods) {
++		kfree(iprtd->sg_list);
++
++		iprtd->sg_list = kcalloc(iprtd->periods + 1,
++				sizeof(struct scatterlist), GFP_KERNEL);
++		if (!iprtd->sg_list)
++			return -ENOMEM;
++		iprtd->sg_count = iprtd->periods + 1;
++	}
++
++	sg_init_table(iprtd->sg_list, iprtd->sg_count);
++	dma_addr = runtime->dma_addr;
++
++	for (i = 0; i < iprtd->periods; i++) {
++		iprtd->sg_list[i].page_link = 0;
++		iprtd->sg_list[i].offset = 0;
++		iprtd->sg_list[i].dma_address = dma_addr;
++		iprtd->sg_list[i].length = iprtd->period;
++		dma_addr += iprtd->period;
++	}
++
++	/* close the loop */
++	iprtd->sg_list[iprtd->sg_count - 1].offset = 0;
++	iprtd->sg_list[iprtd->sg_count - 1].length = 0;
++	iprtd->sg_list[iprtd->sg_count - 1].page_link =
++			((unsigned long) iprtd->sg_list | 0x01) & ~0x02;
++	return 0;
++}
++
++static int snd_imx_pcm_hw_free(struct snd_pcm_substream *substream)
++{
++	struct snd_pcm_runtime *runtime = substream->runtime;
++	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
++
++	if (iprtd->dma >= 0) {
++		imx_dma_free(iprtd->dma);
++		iprtd->dma = -EINVAL;
++	}
++
++	kfree(iprtd->sg_list);
++	iprtd->sg_list = NULL;
++
++	return 0;
++}
++
++static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream)
++{
++	struct snd_pcm_runtime *runtime = substream->runtime;
++	struct snd_soc_pcm_runtime *rtd = substream->private_data;
++	struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data;
++	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
++	int err;
++
++	iprtd->substream = substream;
++	iprtd->buf = (unsigned int *)substream->dma_buffer.area;
++	iprtd->period_cnt = 0;
++
++	pr_debug("%s: buf: %p period: %d periods: %d\n",
++			__func__, iprtd->buf, iprtd->period, iprtd->periods);
++
++	err = imx_dma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count,
++			IMX_DMA_LENGTH_LOOP, dma_params->dma_addr,
++			substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
++			DMA_MODE_WRITE : DMA_MODE_READ);
++	if (err)
++		return err;
++
++	return 0;
++}
++
++static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
++{
++	struct snd_pcm_runtime *runtime = substream->runtime;
++	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
++
++	switch (cmd) {
++	case SNDRV_PCM_TRIGGER_START:
++	case SNDRV_PCM_TRIGGER_RESUME:
++	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
++		imx_dma_enable(iprtd->dma);
++
++		break;
++
++	case SNDRV_PCM_TRIGGER_STOP:
++	case SNDRV_PCM_TRIGGER_SUSPEND:
++	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
++		imx_dma_disable(iprtd->dma);
++
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream)
++{
++	struct snd_pcm_runtime *runtime = substream->runtime;
++	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
++
++	return bytes_to_frames(substream->runtime, iprtd->offset);
++}
++
++static struct snd_pcm_hardware snd_imx_hardware = {
++	.info = SNDRV_PCM_INFO_INTERLEAVED |
++		SNDRV_PCM_INFO_BLOCK_TRANSFER |
++		SNDRV_PCM_INFO_MMAP |
++		SNDRV_PCM_INFO_MMAP_VALID |
++		SNDRV_PCM_INFO_PAUSE |
++		SNDRV_PCM_INFO_RESUME,
++	.formats = SNDRV_PCM_FMTBIT_S16_LE,
++	.rate_min = 8000,
++	.channels_min = 2,
++	.channels_max = 2,
++	.buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
++	.period_bytes_min = 128,
++	.period_bytes_max = 16 * 1024,
++	.periods_min = 2,
++	.periods_max = 255,
++	.fifo_size = 0,
++};
++
++static int snd_imx_open(struct snd_pcm_substream *substream)
++{
++	struct snd_pcm_runtime *runtime = substream->runtime;
++	struct imx_pcm_runtime_data *iprtd;
++	int ret;
++
++	iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
++	runtime->private_data = iprtd;
++
++	ret = snd_pcm_hw_constraint_integer(substream->runtime,
++			SNDRV_PCM_HW_PARAM_PERIODS);
++	if (ret < 0)
++		return ret;
++
++	snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
++	return 0;
++}
++
++static struct snd_pcm_ops imx_pcm_ops = {
++	.open		= snd_imx_open,
++	.ioctl		= snd_pcm_lib_ioctl,
++	.hw_params	= snd_imx_pcm_hw_params,
++	.hw_free	= snd_imx_pcm_hw_free,
++	.prepare	= snd_imx_pcm_prepare,
++	.trigger	= snd_imx_pcm_trigger,
++	.pointer	= snd_imx_pcm_pointer,
++	.mmap		= snd_imx_pcm_mmap,
++};
++
++static struct snd_soc_platform imx_soc_platform_dma = {
++	.name		= "imx-audio",
++	.pcm_ops 	= &imx_pcm_ops,
++	.pcm_new	= imx_pcm_new,
++	.pcm_free	= imx_pcm_free,
++};
++
++struct snd_soc_platform *imx_ssi_dma_mx2_init(struct platform_device *pdev,
++		struct imx_ssi *ssi)
++{
++	ssi->dma_params_tx.burstsize = DMA_TXFIFO_BURST;
++	ssi->dma_params_rx.burstsize = DMA_RXFIFO_BURST;
++
++	return &imx_soc_platform_dma;
++}
++
+diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/imx/imx-pcm-fiq.c
+new file mode 100644
+index 0000000..5532579
+--- /dev/null
++++ b/sound/soc/imx/imx-pcm-fiq.c
+@@ -0,0 +1,277 @@
++/*
++ * imx-pcm-fiq.c  --  ALSA Soc Audio Layer
++ *
++ * Copyright 2009 Sascha Hauer <s.hauer at pengutronix.de>
++ *
++ * This code is based on code copyrighted by Freescale,
++ * Liam Girdwood, Javier Martin and probably others.
++ *
++ *  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/delay.h>
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <sound/core.h>
++#include <sound/initval.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++
++#include <asm/fiq.h>
++
++#include <mach/ssi.h>
++
++#include "imx-ssi.h"
++
++struct imx_pcm_runtime_data {
++	int period;
++	int periods;
++	unsigned long dma_addr;
++	int dma;
++	unsigned long offset;
++	unsigned long size;
++	unsigned long period_cnt;
++	void *buf;
++	struct timer_list timer;
++	int period_time;
++};
++
++static void imx_ssi_timer_callback(unsigned long data)
++{
++	struct snd_pcm_substream *substream = (void *)data;
++	struct snd_pcm_runtime *runtime = substream->runtime;
++	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
++	struct pt_regs regs;
++
++	get_fiq_regs(&regs);
++
++	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++		iprtd->offset = regs.ARM_r8 & 0xffff;
++	else
++		iprtd->offset = regs.ARM_r9 & 0xffff;
++
++	iprtd->timer.expires = jiffies + iprtd->period_time;
++	add_timer(&iprtd->timer);
++	snd_pcm_period_elapsed(substream);
++}
++
++static struct fiq_handler fh = {
++	.name		= DRV_NAME,
++};
++
++static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
++				struct snd_pcm_hw_params *params)
++{
++	struct snd_pcm_runtime *runtime = substream->runtime;
++	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
++
++	iprtd->size = params_buffer_bytes(params);
++	iprtd->periods = params_periods(params);
++	iprtd->period = params_period_bytes(params);
++	iprtd->offset = 0;
++	iprtd->period_time = HZ / (params_rate(params) / params_period_size(params));
++
++	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
++
++	return 0;
++}
++
++static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream)
++{
++	struct snd_pcm_runtime *runtime = substream->runtime;
++	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
++	struct pt_regs regs;
++
++	get_fiq_regs(&regs);
++	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++		regs.ARM_r8 = (iprtd->period * iprtd->periods - 1) << 16;
++	else
++		regs.ARM_r9 = (iprtd->period * iprtd->periods - 1) << 16;
++
++	set_fiq_regs(&regs);
++
++	return 0;
++}
++
++static int fiq_enable;
++static int imx_pcm_fiq;
++
++static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
++{
++	struct snd_pcm_runtime *runtime = substream->runtime;
++	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
++
++	switch (cmd) {
++	case SNDRV_PCM_TRIGGER_START:
++	case SNDRV_PCM_TRIGGER_RESUME:
++	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
++		iprtd->timer.expires = jiffies + iprtd->period_time;
++		add_timer(&iprtd->timer);
++		if (++fiq_enable == 1)
++			enable_fiq(imx_pcm_fiq);
++
++		break;
++
++	case SNDRV_PCM_TRIGGER_STOP:
++	case SNDRV_PCM_TRIGGER_SUSPEND:
++	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
++		del_timer(&iprtd->timer);
++		if (--fiq_enable == 0)
++			disable_fiq(imx_pcm_fiq);
++
++
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream)
++{
++	struct snd_pcm_runtime *runtime = substream->runtime;
++	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
++
++	return bytes_to_frames(substream->runtime, iprtd->offset);
++}
++
++static struct snd_pcm_hardware snd_imx_hardware = {
++	.info = SNDRV_PCM_INFO_INTERLEAVED |
++		SNDRV_PCM_INFO_BLOCK_TRANSFER |
++		SNDRV_PCM_INFO_MMAP |
++		SNDRV_PCM_INFO_MMAP_VALID |
++		SNDRV_PCM_INFO_PAUSE |
++		SNDRV_PCM_INFO_RESUME,
++	.formats = SNDRV_PCM_FMTBIT_S16_LE,
++	.rate_min = 8000,
++	.channels_min = 2,
++	.channels_max = 2,
++	.buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
++	.period_bytes_min = 128,
++	.period_bytes_max = 16 * 1024,
++	.periods_min = 2,
++	.periods_max = 255,
++	.fifo_size = 0,
++};
++
++static int snd_imx_open(struct snd_pcm_substream *substream)
++{
++	struct snd_pcm_runtime *runtime = substream->runtime;
++	struct imx_pcm_runtime_data *iprtd;
++	int ret;
++
++	iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
++	runtime->private_data = iprtd;
++
++	init_timer(&iprtd->timer);
++	iprtd->timer.data = (unsigned long)substream;
++	iprtd->timer.function = imx_ssi_timer_callback;
++
++	ret = snd_pcm_hw_constraint_integer(substream->runtime,
++			SNDRV_PCM_HW_PARAM_PERIODS);
++	if (ret < 0)
++		return ret;
++
++	snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
++	return 0;
++}
++
++static int snd_imx_close(struct snd_pcm_substream *substream)
++{
++	struct snd_pcm_runtime *runtime = substream->runtime;
++	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
++
++	del_timer_sync(&iprtd->timer);
++	kfree(iprtd);
++
++	return 0;
++}
++
++static struct snd_pcm_ops imx_pcm_ops = {
++	.open		= snd_imx_open,
++	.close		= snd_imx_close,
++	.ioctl		= snd_pcm_lib_ioctl,
++	.hw_params	= snd_imx_pcm_hw_params,
++	.prepare	= snd_imx_pcm_prepare,
++	.trigger	= snd_imx_pcm_trigger,
++	.pointer	= snd_imx_pcm_pointer,
++	.mmap		= snd_imx_pcm_mmap,
++};
++
++static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai,
++	struct snd_pcm *pcm)
++{
++	int ret;
++
++	ret = imx_pcm_new(card, dai, pcm);
++	if (ret)
++		return ret;
++
++	if (dai->playback.channels_min) {
++		struct snd_pcm_substream *substream =
++			pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
++		struct snd_dma_buffer *buf = &substream->dma_buffer;
++
++		imx_ssi_fiq_tx_buffer = (unsigned long)buf->area;
++	}
++
++	if (dai->capture.channels_min) {
++		struct snd_pcm_substream *substream =
++			pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
++		struct snd_dma_buffer *buf = &substream->dma_buffer;
++
++		imx_ssi_fiq_rx_buffer = (unsigned long)buf->area;
++	}
++
++	set_fiq_handler(&imx_ssi_fiq_start,
++		&imx_ssi_fiq_end - &imx_ssi_fiq_start);
++
++	return 0;
++}
++
++static struct snd_soc_platform imx_soc_platform_fiq = {
++	.pcm_ops 	= &imx_pcm_ops,
++	.pcm_new	= imx_pcm_fiq_new,
++	.pcm_free	= imx_pcm_free,
++};
++
++struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev,
++		struct imx_ssi *ssi)
++{
++	int ret = 0;
++
++	ret = claim_fiq(&fh);
++	if (ret) {
++		dev_err(&pdev->dev, "failed to claim fiq: %d", ret);
++		return ERR_PTR(ret);
++	}
++
++	mxc_set_irq_fiq(ssi->irq, 1);
++
++	imx_pcm_fiq = ssi->irq;
++
++	imx_ssi_fiq_base = (unsigned long)ssi->base;
++
++	ssi->dma_params_tx.burstsize = 4;
++	ssi->dma_params_rx.burstsize = 6;
++
++	return &imx_soc_platform_fiq;
++}
++
++void imx_ssi_fiq_exit(struct platform_device *pdev,
++		struct imx_ssi *ssi)
++{
++	mxc_set_irq_fiq(ssi->irq, 0);
++	release_fiq(&fh);
++}
++
+diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
+new file mode 100644
+index 0000000..9823425
+--- /dev/null
++++ b/sound/soc/imx/imx-ssi.c
+@@ -0,0 +1,766 @@
++/*
++ * imx-ssi.c  --  ALSA Soc Audio Layer
++ *
++ * Copyright 2009 Sascha Hauer <s.hauer at pengutronix.de>
++ *
++ * This code is based on code copyrighted by Freescale,
++ * Liam Girdwood, Javier Martin and probably others.
++ *
++ *  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.
++ *
++ *
++ * The i.MX SSI core has some nasty limitations in AC97 mode. While most
++ * sane processor vendors have a FIFO per AC97 slot, the i.MX has only
++ * one FIFO which combines all valid receive slots. We cannot even select
++ * which slots we want to receive. The WM9712 with which this driver
++ * was developped with always sends GPIO status data in slot 12 which
++ * we receive in our (PCM-) data stream. The only chance we have is to
++ * manually skip this data in the FIQ handler. With sampling rates different
++ * from 48000Hz not every frame has valid receive data, so the ratio
++ * between pcm data and GPIO status data changes. Our FIQ handler is not
++ * able to handle this, hence this driver only works with 48000Hz sampling
++ * rate.
++ * Reading and writing AC97 registers is another challange. The core
++ * provides us status bits when the read register is updated with *another*
++ * value. When we read the same register two times (and the register still
++ * contains the same value) these status bits are not set. We work
++ * around this by not polling these bits but only wait a fixed delay.
++ * 
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <sound/core.h>
++#include <sound/initval.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++
++#include <mach/ssi.h>
++#include <mach/hardware.h>
++
++#include "imx-ssi.h"
++
++#define SSI_SACNT_DEFAULT (SSI_SACNT_AC97EN | SSI_SACNT_FV)
++
++/*
++ * SSI Network Mode or TDM slots configuration.
++ * Should only be called when port is inactive (i.e. SSIEN = 0).
++ */
++static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
++	unsigned int mask, int slots)
++{
++	struct imx_ssi *ssi = container_of(cpu_dai, struct imx_ssi, dai);
++	u32 sccr;
++
++	sccr = readl(ssi->base + SSI_STCCR);
++	sccr &= ~SSI_STCCR_DC_MASK;
++	sccr |= SSI_STCCR_DC(slots - 1);
++	writel(sccr, ssi->base + SSI_STCCR);
++
++	sccr = readl(ssi->base + SSI_SRCCR);
++	sccr &= ~SSI_STCCR_DC_MASK;
++	sccr |= SSI_STCCR_DC(slots - 1);
++	writel(sccr, ssi->base + SSI_SRCCR);
++
++	writel(0, ssi->base + SSI_STMSK);
++
++	writel(mask, ssi->base + SSI_SRMSK);
++
++	return 0;
++}
++
++/*
++ * SSI DAI format configuration.
++ * Should only be called when port is inactive (i.e. SSIEN = 0).
++ * Note: We don't use the I2S modes but instead manually configure the
++ * SSI for I2S because the I2S mode is only a register preset.
++ */
++static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
++{
++	struct imx_ssi *ssi = container_of(cpu_dai, struct imx_ssi, dai);
++	u32 strcr = 0, scr;
++
++	scr = readl(ssi->base + SSI_SCR) & ~(SSI_SCR_SYN | SSI_SCR_NET);
++
++	/* DAI mode */
++	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
++	case SND_SOC_DAIFMT_I2S:
++		/* data on rising edge of bclk, frame low 1clk before data */
++		strcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0;
++		scr |= SSI_SCR_NET;
++		break;
++	case SND_SOC_DAIFMT_LEFT_J:
++		/* data on rising edge of bclk, frame high with data */
++		strcr |= SSI_STCR_TXBIT0;
++		break;
++	case SND_SOC_DAIFMT_DSP_B:
++		/* data on rising edge of bclk, frame high with data */
++		strcr |= SSI_STCR_TFSL;
++		break;
++	case SND_SOC_DAIFMT_DSP_A:
++		/* data on rising edge of bclk, frame high 1clk before data */
++		strcr |= SSI_STCR_TFSL | SSI_STCR_TEFS;
++		break;
++	}
++
++	/* DAI clock inversion */
++	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
++	case SND_SOC_DAIFMT_IB_IF:
++		strcr &= ~(SSI_STCR_TSCKP | SSI_STCR_TFSI);
++		break;
++	case SND_SOC_DAIFMT_IB_NF:
++		strcr |= SSI_STCR_TFSI;
++		strcr &= ~SSI_STCR_TSCKP;
++		break;
++	case SND_SOC_DAIFMT_NB_IF:
++		strcr |= SSI_STCR_TSCKP;
++		strcr &= ~SSI_STCR_TFSI;
++		break;
++	case SND_SOC_DAIFMT_NB_NF:
++		strcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP;
++		break;
++	}
++
++	/* DAI clock master masks */
++	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
++	case SND_SOC_DAIFMT_CBS_CFS:
++		strcr |= SSI_STCR_TFDIR | SSI_STCR_TXDIR;
++		break;
++	case SND_SOC_DAIFMT_CBM_CFS:
++		strcr |= SSI_STCR_TFDIR;
++		break;
++	case SND_SOC_DAIFMT_CBS_CFM:
++		strcr |= SSI_STCR_TXDIR;
++		break;
++	case SND_SOC_DAIFMT_CBM_CFM:
++		strcr &= ~(SSI_STCR_TFDIR | SSI_STCR_TXDIR);
++		break;
++	}
++
++	strcr |= SSI_STCR_TFEN0;
++
++	writel(strcr, ssi->base + SSI_STCR);
++	writel(strcr, ssi->base + SSI_SRCR);
++	writel(scr, ssi->base + SSI_SCR);
++
++	return 0;
++}
++
++/*
++ * SSI system clock configuration.
++ * Should only be called when port is inactive (i.e. SSIEN = 0).
++ */
++static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
++				  int clk_id, unsigned int freq, int dir)
++{
++	struct imx_ssi *ssi = container_of(cpu_dai, struct imx_ssi, dai);
++	u32 scr;
++
++	scr = readl(ssi->base + SSI_SCR);
++
++	switch (clk_id) {
++	case IMX_SSP_SYS_CLK:
++		if (dir == SND_SOC_CLOCK_OUT)
++			scr |= SSI_SCR_SYS_CLK_EN;
++		else
++			scr &= ~SSI_SCR_SYS_CLK_EN;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	writel(scr, ssi->base + SSI_SCR);
++
++	return 0;
++}
++
++/*
++ * SSI Clock dividers
++ * Should only be called when port is inactive (i.e. SSIEN = 0).
++ */
++static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
++				  int div_id, int div)
++{
++	struct imx_ssi *ssi = container_of(cpu_dai, struct imx_ssi, dai);
++	u32 stccr, srccr;
++
++	stccr = readl(ssi->base + SSI_STCCR);
++	srccr = readl(ssi->base + SSI_SRCCR);
++
++	switch (div_id) {
++	case IMX_SSI_TX_DIV_2:
++		stccr &= ~SSI_STCCR_DIV2;
++		stccr |= div;
++		break;
++	case IMX_SSI_TX_DIV_PSR:
++		stccr &= ~SSI_STCCR_PSR;
++		stccr |= div;
++		break;
++	case IMX_SSI_TX_DIV_PM:
++		stccr &= ~0xff;
++		stccr |= SSI_STCCR_PM(div);
++		break;
++	case IMX_SSI_RX_DIV_2:
++		stccr &= ~SSI_STCCR_DIV2;
++		stccr |= div;
++		break;
++	case IMX_SSI_RX_DIV_PSR:
++		stccr &= ~SSI_STCCR_PSR;
++		stccr |= div;
++		break;
++	case IMX_SSI_RX_DIV_PM:
++		stccr &= ~0xff;
++		stccr |= SSI_STCCR_PM(div);
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	writel(stccr, ssi->base + SSI_STCCR);
++	writel(srccr, ssi->base + SSI_SRCCR);
++
++	return 0;
++}
++
++/*
++ * Should only be called when port is inactive (i.e. SSIEN = 0),
++ * although can be called multiple times by upper layers.
++ */
++static int imx_ssi_hw_params(struct snd_pcm_substream *substream,
++			     struct snd_pcm_hw_params *params,
++			     struct snd_soc_dai *cpu_dai)
++{
++	struct imx_ssi *ssi = container_of(cpu_dai, struct imx_ssi, dai);
++	u32 reg, sccr;
++
++	/* Tx/Rx config */
++	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++		reg = SSI_STCCR;
++		cpu_dai->dma_data = &ssi->dma_params_tx;
++	} else {
++		reg = SSI_SRCCR;
++		cpu_dai->dma_data = &ssi->dma_params_rx;
++	}
++
++	sccr = readl(ssi->base + reg) & ~SSI_STCCR_WL_MASK;
++
++	/* DAI data (word) size */
++	switch (params_format(params)) {
++	case SNDRV_PCM_FORMAT_S16_LE:
++		sccr |= SSI_SRCCR_WL(16);
++		break;
++	case SNDRV_PCM_FORMAT_S20_3LE:
++		sccr |= SSI_SRCCR_WL(20);
++		break;
++	case SNDRV_PCM_FORMAT_S24_LE:
++		sccr |= SSI_SRCCR_WL(24);
++		break;
++	}
++
++	writel(sccr, ssi->base + reg);
++
++	return 0;
++}
++
++static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
++		struct snd_soc_dai *dai)
++{
++	struct snd_soc_pcm_runtime *rtd = substream->private_data;
++	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
++	struct imx_ssi *ssi = container_of(cpu_dai, struct imx_ssi, dai);
++	unsigned int sier_bits, sier;
++	unsigned int scr;
++
++	scr = readl(ssi->base + SSI_SCR);
++	sier = readl(ssi->base + SSI_SIER);
++
++	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++		if (ssi->flags & IMX_SSI_DMA)
++			sier_bits = SSI_SIER_TDMAE;
++		else
++			sier_bits = SSI_SIER_TIE | SSI_SIER_TFE0_EN;
++	} else {
++		if (ssi->flags & IMX_SSI_DMA)
++			sier_bits = SSI_SIER_RDMAE;
++		else
++			sier_bits = SSI_SIER_RIE | SSI_SIER_RFF0_EN;
++	}
++
++	switch (cmd) {
++	case SNDRV_PCM_TRIGGER_START:
++	case SNDRV_PCM_TRIGGER_RESUME:
++	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
++		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++			scr |= SSI_SCR_TE;
++		else
++			scr |= SSI_SCR_RE;
++		sier |= sier_bits;
++
++		if (++ssi->enabled == 1)
++			scr |= SSI_SCR_SSIEN;
++
++		break;
++
++	case SNDRV_PCM_TRIGGER_STOP:
++	case SNDRV_PCM_TRIGGER_SUSPEND:
++	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
++		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++			scr &= ~SSI_SCR_TE;
++		else
++			scr &= ~SSI_SCR_RE;
++		sier &= ~sier_bits;
++
++		if (--ssi->enabled == 0)
++			scr &= ~SSI_SCR_SSIEN;
++
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	if (!(ssi->flags & IMX_SSI_USE_AC97))
++		/* rx/tx are always enabled to access ac97 registers */
++		writel(scr, ssi->base + SSI_SCR);
++
++	writel(sier, ssi->base + SSI_SIER);
++
++	return 0;
++}
++
++static struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
++	.hw_params	= imx_ssi_hw_params,
++	.set_fmt	= imx_ssi_set_dai_fmt,
++	.set_clkdiv	= imx_ssi_set_dai_clkdiv,
++	.set_sysclk	= imx_ssi_set_dai_sysclk,
++	.set_tdm_slot	= imx_ssi_set_dai_tdm_slot,
++	.trigger	= imx_ssi_trigger,
++};
++
++static struct snd_soc_dai imx_ssi_dai = {
++	.playback = {
++		.channels_min = 2,
++		.channels_max = 2,
++		.rates = SNDRV_PCM_RATE_8000_96000,
++		.formats = SNDRV_PCM_FMTBIT_S16_LE,
++	},
++	.capture = {
++		.channels_min = 2,
++		.channels_max = 2,
++		.rates = SNDRV_PCM_RATE_8000_96000,
++		.formats = SNDRV_PCM_FMTBIT_S16_LE,
++	},
++	.ops = &imx_ssi_pcm_dai_ops,
++};
++
++int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
++		struct vm_area_struct *vma)
++{
++	struct snd_pcm_runtime *runtime = substream->runtime;
++	int ret;
++
++	ret = dma_mmap_coherent(NULL, vma, runtime->dma_area,
++			runtime->dma_addr, runtime->dma_bytes);
++
++	pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret,
++			runtime->dma_area,
++			runtime->dma_addr,
++			runtime->dma_bytes);
++	return ret;
++}
++
++static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
++{
++	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
++	struct snd_dma_buffer *buf = &substream->dma_buffer;
++	size_t size = IMX_SSI_DMABUF_SIZE;
++
++	buf->dev.type = SNDRV_DMA_TYPE_DEV;
++	buf->dev.dev = pcm->card->dev;
++	buf->private_data = NULL;
++	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
++					   &buf->addr, GFP_KERNEL);
++	if (!buf->area)
++		return -ENOMEM;
++	buf->bytes = size;
++
++	return 0;
++}
++
++static u64 imx_pcm_dmamask = DMA_BIT_MASK(32);
++
++int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
++	struct snd_pcm *pcm)
++{
++
++	int ret = 0;
++
++	if (!card->dev->dma_mask)
++		card->dev->dma_mask = &imx_pcm_dmamask;
++	if (!card->dev->coherent_dma_mask)
++		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
++	if (dai->playback.channels_min) {
++		ret = imx_pcm_preallocate_dma_buffer(pcm,
++			SNDRV_PCM_STREAM_PLAYBACK);
++		if (ret)
++			goto out;
++	}
++
++	if (dai->capture.channels_min) {
++		ret = imx_pcm_preallocate_dma_buffer(pcm,
++			SNDRV_PCM_STREAM_CAPTURE);
++		if (ret)
++			goto out;
++	}
++
++out:
++	return ret;
++}
++
++void imx_pcm_free(struct snd_pcm *pcm)
++{
++	struct snd_pcm_substream *substream;
++	struct snd_dma_buffer *buf;
++	int stream;
++
++	for (stream = 0; stream < 2; stream++) {
++		substream = pcm->streams[stream].substream;
++		if (!substream)
++			continue;
++
++		buf = &substream->dma_buffer;
++		if (!buf->area)
++			continue;
++
++		dma_free_writecombine(pcm->card->dev, buf->bytes,
++				      buf->area, buf->addr);
++		buf->area = NULL;
++	}
++}
++
++struct snd_soc_platform imx_soc_platform = {
++	.name		= "imx-audio",
++};
++EXPORT_SYMBOL_GPL(imx_soc_platform);
++
++static struct snd_soc_dai imx_ac97_dai = {
++	.name = "AC97",
++	.ac97_control = 1,
++	.playback = {
++		.stream_name = "AC97 Playback",
++		.channels_min = 2,
++		.channels_max = 2,
++		.rates = SND_SOC_STD_AC97_FMTS,
++		.formats = SNDRV_PCM_FMTBIT_S16_LE,
++	},
++	.capture = {
++		.stream_name = "AC97 Capture",
++		.channels_min = 2,
++		.channels_max = 2,
++		.rates = SNDRV_PCM_RATE_48000,
++		.formats = SNDRV_PCM_FMTBIT_S16_LE,
++	},
++	.ops = &imx_ssi_pcm_dai_ops,
++};
++
++static void setup_channel_to_ac97(struct imx_ssi *imx_ssi)
++{
++	void __iomem *base = imx_ssi->base;
++
++	writel(0x0, base + SSI_SCR);
++	writel(0x0, base + SSI_STCR);
++	writel(0x0, base + SSI_SRCR);
++
++	writel(SSI_SCR_SYN | SSI_SCR_NET, base + SSI_SCR);
++
++	writel(SSI_SFCSR_RFWM0(8) |
++		SSI_SFCSR_TFWM0(8) |
++		SSI_SFCSR_RFWM1(8) |
++		SSI_SFCSR_TFWM1(8), base + SSI_SFCSR);
++
++	writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_STCCR);
++	writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_SRCCR);
++
++	writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN, base + SSI_SCR);
++	writel(SSI_SOR_WAIT(3), base + SSI_SOR);
++
++	writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN |
++			SSI_SCR_TE | SSI_SCR_RE,
++			base + SSI_SCR);
++
++	writel(SSI_SACNT_DEFAULT, base + SSI_SACNT);
++	writel(0xff, base + SSI_SACCDIS);
++	writel(0x300, base + SSI_SACCEN);
++}
++
++static struct imx_ssi *ac97_ssi;
++
++static void imx_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
++		unsigned short val)
++{
++	struct imx_ssi *imx_ssi = ac97_ssi;
++	void __iomem *base = imx_ssi->base;
++	unsigned int lreg;
++	unsigned int lval;
++
++	if (reg > 0x7f)
++		return;
++
++	pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
++
++	lreg = reg <<  12;
++	writel(lreg, base + SSI_SACADD);
++
++	lval = val << 4;
++	writel(lval , base + SSI_SACDAT);
++
++	writel(SSI_SACNT_DEFAULT | SSI_SACNT_WR, base + SSI_SACNT);
++	udelay(100);
++}
++
++static unsigned short imx_ssi_ac97_read(struct snd_ac97 *ac97,
++		unsigned short reg)
++{
++	struct imx_ssi *imx_ssi = ac97_ssi;
++	void __iomem *base = imx_ssi->base;
++
++	unsigned short val = -1;
++	unsigned int lreg;
++
++	lreg = (reg & 0x7f) <<  12 ;
++	writel(lreg, base + SSI_SACADD);
++	writel(SSI_SACNT_DEFAULT | SSI_SACNT_RD, base + SSI_SACNT);
++
++	udelay(100);
++
++	val = (readl(base + SSI_SACDAT) >> 4) & 0xffff;
++
++	pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
++
++	return val;
++}
++
++static void imx_ssi_ac97_reset(struct snd_ac97 *ac97)
++{
++	struct imx_ssi *imx_ssi = ac97_ssi;
++
++	if (imx_ssi->ac97_reset)
++		imx_ssi->ac97_reset(ac97);
++}
++
++static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97)
++{
++	struct imx_ssi *imx_ssi = ac97_ssi;
++
++	if (imx_ssi->ac97_warm_reset)
++		imx_ssi->ac97_warm_reset(ac97);
++}
++
++struct snd_ac97_bus_ops soc_ac97_ops = {
++	.read		= imx_ssi_ac97_read,
++	.write		= imx_ssi_ac97_write,
++	.reset		= imx_ssi_ac97_reset,
++	.warm_reset	= imx_ssi_ac97_warm_reset
++};
++EXPORT_SYMBOL_GPL(soc_ac97_ops);
++
++struct snd_soc_dai *imx_ssi_pcm_dai[2];
++EXPORT_SYMBOL_GPL(imx_ssi_pcm_dai);
++
++static int imx_ssi_probe(struct platform_device *pdev)
++{
++	struct resource *res;
++	struct imx_ssi *ssi;
++	struct imx_ssi_platform_data *pdata = pdev->dev.platform_data;
++	struct snd_soc_platform *platform;
++	int ret = 0;
++	unsigned int val;
++
++	ssi = kzalloc(sizeof(*ssi), GFP_KERNEL);
++	if (!ssi)
++		return -ENOMEM;
++
++	if (pdata) {
++		ssi->ac97_reset = pdata->ac97_reset;
++		ssi->ac97_warm_reset = pdata->ac97_warm_reset;
++		ssi->flags = pdata->flags;
++	}
++
++	imx_ssi_pcm_dai[pdev->id] = &ssi->dai;
++
++	ssi->irq = platform_get_irq(pdev, 0);
++
++	ssi->clk = clk_get(&pdev->dev, NULL);
++	if (IS_ERR(ssi->clk)) {
++		ret = PTR_ERR(ssi->clk);
++		dev_err(&pdev->dev, "Cannot get the clock: %d\n",
++			ret);
++		goto failed_clk;
++	}
++	clk_enable(ssi->clk);
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		ret = -ENODEV;
++		goto failed_get_resource;
++	}
++
++	if (!request_mem_region(res->start, resource_size(res), DRV_NAME)) {
++		dev_err(&pdev->dev, "request_mem_region failed\n");
++		ret = -EBUSY;
++		goto failed_get_resource;
++	}
++
++	ssi->base = ioremap(res->start, resource_size(res));
++	if (!ssi->base) {
++		dev_err(&pdev->dev, "ioremap failed\n");
++		ret = -ENODEV;
++		goto failed_ioremap;
++	}
++
++	if (ssi->flags & IMX_SSI_USE_AC97) {
++		if (ac97_ssi) {
++			ret = -EBUSY;
++			goto failed_ac97;
++		}
++		ac97_ssi = ssi;
++		setup_channel_to_ac97(ssi);
++		memcpy(&ssi->dai, &imx_ac97_dai, sizeof(imx_ac97_dai));
++	} else
++		memcpy(&ssi->dai, &imx_ssi_dai, sizeof(imx_ssi_dai));
++
++	ssi->dai.id = pdev->id;
++	ssi->dai.dev = &pdev->dev;
++	ssi->dai.name = kasprintf(GFP_KERNEL, "imx-ssi.%d", pdev->id);
++
++	writel(0x0, ssi->base + SSI_SIER);
++
++	ssi->dma_params_rx.dma_addr = res->start + SSI_SRX0;
++	ssi->dma_params_tx.dma_addr = res->start + SSI_STX0;
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
++	if (res)
++		ssi->dma_params_tx.dma = res->start;
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0");
++	if (res)
++		ssi->dma_params_rx.dma = res->start;
++
++	ssi->dai.id = pdev->id;
++	ssi->dai.dev = &pdev->dev;
++	ssi->dai.name = kasprintf(GFP_KERNEL, "imx-ssi.%d", pdev->id);
++
++	if ((cpu_is_mx27() || cpu_is_mx21()) &&
++			!(ssi->flags & IMX_SSI_USE_AC97)) {
++		ssi->flags |= IMX_SSI_DMA;
++		platform = imx_ssi_dma_mx2_init(pdev, ssi);
++	} else
++		platform = imx_ssi_fiq_init(pdev, ssi);
++
++	imx_soc_platform.pcm_ops = platform->pcm_ops;
++	imx_soc_platform.pcm_new = platform->pcm_new;
++	imx_soc_platform.pcm_free = platform->pcm_free;
++
++	val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) |
++		SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize);
++	writel(val, ssi->base + SSI_SFCSR);
++
++	ret = snd_soc_register_dai(&ssi->dai);
++	if (ret) {
++		dev_err(&pdev->dev, "register DAI failed\n");
++		goto failed_register;
++	}
++
++	platform_set_drvdata(pdev, ssi);
++
++	return 0;
++
++failed_register:
++failed_ac97:
++	iounmap(ssi->base);
++failed_ioremap:
++	release_mem_region(res->start, resource_size(res));
++failed_get_resource:
++	clk_disable(ssi->clk);
++	clk_put(ssi->clk);
++failed_clk:
++	kfree(ssi);
++
++	return ret;
++}
++
++static int __devexit imx_ssi_remove(struct platform_device *pdev)
++{
++	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	struct imx_ssi *ssi = platform_get_drvdata(pdev);
++
++	snd_soc_unregister_dai(&ssi->dai);
++
++	if (ssi->flags & IMX_SSI_USE_AC97)
++		ac97_ssi = NULL;
++
++	if (!(ssi->flags & IMX_SSI_DMA))
++		imx_ssi_fiq_exit(pdev, ssi);
++
++	iounmap(ssi->base);
++	release_mem_region(res->start, resource_size(res));
++	clk_disable(ssi->clk);
++	clk_put(ssi->clk);
++	kfree(ssi);
++
++	return 0;
++}
++
++static struct platform_driver imx_ssi_driver = {
++	.probe = imx_ssi_probe,
++	.remove = __devexit_p(imx_ssi_remove),
++
++	.driver = {
++		.name = DRV_NAME,
++		.owner = THIS_MODULE,
++	},
++};
++
++static int __init imx_ssi_init(void)
++{
++	int ret;
++
++	ret = snd_soc_register_platform(&imx_soc_platform);
++	if (ret) {
++		pr_err("failed to register soc platform: %d\n", ret);
++		return ret;
++	}
++
++	ret = platform_driver_register(&imx_ssi_driver);
++	if (ret) {
++		snd_soc_unregister_platform(&imx_soc_platform);
++		return ret;
++	}
++
++	return 0;
++}
++
++static void __exit imx_ssi_exit(void)
++{
++	platform_driver_unregister(&imx_ssi_driver);
++	snd_soc_unregister_platform(&imx_soc_platform);
++}
++
++module_init(imx_ssi_init);
++module_exit(imx_ssi_exit);
++
++/* Module information */
++MODULE_AUTHOR("Sascha Hauer, <s.hauer at pengutronix.de>");
++MODULE_DESCRIPTION("i.MX I2S/ac97 SoC Interface");
++MODULE_LICENSE("GPL");
++
+diff --git a/sound/soc/imx/imx-ssi.h b/sound/soc/imx/imx-ssi.h
+new file mode 100644
+index 0000000..2823fd0
+--- /dev/null
++++ b/sound/soc/imx/imx-ssi.h
+@@ -0,0 +1,238 @@
++/*
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef _IMX_SSI_H
++#define _IMX_SSI_H
++
++#define SSI_STX0	0x00
++#define SSI_STX1	0x04
++#define SSI_SRX0	0x08
++#define SSI_SRX1	0x0c
++
++#define SSI_SCR		0x10
++#define SSI_SCR_CLK_IST		(1 << 9)
++#define SSI_SCR_CLK_IST_SHIFT	9
++#define SSI_SCR_TCH_EN		(1 << 8)
++#define SSI_SCR_SYS_CLK_EN	(1 << 7)
++#define SSI_SCR_I2S_MODE_NORM	(0 << 5)
++#define SSI_SCR_I2S_MODE_MSTR	(1 << 5)
++#define SSI_SCR_I2S_MODE_SLAVE	(2 << 5)
++#define SSI_I2S_MODE_MASK	(3 << 5)
++#define SSI_SCR_SYN		(1 << 4)
++#define SSI_SCR_NET		(1 << 3)
++#define SSI_SCR_RE		(1 << 2)
++#define SSI_SCR_TE		(1 << 1)
++#define SSI_SCR_SSIEN		(1 << 0)
++
++#define SSI_SISR	0x14
++#define SSI_SISR_MASK		((1 << 19) - 1)
++#define SSI_SISR_CMDAU		(1 << 18)
++#define SSI_SISR_CMDDU		(1 << 17)
++#define SSI_SISR_RXT		(1 << 16)
++#define SSI_SISR_RDR1		(1 << 15)
++#define SSI_SISR_RDR0		(1 << 14)
++#define SSI_SISR_TDE1		(1 << 13)
++#define SSI_SISR_TDE0		(1 << 12)
++#define SSI_SISR_ROE1		(1 << 11)
++#define SSI_SISR_ROE0		(1 << 10)
++#define SSI_SISR_TUE1		(1 << 9)
++#define SSI_SISR_TUE0		(1 << 8)
++#define SSI_SISR_TFS		(1 << 7)
++#define SSI_SISR_RFS		(1 << 6)
++#define SSI_SISR_TLS		(1 << 5)
++#define SSI_SISR_RLS		(1 << 4)
++#define SSI_SISR_RFF1		(1 << 3)
++#define SSI_SISR_RFF0		(1 << 2)
++#define SSI_SISR_TFE1		(1 << 1)
++#define SSI_SISR_TFE0		(1 << 0)
++
++#define SSI_SIER	0x18
++#define SSI_SIER_RDMAE		(1 << 22)
++#define SSI_SIER_RIE		(1 << 21)
++#define SSI_SIER_TDMAE		(1 << 20)
++#define SSI_SIER_TIE		(1 << 19)
++#define SSI_SIER_CMDAU_EN	(1 << 18)
++#define SSI_SIER_CMDDU_EN	(1 << 17)
++#define SSI_SIER_RXT_EN		(1 << 16)
++#define SSI_SIER_RDR1_EN	(1 << 15)
++#define SSI_SIER_RDR0_EN	(1 << 14)
++#define SSI_SIER_TDE1_EN	(1 << 13)
++#define SSI_SIER_TDE0_EN	(1 << 12)
++#define SSI_SIER_ROE1_EN	(1 << 11)
++#define SSI_SIER_ROE0_EN	(1 << 10)
++#define SSI_SIER_TUE1_EN	(1 << 9)
++#define SSI_SIER_TUE0_EN	(1 << 8)
++#define SSI_SIER_TFS_EN		(1 << 7)
++#define SSI_SIER_RFS_EN		(1 << 6)
++#define SSI_SIER_TLS_EN		(1 << 5)
++#define SSI_SIER_RLS_EN		(1 << 4)
++#define SSI_SIER_RFF1_EN	(1 << 3)
++#define SSI_SIER_RFF0_EN	(1 << 2)
++#define SSI_SIER_TFE1_EN	(1 << 1)
++#define SSI_SIER_TFE0_EN	(1 << 0)
++
++#define SSI_STCR	0x1c
++#define SSI_STCR_TXBIT0		(1 << 9)
++#define SSI_STCR_TFEN1		(1 << 8)
++#define SSI_STCR_TFEN0		(1 << 7)
++#define SSI_FIFO_ENABLE_0_SHIFT 7
++#define SSI_STCR_TFDIR		(1 << 6)
++#define SSI_STCR_TXDIR		(1 << 5)
++#define SSI_STCR_TSHFD		(1 << 4)
++#define SSI_STCR_TSCKP		(1 << 3)
++#define SSI_STCR_TFSI		(1 << 2)
++#define SSI_STCR_TFSL		(1 << 1)
++#define SSI_STCR_TEFS		(1 << 0)
++
++#define SSI_SRCR	0x20
++#define SSI_SRCR_RXBIT0		(1 << 9)
++#define SSI_SRCR_RFEN1		(1 << 8)
++#define SSI_SRCR_RFEN0		(1 << 7)
++#define SSI_FIFO_ENABLE_0_SHIFT 7
++#define SSI_SRCR_RFDIR		(1 << 6)
++#define SSI_SRCR_RXDIR		(1 << 5)
++#define SSI_SRCR_RSHFD		(1 << 4)
++#define SSI_SRCR_RSCKP		(1 << 3)
++#define SSI_SRCR_RFSI		(1 << 2)
++#define SSI_SRCR_RFSL		(1 << 1)
++#define SSI_SRCR_REFS		(1 << 0)
++
++#define SSI_SRCCR		0x28
++#define SSI_SRCCR_DIV2		(1 << 18)
++#define SSI_SRCCR_PSR		(1 << 17)
++#define SSI_SRCCR_WL(x)		((((x) - 2) >> 1) << 13)
++#define SSI_SRCCR_DC(x)		(((x) & 0x1f) << 8)
++#define SSI_SRCCR_PM(x)		(((x) & 0xff) << 0)
++#define SSI_SRCCR_WL_MASK	(0xf << 13)
++#define SSI_SRCCR_DC_MASK	(0x1f << 8)
++#define SSI_SRCCR_PM_MASK	(0xff << 0)
++
++#define SSI_STCCR		0x24
++#define SSI_STCCR_DIV2		(1 << 18)
++#define SSI_STCCR_PSR		(1 << 17)
++#define SSI_STCCR_WL(x)		((((x) - 2) >> 1) << 13)
++#define SSI_STCCR_DC(x)		(((x) & 0x1f) << 8)
++#define SSI_STCCR_PM(x)		(((x) & 0xff) << 0)
++#define SSI_STCCR_WL_MASK	(0xf << 13)
++#define SSI_STCCR_DC_MASK	(0x1f << 8)
++#define SSI_STCCR_PM_MASK	(0xff << 0)
++
++#define SSI_SFCSR	0x2c
++#define SSI_SFCSR_RFCNT1(x)	(((x) & 0xf) << 28)
++#define SSI_RX_FIFO_1_COUNT_SHIFT 28
++#define SSI_SFCSR_TFCNT1(x)	(((x) & 0xf) << 24)
++#define SSI_TX_FIFO_1_COUNT_SHIFT 24
++#define SSI_SFCSR_RFWM1(x)	(((x) & 0xf) << 20)
++#define SSI_SFCSR_TFWM1(x)	(((x) & 0xf) << 16)
++#define SSI_SFCSR_RFCNT0(x)	(((x) & 0xf) << 12)
++#define SSI_RX_FIFO_0_COUNT_SHIFT 12
++#define SSI_SFCSR_TFCNT0(x)	(((x) & 0xf) <<  8)
++#define SSI_TX_FIFO_0_COUNT_SHIFT 8
++#define SSI_SFCSR_RFWM0(x)	(((x) & 0xf) <<  4)
++#define SSI_SFCSR_TFWM0(x)	(((x) & 0xf) <<  0)
++#define SSI_SFCSR_RFWM0_MASK	(0xf <<  4)
++#define SSI_SFCSR_TFWM0_MASK	(0xf <<  0)
++
++#define SSI_STR		0x30
++#define SSI_STR_TEST		(1 << 15)
++#define SSI_STR_RCK2TCK		(1 << 14)
++#define SSI_STR_RFS2TFS		(1 << 13)
++#define SSI_STR_RXSTATE(x)	(((x) & 0xf) << 8)
++#define SSI_STR_TXD2RXD		(1 <<  7)
++#define SSI_STR_TCK2RCK		(1 <<  6)
++#define SSI_STR_TFS2RFS		(1 <<  5)
++#define SSI_STR_TXSTATE(x)	(((x) & 0xf) << 0)
++
++#define SSI_SOR		0x34
++#define SSI_SOR_CLKOFF		(1 << 6)
++#define SSI_SOR_RX_CLR		(1 << 5)
++#define SSI_SOR_TX_CLR		(1 << 4)
++#define SSI_SOR_INIT		(1 << 3)
++#define SSI_SOR_WAIT(x)		(((x) & 0x3) << 1)
++#define SSI_SOR_WAIT_MASK	(0x3 << 1)
++#define SSI_SOR_SYNRST		(1 << 0)
++
++#define SSI_SACNT	0x38
++#define SSI_SACNT_FRDIV(x)	(((x) & 0x3f) << 5)
++#define SSI_SACNT_WR		(1 << 4)
++#define SSI_SACNT_RD		(1 << 3)
++#define SSI_SACNT_TIF		(1 << 2)
++#define SSI_SACNT_FV		(1 << 1)
++#define SSI_SACNT_AC97EN	(1 << 0)
++
++#define SSI_SACADD	0x3c
++#define SSI_SACDAT	0x40
++#define SSI_SATAG	0x44
++#define SSI_STMSK	0x48
++#define SSI_SRMSK	0x4c
++#define SSI_SACCST	0x50
++#define SSI_SACCEN	0x54
++#define SSI_SACCDIS	0x58
++
++/* SSI clock sources */
++#define IMX_SSP_SYS_CLK		0
++
++/* SSI audio dividers */
++#define IMX_SSI_TX_DIV_2	0
++#define IMX_SSI_TX_DIV_PSR	1
++#define IMX_SSI_TX_DIV_PM	2
++#define IMX_SSI_RX_DIV_2	3
++#define IMX_SSI_RX_DIV_PSR	4
++#define IMX_SSI_RX_DIV_PM	5
++
++extern struct snd_soc_dai *imx_ssi_pcm_dai[2];
++extern struct snd_soc_platform imx_soc_platform;
++
++#define DRV_NAME "imx-ssi"
++
++struct imx_pcm_dma_params {
++	int dma;
++	unsigned long dma_addr;
++	int burstsize;
++};
++
++struct imx_ssi {
++	struct snd_soc_dai dai;
++	struct platform_device *ac97_dev;
++
++	struct snd_soc_device imx_ac97;
++	struct clk *clk;
++	void __iomem *base;
++	int irq;
++	int fiq_enable;
++	unsigned int offset;
++
++	unsigned int flags;
++
++	void (*ac97_reset) (struct snd_ac97 *ac97);
++	void (*ac97_warm_reset)(struct snd_ac97 *ac97);
++
++	struct imx_pcm_dma_params	dma_params_rx;
++	struct imx_pcm_dma_params	dma_params_tx;
++
++	int enabled;
++};
++
++struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev,
++		struct imx_ssi *ssi);
++void imx_ssi_fiq_exit(struct platform_device *pdev, struct imx_ssi *ssi);
++struct snd_soc_platform *imx_ssi_dma_mx2_init(struct platform_device *pdev,
++		struct imx_ssi *ssi);
++
++int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma);
++int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
++	struct snd_pcm *pcm);
++void imx_pcm_free(struct snd_pcm *pcm);
++
++/*
++ * Do not change this as the FIQ handler depends on this size
++ */
++#define IMX_SSI_DMABUF_SIZE	(64 * 1024)
++
++#define DMA_RXFIFO_BURST      0x4
++#define DMA_TXFIFO_BURST      0x2
++
++#endif /* _IMX_SSI_H */
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0014-mxc_nand-Get-rid-of-pagesize_2k-flag.patch b/recipes/linux/linux-2.6.31/pcm043/0014-mxc_nand-Get-rid-of-pagesize_2k-flag.patch
new file mode 100644
index 0000000..e0c0226
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0014-mxc_nand-Get-rid-of-pagesize_2k-flag.patch
@@ -0,0 +1,128 @@
+From 8b4c0d1da3ec208fa4c79f495f75fcf0a5b01de5 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Mon, 5 Oct 2009 11:24:02 +0200
+Subject: [PATCH] mxc_nand: Get rid of pagesize_2k flag
+
+Later versions of this controller also allow 4k pagesize,
+so use mtd->writesize instead of a flag.
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand.c |   29 ++++++++++++++---------------
+ 1 files changed, 14 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
+index 450db4e..6525d0f 100644
+--- a/drivers/mtd/nand/mxc_nand.c
++++ b/drivers/mtd/nand/mxc_nand.c
+@@ -101,7 +101,6 @@ struct mxc_nand_host {
+ 	void __iomem		*base;
+ 	void __iomem		*regs;
+ 	int			status_request;
+-	int			pagesize_2k;
+ 	struct clk		*clk;
+ 	int			clk_act;
+ 	int			irq;
+@@ -214,11 +213,13 @@ static void send_addr(struct mxc_nand_host *host, uint16_t addr, int islast)
+ 	wait_op_done(host, TROP_US_DELAY, islast);
+ }
+ 
+-static void send_page(struct mxc_nand_host *host, unsigned int ops)
++static void send_page(struct mtd_info *mtd, unsigned int ops)
+ {
++	struct nand_chip *nand_chip = mtd->priv;
++	struct mxc_nand_host *host = nand_chip->priv;
+ 	int bufs, i;
+ 
+-	if (host->pagesize_2k)
++	if (mtd->writesize > 512)
+ 		bufs = 4;
+ 	else
+ 		bufs = 1;
+@@ -490,7 +491,7 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
+ 		 * the full page.
+ 		 */
+ 		send_addr(host, 0, page_addr == -1);
+-		if (host->pagesize_2k)
++		if (mtd->writesize > 512)
+ 			/* another col addr cycle for 2k page */
+ 			send_addr(host, 0, false);
+ 	}
+@@ -500,7 +501,7 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
+ 		/* paddr_0 - p_addr_7 */
+ 		send_addr(host, (page_addr & 0xff), false);
+ 
+-		if (host->pagesize_2k) {
++		if (mtd->writesize > 512) {
+ 			if (mtd->size >= 0x10000000) {
+ 				/* paddr_8 - paddr_15 */
+ 				send_addr(host, (page_addr >> 8) & 0xff, false);
+@@ -554,16 +555,16 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ 		else
+ 			host->buf_start = column + mtd->writesize;
+ 
+-		if (host->pagesize_2k)
++		if (mtd->writesize > 512)
+ 			command = NAND_CMD_READ0; /* only READ0 is valid */
+ 
+ 		send_cmd(host, command, false);
+ 		mxc_do_addr_cycle(mtd, column, page_addr);
+ 
+-		if (host->pagesize_2k)
++		if (mtd->writesize > 512)
+ 			send_cmd(host, NAND_CMD_READSTART, true);
+ 
+-		send_page(host, NFC_OUTPUT);
++		send_page(mtd, NFC_OUTPUT);
+ 
+ 		memcpy(host->data_buf, host->main_area0, mtd->writesize);
+ 		copy_spare(mtd, true);
+@@ -578,7 +579,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ 			 * pointer to spare area, we must write the whole page
+ 			 * including OOB together.
+ 			 */
+-			if (host->pagesize_2k)
++			if (mtd->writesize > 512)
+ 				/* call ourself to read a page */
+ 				mxc_nand_command(mtd, NAND_CMD_READ0, 0,
+ 						page_addr);
+@@ -586,13 +587,13 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ 			host->buf_start = column;
+ 
+ 			/* Set program pointer to spare region */
+-			if (!host->pagesize_2k)
++			if (mtd->writesize == 512)
+ 				send_cmd(host, NAND_CMD_READOOB, false);
+ 		} else {
+ 			host->buf_start = column;
+ 
+ 			/* Set program pointer to page start */
+-			if (!host->pagesize_2k)
++			if (mtd->writesize == 512)
+ 				send_cmd(host, NAND_CMD_READ0, false);
+ 		}
+ 
+@@ -603,7 +604,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ 	case NAND_CMD_PAGEPROG:
+ 		memcpy(host->main_area0, host->data_buf, mtd->writesize);
+ 		copy_spare(mtd, false);
+-		send_page(host, NFC_INPUT);
++		send_page(mtd, NFC_INPUT);
+ 		send_cmd(host, command, true);
+ 		mxc_do_addr_cycle(mtd, column, page_addr);
+ 		break;
+@@ -745,10 +746,8 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 		goto escan;
+ 	}
+ 
+-	if (mtd->writesize == 2048) {
+-		host->pagesize_2k = 1;
++	if (mtd->writesize == 2048)
+ 		this->ecc.layout = &nand_hw_eccoob_largepage;
+-	}
+ 
+ 	/* second phase scan */
+ 	if (nand_scan_tail(mtd)) {
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0015-MXC-NFC-unlock_addr-is-only-used-while-__init-pha.patch b/recipes/linux/linux-2.6.31/pcm043/0015-MXC-NFC-unlock_addr-is-only-used-while-__init-pha.patch
new file mode 100644
index 0000000..6c1b6a0
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0015-MXC-NFC-unlock_addr-is-only-used-while-__init-pha.patch
@@ -0,0 +1,28 @@
+From 7c796b820f5aee73485636f5aafc13fcbb1cfacd Mon Sep 17 00:00:00 2001
+From: Juergen Beisert <j.beisert at pengutronix.de>
+Date: Wed, 30 Sep 2009 17:21:28 +0200
+Subject: [PATCH 15/15] MXC NFC: unlock_addr() is only used while __init phase
+
+unlock_addr() is only used while __init phase, so mark is as __init.
+
+Signed-off-by: Juergen Beisert <j.beisert at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand_v2.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand_v2.c b/drivers/mtd/nand/mxc_nand_v2.c
+index bab3712..9dd124c 100644
+--- a/drivers/mtd/nand/mxc_nand_v2.c
++++ b/drivers/mtd/nand/mxc_nand_v2.c
+@@ -781,7 +781,7 @@ static struct nand_bbt_descr bbt_mirror_descr = {
+ 	.pattern = mirror_pattern
+ };
+ 
+-static void unlock_addr(struct mxc_nand_host *host, unsigned int start_addr, unsigned int end_addr)
++static void __init unlock_addr(struct mxc_nand_host *host, unsigned int start_addr, unsigned int end_addr)
+ {
+ 	if (nfc_is_v21()) {
+ 		writew(start_addr, host->regs + NFC_V21_UNLOCKSTART_BLKADDR);
+-- 
+1.6.1
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0015-add-phycore-ac97-sound-support.patch b/recipes/linux/linux-2.6.31/pcm043/0015-add-phycore-ac97-sound-support.patch
new file mode 100644
index 0000000..2a588aa
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0015-add-phycore-ac97-sound-support.patch
@@ -0,0 +1,140 @@
+From cab3d12f55b4e89e6504a4fd9b1e950a3f2beae2 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Wed, 25 Nov 2009 16:18:28 +0100
+Subject: [PATCH 15/28] add phycore-ac97 sound support
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ sound/soc/imx/Kconfig        |    9 ++++
+ sound/soc/imx/Makefile       |    2 +
+ sound/soc/imx/phycore-ac97.c |   91 ++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 102 insertions(+), 0 deletions(-)
+ create mode 100644 sound/soc/imx/phycore-ac97.c
+
+diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
+index 84a25e6..2a8c990 100644
+--- a/sound/soc/imx/Kconfig
++++ b/sound/soc/imx/Kconfig
+@@ -11,3 +11,12 @@ config SND_IMX_SOC
+ config SND_MXC_SOC_SSI
+ 	tristate
+ 
++config SND_SOC_PHYCORE_AC97
++	tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
++	depends on MACH_PCM043 || MACH_PCA100
++	select SND_MXC_SOC_SSI
++	select SND_SOC_WM9712
++	help
++	  Say Y if you want to add support for SoC audio on Phytec phyCORE
++	  and phyCARD boards in AC97 mode
++
+diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
+index d05cc95..9f8bb92 100644
+--- a/sound/soc/imx/Makefile
++++ b/sound/soc/imx/Makefile
+@@ -8,3 +8,5 @@ endif
+ obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o
+ 
+ # i.MX Machine Support
++snd-soc-phycore-ac97-objs := phycore-ac97.o
++obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
+diff --git a/sound/soc/imx/phycore-ac97.c b/sound/soc/imx/phycore-ac97.c
+new file mode 100644
+index 0000000..8e3474b
+--- /dev/null
++++ b/sound/soc/imx/phycore-ac97.c
+@@ -0,0 +1,91 @@
++/*
++ * phycore.c  --  SoC audio for imx_phycore
++ *
++ * Copyright 2009 Sascha Hauer, Pengutronix <s.hauer at pengutronix.de>
++ *
++ *  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/moduleparam.h>
++#include <linux/device.h>
++#include <linux/i2c.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/soc.h>
++#include <sound/soc-dapm.h>
++#include <asm/mach-types.h>
++
++#include "../codecs/mc13783.h"
++#include "../codecs/wm9712.h"
++#include "imx-ssi.h"
++
++static struct snd_soc_card imx_phycore;
++
++static struct snd_soc_ops imx_phycore_hifi_ops = {
++};
++
++static struct snd_soc_dai_link imx_phycore_dai_ac97[] = {
++	{
++		.name		= "HiFi",
++		.stream_name	= "HiFi",
++		.codec_dai	= &wm9712_dai[WM9712_DAI_AC97_HIFI],
++		.ops		= &imx_phycore_hifi_ops,
++	},
++};
++
++static struct snd_soc_card imx_phycore = {
++	.name		= "PhyCORE-audio",
++	.platform	= &imx_soc_platform,
++	.dai_link	= imx_phycore_dai_ac97,
++	.num_links	= ARRAY_SIZE(imx_phycore_dai_ac97),
++};
++
++static struct snd_soc_device imx_phycore_snd_devdata = {
++	.card		= &imx_phycore,
++	.codec_dev	= &soc_codec_dev_wm9712,
++};
++
++static struct platform_device *imx_phycore_snd_device;
++
++static int __init imx_phycore_init(void)
++{
++	int ret;
++
++	if (!machine_is_pcm043() && !machine_is_pca100())
++		/* return happy. We might run on a totally different machine */
++		return 0;
++	
++	imx_phycore_snd_device = platform_device_alloc("soc-audio", -1);
++	if (!imx_phycore_snd_device)
++		return -ENOMEM;
++
++	imx_phycore_dai_ac97[0].cpu_dai = imx_ssi_pcm_dai[0];
++
++	platform_set_drvdata(imx_phycore_snd_device, &imx_phycore_snd_devdata);
++	imx_phycore_snd_devdata.dev = &imx_phycore_snd_device->dev;
++	ret = platform_device_add(imx_phycore_snd_device);
++
++	if (ret) {
++		printk(KERN_ERR "ASoC: Platform device allocation failed\n");
++		platform_device_put(imx_phycore_snd_device);
++	}
++
++	return ret;
++}
++
++static void __exit imx_phycore_exit(void)
++{
++	platform_device_unregister(imx_phycore_snd_device);
++}
++
++late_initcall(imx_phycore_init);
++module_exit(imx_phycore_exit);
++
++MODULE_AUTHOR("Sascha Hauer <s.hauer at pengutronix.de>");
++MODULE_DESCRIPTION("PhyCORE ALSA SoC driver");
++MODULE_LICENSE("GPL");
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0015-mxc_nand-Add-NFC-V2-support.patch b/recipes/linux/linux-2.6.31/pcm043/0015-mxc_nand-Add-NFC-V2-support.patch
new file mode 100644
index 0000000..a600e78
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0015-mxc_nand-Add-NFC-V2-support.patch
@@ -0,0 +1,191 @@
+From 7874c1c277ff88843747ccb2e1582c19cfb21986 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Mon, 5 Oct 2009 12:14:21 +0200
+Subject: [PATCH] mxc_nand: Add NFC V2 support
+
+The v2 version of this controller is used on i.MX35/25 SoCs.
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand.c |   81 ++++++++++++++++++++++++++++++++++++-------
+ 1 files changed, 68 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
+index 6525d0f..f2297eb 100644
+--- a/drivers/mtd/nand/mxc_nand.c
++++ b/drivers/mtd/nand/mxc_nand.c
+@@ -33,9 +33,13 @@
+ 
+ #include <asm/mach/flash.h>
+ #include <mach/mxc_nand.h>
++#include <mach/hardware.h>
+ 
+ #define DRIVER_NAME "mxc_nand"
+ 
++#define nfc_is_v21()		(cpu_is_mx25() || cpu_is_mx35())
++#define nfc_is_v1()		(cpu_is_mx31() || cpu_is_mx27())
++
+ /* Addresses for NFC registers */
+ #define NFC_BUF_SIZE		0xE00
+ #define NFC_BUF_ADDR		0xE04
+@@ -46,8 +50,10 @@
+ #define NFC_RSLTMAIN_AREA	0xE0E
+ #define NFC_RSLTSPARE_AREA	0xE10
+ #define NFC_WRPROT		0xE12
+-#define NFC_UNLOCKSTART_BLKADDR	0xE14
+-#define NFC_UNLOCKEND_BLKADDR	0xE16
++#define NFC_V1_UNLOCKSTART_BLKADDR	0xe14
++#define NFC_V1_UNLOCKEND_BLKADDR	0xe16
++#define NFC_V21_UNLOCKSTART_BLKADDR	0xe20
++#define NFC_V21_UNLOCKEND_BLKADDR	0xe22
+ #define NFC_NF_WRPRST		0xE18
+ #define NFC_CONFIG1		0xE1A
+ #define NFC_CONFIG2		0xE1C
+@@ -116,19 +122,47 @@ struct mxc_nand_host {
+ #define TROP_US_DELAY   2000
+ 
+ /* OOB placement block for use with hardware ecc generation */
+-static struct nand_ecclayout nand_hw_eccoob_smallpage = {
++static struct nand_ecclayout nandv1_hw_eccoob_smallpage = {
+ 	.eccbytes = 5,
+ 	.eccpos = {6, 7, 8, 9, 10},
+ 	.oobfree = {{0, 5}, {12, 4}, }
+ };
+ 
+-static struct nand_ecclayout nand_hw_eccoob_largepage = {
++static struct nand_ecclayout nandv1_hw_eccoob_largepage = {
+ 	.eccbytes = 20,
+ 	.eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26,
+ 		   38, 39, 40, 41, 42, 54, 55, 56, 57, 58},
+ 	.oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, }
+ };
+ 
++/* OOB description for 512 byte pages with 16 byte OOB */
++static struct nand_ecclayout nandv2_hw_eccoob_smallpage = {
++	.eccbytes = 1 * 9,
++	.eccpos = {
++		 7,  8,  9, 10, 11, 12, 13, 14, 15
++	},
++	.oobfree = {
++		{.offset = 0, .length = 5}
++	}
++};
++
++/* OOB description for 2048 byte pages with 64 byte OOB */
++static struct nand_ecclayout nandv2_hw_eccoob_largepage = {
++	.eccbytes = 4 * 9,
++	.eccpos = {
++		 7,  8,  9, 10, 11, 12, 13, 14, 15,
++		23, 24, 25, 26, 27, 28, 29, 30, 31,
++		39, 40, 41, 42, 43, 44, 45, 46, 47,
++		55, 56, 57, 58, 59, 60, 61, 62, 63
++	},
++	.oobfree = {
++		{.offset = 2, .length = 4},
++		{.offset = 16, .length = 7},
++		{.offset = 32, .length = 7},
++		{.offset = 48, .length = 7}
++	}
++};
++
+ #ifdef CONFIG_MTD_PARTITIONS
+ static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL };
+ #endif
+@@ -219,7 +253,7 @@ static void send_page(struct mtd_info *mtd, unsigned int ops)
+ 	struct mxc_nand_host *host = nand_chip->priv;
+ 	int bufs, i;
+ 
+-	if (mtd->writesize > 512)
++	if (nfc_is_v1() && mtd->writesize > 512)
+ 		bufs = 4;
+ 	else
+ 		bufs = 1;
+@@ -613,6 +647,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ 		send_cmd(host, command, true);
+ 		mxc_do_addr_cycle(mtd, column, page_addr);
+ 		send_read_id(host);
++		host->buf_start = column;
+ 		break;
+ 
+ 	case NAND_CMD_ERASE1:
+@@ -633,6 +668,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 	struct resource *res;
+ 	uint16_t tmp;
+ 	int err = 0, nr_parts = 0;
++	struct nand_ecclayout *oob_smallpage, *oob_largepage;
+ 
+ 	/* Allocate memory for MTD device structure and private data */
+ 	host = kzalloc(sizeof(struct mxc_nand_host) + NAND_MAX_PAGESIZE +
+@@ -641,7 +677,6 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 		return -ENOMEM;
+ 
+ 	host->data_buf = (uint8_t *)(host + 1);
+-	host->spare_len = 16;
+ 
+ 	host->dev = &pdev->dev;
+ 	/* structures must be linked */
+@@ -686,10 +721,23 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 		goto eres;
+ 	}
+ 
+-	host->regs = host->base;
+ 	host->main_area0 = host->base;
+ 	host->main_area1 = host->base + 0x200;
+-	host->spare0 = host->base + 0x800;
++
++	if (nfc_is_v21()) {
++		host->regs = host->base + 0x1000;
++		host->spare0 = host->base + 0x1000;
++		host->spare_len = 64;
++		oob_smallpage = &nandv2_hw_eccoob_smallpage;
++		oob_largepage = &nandv2_hw_eccoob_largepage;
++	} else if (nfc_is_v1()) {
++		host->regs = host->base;
++		host->spare0 = host->base + 0x800;
++		host->spare_len = 16;
++		oob_smallpage = &nandv1_hw_eccoob_smallpage;
++		oob_largepage = &nandv1_hw_eccoob_largepage;
++	} else
++		BUG();
+ 
+ 	tmp = readw(host->regs + NFC_CONFIG1);
+ 	tmp |= NFC_INT_MSK;
+@@ -711,15 +759,22 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 	writew(0x2, host->regs + NFC_CONFIG);
+ 
+ 	/* Blocks to be unlocked */
+-	writew(0x0, host->regs + NFC_UNLOCKSTART_BLKADDR);
+-	writew(0x4000, host->regs + NFC_UNLOCKEND_BLKADDR);
++	if (nfc_is_v21()) {
++		writew(0x0, host->regs + NFC_V21_UNLOCKSTART_BLKADDR);
++	        writew(0xffff, host->regs + NFC_V21_UNLOCKEND_BLKADDR);
++		this->ecc.bytes = 9;
++	} else if (nfc_is_v1()) {
++		writew(0x0, host->regs + NFC_V1_UNLOCKSTART_BLKADDR);
++	        writew(0x4000, host->regs + NFC_V1_UNLOCKEND_BLKADDR);
++		this->ecc.bytes = 3;
++	} else
++		BUG();
+ 
+ 	/* Unlock Block Command for given address range */
+ 	writew(0x4, host->regs + NFC_WRPROT);
+ 
+ 	this->ecc.size = 512;
+-	this->ecc.bytes = 3;
+-	this->ecc.layout = &nand_hw_eccoob_smallpage;
++	this->ecc.layout = oob_smallpage;
+ 
+ 	if (pdata->hw_ecc) {
+ 		this->ecc.calculate = mxc_nand_calculate_ecc;
+@@ -747,7 +802,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 	}
+ 
+ 	if (mtd->writesize == 2048)
+-		this->ecc.layout = &nand_hw_eccoob_largepage;
++		this->ecc.layout = oob_largepage;
+ 
+ 	/* second phase scan */
+ 	if (nand_scan_tail(mtd)) {
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0016-add-phycore-mc13783-sound-support.patch b/recipes/linux/linux-2.6.31/pcm043/0016-add-phycore-mc13783-sound-support.patch
new file mode 100644
index 0000000..629f551
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0016-add-phycore-mc13783-sound-support.patch
@@ -0,0 +1,211 @@
+From 62b2363d03aa1d58d2ff23eff6c535d1e3715277 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Wed, 25 Nov 2009 16:18:38 +0100
+Subject: [PATCH 16/28] add phycore-mc13783 sound support
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ sound/soc/imx/Kconfig           |   10 +++
+ sound/soc/imx/Makefile          |    3 +
+ sound/soc/imx/phycore-mc13783.c |  160 +++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 173 insertions(+), 0 deletions(-)
+ create mode 100644 sound/soc/imx/phycore-mc13783.c
+
+diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
+index 2a8c990..e145212 100644
+--- a/sound/soc/imx/Kconfig
++++ b/sound/soc/imx/Kconfig
+@@ -20,3 +20,13 @@ config SND_SOC_PHYCORE_AC97
+ 	  Say Y if you want to add support for SoC audio on Phytec phyCORE
+ 	  and phyCARD boards in AC97 mode
+ 
++config SND_SOC_PHYCORE_MC13783
++	tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
++	depends on MACH_PCM038 || MACH_PCM037
++	select SND_MXC_SOC_SSI
++	select SND_SOC_MC13783
++	select SND_SOC_WM9712 if MACH_PCM043 || MACH_PCA100
++	help
++	  Say Y if you want to add support for SoC audio on Phytec phyCORE
++	  boards using a MC13783 Codec.
++
+diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
+index 9f8bb92..425ffaf 100644
+--- a/sound/soc/imx/Makefile
++++ b/sound/soc/imx/Makefile
+@@ -10,3 +10,6 @@ obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o
+ # i.MX Machine Support
+ snd-soc-phycore-ac97-objs := phycore-ac97.o
+ obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
++
++snd-soc-phycore-mc13783-objs := phycore-mc13783.o
++obj-$(CONFIG_SND_SOC_PHYCORE_MC13783) += snd-soc-phycore-mc13783.o
+diff --git a/sound/soc/imx/phycore-mc13783.c b/sound/soc/imx/phycore-mc13783.c
+new file mode 100644
+index 0000000..3743e0f
+--- /dev/null
++++ b/sound/soc/imx/phycore-mc13783.c
+@@ -0,0 +1,160 @@
++/*
++ * phycore.c  --  SoC audio for imx_phycore
++ *
++ * Copyright 2009 Sascha Hauer, Pengutronix <s.hauer at pengutronix.de>
++ *
++ *  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/moduleparam.h>
++#include <linux/device.h>
++#include <linux/i2c.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/soc.h>
++#include <sound/soc-dapm.h>
++#include <asm/mach-types.h>
++
++#include "../codecs/mc13783.h"
++#include "../codecs/wm9712.h"
++#include "imx-ssi.h"
++
++static struct snd_soc_card imx_phycore;
++
++#define FMT_PLAYBACK (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \
++		SND_SOC_DAIFMT_CBM_CFM)
++#define FMT_CAPTURE (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | \
++		SND_SOC_DAIFMT_CBM_CFM)
++
++static int imx_phycore_hifi_hw_params(struct snd_pcm_substream *substream,
++	struct snd_pcm_hw_params *params)
++{
++	struct snd_soc_pcm_runtime *rtd = substream->private_data;
++	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
++	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
++	int ret;
++
++	/* set cpu DAI configuration */
++	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++		ret = snd_soc_dai_set_fmt(codec_dai, FMT_PLAYBACK);
++		if (ret)
++			return ret;
++		ret = snd_soc_dai_set_fmt(cpu_dai, FMT_PLAYBACK);
++		if (ret)
++			return ret;
++	} else {
++		ret = snd_soc_dai_set_fmt(codec_dai, FMT_CAPTURE);
++		if (ret)
++			return ret;
++		ret = snd_soc_dai_set_fmt(cpu_dai, FMT_CAPTURE);
++		if (ret)
++			return ret;
++		ret = snd_soc_dai_set_tdm_slot(codec_dai, 0, 4);
++		if (ret)
++			return ret;
++	}
++
++	ret = snd_soc_dai_set_sysclk(codec_dai, MC13783_CLK_CLIA, 26000000, 0);
++	if (ret)
++		return ret;
++
++	ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xfffffffc, 4);
++	if (ret)
++		return ret;
++
++	return 0;
++}
++
++static int imx_phycore_hifi_hw_free(struct snd_pcm_substream *substream)
++{
++	return 0;
++}
++
++static struct snd_soc_ops imx_phycore_hifi_ops = {
++	.hw_params = imx_phycore_hifi_hw_params,
++	.hw_free = imx_phycore_hifi_hw_free,
++};
++
++static int imx_phycore_probe(struct platform_device *pdev)
++{
++	return 0;
++}
++
++static int imx_phycore_remove(struct platform_device *pdev)
++{
++	return 0;
++}
++
++static struct snd_soc_dai_link imx_phycore_dai_mc13783[] = {
++	{
++		.name = "MC13783 Playback",
++		.stream_name	= "Playback",
++		.codec_dai	= &mc13783_dai[0],
++		.ops		= &imx_phycore_hifi_ops,
++	}, {
++		.name = "MC13783 Capture",
++		.stream_name	= "Capture",
++		.codec_dai	= &mc13783_dai[1],
++		.ops		= &imx_phycore_hifi_ops,
++	},
++};
++
++static struct snd_soc_card imx_phycore = {
++	.name		= "PhyCORE-audio",
++	.platform	= &imx_soc_platform,
++	.probe		= imx_phycore_probe,
++	.remove		= imx_phycore_remove,
++	.dai_link	= imx_phycore_dai_mc13783,
++	.num_links	= ARRAY_SIZE(imx_phycore_dai_mc13783),
++};
++
++static struct snd_soc_device imx_phycore_snd_devdata = {
++	.card		= &imx_phycore,
++	.codec_dev	= &soc_codec_dev_mc13783,
++};
++
++static struct platform_device *imx_phycore_snd_device;
++
++static int __init imx_phycore_init(void)
++{
++	int ret;
++
++	if (!machine_is_pcm038() && !machine_is_pcm037())
++		/* return happy. We might run on a totally different machine */
++		return 0;
++
++	imx_phycore_snd_device = platform_device_alloc("soc-audio", -1);
++	if (!imx_phycore_snd_device)
++		return -ENOMEM;
++
++	imx_phycore_dai_mc13783[0].cpu_dai = imx_ssi_pcm_dai[0];
++	imx_phycore_dai_mc13783[1].cpu_dai = imx_ssi_pcm_dai[0];
++
++	platform_set_drvdata(imx_phycore_snd_device, &imx_phycore_snd_devdata);
++	imx_phycore_snd_devdata.dev = &imx_phycore_snd_device->dev;
++	ret = platform_device_add(imx_phycore_snd_device);
++
++	if (ret) {
++		printk(KERN_ERR "ASoC: Platform device allocation failed\n");
++		platform_device_put(imx_phycore_snd_device);
++	}
++
++	return ret;
++}
++
++static void __exit imx_phycore_exit(void)
++{
++	platform_device_unregister(imx_phycore_snd_device);
++}
++
++late_initcall(imx_phycore_init);
++module_exit(imx_phycore_exit);
++
++MODULE_AUTHOR("Sascha Hauer <s.hauer at pengutronix.de>");
++MODULE_DESCRIPTION("PhyCORE ALSA SoC driver");
++MODULE_LICENSE("GPL");
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0016-mxc_nand-disable-sp_en-bit-only-once.patch b/recipes/linux/linux-2.6.31/pcm043/0016-mxc_nand-disable-sp_en-bit-only-once.patch
new file mode 100644
index 0000000..f926c8f
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0016-mxc_nand-disable-sp_en-bit-only-once.patch
@@ -0,0 +1,66 @@
+From b21f4e602fec63eb29aea9dc9bc59d31f6e027c5 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Mon, 5 Oct 2009 17:18:42 +0200
+Subject: [PATCH] mxc_nand: disable sp_en bit only once
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand.c |   15 +++------------
+ 1 files changed, 3 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
+index f2297eb..199a5f2 100644
+--- a/drivers/mtd/nand/mxc_nand.c
++++ b/drivers/mtd/nand/mxc_nand.c
+@@ -274,16 +274,10 @@ static void send_page(struct mtd_info *mtd, unsigned int ops)
+ static void send_read_id(struct mxc_nand_host *host)
+ {
+ 	struct nand_chip *this = &host->nand;
+-	uint16_t tmp;
+ 
+ 	/* NANDFC buffer 0 is used for device ID output */
+ 	writew(0x0, host->regs + NFC_BUF_ADDR);
+ 
+-	/* Read ID into main buffer */
+-	tmp = readw(host->regs + NFC_CONFIG1);
+-	tmp &= ~NFC_SP_EN;
+-	writew(tmp, host->regs + NFC_CONFIG1);
+-
+ 	writew(NFC_ID, host->regs + NFC_CONFIG2);
+ 
+ 	/* Wait for operation to complete */
+@@ -307,7 +301,7 @@ static uint16_t get_dev_status(struct mxc_nand_host *host)
+ {
+ 	void __iomem *main_buf = host->main_area1;
+ 	uint32_t store;
+-	uint16_t ret, tmp;
++	uint16_t ret;
+ 	/* Issue status request to NAND device */
+ 
+ 	/* store the main area1 first word, later do recovery */
+@@ -316,11 +310,6 @@ static uint16_t get_dev_status(struct mxc_nand_host *host)
+ 	 * corruption of read/write buffer on status requests. */
+ 	writew(1, host->regs + NFC_BUF_ADDR);
+ 
+-	/* Read status into main buffer */
+-	tmp = readw(host->regs + NFC_CONFIG1);
+-	tmp &= ~NFC_SP_EN;
+-	writew(tmp, host->regs + NFC_CONFIG1);
+-
+ 	writew(NFC_STATUS, host->regs + NFC_CONFIG2);
+ 
+ 	/* Wait for operation to complete */
+@@ -739,8 +728,10 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 	} else
+ 		BUG();
+ 
++	/* disable interrupt and spare enable */
+ 	tmp = readw(host->regs + NFC_CONFIG1);
+ 	tmp |= NFC_INT_MSK;
++	tmp &= ~NFC_SP_EN;
+ 	writew(tmp, host->regs + NFC_CONFIG1);
+ 
+ 	init_waitqueue_head(&host->irq_waitq);
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0017-mxc_nand-Allow-flash-based-bbt.patch b/recipes/linux/linux-2.6.31/pcm043/0017-mxc_nand-Allow-flash-based-bbt.patch
new file mode 100644
index 0000000..1f3f9ee
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0017-mxc_nand-Allow-flash-based-bbt.patch
@@ -0,0 +1,79 @@
+From b865b0240161ad328bb2fe69eea58111c8df6a29 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Wed, 21 Oct 2009 14:25:27 +0200
+Subject: [PATCH] mxc_nand: Allow flash based bbt
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/plat-mxc/include/mach/mxc_nand.h |    3 +-
+ drivers/mtd/nand/mxc_nand.c               |   34 +++++++++++++++++++++++++++++
+ 2 files changed, 36 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/plat-mxc/include/mach/mxc_nand.h b/arch/arm/plat-mxc/include/mach/mxc_nand.h
+index 2b972df..5d2d21d 100644
+--- a/arch/arm/plat-mxc/include/mach/mxc_nand.h
++++ b/arch/arm/plat-mxc/include/mach/mxc_nand.h
+@@ -22,6 +22,7 @@
+ 
+ struct mxc_nand_platform_data {
+ 	int width;	/* data bus width in bytes */
+-	int hw_ecc;	/* 0 if supress hardware ECC */
++	int hw_ecc:1;	/* 0 if supress hardware ECC */
++	int flash_bbt:1; /* set to 1 to use a flash based bbt */
+ };
+ #endif /* __ASM_ARCH_NAND_H */
+diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
+index 199a5f2..3fdc172 100644
+--- a/drivers/mtd/nand/mxc_nand.c
++++ b/drivers/mtd/nand/mxc_nand.c
+@@ -648,6 +648,33 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
+ 	}
+ }
+ 
++/*
++ * The generic flash bbt decriptors overlap with our ecc
++ * hardware, so define some i.MX specific ones.
++ */
++static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
++static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' };
++
++static struct nand_bbt_descr bbt_main_descr = {
++	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++	    | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
++	.offs = 0,
++	.len = 4,
++	.veroffs = 4,
++	.maxblocks = 4,
++	.pattern = bbt_pattern,
++};
++
++static struct nand_bbt_descr bbt_mirror_descr = {
++	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++	    | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
++	.offs = 0,
++	.len = 4,
++	.veroffs = 4,
++	.maxblocks = 4,
++	.pattern = mirror_pattern,
++};
++
+ static int __init mxcnd_probe(struct platform_device *pdev)
+ {
+ 	struct nand_chip *this;
+@@ -786,6 +813,13 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 	if (pdata->width == 2)
+ 		this->options |= NAND_BUSWIDTH_16;
+ 
++	if (pdata->flash_bbt) {
++		this->bbt_td = &bbt_main_descr;
++		this->bbt_md = &bbt_mirror_descr;
++		/* update flash based bbt */
++		this->options |= NAND_USE_FLASH_BBT;
++	}
++
+ 	/* first scan to find the device and get the page size */
+ 	if (nand_scan_ident(mtd, 1)) {
+ 		err = -ENXIO;
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0017-pcm043-add-sound-support.patch b/recipes/linux/linux-2.6.31/pcm043/0017-pcm043-add-sound-support.patch
new file mode 100644
index 0000000..d4c1527
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0017-pcm043-add-sound-support.patch
@@ -0,0 +1,161 @@
+From 9ce0a3fb1764c093452db1f34dfecbca1ea41833 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Thu, 29 Oct 2009 17:17:31 +0100
+Subject: [PATCH 17/28] pcm043: add sound support
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/mach-mx3/pcm043.c |  104 +++++++++++++++++++++++++++++++++++++++++++-
+ 1 files changed, 103 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/mach-mx3/pcm043.c b/arch/arm/mach-mx3/pcm043.c
+index 8d27c32..d1b6f53 100644
+--- a/arch/arm/mach-mx3/pcm043.c
++++ b/arch/arm/mach-mx3/pcm043.c
+@@ -28,6 +28,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/i2c.h>
+ #include <linux/i2c/at24.h>
++#include <linux/delay.h>
+ 
+ #include <asm/mach-types.h>
+ #include <asm/mach/arch.h>
+@@ -43,6 +44,8 @@
+ #include <mach/iomux-mx35.h>
+ #include <mach/ipu.h>
+ #include <mach/mx3fb.h>
++#include <mach/audmux.h>
++#include <mach/ssi.h>
+ 
+ #include "devices.h"
+ 
+@@ -203,7 +206,92 @@ static struct pad_desc pcm043_pads[] = {
+ 	MX35_PAD_D3_VSYNC__IPU_DISPB_D3_VSYNC,
+ 	MX35_PAD_D3_REV__IPU_DISPB_D3_REV,
+ 	MX35_PAD_D3_CLS__IPU_DISPB_D3_CLS,
+-	MX35_PAD_D3_SPL__IPU_DISPB_D3_SPL
++	MX35_PAD_D3_SPL__IPU_DISPB_D3_SPL,
++	/* SSI */
++	MX35_PAD_STXFS4__AUDMUX_AUD4_TXFS,
++	MX35_PAD_STXD4__AUDMUX_AUD4_TXD,
++	MX35_PAD_SRXD4__AUDMUX_AUD4_RXD,
++	MX35_PAD_SCK4__AUDMUX_AUD4_TXC,
++};
++
++#define AC97_GPIO_TXFS	(1 * 32 + 31)
++#define AC97_GPIO_TXD	(1 * 32 + 28)
++#define AC97_GPIO_RESET	(1 * 32 + 0)
++
++static void pcm043_ac97_warm_reset(struct snd_ac97 *ac97)
++{
++	struct pad_desc txfs_gpio = MX35_PAD_STXFS4__GPIO2_31;
++	struct pad_desc txfs = MX35_PAD_STXFS4__AUDMUX_AUD4_TXFS;
++	int ret;
++
++	ret = gpio_request(AC97_GPIO_TXFS, "SSI");
++	if (ret) {
++		printk("failed to get GPIO_TXFS: %d\n", ret);
++		return;
++	}
++
++	mxc_iomux_v3_setup_pad(&txfs_gpio);
++
++	/* warm reset */
++	gpio_direction_output(AC97_GPIO_TXFS, 1);
++	udelay(2);
++	gpio_set_value(AC97_GPIO_TXFS, 0);
++
++	gpio_free(AC97_GPIO_TXFS);
++	mxc_iomux_v3_setup_pad(&txfs);
++}
++
++static void pcm043_ac97_cold_reset(struct snd_ac97 *ac97)
++{
++	struct pad_desc txfs_gpio = MX35_PAD_STXFS4__GPIO2_31;
++	struct pad_desc txfs = MX35_PAD_STXFS4__AUDMUX_AUD4_TXFS;
++	struct pad_desc txd_gpio = MX35_PAD_STXD4__GPIO2_28;
++	struct pad_desc txd = MX35_PAD_STXD4__AUDMUX_AUD4_TXD;
++	struct pad_desc reset_gpio = MX35_PAD_SD2_CMD__GPIO2_0;
++	int ret;
++
++	ret = gpio_request(AC97_GPIO_TXFS, "SSI");
++	if (ret)
++		goto err1;
++
++	ret = gpio_request(AC97_GPIO_TXD, "SSI");
++	if (ret)
++		goto err2;
++
++	ret = gpio_request(AC97_GPIO_RESET, "SSI");
++	if (ret)
++		goto err3;
++
++	mxc_iomux_v3_setup_pad(&txfs_gpio);
++	mxc_iomux_v3_setup_pad(&txd_gpio);
++	mxc_iomux_v3_setup_pad(&reset_gpio);
++
++	gpio_direction_output(AC97_GPIO_TXFS, 0);
++	gpio_direction_output(AC97_GPIO_TXD, 0);
++
++	/* cold reset */
++	gpio_direction_output(AC97_GPIO_RESET, 0);
++	udelay(10);
++	gpio_direction_output(AC97_GPIO_RESET, 1);
++
++	mxc_iomux_v3_setup_pad(&txd);
++	mxc_iomux_v3_setup_pad(&txfs);
++
++	gpio_free(AC97_GPIO_RESET);
++err3:
++	gpio_free(AC97_GPIO_TXD);
++err2:
++	gpio_free(AC97_GPIO_TXFS);
++err1:
++	if (ret)
++		printk("%s failed with %d\n", __func__, ret);
++	mdelay(1);
++}
++
++static struct imx_ssi_platform_data pcm043_ssi_pdata = {
++	.ac97_reset = pcm043_ac97_cold_reset,
++	.ac97_warm_reset = pcm043_ac97_warm_reset,
++	.flags = IMX_SSI_USE_AC97,
+ };
+ 
+ /*
+@@ -213,11 +301,24 @@ static void __init mxc_board_init(void)
+ {
+ 	mxc_iomux_v3_setup_multiple_pads(pcm043_pads, ARRAY_SIZE(pcm043_pads));
+ 
++	mxc_audmux_v2_configure_port(3,
++			MXC_AUDMUX_V2_PTCR_SYN | /* 4wire mode */
++			MXC_AUDMUX_V2_PTCR_TFSEL(0) |
++			MXC_AUDMUX_V2_PTCR_TFSDIR,
++			MXC_AUDMUX_V2_PDCR_RXDSEL(0));
++
++	mxc_audmux_v2_configure_port(0,
++			MXC_AUDMUX_V2_PTCR_SYN | /* 4wire mode */
++			MXC_AUDMUX_V2_PTCR_TCSEL(3) |
++			MXC_AUDMUX_V2_PTCR_TCLKDIR, /* clock is output */
++			MXC_AUDMUX_V2_PDCR_RXDSEL(3));
++
+ 	platform_add_devices(devices, ARRAY_SIZE(devices));
+ 
+ 	mxc_register_device(&mxc_uart_device0, &uart_pdata);
+ 
+ 	mxc_register_device(&mxc_uart_device1, &uart_pdata);
++	mxc_register_device(&imx_ssi_device0, &pcm043_ssi_pdata);
+ 
+ #if defined CONFIG_I2C_IMX || defined CONFIG_I2C_IMX_MODULE
+ 	i2c_register_board_info(0, pcm043_i2c_devices,
+@@ -232,6 +333,7 @@ static void __init mxc_board_init(void)
+ 
+ static void __init pcm043_timer_init(void)
+ {
++	printk("mx35_clocks_init()\n");
+ 	mx35_clocks_init();
+ }
+ 
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0018-mxc_nand-remove-TROP_US_DELAY.patch b/recipes/linux/linux-2.6.31/pcm043/0018-mxc_nand-remove-TROP_US_DELAY.patch
new file mode 100644
index 0000000..9d8d266
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0018-mxc_nand-remove-TROP_US_DELAY.patch
@@ -0,0 +1,88 @@
+From 55f91a40d858b579960bb9d3e29d8339b7210be2 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Wed, 21 Oct 2009 16:01:02 +0200
+Subject: [PATCH] mxc_nand: remove TROP_US_DELAY
+
+wait_op_done is only called with the same timeout, so
+code the timeout into the function itself.
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand.c |   17 +++++++----------
+ 1 files changed, 7 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
+index 3fdc172..dd80e88 100644
+--- a/drivers/mtd/nand/mxc_nand.c
++++ b/drivers/mtd/nand/mxc_nand.c
+@@ -118,9 +118,6 @@ struct mxc_nand_host {
+ 	int			spare_len;
+ };
+ 
+-/* Define delays in microsec for NAND device operations */
+-#define TROP_US_DELAY   2000
+-
+ /* OOB placement block for use with hardware ecc generation */
+ static struct nand_ecclayout nandv1_hw_eccoob_smallpage = {
+ 	.eccbytes = 5,
+@@ -185,10 +182,10 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
+ /* This function polls the NANDFC to wait for the basic operation to
+  * complete by checking the INT bit of config2 register.
+  */
+-static void wait_op_done(struct mxc_nand_host *host, int max_retries,
+-				int useirq)
++static void wait_op_done(struct mxc_nand_host *host, int useirq)
+ {
+ 	uint32_t tmp;
++	int max_retries = 2000;
+ 
+ 	if (useirq) {
+ 		if ((readw(host->regs + NFC_CONFIG2) & NFC_INT) == 0) {
+@@ -230,7 +227,7 @@ static void send_cmd(struct mxc_nand_host *host, uint16_t cmd, int useirq)
+ 	writew(NFC_CMD, host->regs + NFC_CONFIG2);
+ 
+ 	/* Wait for operation to complete */
+-	wait_op_done(host, TROP_US_DELAY, useirq);
++	wait_op_done(host, useirq);
+ }
+ 
+ /* This function sends an address (or partial address) to the
+@@ -244,7 +241,7 @@ static void send_addr(struct mxc_nand_host *host, uint16_t addr, int islast)
+ 	writew(NFC_ADDR, host->regs + NFC_CONFIG2);
+ 
+ 	/* Wait for operation to complete */
+-	wait_op_done(host, TROP_US_DELAY, islast);
++	wait_op_done(host, islast);
+ }
+ 
+ static void send_page(struct mtd_info *mtd, unsigned int ops)
+@@ -266,7 +263,7 @@ static void send_page(struct mtd_info *mtd, unsigned int ops)
+ 		writew(ops, host->regs + NFC_CONFIG2);
+ 
+ 		/* Wait for operation to complete */
+-		wait_op_done(host, TROP_US_DELAY, true);
++		wait_op_done(host, true);
+ 	}
+ }
+ 
+@@ -281,7 +278,7 @@ static void send_read_id(struct mxc_nand_host *host)
+ 	writew(NFC_ID, host->regs + NFC_CONFIG2);
+ 
+ 	/* Wait for operation to complete */
+-	wait_op_done(host, TROP_US_DELAY, true);
++	wait_op_done(host, true);
+ 
+ 	if (this->options & NAND_BUSWIDTH_16) {
+ 		void __iomem *main_buf = host->main_area0;
+@@ -313,7 +310,7 @@ static uint16_t get_dev_status(struct mxc_nand_host *host)
+ 	writew(NFC_STATUS, host->regs + NFC_CONFIG2);
+ 
+ 	/* Wait for operation to complete */
+-	wait_op_done(host, TROP_US_DELAY, true);
++	wait_op_done(host, true);
+ 
+ 	/* Status is placed in first word of main buffer */
+ 	/* get status, then recovery area 1 data */
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0018-pcm038-Add-SPI-MC13783-support.patch b/recipes/linux/linux-2.6.31/pcm043/0018-pcm038-Add-SPI-MC13783-support.patch
new file mode 100644
index 0000000..447936a
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0018-pcm038-Add-SPI-MC13783-support.patch
@@ -0,0 +1,146 @@
+From d29530587128ca197998d1b02a3e9e3286cf98e1 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Thu, 24 Sep 2009 10:01:53 +0200
+Subject: [PATCH 18/28] pcm038: Add SPI/MC13783 support
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/mach-mx2/pcm038.c |   94 +++++++++++++++++++++++++++++++++++++++++++-
+ 1 files changed, 92 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/mach-mx2/pcm038.c b/arch/arm/mach-mx2/pcm038.c
+index a4628d0..b3a8ed8 100644
+--- a/arch/arm/mach-mx2/pcm038.c
++++ b/arch/arm/mach-mx2/pcm038.c
+@@ -23,6 +23,10 @@
+ #include <linux/mtd/plat-ram.h>
+ #include <linux/mtd/physmap.h>
+ #include <linux/platform_device.h>
++#include <linux/regulator/machine.h>
++#include <linux/mfd/mc13783.h>
++#include <linux/spi/spi.h>
++#include <linux/irq.h>
+ 
+ #include <asm/mach-types.h>
+ #include <asm/mach/arch.h>
+@@ -35,6 +39,7 @@
+ #include <mach/iomux.h>
+ #include <mach/imx-uart.h>
+ #include <mach/mxc_nand.h>
++#include <mach/spi.h>
+ 
+ #include "devices.h"
+ 
+@@ -78,8 +83,6 @@ static int pcm038_pins[] = {
+ 	PC6_PF_I2C2_SCL,
+ 	/* SPI1 */
+ 	PD25_PF_CSPI1_RDY,
+-	PD27_PF_CSPI1_SS1,
+-	PD28_PF_CSPI1_SS0,
+ 	PD29_PF_CSPI1_SCLK,
+ 	PD30_PF_CSPI1_MISO,
+ 	PD31_PF_CSPI1_MOSI,
+@@ -200,6 +203,86 @@ static struct i2c_board_info pcm038_i2c_devices[] = {
+ 	}
+ };
+ 
++static int pcm038_spi_cs[] = {GPIO_PORTD + 28};
++
++static struct spi_imx_master pcm038_spi_0_data = {
++	.chipselect = pcm038_spi_cs,
++	.num_chipselect = ARRAY_SIZE(pcm038_spi_cs),
++};
++
++static struct regulator_consumer_supply sdhc1_consumers[] = {
++	{
++		.dev	= &mxc_sdhc_device1.dev,
++		.supply	= "sdhc_vcc",
++	},
++};
++
++static struct regulator_init_data sdhc1_data = {
++	.constraints = {
++		.min_uV = 3000000,
++		.max_uV = 3400000,
++		.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
++			REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS,
++		.valid_modes_mask = REGULATOR_MODE_NORMAL |
++			REGULATOR_MODE_FAST,
++		.always_on = 0,
++		.boot_on = 0,
++	},
++	.num_consumer_supplies = ARRAY_SIZE(sdhc1_consumers),
++	.consumer_supplies = sdhc1_consumers,
++};
++
++static struct regulator_consumer_supply cam_consumers[] = {
++	{
++		.dev	= NULL,
++		.supply	= "imx_cam_vcc",
++	},
++};
++
++static struct regulator_init_data cam_data = {
++	.constraints = {
++		.min_uV = 3000000,
++		.max_uV = 3400000,
++		.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
++			REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS,
++		.valid_modes_mask = REGULATOR_MODE_NORMAL |
++			REGULATOR_MODE_FAST,
++		.always_on = 0,
++		.boot_on = 0,
++	},
++	.num_consumer_supplies = ARRAY_SIZE(cam_consumers),
++	.consumer_supplies = cam_consumers,
++};
++
++struct mc13783_regulator_init_data pcm038_regulators[] = {
++	{
++		.id = MC13783_REGU_VCAM,
++		.init_data = &cam_data,
++	}, {
++		.id = MC13783_REGU_VMMC1,
++		.init_data = &sdhc1_data,
++	},
++};
++
++static struct mc13783_platform_data pcm038_pmic = {
++	.regulators = pcm038_regulators,
++	.num_regulators = ARRAY_SIZE(pcm038_regulators),
++	.flags = MC13783_USE_ADC | MC13783_USE_REGULATOR |
++		 MC13783_USE_TOUCHSCREEN,
++};
++
++static struct spi_board_info pcm038_spi_board_info[] __initdata = {
++	{
++		.modalias = "mc13783",
++		.irq = IRQ_GPIOB(23),
++		.max_speed_hz = 300000,
++		.bus_num = 0,
++		.chip_select = 0,
++		.platform_data = &pcm038_pmic,
++		.mode = SPI_CS_HIGH,
++	}
++};
++
+ static void __init pcm038_init(void)
+ {
+ 	mxc_gpio_setup_multiple_pins(pcm038_pins, ARRAY_SIZE(pcm038_pins),
+@@ -220,6 +303,13 @@ static void __init pcm038_init(void)
+ 
+ 	mxc_register_device(&mxc_i2c_device1, &pcm038_i2c_1_data);
+ 
++	/* MC13783 IRQ */
++	mxc_gpio_mode(GPIO_PORTB | 23 | GPIO_GPIO | GPIO_IN);
++
++	mxc_register_device(&mxc_spi_device0, &pcm038_spi_0_data);
++	spi_register_board_info(pcm038_spi_board_info,
++				ARRAY_SIZE(pcm038_spi_board_info));
++
+ 	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+ 
+ #ifdef CONFIG_MACH_PCM970_BASEBOARD
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0019-mx27-add-support-for-phytec-pca100-phyCARD-s-board.patch b/recipes/linux/linux-2.6.31/pcm043/0019-mx27-add-support-for-phytec-pca100-phyCARD-s-board.patch
new file mode 100644
index 0000000..fbada0b
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0019-mx27-add-support-for-phytec-pca100-phyCARD-s-board.patch
@@ -0,0 +1,293 @@
+From 11082d5306315626cb67dc73b13c95baefd6bc9c Mon Sep 17 00:00:00 2001
+From: Luotao Fu <l.fu at pengutronix.de>
+Date: Thu, 6 Aug 2009 11:19:39 +0200
+Subject: [PATCH 19/28] mx27: add support for phytec pca100 (phyCARD-s) board
+
+Signed-off-by: Luotao Fu <l.fu at pengutronix.de>
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/mach-mx2/Kconfig  |    7 ++
+ arch/arm/mach-mx2/Makefile |    2 +-
+ arch/arm/mach-mx2/pca100.c |  244 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 252 insertions(+), 1 deletions(-)
+ create mode 100644 arch/arm/mach-mx2/pca100.c
+
+diff --git a/arch/arm/mach-mx2/Kconfig b/arch/arm/mach-mx2/Kconfig
+index 0d08c34..69e2a9b 100644
+--- a/arch/arm/mach-mx2/Kconfig
++++ b/arch/arm/mach-mx2/Kconfig
+@@ -69,4 +69,11 @@ config MACH_MX27LITE
+ 	  Include support for MX27 LITEKIT platform. This includes specific
+ 	  configurations for the board and its peripherals.
+ 
++config MACH_PCA100
++	bool "Phytec phyCARD-s (pca100)"
++	depends on MACH_MX27
++	help
++	  Include support for phyCARD-s (aka pca100) platform. This
++	  includes specific configurations for the module and its peripherals.
++
+ endif
+diff --git a/arch/arm/mach-mx2/Makefile b/arch/arm/mach-mx2/Makefile
+index b9b1cca..046c115 100644
+--- a/arch/arm/mach-mx2/Makefile
++++ b/arch/arm/mach-mx2/Makefile
+@@ -17,4 +17,4 @@ obj-$(CONFIG_MACH_PCM038) += pcm038.o
+ obj-$(CONFIG_MACH_PCM970_BASEBOARD) += pcm970-baseboard.o
+ obj-$(CONFIG_MACH_MX27_3DS) += mx27pdk.o
+ obj-$(CONFIG_MACH_MX27LITE) += mx27lite.o
+-
++obj-$(CONFIG_MACH_PCA100) += pca100.o
+diff --git a/arch/arm/mach-mx2/pca100.c b/arch/arm/mach-mx2/pca100.c
+new file mode 100644
+index 0000000..fe5b165
+--- /dev/null
++++ b/arch/arm/mach-mx2/pca100.c
+@@ -0,0 +1,244 @@
++/*
++ * Copyright 2007 Robert Schwebel <r.schwebel at pengutronix.de>, Pengutronix
++ * Copyright (C) 2009 Sascha Hauer (kernel at pengutronix.de)
++ *
++ * 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., 51 Franklin Street, Fifth Floor, Boston,
++ * MA 02110-1301, USA.
++ */
++
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/i2c.h>
++#include <linux/i2c/at24.h>
++#include <linux/dma-mapping.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/eeprom.h>
++#include <linux/irq.h>
++#include <linux/gpio.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach-types.h>
++#include <mach/common.h>
++#include <mach/hardware.h>
++#include <mach/iomux.h>
++#include <mach/i2c.h>
++#include <asm/mach/time.h>
++#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
++#include <mach/spi.h>
++#endif
++#include <mach/imx-uart.h>
++#include <mach/mxc_nand.h>
++#include <mach/irqs.h>
++#include <mach/mmc.h>
++
++#include "devices.h"
++
++static int pca100_pins[] = {
++	/* UART1 */
++	PE12_PF_UART1_TXD,
++	PE13_PF_UART1_RXD,
++	PE14_PF_UART1_CTS,
++	PE15_PF_UART1_RTS,
++	/* SDHC */
++	PB4_PF_SD2_D0,
++	PB5_PF_SD2_D1,
++	PB6_PF_SD2_D2,
++	PB7_PF_SD2_D3,
++	PB8_PF_SD2_CMD,
++	PB9_PF_SD2_CLK,
++	/* FEC */
++	PD0_AIN_FEC_TXD0,
++	PD1_AIN_FEC_TXD1,
++	PD2_AIN_FEC_TXD2,
++	PD3_AIN_FEC_TXD3,
++	PD4_AOUT_FEC_RX_ER,
++	PD5_AOUT_FEC_RXD1,
++	PD6_AOUT_FEC_RXD2,
++	PD7_AOUT_FEC_RXD3,
++	PD8_AF_FEC_MDIO,
++	PD9_AIN_FEC_MDC,
++	PD10_AOUT_FEC_CRS,
++	PD11_AOUT_FEC_TX_CLK,
++	PD12_AOUT_FEC_RXD0,
++	PD13_AOUT_FEC_RX_DV,
++	PD14_AOUT_FEC_RX_CLK,
++	PD15_AOUT_FEC_COL,
++	PD16_AIN_FEC_TX_ER,
++	PF23_AIN_FEC_TX_EN,
++	/* SSI1 */
++	PC20_PF_SSI1_FS,
++	PC21_PF_SSI1_RXD,
++	PC22_PF_SSI1_TXD,
++	PC23_PF_SSI1_CLK,
++	/* onboard I2C */
++	PC5_PF_I2C2_SDA,
++	PC6_PF_I2C2_SCL,
++	/* external I2C */
++	PD17_PF_I2C_DATA,
++	PD18_PF_I2C_CLK,
++	/* SPI1 */
++	PD25_PF_CSPI1_RDY,
++	PD29_PF_CSPI1_SCLK,
++	PD30_PF_CSPI1_MISO,
++	PD31_PF_CSPI1_MOSI,
++};
++
++static struct imxuart_platform_data uart_pdata = {
++	.flags = IMXUART_HAVE_RTSCTS,
++};
++
++static struct mxc_nand_platform_data pca100_nand_board_info = {
++	.width = 1,
++	.hw_ecc = 1,
++};
++
++static struct platform_device *platform_devices[] __initdata = {
++	&mxc_w1_master_device,
++	&mxc_fec_device,
++};
++
++static struct imxi2c_platform_data pca100_i2c_1_data = {
++	.bitrate = 100000,
++};
++
++static struct at24_platform_data board_eeprom = {
++	.byte_len = 4096,
++	.page_size = 32,
++	.flags = AT24_FLAG_ADDR16,
++};
++
++static struct i2c_board_info pca100_i2c_devices[] = {
++	{
++		I2C_BOARD_INFO("at24", 0x52), /* E0=0, E1=1, E2=0 */
++		.platform_data = &board_eeprom,
++	}, {
++		I2C_BOARD_INFO("rtc-pcf8563", 0x51),
++		.type = "pcf8563"
++	}, {
++		I2C_BOARD_INFO("lm75", 0x4a),
++		.type = "lm75"
++	}
++};
++
++#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
++static struct spi_eeprom at25320 = {
++	.name		= "at25320an",
++	.byte_len	= 4096,
++	.page_size	= 32,
++	.flags		= EE_ADDR2,
++};
++
++static struct spi_board_info pca100_spi_board_info[] __initdata = {
++	{
++		.modalias = "at25",
++		.max_speed_hz = 30000,
++		.bus_num = 0,
++		.chip_select = 1,
++		.platform_data = &at25320,
++	},
++};
++
++static int pca100_spi_cs[] = {GPIO_PORTD + 28, GPIO_PORTD + 27};
++
++static struct spi_imx_master pca100_spi_0_data = {
++	.chipselect	= pca100_spi_cs,
++	.num_chipselect = ARRAY_SIZE(pca100_spi_cs),
++};
++#endif
++
++static int pca100_sdhc2_init(struct device *dev, irq_handler_t detect_irq,
++		void *data)
++{
++	int ret;
++
++	ret = request_irq(IRQ_GPIOC(29), detect_irq,
++			  IRQF_DISABLED | IRQF_TRIGGER_FALLING,
++			  "imx-mmc-detect", data);
++	if (ret)
++		printk(KERN_ERR
++			"pca100: Failed to reuest irq for sd/mmc detection\n");
++
++	return ret;
++}
++
++static void pca100_sdhc2_exit(struct device *dev, void *data)
++{
++	free_irq(IRQ_GPIOC(29), data);
++}
++
++static struct imxmmc_platform_data sdhc_pdata = {
++	.init = pca100_sdhc2_init,
++	.exit = pca100_sdhc2_exit,
++};
++
++static void __init pca100_init(void)
++{
++	int ret;
++
++	ret = mxc_gpio_setup_multiple_pins(pca100_pins,
++			ARRAY_SIZE(pca100_pins), "PCA100");
++	if (ret)
++		printk(KERN_ERR "pca100: Failed to setup pins (%d)\n", ret);
++
++	mxc_register_device(&mxc_uart_device0, &uart_pdata);
++
++	mxc_gpio_mode(GPIO_PORTC | 29 | GPIO_GPIO | GPIO_IN);
++	mxc_register_device(&mxc_sdhc_device1, &sdhc_pdata);
++
++	mxc_register_device(&mxc_nand_device, &pca100_nand_board_info);
++
++	/* only the i2c master 1 is used on this CPU card */
++	i2c_register_board_info(1, pca100_i2c_devices,
++				ARRAY_SIZE(pca100_i2c_devices));
++
++	mxc_register_device(&mxc_i2c_device1, &pca100_i2c_1_data);
++
++	mxc_gpio_mode(GPIO_PORTD | 28 | GPIO_GPIO | GPIO_OUT);
++	mxc_gpio_mode(GPIO_PORTD | 27 | GPIO_GPIO | GPIO_OUT);
++
++	/* GPIO0_IRQ */
++	mxc_gpio_mode(GPIO_PORTC | 31 | GPIO_GPIO | GPIO_IN);
++	/* GPIO1_IRQ */
++	mxc_gpio_mode(GPIO_PORTC | 25 | GPIO_GPIO | GPIO_IN);
++	/* GPIO2_IRQ */
++	mxc_gpio_mode(GPIO_PORTE | 5 | GPIO_GPIO | GPIO_IN);
++
++#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
++	spi_register_board_info(pca100_spi_board_info,
++				ARRAY_SIZE(pca100_spi_board_info));
++	mxc_register_device(&mxc_spi_device0, &pca100_spi_0_data);
++#endif
++
++	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
++}
++
++static void __init pca100_timer_init(void)
++{
++	mx27_clocks_init(26000000);
++}
++
++static struct sys_timer pca100_timer = {
++	.init = pca100_timer_init,
++};
++
++MACHINE_START(PCA100, "phyCARD-i.MX27")
++	.phys_io        = AIPI_BASE_ADDR,
++	.io_pg_offst    = ((AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
++	.boot_params    = PHYS_OFFSET + 0x100,
++	.map_io         = mx27_map_io,
++	.init_irq       = mxc_init_irq,
++	.init_machine   = pca100_init,
++	.timer          = &pca100_timer,
++MACHINE_END
++
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0019-mxc_nand-use-DRIVER_NAME-where-appropriate.patch b/recipes/linux/linux-2.6.31/pcm043/0019-mxc_nand-use-DRIVER_NAME-where-appropriate.patch
new file mode 100644
index 0000000..919ea3c
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0019-mxc_nand-use-DRIVER_NAME-where-appropriate.patch
@@ -0,0 +1,35 @@
+From b3fc73608b3fee8aa3dbccf4826fe21ffa69850b Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Wed, 21 Oct 2009 16:06:27 +0200
+Subject: [PATCH] mxc_nand: use DRIVER_NAME where appropriate
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ drivers/mtd/nand/mxc_nand.c |    4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
+index dd80e88..d5445cd 100644
+--- a/drivers/mtd/nand/mxc_nand.c
++++ b/drivers/mtd/nand/mxc_nand.c
+@@ -698,7 +698,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 	mtd->priv = this;
+ 	mtd->owner = THIS_MODULE;
+ 	mtd->dev.parent = &pdev->dev;
+-	mtd->name = "mxc_nand";
++	mtd->name = DRIVER_NAME;
+ 
+ 	/* 50 us command delay time */
+ 	this->chip_delay = 5;
+@@ -762,7 +762,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
+ 
+ 	host->irq = platform_get_irq(pdev, 0);
+ 
+-	err = request_irq(host->irq, mxc_nfc_irq, 0, "mxc_nd", host);
++	err = request_irq(host->irq, mxc_nfc_irq, 0, DRIVER_NAME, host);
+ 	if (err)
+ 		goto eirq;
+ 
+-- 
+1.6.0.4
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0020-MX2-Add-SPI-devices-resources.patch b/recipes/linux/linux-2.6.31/pcm043/0020-MX2-Add-SPI-devices-resources.patch
new file mode 100644
index 0000000..45142f7
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0020-MX2-Add-SPI-devices-resources.patch
@@ -0,0 +1,92 @@
+From 0e60c1eae435eee1188d751f29802ce1cce61021 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Fri, 19 Dec 2008 14:32:14 +0100
+Subject: [PATCH 20/28] MX2: Add SPI devices/resources
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/mach-mx2/devices.c |   68 +++++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 68 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-mx2/devices.c b/arch/arm/mach-mx2/devices.c
+index f877baa..39cd74f 100644
+--- a/arch/arm/mach-mx2/devices.c
++++ b/arch/arm/mach-mx2/devices.c
+@@ -64,6 +64,74 @@ struct platform_device mxc_irda_device = {
+ };
+ 
+ /*
++ * SPI master controller
++ *
++ * - i.MX1: 2 channel (slighly different register setting)
++ * - i.MX21: 2 channel
++ * - i.MX27: 3 channel
++ */
++static struct resource mxc_spi_resources0[] = {
++	{
++	       .start = CSPI1_BASE_ADDR,
++	       .end = CSPI1_BASE_ADDR + SZ_4K - 1,
++	       .flags = IORESOURCE_MEM,
++	}, {
++	       .start = MXC_INT_CSPI1,
++	       .end = MXC_INT_CSPI1,
++	       .flags = IORESOURCE_IRQ,
++	},
++};
++
++static struct resource mxc_spi_resources1[] = {
++	{
++		.start = CSPI2_BASE_ADDR,
++		.end = CSPI2_BASE_ADDR + SZ_4K - 1,
++		.flags = IORESOURCE_MEM,
++	}, {
++		.start = MXC_INT_CSPI2,
++		.end = MXC_INT_CSPI2,
++		.flags = IORESOURCE_IRQ,
++	},
++};
++
++#ifdef CONFIG_MACH_MX27
++static struct resource mxc_spi_resources2[] = {
++	{
++		.start = CSPI3_BASE_ADDR,
++		.end = CSPI3_BASE_ADDR + SZ_4K - 1,
++		.flags = IORESOURCE_MEM,
++	}, {
++		.start = MXC_INT_CSPI3,
++		.end = MXC_INT_CSPI3,
++		.flags = IORESOURCE_IRQ,
++	},
++};
++#endif
++
++struct platform_device mxc_spi_device0 = {
++	.name = "spi_imx",
++	.id = 0,
++	.num_resources = ARRAY_SIZE(mxc_spi_resources0),
++	.resource = mxc_spi_resources0,
++};
++
++struct platform_device mxc_spi_device1 = {
++	.name = "spi_imx",
++	.id = 1,
++	.num_resources = ARRAY_SIZE(mxc_spi_resources1),
++	.resource = mxc_spi_resources1,
++};
++
++#ifdef CONFIG_MACH_MX27
++struct platform_device mxc_spi_device2 = {
++	.name = "spi_imx",
++	.id = 2,
++	.num_resources = ARRAY_SIZE(mxc_spi_resources2),
++	.resource = mxc_spi_resources2,
++};
++#endif
++
++/*
+  * General Purpose Timer
+  * - i.MX1: 2 timer (slighly different register handling)
+  * - i.MX21: 3 timer
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0021-Early-printk.patch b/recipes/linux/linux-2.6.31/pcm043/0021-Early-printk.patch
new file mode 100644
index 0000000..24f2264
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0021-Early-printk.patch
@@ -0,0 +1,106 @@
+From 286132d92272ffb0ae06ec3ecbe0cb3cfbd611c3 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Thu, 29 Jan 2009 16:39:15 +0100
+Subject: [PATCH 021/101] Early printk
+
+Hi,
+
+Below is a patch which I have in my repository for some time now. It
+adds an early console using the printch function. Unlike the printk
+patch this one does not require patching the kernel and you do not get
+duplicated kernel output lines. I don't know if this solution starts to
+work at a later point than the printk patch, but it has proven useful in
+several situations now. What do you think?
+
+Sascha
+
+commit 57242f4143c9ce48e3c49ddf3b206f780184991c
+Author: Sascha Hauer <s.hauer at pengutronix.de>
+Date:   Thu Jan 29 16:32:30 2009 +0100
+
+    [ARM] Add an early debug console
+
+    Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+
+rebased to  2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel at phytec.de>
+---
+ arch/arm/Kconfig.debug         |    8 ++++++++
+ arch/arm/kernel/Makefile       |    1 +
+ arch/arm/kernel/early_printk.c |   38 ++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 47 insertions(+), 0 deletions(-)
+ create mode 100644 arch/arm/kernel/early_printk.c
+
+Index: linux-2.6.31.6/arch/arm/Kconfig.debug
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/Kconfig.debug	2009-12-07 15:58:21.683889680 +0100
++++ linux-2.6.31.6/arch/arm/Kconfig.debug	2009-12-07 16:00:33.757198435 +0100
+@@ -70,6 +70,14 @@
+ 	  in the kernel.  This is helpful if you are debugging code that
+ 	  executes before the console is initialized.
+ 
++config DEBUG_LL_CONSOLE
++	bool "Kernel early console"
++	depends on DEBUG_LL
++	help
++	  Say Y here if you want to have an early console using the Kernel
++	  low-level debugging functions. Add earlyprintk to your kernel
++	  parameters to enable this console.
++
+ config DEBUG_ICEDCC
+ 	bool "Kernel low-level debugging via EmbeddedICE DCC channel"
+ 	depends on DEBUG_LL
+Index: linux-2.6.31.6/arch/arm/kernel/Makefile
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/kernel/Makefile	2009-12-07 15:58:21.673849262 +0100
++++ linux-2.6.31.6/arch/arm/kernel/Makefile	2009-12-07 16:00:33.757198435 +0100
+@@ -49,5 +49,6 @@
+ 
+ head-y			:= head$(MMUEXT).o
+ obj-$(CONFIG_DEBUG_LL)	+= debug.o
++obj-$(CONFIG_DEBUG_LL_CONSOLE)	+= early_printk.o
+ 
+ extra-y := $(head-y) init_task.o vmlinux.lds
+Index: linux-2.6.31.6/arch/arm/kernel/early_printk.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.31.6/arch/arm/kernel/early_printk.c	2009-12-07 16:00:33.757198435 +0100
+@@ -0,0 +1,38 @@
++/*
++ *  linux/arch/arm/kernel/early_printk.c
++ *
++ *  Copyright (C) 2009 Sascha Hauer <s.hauer at 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.
++ */
++#include <linux/console.h>
++#include <linux/init.h>
++
++extern void printch(int);
++
++static void early_serial_write(struct console *con, const char *s, unsigned n)
++{
++	while (*s && n-- > 0) {
++		if (*s == '\n')
++			printch('\r');
++		printch(*s);
++		s++;
++	}
++}
++
++static struct console early_serial_console = {
++	.name =		"earlyser",
++	.write =	early_serial_write,
++	.flags =	CON_PRINTBUFFER | CON_BOOT,
++	.index =	-1,
++};
++
++static int __init setup_early_printk(char *buf)
++{
++	register_console(&early_serial_console);
++	return 0;
++}
++
++early_param("earlyprintk", setup_early_printk);
diff --git a/recipes/linux/linux-2.6.31/pcm043/0021-mxc-mx1-mx2-DMA-add-a-possibility-to-create-an-endle.patch b/recipes/linux/linux-2.6.31/pcm043/0021-mxc-mx1-mx2-DMA-add-a-possibility-to-create-an-endle.patch
new file mode 100644
index 0000000..026d9d5
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0021-mxc-mx1-mx2-DMA-add-a-possibility-to-create-an-endle.patch
@@ -0,0 +1,50 @@
+From 5e93e22102052940681b45b6e3ec5d037983e256 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Wed, 18 Nov 2009 15:21:44 +0100
+Subject: [PATCH 21/28] mxc: mx1/mx2 DMA: add a possibility to create an endless DMA transfer
+
+This is useful for audio where we do not want to setup a new scatterlist
+after playing 4GB of audio data. This would cause skips in the playback.
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/plat-mxc/dma-mx1-mx2.c              |    3 ++-
+ arch/arm/plat-mxc/include/mach/dma-mx1-mx2.h |    8 ++++++++
+ 2 files changed, 10 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/plat-mxc/dma-mx1-mx2.c b/arch/arm/plat-mxc/dma-mx1-mx2.c
+index 7764643..9c1b3f9 100644
+--- a/arch/arm/plat-mxc/dma-mx1-mx2.c
++++ b/arch/arm/plat-mxc/dma-mx1-mx2.c
+@@ -156,7 +156,8 @@ static inline int imx_dma_sg_next(int channel, struct scatterlist *sg)
+ 	}
+ 
+ 	now = min(imxdma->resbytes, sg->length);
+-	imxdma->resbytes -= now;
++	if (imxdma->resbytes != IMX_DMA_LENGTH_LOOP)
++		imxdma->resbytes -= now;
+ 
+ 	if ((imxdma->dma_mode & DMA_MODE_MASK) == DMA_MODE_READ)
+ 		__raw_writel(sg->dma_address, DMA_BASE + DMA_DAR(channel));
+diff --git a/arch/arm/plat-mxc/include/mach/dma-mx1-mx2.h b/arch/arm/plat-mxc/include/mach/dma-mx1-mx2.h
+index b3876cc..07be8ad 100644
+--- a/arch/arm/plat-mxc/include/mach/dma-mx1-mx2.h
++++ b/arch/arm/plat-mxc/include/mach/dma-mx1-mx2.h
+@@ -58,6 +58,14 @@ imx_dma_setup_single(int channel, dma_addr_t dma_address,
+ 		unsigned int dma_length, unsigned int dev_addr,
+ 		unsigned int dmamode);
+ 
++
++/*
++ * Use this flag as the dma_length argument to imx_dma_setup_sg()
++ * to create an endless running dma loop. The end of the scatterlist
++ * must be linked to the beginning for this to work.
++ */
++#define IMX_DMA_LENGTH_LOOP	((unsigned int)-1)
++
+ int
+ imx_dma_setup_sg(int channel, struct scatterlist *sg,
+ 		unsigned int sgcount, unsigned int dma_length,
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0022-ASoC-Allow-32-bit-registers-for-DAPM.patch b/recipes/linux/linux-2.6.31/pcm043/0022-ASoC-Allow-32-bit-registers-for-DAPM.patch
new file mode 100644
index 0000000..af34209
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0022-ASoC-Allow-32-bit-registers-for-DAPM.patch
@@ -0,0 +1,203 @@
+From f3f4462475d2c86023f7d48c40359d925730ee1b Mon Sep 17 00:00:00 2001
+From: Daniel Ribeiro <drwyrm at gmail.com>
+Date: Sun, 7 Jun 2009 02:49:11 -0300
+Subject: [PATCH 22/28] ASoC: Allow 32 bit registers for DAPM
+
+Replace the remaining unsigned shorts with unsigned ints.
+Tested with pcap2 codec (25 bits registers).
+
+Signed-off-by: Daniel Ribeiro <drwyrm at gmail.com>
+Signed-off-by: Mark Brown <broonie at opensource.wolfsonmicro.com>
+---
+ include/sound/soc.h  |    4 ++--
+ sound/soc/soc-core.c |   28 ++++++++++++++--------------
+ sound/soc/soc-dapm.c |   16 ++++++++--------
+ 3 files changed, 24 insertions(+), 24 deletions(-)
+
+diff --git a/include/sound/soc.h b/include/sound/soc.h
+index cf6111d..a167b49 100644
+--- a/include/sound/soc.h
++++ b/include/sound/soc.h
+@@ -216,9 +216,9 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
+ 
+ /* codec register bit access */
+ int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
+-				unsigned short mask, unsigned short value);
++				unsigned int mask, unsigned int value);
+ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
+-				unsigned short mask, unsigned short value);
++				unsigned int mask, unsigned int value);
+ 
+ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
+ 	struct snd_ac97_bus_ops *ops, int num);
+diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
+index 1d70829..9b88c74 100644
+--- a/sound/soc/soc-core.c
++++ b/sound/soc/soc-core.c
+@@ -1264,10 +1264,10 @@ EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
+  * Returns 1 for change else 0.
+  */
+ int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
+-				unsigned short mask, unsigned short value)
++				unsigned int mask, unsigned int value)
+ {
+ 	int change;
+-	unsigned short old, new;
++	unsigned int old, new;
+ 
+ 	mutex_lock(&io_mutex);
+ 	old = snd_soc_read(codec, reg);
+@@ -1294,10 +1294,10 @@ EXPORT_SYMBOL_GPL(snd_soc_update_bits);
+  * Returns 1 for change else 0.
+  */
+ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
+-				unsigned short mask, unsigned short value)
++				unsigned int mask, unsigned int value)
+ {
+ 	int change;
+-	unsigned short old, new;
++	unsigned int old, new;
+ 
+ 	mutex_lock(&io_mutex);
+ 	old = snd_soc_read(codec, reg);
+@@ -1586,7 +1586,7 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
+ {
+ 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+-	unsigned short val, bitmask;
++	unsigned int val, bitmask;
+ 
+ 	for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
+ 		;
+@@ -1615,8 +1615,8 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
+ {
+ 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+-	unsigned short val;
+-	unsigned short mask, bitmask;
++	unsigned int val;
++	unsigned int mask, bitmask;
+ 
+ 	for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
+ 		;
+@@ -1652,7 +1652,7 @@ int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol,
+ {
+ 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+-	unsigned short reg_val, val, mux;
++	unsigned int reg_val, val, mux;
+ 
+ 	reg_val = snd_soc_read(codec, e->reg);
+ 	val = (reg_val >> e->shift_l) & e->mask;
+@@ -1691,8 +1691,8 @@ int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol,
+ {
+ 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+-	unsigned short val;
+-	unsigned short mask;
++	unsigned int val;
++	unsigned int mask;
+ 
+ 	if (ucontrol->value.enumerated.item[0] > e->max - 1)
+ 		return -EINVAL;
+@@ -1852,7 +1852,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
+ 	int max = mc->max;
+ 	unsigned int mask = (1 << fls(max)) - 1;
+ 	unsigned int invert = mc->invert;
+-	unsigned short val, val2, val_mask;
++	unsigned int val, val2, val_mask;
+ 
+ 	val = (ucontrol->value.integer.value[0] & mask);
+ 	if (invert)
+@@ -1918,7 +1918,7 @@ int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
+ 	unsigned int reg2 = mc->rreg;
+ 	unsigned int shift = mc->shift;
+ 	int max = mc->max;
+-	unsigned int mask = (1<<fls(max))-1;
++	unsigned int mask = (1 << fls(max)) - 1;
+ 	unsigned int invert = mc->invert;
+ 
+ 	ucontrol->value.integer.value[0] =
+@@ -1958,7 +1958,7 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
+ 	unsigned int mask = (1 << fls(max)) - 1;
+ 	unsigned int invert = mc->invert;
+ 	int err;
+-	unsigned short val, val2, val_mask;
++	unsigned int val, val2, val_mask;
+ 
+ 	val_mask = mask << shift;
+ 	val = (ucontrol->value.integer.value[0] & mask);
+@@ -2050,7 +2050,7 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
+ 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ 	unsigned int reg = mc->reg;
+ 	int min = mc->min;
+-	unsigned short val;
++	unsigned int val;
+ 
+ 	val = (ucontrol->value.integer.value[0]+min) & 0xff;
+ 	val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8;
+diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
+index 21c6907..7ad8afa 100644
+--- a/sound/soc/soc-dapm.c
++++ b/sound/soc/soc-dapm.c
+@@ -268,7 +268,7 @@ static int dapm_connect_mixer(struct snd_soc_codec *codec,
+ static int dapm_update_bits(struct snd_soc_dapm_widget *widget)
+ {
+ 	int change, power;
+-	unsigned short old, new;
++	unsigned int old, new;
+ 	struct snd_soc_codec *codec = widget->codec;
+ 
+ 	/* check for valid widgets */
+@@ -1372,7 +1372,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
+ 	int max = mc->max;
+ 	unsigned int mask = (1 << fls(max)) - 1;
+ 	unsigned int invert = mc->invert;
+-	unsigned short val, val2, val_mask;
++	unsigned int val, val2, val_mask;
+ 	int ret;
+ 
+ 	val = (ucontrol->value.integer.value[0] & mask);
+@@ -1436,7 +1436,7 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
+ {
+ 	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+ 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+-	unsigned short val, bitmask;
++	unsigned int val, bitmask;
+ 
+ 	for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
+ 		;
+@@ -1464,8 +1464,8 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
+ {
+ 	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+ 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+-	unsigned short val, mux;
+-	unsigned short mask, bitmask;
++	unsigned int val, mux;
++	unsigned int mask, bitmask;
+ 	int ret = 0;
+ 
+ 	for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
+@@ -1523,7 +1523,7 @@ int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
+ {
+ 	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+ 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+-	unsigned short reg_val, val, mux;
++	unsigned int reg_val, val, mux;
+ 
+ 	reg_val = snd_soc_read(widget->codec, e->reg);
+ 	val = (reg_val >> e->shift_l) & e->mask;
+@@ -1563,8 +1563,8 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
+ {
+ 	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+ 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+-	unsigned short val, mux;
+-	unsigned short mask;
++	unsigned int val, mux;
++	unsigned int mask;
+ 	int ret = 0;
+ 
+ 	if (ucontrol->value.enumerated.item[0] > e->max - 1)
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0023-pca100-add-sound-support.patch b/recipes/linux/linux-2.6.31/pcm043/0023-pca100-add-sound-support.patch
new file mode 100644
index 0000000..623d80a
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0023-pca100-add-sound-support.patch
@@ -0,0 +1,99 @@
+From f58f54a10075e0ff2d952b9264ce880c1ecbf439 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Fri, 6 Nov 2009 15:29:58 +0100
+Subject: [PATCH 23/28] pca100: add sound support
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/mach-mx2/pca100.c |   52 ++++++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 52 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-mx2/pca100.c b/arch/arm/mach-mx2/pca100.c
+index fe5b165..e0a464d 100644
+--- a/arch/arm/mach-mx2/pca100.c
++++ b/arch/arm/mach-mx2/pca100.c
+@@ -26,6 +26,7 @@
+ #include <linux/spi/eeprom.h>
+ #include <linux/irq.h>
+ #include <linux/gpio.h>
++#include <linux/delay.h>
+ 
+ #include <asm/mach/arch.h>
+ #include <asm/mach-types.h>
+@@ -41,6 +42,8 @@
+ #include <mach/mxc_nand.h>
+ #include <mach/irqs.h>
+ #include <mach/mmc.h>
++#include <mach/audmux.h>
++#include <mach/ssi.h>
+ 
+ #include "devices.h"
+ 
+@@ -182,15 +185,64 @@ static struct imxmmc_platform_data sdhc_pdata = {
+ 	.exit = pca100_sdhc2_exit,
+ };
+ 
++static void pca100_ac97_warm_reset(struct snd_ac97 *ac97)
++{
++	printk("%s\n", __func__);
++
++	mxc_gpio_mode(GPIO_PORTC | 20 | GPIO_GPIO | GPIO_OUT);
++	gpio_set_value(GPIO_PORTC + 20, 1);
++	udelay(2);
++	gpio_set_value(GPIO_PORTC + 20, 0);
++	mxc_gpio_mode(PC20_PF_SSI1_FS);
++	msleep(2);
++}
++
++static void pca100_ac97_cold_reset(struct snd_ac97 *ac97)
++{
++	printk("%s\n", __func__);
++
++	mxc_gpio_mode(GPIO_PORTC | 20 | GPIO_GPIO | GPIO_OUT);  /* FS */
++	gpio_set_value(GPIO_PORTC + 20, 0);
++	mxc_gpio_mode(GPIO_PORTC | 22 | GPIO_GPIO | GPIO_OUT);  /* TX */
++	gpio_set_value(GPIO_PORTC + 22, 0);
++	mxc_gpio_mode(GPIO_PORTC | 28 | GPIO_GPIO | GPIO_OUT);  /* reset */
++	gpio_set_value(GPIO_PORTC + 28, 0);
++	udelay(10);
++	gpio_set_value(GPIO_PORTC + 28, 1);
++	mxc_gpio_mode(PC20_PF_SSI1_FS);
++	mxc_gpio_mode(PC22_PF_SSI1_TXD);
++	msleep(2);
++}
++
++static struct imx_ssi_platform_data pca100_ssi_pdata = {
++	.ac97_reset		= pca100_ac97_cold_reset,
++	.ac97_warm_reset	= pca100_ac97_warm_reset,
++	.flags			= IMX_SSI_USE_AC97,
++};
++
+ static void __init pca100_init(void)
+ {
+ 	int ret;
+ 
++	/* SSI unit */
++	mxc_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
++				  MXC_AUDMUX_V1_PCR_SYN | /* 4wire mode */
++				  MXC_AUDMUX_V1_PCR_TFCSEL(3) |
++				  MXC_AUDMUX_V1_PCR_TCLKDIR | /* clock is output */
++				  MXC_AUDMUX_V1_PCR_RXDSEL(3));
++	mxc_audmux_v1_configure_port(4,
++				  MXC_AUDMUX_V1_PCR_SYN | /* 4wire mode */
++				  MXC_AUDMUX_V1_PCR_TFCSEL(0) |
++				  MXC_AUDMUX_V1_PCR_TFSDIR |
++				  MXC_AUDMUX_V1_PCR_RXDSEL(0));
++
+ 	ret = mxc_gpio_setup_multiple_pins(pca100_pins,
+ 			ARRAY_SIZE(pca100_pins), "PCA100");
+ 	if (ret)
+ 		printk(KERN_ERR "pca100: Failed to setup pins (%d)\n", ret);
+ 
++	mxc_register_device(&imx_ssi_device0, &pca100_ssi_pdata);
++
+ 	mxc_register_device(&mxc_uart_device0, &uart_pdata);
+ 
+ 	mxc_gpio_mode(GPIO_PORTC | 29 | GPIO_GPIO | GPIO_IN);
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0024-MX31-Clock-updates.patch b/recipes/linux/linux-2.6.31/pcm043/0024-MX31-Clock-updates.patch
new file mode 100644
index 0000000..9bb85dd
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0024-MX31-Clock-updates.patch
@@ -0,0 +1,40 @@
+From f9a58060254e1c7d6d2bedf6044577aa61885ca3 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Fri, 20 Mar 2009 19:25:01 +0100
+Subject: [PATCH 024/101] MX31 Clock updates
+
+- register correct ehci clocks
+- update spi clock names
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+
+rebased to  2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel at phytec.de>
+---
+ arch/arm/mach-mx3/clock.c |   12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+Index: arch/arm/mach-mx3/clock.c
+===================================================================
+--- arch/arm/mach-mx3/clock.c.orig	2009-12-07 15:20:31.943942228 +0100
++++ arch/arm/mach-mx3/clock.c	2009-12-07 16:10:37.774566402 +0100
+@@ -523,7 +523,7 @@
+ 	_REGISTER_CLOCK("spi_imx.2", NULL, cspi3_clk)
+ 	_REGISTER_CLOCK(NULL, "gpt", gpt_clk)
+ 	_REGISTER_CLOCK(NULL, "pwm", pwm_clk)
+-	_REGISTER_CLOCK(NULL, "wdog", wdog_clk)
++	_REGISTER_CLOCK("imx-wdt.0", NULL, wdog_clk)
+ 	_REGISTER_CLOCK(NULL, "rtc", rtc_clk)
+ 	_REGISTER_CLOCK(NULL, "epit", epit1_clk)
+ 	_REGISTER_CLOCK(NULL, "epit", epit2_clk)
+@@ -531,6 +531,10 @@
+ 	_REGISTER_CLOCK("ipu-core", NULL, ipu_clk)
+ 	_REGISTER_CLOCK("mx3_sdc_fb", NULL, ipu_clk)
+ 	_REGISTER_CLOCK(NULL, "kpp", kpp_clk)
++	/* FIXME: mxc-ehci now misses the secondary clock */
++	_REGISTER_CLOCK("mxc-ehci.0", NULL, usb_clk1)
++	_REGISTER_CLOCK("mxc-ehci.1", NULL, usb_clk1)
++	_REGISTER_CLOCK("mxc-ehci.2", NULL, usb_clk1)
+ 	_REGISTER_CLOCK("fsl-usb2-udc", "usb", usb_clk1)
+ 	_REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", usb_clk2)
+ 	_REGISTER_CLOCK("mx3-camera.0", NULL, csi_clk)
diff --git a/recipes/linux/linux-2.6.31/pcm043/0024-pcm038-add-sound-support.patch b/recipes/linux/linux-2.6.31/pcm043/0024-pcm038-add-sound-support.patch
new file mode 100644
index 0000000..bebcb3a
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0024-pcm038-add-sound-support.patch
@@ -0,0 +1,72 @@
+From 76c72535c2ae04d10a52c1958add9a08b97a11be Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Fri, 6 Nov 2009 09:45:42 +0100
+Subject: [PATCH 24/28] pcm038: add sound support
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/mach-mx2/pcm038.c |   23 ++++++++++++++++++++++-
+ 1 files changed, 22 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/mach-mx2/pcm038.c b/arch/arm/mach-mx2/pcm038.c
+index b3a8ed8..b0c38b9 100644
+--- a/arch/arm/mach-mx2/pcm038.c
++++ b/arch/arm/mach-mx2/pcm038.c
+@@ -39,7 +39,9 @@
+ #include <mach/iomux.h>
+ #include <mach/imx-uart.h>
+ #include <mach/mxc_nand.h>
++#include <mach/audmux.h>
+ #include <mach/spi.h>
++#include <mach/ssi.h>
+ 
+ #include "devices.h"
+ 
+@@ -268,7 +270,7 @@ static struct mc13783_platform_data pcm038_pmic = {
+ 	.regulators = pcm038_regulators,
+ 	.num_regulators = ARRAY_SIZE(pcm038_regulators),
+ 	.flags = MC13783_USE_ADC | MC13783_USE_REGULATOR |
+-		 MC13783_USE_TOUCHSCREEN,
++		 MC13783_USE_TOUCHSCREEN | MC13783_USE_CODEC,
+ };
+ 
+ static struct spi_board_info pcm038_spi_board_info[] __initdata = {
+@@ -283,16 +285,35 @@ static struct spi_board_info pcm038_spi_board_info[] __initdata = {
+ 	}
+ };
+ 
++struct imx_ssi_platform_data pcm038_ssi_pdata = {
++	.flags = IMX_SSI_DMA,
++};
++
+ static void __init pcm038_init(void)
+ {
+ 	mxc_gpio_setup_multiple_pins(pcm038_pins, ARRAY_SIZE(pcm038_pins),
+ 			"PCM038");
+ 
++	mxc_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
++		MXC_AUDMUX_V1_PCR_TFSDIR |
++		MXC_AUDMUX_V1_PCR_TCLKDIR |
++		MXC_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1) |
++		MXC_AUDMUX_V1_PCR_RFSDIR |
++		MXC_AUDMUX_V1_PCR_RCLKDIR |
++		MXC_AUDMUX_V1_PCR_RFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) |
++		MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4));
++	mxc_audmux_v1_configure_port(MX27_AUDMUX_HPCR3_SSI_PINS_4,
++		MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0));
++	mxc_audmux_v1_configure_port(MX27_AUDMUX_PPCR1_SSI_PINS_1,
++		MXC_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_HPCR1_SSI0) |
++		MXC_AUDMUX_V1_PCR_RFCSEL(MX27_AUDMUX_HPCR1_SSI0));
++
+ 	pcm038_init_sram();
+ 
+ 	mxc_register_device(&mxc_uart_device0, &uart_pdata[0]);
+ 	mxc_register_device(&mxc_uart_device1, &uart_pdata[1]);
+ 	mxc_register_device(&mxc_uart_device2, &uart_pdata[2]);
++	mxc_register_device(&imx_ssi_device0, &pcm038_ssi_pdata);
+ 
+ 	mxc_gpio_mode(PE16_AF_OWIRE);
+ 	mxc_register_device(&mxc_nand_device, &pcm038_nand_board_info);
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0025-pcm037-Add-sound-support.patch b/recipes/linux/linux-2.6.31/pcm043/0025-pcm037-Add-sound-support.patch
new file mode 100644
index 0000000..cba390c
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0025-pcm037-Add-sound-support.patch
@@ -0,0 +1,144 @@
+From 8b4873639bb66d8269f0767ddfbb4c8a7f8082f7 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Thu, 12 Nov 2009 14:02:13 +0100
+Subject: [PATCH 25/28] pcm037: Add sound support
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/mach-mx3/pcm037.c |   71 ++++++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 71 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-mx3/pcm037.c b/arch/arm/mach-mx3/pcm037.c
+index 840cfda..8ef6c79 100644
+--- a/arch/arm/mach-mx3/pcm037.c
++++ b/arch/arm/mach-mx3/pcm037.c
+@@ -32,6 +32,7 @@
+ #include <linux/spi/spi.h>
+ #include <linux/irq.h>
+ #include <linux/fsl_devices.h>
++#include <linux/mfd/mc13783.h>
+ 
+ #include <media/soc_camera.h>
+ 
+@@ -50,6 +51,9 @@
+ #include <mach/mx3_camera.h>
+ #include <mach/mx3fb.h>
+ #include <mach/mxc_nand.h>
++#include <mach/spi.h>
++#include <mach/audmux.h>
++#include <mach/ssi.h>
+ 
+ #include "devices.h"
+ #include "pcm037.h"
+@@ -123,6 +127,8 @@ static unsigned int pcm037_pins[] = {
+ 	MX31_PIN_CSPI3_SPI_RDY__CTS3,
+ 	/* LAN9217 irq pin */
+ 	IOMUX_MODE(MX31_PIN_GPIO3_1, IOMUX_CONFIG_GPIO),
++	/* MC13783 IRQ pim */
++	IOMUX_MODE(MX31_PIN_GPIO3_0, IOMUX_CONFIG_GPIO),
+ 	/* Onewire */
+ 	MX31_PIN_BATT_LINE__OWIRE,
+ 	/* Framebuffer */
+@@ -169,6 +175,15 @@ static unsigned int pcm037_pins[] = {
+ 	MX31_PIN_CSI_MCLK__CSI_MCLK,
+ 	MX31_PIN_CSI_PIXCLK__CSI_PIXCLK,
+ 	MX31_PIN_CSI_VSYNC__CSI_VSYNC,
++	/* SSI */
++	MX31_PIN_STXD4__STXD4,
++	MX31_PIN_SRXD4__SRXD4,
++	MX31_PIN_SCK4__SCK4,
++	MX31_PIN_SFS4__SFS4,
++	MX31_PIN_STXD5__STXD5,
++	MX31_PIN_SRXD5__SRXD5,
++	MX31_PIN_SCK5__SCK5,
++	MX31_PIN_SFS5__SFS5,
+ };
+ 
+ static struct physmap_flash_data pcm037_flash_data = {
+@@ -406,6 +421,31 @@ static void pcm970_sdhc1_exit(struct device *dev, void *data)
+ 	gpio_free(SDHC1_GPIO_WP);
+ }
+ 
++#ifdef CONFIG_SPI
++static struct mc13783_platform_data pcm037_pmic = {
++	.flags = MC13783_USE_ADC | MC13783_USE_TOUCHSCREEN |
++		 MC13783_USE_CODEC,
++};
++
++static unsigned int pcm037_spi_cs[] = {MXC_SPI_CS(0), };
++
++static struct spi_imx_master pcm037_spi_0_data = {
++	.chipselect = pcm037_spi_cs,
++	.num_chipselect = ARRAY_SIZE(pcm037_spi_cs),
++};
++
++static struct spi_board_info pcm037_spi_board_info[] __initdata = {
++	{
++		.modalias	= "mc13783",
++		.irq		= IOMUX_TO_IRQ(MX31_PIN_GPIO3_0),
++		.max_speed_hz	= 3000000,
++		.bus_num	= 0,
++		.platform_data	= &pcm037_pmic,
++		.chip_select	= 0,
++	}
++};
++#endif /* CONFIG_SPI */
++
+ static struct imxmmc_platform_data sdhc_pdata = {
+ #ifdef PCM970_SDHC_RW_SWITCH
+ 	.get_ro = pcm970_sdhc1_get_ro,
+@@ -515,6 +555,9 @@ static struct mx3fb_platform_data mx3fb_pdata = {
+ 	.num_modes	= ARRAY_SIZE(fb_modedb),
+ };
+ 
++struct imx_ssi_platform_data pcm037_ssi_pdata = {
++};
++
+ /*
+  * Board specific initialization.
+  */
+@@ -522,6 +565,26 @@ static void __init mxc_board_init(void)
+ {
+ 	int ret;
+ 
++	mxc_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0,
++			MXC_AUDMUX_V2_PTCR_TFSDIR |
++			MXC_AUDMUX_V2_PTCR_TCLKDIR |
++			MXC_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
++			MXC_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
++			MXC_AUDMUX_V2_PTCR_RFSDIR |
++			MXC_AUDMUX_V2_PTCR_RCLKDIR |
++			MXC_AUDMUX_V2_PTCR_RFSEL(MX31_AUDMUX_PORT5_SSI_PINS_5) |
++			MXC_AUDMUX_V2_PTCR_RCSEL(MX31_AUDMUX_PORT5_SSI_PINS_5),
++			MXC_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT5_SSI_PINS_5));
++	mxc_audmux_v2_configure_port(MX31_AUDMUX_PORT5_SSI_PINS_5,
++			0,
++			MXC_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0));
++	mxc_audmux_v2_configure_port(MX31_AUDMUX_PORT4_SSI_PINS_4,
++			MXC_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT1_SSI0) |
++			MXC_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT1_SSI0) |
++			MXC_AUDMUX_V2_PTCR_RFSEL(MX31_AUDMUX_PORT1_SSI0) |
++			MXC_AUDMUX_V2_PTCR_RCSEL(MX31_AUDMUX_PORT1_SSI0),
++			0);
++
+ 	mxc_iomux_setup_multiple_pins(pcm037_pins, ARRAY_SIZE(pcm037_pins),
+ 			"pcm037");
+ 
+@@ -575,6 +638,14 @@ static void __init mxc_board_init(void)
+ 
+ 	if (!pcm037_camera_alloc_dma(4 * 1024 * 1024))
+ 		mxc_register_device(&mx3_camera, &camera_pdata);
++
++#ifdef CONFIG_SPI
++	mxc_register_device(&imx_spi_device0, &pcm037_spi_0_data);
++
++	spi_register_board_info(pcm037_spi_board_info,
++			ARRAY_SIZE(pcm037_spi_board_info));
++#endif
++	mxc_register_device(&imx_ssi_device0, &pcm037_ssi_pdata);
+ }
+ 
+ static void __init pcm037_timer_init(void)
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0026-imx-ssi-Fix-AC97-rates.patch b/recipes/linux/linux-2.6.31/pcm043/0026-imx-ssi-Fix-AC97-rates.patch
new file mode 100644
index 0000000..53b1a60
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0026-imx-ssi-Fix-AC97-rates.patch
@@ -0,0 +1,37 @@
+From da230ac4c6dce39cc85b95a08bceec2976288419 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Fri, 27 Nov 2009 16:28:59 +0100
+Subject: [PATCH 26/28] imx-ssi: Fix AC97 rates
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ sound/soc/imx/imx-ssi.c |    6 +++++-
+ 1 files changed, 5 insertions(+), 1 deletions(-)
+
+diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
+index 9823425..6219df9 100644
+--- a/sound/soc/imx/imx-ssi.c
++++ b/sound/soc/imx/imx-ssi.c
+@@ -453,6 +453,10 @@ struct snd_soc_platform imx_soc_platform = {
+ };
+ EXPORT_SYMBOL_GPL(imx_soc_platform);
+ 
++#define IMX_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
++		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
++		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
++
+ static struct snd_soc_dai imx_ac97_dai = {
+ 	.name = "AC97",
+ 	.ac97_control = 1,
+@@ -460,7 +464,7 @@ static struct snd_soc_dai imx_ac97_dai = {
+ 		.stream_name = "AC97 Playback",
+ 		.channels_min = 2,
+ 		.channels_max = 2,
+-		.rates = SND_SOC_STD_AC97_FMTS,
++		.rates = IMX_AC97_RATES,
+ 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+ 	},
+ 	.capture = {
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0027-Add-EHCI-support-for-MX27-and-MX31-based-boards.patch b/recipes/linux/linux-2.6.31/pcm043/0027-Add-EHCI-support-for-MX27-and-MX31-based-boards.patch
new file mode 100644
index 0000000..1c60690
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0027-Add-EHCI-support-for-MX27-and-MX31-based-boards.patch
@@ -0,0 +1,347 @@
+From ce297d614ab56284823043e1743200388d9f466f Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Mon, 9 Mar 2009 12:29:23 +0100
+Subject: [PATCH 027/101] Add EHCI support for MX27 and MX31 based boards
+
+The Freescale MX27 and MX31 SoCs have a EHCI controller onboard.
+The controller is capable of USB on the go. This patch adds
+support for the host controller only.
+
+The USB OTG core used here is the ARC core, so the driver should
+be renamed.
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+
+rebased to  2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel at phytec.de>
+---
+ arch/arm/plat-mxc/include/mach/mxc_ehci.h |    9 +
+ drivers/usb/Kconfig                       |    1 +
+ drivers/usb/host/Kconfig                  |    7 +
+ drivers/usb/host/ehci-hcd.c               |    5 +
+ drivers/usb/host/ehci-mxc.c               |  256 +++++++++++++++++++++++++++++
+ 5 files changed, 278 insertions(+), 0 deletions(-)
+ create mode 100644 arch/arm/plat-mxc/include/mach/mxc_ehci.h
+ create mode 100644 drivers/usb/host/ehci-mxc.c
+
+Index: linux-2.6.31.6/arch/arm/plat-mxc/include/mach/mxc_ehci.h
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.31.6/arch/arm/plat-mxc/include/mach/mxc_ehci.h	2009-12-10 11:40:43.315272374 +0100
+@@ -0,0 +1,9 @@
++#ifndef __INCLUDE_ASM_ARCH_MXC_EHCI_H
++#define __INCLUDE_ASM_ARCH_MXC_EHCI_H
++
++struct mxc_usbh_platform_data {
++	int (*init)(struct platform_device *pdev);
++	int (*exit)(struct platform_device *pdev);
++};
++#endif /* __INCLUDE_ASM_ARCH_MXC_EHCI_H */
++
+Index: linux-2.6.31.6/drivers/usb/Kconfig
+===================================================================
+--- linux-2.6.31.6.orig/drivers/usb/Kconfig	2009-11-10 01:32:31.000000000 +0100
++++ linux-2.6.31.6/drivers/usb/Kconfig	2009-12-10 11:40:43.315272374 +0100
+@@ -58,6 +58,7 @@
+ 	default y if PPC_83xx
+ 	default y if SOC_AU1200
+ 	default y if ARCH_IXP4XX
++	default y if ARCH_MXC
+ 	default PCI
+ 
+ # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
+Index: linux-2.6.31.6/drivers/usb/host/Kconfig
+===================================================================
+--- linux-2.6.31.6.orig/drivers/usb/host/Kconfig	2009-11-10 01:32:31.000000000 +0100
++++ linux-2.6.31.6/drivers/usb/host/Kconfig	2009-12-10 11:40:43.315272374 +0100
+@@ -105,6 +105,13 @@
+ 	---help---
+ 	  Variation of ARC USB block used in some Freescale chips.
+ 
++config USB_EHCI_MXC
++	bool "Support for Freescale on-chip EHCI USB controller"
++	depends on USB_EHCI_HCD && ARCH_MXC
++	select USB_EHCI_ROOT_HUB_TT
++	---help---
++	  Variation of ARC USB block used in some Freescale chips.
++
+ config USB_EHCI_HCD_PPC_OF
+ 	bool "EHCI support for PPC USB controller on OF platform bus"
+ 	depends on USB_EHCI_HCD && PPC_OF
+Index: linux-2.6.31.6/drivers/usb/host/ehci-hcd.c
+===================================================================
+--- linux-2.6.31.6.orig/drivers/usb/host/ehci-hcd.c	2009-11-10 01:32:31.000000000 +0100
++++ linux-2.6.31.6/drivers/usb/host/ehci-hcd.c	2009-12-10 11:40:43.315272374 +0100
+@@ -1092,6 +1092,11 @@
+ #define	PLATFORM_DRIVER		ehci_fsl_driver
+ #endif
+ 
++#ifdef CONFIG_USB_EHCI_MXC
++#include "ehci-mxc.c"
++#define PLATFORM_DRIVER		ehci_mxc_driver
++#endif
++
+ #ifdef CONFIG_SOC_AU1200
+ #include "ehci-au1xxx.c"
+ #define	PLATFORM_DRIVER		ehci_hcd_au1xxx_driver
+Index: linux-2.6.31.6/drivers/usb/host/ehci-mxc.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.31.6/drivers/usb/host/ehci-mxc.c	2009-12-10 11:40:43.315272374 +0100
+@@ -0,0 +1,256 @@
++/*
++ * Copyright (c) 2008 Sascha Hauer <s.hauer at pengutronix.de>, Pengutronix
++ *
++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++#include <mach/mxc_ehci.h>
++
++struct ehci_mxc_priv {
++	struct clk *usbclk, *ahbclk;
++	struct usb_hcd *hcd;
++};
++
++/* called during probe() after chip reset completes */
++static int ehci_mxc_setup(struct usb_hcd *hcd)
++{
++	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++	int retval;
++
++	/* EHCI registers start at offset 0x100 */
++	ehci->caps = hcd->regs + 0x100;
++	ehci->regs = hcd->regs + 0x100 +
++	    HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
++	dbg_hcs_params(ehci, "reset");
++	dbg_hcc_params(ehci, "reset");
++
++	/* cache this readonly data; minimize chip reads */
++	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
++
++	retval = ehci_halt(ehci);
++	if (retval)
++		return retval;
++
++	/* data structure init */
++	retval = ehci_init(hcd);
++	if (retval)
++		return retval;
++
++	hcd->has_tt = 1;
++
++	ehci->sbrn = 0x20;
++
++	ehci_reset(ehci);
++
++	ehci_port_power(ehci, 0);
++	return 0;
++}
++
++static const struct hc_driver ehci_mxc_hc_driver = {
++	.description = hcd_name,
++	.product_desc = "Freescale On-Chip EHCI Host Controller",
++	.hcd_priv_size = sizeof(struct ehci_hcd),
++
++	/*
++	 * generic hardware linkage
++	 */
++	.irq = ehci_irq,
++	.flags = HCD_USB2 | HCD_MEMORY,
++
++	/*
++	 * basic lifecycle operations
++	 */
++	.reset = ehci_mxc_setup,
++	.start = ehci_run,
++	.stop = ehci_stop,
++	.shutdown = ehci_shutdown,
++
++	/*
++	 * managing i/o requests and associated device resources
++	 */
++	.urb_enqueue = ehci_urb_enqueue,
++	.urb_dequeue = ehci_urb_dequeue,
++	.endpoint_disable = ehci_endpoint_disable,
++
++	/*
++	 * scheduling support
++	 */
++	.get_frame_number = ehci_get_frame,
++
++	/*
++	 * root hub support
++	 */
++	.hub_status_data = ehci_hub_status_data,
++	.hub_control = ehci_hub_control,
++	.bus_suspend = ehci_bus_suspend,
++	.bus_resume = ehci_bus_resume,
++	.relinquish_port = ehci_relinquish_port,
++	.port_handed_over = ehci_port_handed_over,
++};
++
++static int ehci_mxc_drv_probe(struct platform_device *pdev)
++{
++	struct mxc_usbh_platform_data *pdata;
++	struct usb_hcd *hcd;
++	struct resource *res;
++	int irq, ret, temp;
++	struct ehci_mxc_priv *priv;
++
++	dev_info(&pdev->dev, "initializing i.MX USB Controller\n");
++
++	pdata = (struct mxc_usbh_platform_data *)pdev->dev.platform_data;
++
++	irq = platform_get_irq(pdev, 0);
++
++	hcd = usb_create_hcd(&ehci_mxc_hc_driver, &pdev->dev, dev_name(&pdev->dev));
++	if (!hcd)
++		return -ENOMEM;
++
++	priv = kzalloc(sizeof (*priv), GFP_KERNEL);
++	if (!priv) {
++		ret = -ENOMEM;
++		goto err_alloc;
++	}
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		dev_err(&pdev->dev,
++			"Found HC with no register addr. Check setup!\n");
++		ret = -ENODEV;
++		goto err_get_resource;
++	}
++
++	hcd->rsrc_start = res->start;
++	hcd->rsrc_len = resource_size(res);
++
++	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
++		dev_dbg(&pdev->dev, "controller already in use\n");
++		ret = -EBUSY;
++		goto err_request_mem;
++	}
++
++	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
++	if (!hcd->regs) {
++		dev_err(&pdev->dev, "error mapping memory\n");
++		ret = -EFAULT;
++		goto err_ioremap;
++	}
++
++	priv->usbclk = clk_get(&pdev->dev, "usb");
++	if (IS_ERR(priv->usbclk)) {
++		ret = PTR_ERR(priv->usbclk);
++		goto err_clk;
++	}
++	clk_enable(priv->usbclk);
++
++	if (!cpu_is_mx35()) {
++		priv->ahbclk = clk_get(&pdev->dev, "usb_ahb");
++		if (IS_ERR(priv->ahbclk)) {
++			ret = PTR_ERR(priv->ahbclk);
++			goto err_clk_ahb;
++		}
++		clk_enable(priv->ahbclk);
++	}
++
++	if (pdata && pdata->init) {
++		ret = pdata->init(pdev);
++		if (ret) {
++			dev_err(&pdev->dev, "platform init failed\n");
++			goto err_init;
++		}
++	}
++
++	/* Set to Host mode */
++	temp = readl(hcd->regs + 0x1a8);
++	writel(temp | 0x3, hcd->regs + 0x1a8);
++
++	priv->hcd = hcd;
++	platform_set_drvdata(pdev, priv);
++
++	ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
++	if (ret)
++		goto err_add;
++
++	return 0;
++
++err_add:
++	if (pdata && pdata->exit)
++		pdata->exit(pdev);
++err_init:
++	if (priv->ahbclk) {
++		clk_disable(priv->ahbclk);
++		clk_put(priv->ahbclk);
++	}
++err_clk_ahb:
++	clk_disable(priv->usbclk);
++	clk_put(priv->usbclk);
++err_clk:
++	iounmap(hcd->regs);
++err_ioremap:
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++err_request_mem:
++err_get_resource:
++	kfree(priv);
++err_alloc:
++	usb_put_hcd(hcd);
++	return ret;
++}
++
++static int __exit ehci_mxc_drv_remove(struct platform_device *pdev)
++{
++	struct ehci_mxc_priv *priv = platform_get_drvdata(pdev);
++	struct usb_hcd *hcd = priv->hcd;
++
++	usb_remove_hcd(hcd);
++	iounmap(hcd->regs);
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++	usb_put_hcd(hcd);
++	platform_set_drvdata(pdev, NULL);
++
++	clk_disable(priv->usbclk);
++	clk_put(priv->usbclk);
++	if (priv->ahbclk) {
++		clk_disable(priv->ahbclk);
++		clk_put(priv->ahbclk);
++	}
++
++	kfree(priv);
++
++	return 0;
++}
++
++static void
++ehci_mxc_shutdown(struct platform_device *pdev)
++{
++	struct ehci_mxc_priv *priv = platform_get_drvdata(pdev);
++	struct usb_hcd *hcd = priv->hcd;
++
++	if (hcd->driver->shutdown)
++		hcd->driver->shutdown(hcd);
++}
++
++MODULE_ALIAS("platform:mxc-ehci");
++
++static struct platform_driver ehci_mxc_driver = {
++	.probe = ehci_mxc_drv_probe,
++	.remove = __exit_p(ehci_mxc_drv_remove),
++	.shutdown = ehci_mxc_shutdown,
++	.driver = {
++		   .name = "mxc-ehci",
++	},
++};
diff --git a/recipes/linux/linux-2.6.31/pcm043/0027-imx-ssi-flush-fifos.patch b/recipes/linux/linux-2.6.31/pcm043/0027-imx-ssi-flush-fifos.patch
new file mode 100644
index 0000000..56fcd9e
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0027-imx-ssi-flush-fifos.patch
@@ -0,0 +1,29 @@
+From 447b943dc48d3775e59be1800a3198f65265536d Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Wed, 2 Dec 2009 11:59:05 +0100
+Subject: [PATCH 27/28] imx-ssi: flush fifos
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ sound/soc/imx/imx-ssi.c |    5 +++++
+ 1 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
+index 6219df9..d25ee2b 100644
+--- a/sound/soc/imx/imx-ssi.c
++++ b/sound/soc/imx/imx-ssi.c
+@@ -333,6 +333,11 @@ static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
+ 		/* rx/tx are always enabled to access ac97 registers */
+ 		writel(scr, ssi->base + SSI_SCR);
+ 
++	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++		writel(SSI_SOR_TX_CLR, ssi->base + SSI_SOR);
++	else
++		writel(SSI_SOR_RX_CLR, ssi->base + SSI_SOR);
++
+ 	writel(sier, ssi->base + SSI_SIER);
+ 
+ 	return 0;
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0028-imx-ssi-Fix-occasional-AC97-reset-failure.patch b/recipes/linux/linux-2.6.31/pcm043/0028-imx-ssi-Fix-occasional-AC97-reset-failure.patch
new file mode 100644
index 0000000..fcb26ac
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0028-imx-ssi-Fix-occasional-AC97-reset-failure.patch
@@ -0,0 +1,37 @@
+From fb79a42a2badc12714a50ad5cc360927a138e8a6 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Thu, 17 Dec 2009 11:19:38 +0100
+Subject: [PATCH 28/28] imx-ssi: Fix occasional AC97 reset failure
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ sound/soc/imx/imx-ssi.c |    6 ++++++
+ 1 files changed, 6 insertions(+), 0 deletions(-)
+
+diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
+index d25ee2b..94ef361 100644
+--- a/sound/soc/imx/imx-ssi.c
++++ b/sound/soc/imx/imx-ssi.c
+@@ -565,6 +565,9 @@ static void imx_ssi_ac97_reset(struct snd_ac97 *ac97)
+ 
+ 	if (imx_ssi->ac97_reset)
+ 		imx_ssi->ac97_reset(ac97);
++
++	/* First read sometimes fails, do a dummy read */
++	imx_ssi_ac97_read(ac97, 0);
+ }
+ 
+ static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97)
+@@ -573,6 +576,9 @@ static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97)
+ 
+ 	if (imx_ssi->ac97_warm_reset)
+ 		imx_ssi->ac97_warm_reset(ac97);
++
++	/* First read sometimes fails, do a dummy read */
++	imx_ssi_ac97_read(ac97, 0);
+ }
+ 
+ struct snd_ac97_bus_ops soc_ac97_ops = {
+-- 
+1.6.5.2
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0029-MX31-Add-USB-platform-devices-and-resources.patch b/recipes/linux/linux-2.6.31/pcm043/0029-MX31-Add-USB-platform-devices-and-resources.patch
new file mode 100644
index 0000000..63eef36
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0029-MX31-Add-USB-platform-devices-and-resources.patch
@@ -0,0 +1,100 @@
+From f9a5d99348fb2c9cacdbbc0334f372ec6e5962de Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Fri, 19 Dec 2008 14:32:11 +0100
+Subject: [PATCH 029/101] MX31: Add USB platform devices and resources
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+
+rebased to  2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel at phytec.de>
+---
+ arch/arm/mach-mx3/devices.c |   75 +++++++++++++++++++++++++++++++++++++++++++
+ arch/arm/mach-mx3/devices.h |    3 ++
+ 2 files changed, 78 insertions(+), 0 deletions(-)
+
+Index: linux-2.6.31.6/arch/arm/mach-mx3/devices.c
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/mach-mx3/devices.c	2009-12-08 11:08:01.138690103 +0100
++++ linux-2.6.31.6/arch/arm/mach-mx3/devices.c	2009-12-08 11:17:36.012748409 +0100
+@@ -395,6 +395,67 @@
+ 	.num_resources	= ARRAY_SIZE(otg_resources),
+ };
+ 
++struct platform_device mxc_otg = {
++	.name = "mxc-ehci",
++	.id = 0,
++	.dev = {
++		.coherent_dma_mask = 0xffffffff,
++		.dma_mask = &otg_dmamask,
++	},
++	.resource = otg_resources,
++	.num_resources = ARRAY_SIZE(otg_resources),
++};
++
++static u64 usbh1_dmamask = ~(u32)0;
++
++static struct resource mxc_usbh1_resources[] = {
++	{
++		.start = OTG_BASE_ADDR + 0x200,
++		.end = OTG_BASE_ADDR + 0x3ff,
++		.flags = IORESOURCE_MEM,
++	}, {
++		.start = MXC_INT_USB1,
++		.end = MXC_INT_USB1,
++		.flags = IORESOURCE_IRQ,
++	},
++};
++
++struct platform_device mxc_usbh1 = {
++	.name = "mxc-ehci",
++	.id = 1,
++	.dev = {
++		.coherent_dma_mask = 0xffffffff,
++		.dma_mask = &usbh1_dmamask,
++	},
++	.resource = mxc_usbh1_resources,
++	.num_resources = ARRAY_SIZE(mxc_usbh1_resources),
++};
++
++static u64 usbh2_dmamask = ~(u32)0;
++
++static struct resource mxc_usbh2_resources[] = {
++	{
++		.start = OTG_BASE_ADDR + 0x400,
++		.end = OTG_BASE_ADDR + 0x5ff,
++		.flags = IORESOURCE_MEM,
++	}, {
++		.start = MXC_INT_USB2,
++		.end = MXC_INT_USB2,
++		.flags = IORESOURCE_IRQ,
++	},
++};
++
++struct platform_device mxc_usbh2 = {
++	.name = "mxc-ehci",
++	.id = 2,
++	.dev = {
++		.coherent_dma_mask = 0xffffffff,
++		.dma_mask = &usbh2_dmamask,
++	},
++	.resource = mxc_usbh2_resources,
++	.num_resources = ARRAY_SIZE(mxc_usbh2_resources),
++};
++
+ #ifdef CONFIG_ARCH_MX35
+ static struct resource mxc_fec_resources[] = {
+ 	{
+Index: linux-2.6.31.6/arch/arm/mach-mx3/devices.h
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/mach-mx3/devices.h	2009-12-08 11:08:01.138690103 +0100
++++ linux-2.6.31.6/arch/arm/mach-mx3/devices.h	2009-12-08 11:16:59.408625374 +0100
+@@ -16,6 +16,9 @@
+ extern struct platform_device mxcsdhc_device0;
+ extern struct platform_device mxcsdhc_device1;
+ extern struct platform_device mxc_otg_udc_device;
++extern struct platform_device mxc_otg;
++extern struct platform_device mxc_usbh1;
++extern struct platform_device mxc_usbh2;
+ extern struct platform_device mxc_rnga_device;
+ extern struct platform_device imx_ssi_device0;
+ extern struct platform_device imx_ssi_device1;
diff --git a/recipes/linux/linux-2.6.31/pcm043/0053-Watchdog-driver-for-IMX-MXC.patch b/recipes/linux/linux-2.6.31/pcm043/0053-Watchdog-driver-for-IMX-MXC.patch
new file mode 100644
index 0000000..2f19c1c
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0053-Watchdog-driver-for-IMX-MXC.patch
@@ -0,0 +1,490 @@
+From 384c73ff72ecf48d438ef54cb297b035c4060347 Mon Sep 17 00:00:00 2001
+From: Darius Augulis <augulis.darius at gmail.com>
+Date: Mon, 9 Mar 2009 17:10:25 +0200
+Subject: [PATCH 053/101] Watchdog driver for IMX/MXC
+
+Driver for watchdog timer on Freesale IMX processors.
+
+Signed-off-by: Darius Augulis <augulis.darius at gmail.com>
+
+rebased to  2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel at phytec.de>
+---
+ drivers/watchdog/Kconfig   |   12 ++
+ drivers/watchdog/Makefile  |    1 +
+ drivers/watchdog/imx-wdt.c |  432 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 445 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/watchdog/imx-wdt.c
+
+Index: linux-2.6.31.6/drivers/watchdog/Kconfig
+===================================================================
+--- linux-2.6.31.6.orig/drivers/watchdog/Kconfig	2009-11-10 01:32:31.000000000 +0100
++++ linux-2.6.31.6/drivers/watchdog/Kconfig	2009-12-08 08:59:05.611195459 +0100
+@@ -66,6 +66,18 @@
+ 
+ # ARM Architecture
+ 
++config IMX_WDT
++	tristate "IMX Watchdog"
++	depends on ARCH_MXC
++	help
++	  This is the driver for the hardware watchdog
++	  on the Freescale IMX processors.
++	  If you have one of these processors and wish to have
++	  watchdog support enabled, say Y, otherwise say N.
++
++	  To compile this driver as a module, choose M here: the
++	  module will be called imx_wdt.
++
+ config AT91RM9200_WATCHDOG
+ 	tristate "AT91RM9200 watchdog"
+ 	depends on ARCH_AT91RM9200
+Index: linux-2.6.31.6/drivers/watchdog/Makefile
+===================================================================
+--- linux-2.6.31.6.orig/drivers/watchdog/Makefile	2009-11-10 01:32:31.000000000 +0100
++++ linux-2.6.31.6/drivers/watchdog/Makefile	2009-12-08 09:00:06.603252242 +0100
+@@ -44,6 +44,7 @@
+ obj-$(CONFIG_ORION_WATCHDOG) += orion_wdt.o
+ obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o
+ obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3xxx_wdt.o
++obj-$(CONFIG_IMX_WDT) += imx-wdt.o
+ 
+ # AVR32 Architecture
+ obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
+Index: linux-2.6.31.6/drivers/watchdog/imx-wdt.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.31.6/drivers/watchdog/imx-wdt.c	2009-12-08 08:59:05.611195459 +0100
+@@ -0,0 +1,432 @@
++/*
++ * Watchdog driver for IMX processors
++ *
++ *  Copyright (C) 2008 Darius Augulis <augulis.darius at gmail.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.
++ *
++ */
++
++/*
++ * NOTE: MX1 arch has a bit different Watchdog than MX2 and MX3.
++ * It's not possible to turn off watchdog on MX2 or MX3 since it's enabled.
++ * Timeout changing with IOCTL command is possible only on MX1.
++ * WD timer halting during suspend is implemented in all archs but in
++ * different way.
++ * MX2 and MX3 has 16 bit watchdog registers compared to 32 bit on MX1.
++ *
++ */
++
++/*#define DEBUG*/
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/miscdevice.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/platform_device.h>
++#include <linux/types.h>
++#include <linux/fs.h>
++#include <linux/io.h>
++#include <linux/bitops.h>
++#include <linux/errno.h>
++#include <linux/watchdog.h>
++#include <linux/uaccess.h>
++#include <mach/hardware.h>
++#include <linux/clk.h>
++
++#ifdef CONFIG_ARCH_MX1
++# define WDT_MAX_TIME		63		/* seconds */
++
++# define IMX_WDT_WCR		0x00		/* Control reg */
++# define IMX_WDT_WSR		0x04		/* Service reg */
++# define IMX_WDT_WSTR		0x08		/* Status reg */
++
++# define WCR_WT			(0x7F<<8)
++# define WCR_WDEC		(1<<1)
++# define WCR_WDE		(1<<0)
++# define WCR_WHALT		(1<<15)
++#else
++# define WDT_MAX_TIME		127		/* seconds */
++
++# define IMX_WDT_WCR		0x00		/* Control reg */
++# define IMX_WDT_WSR		0x02		/* Service reg */
++# define IMX_WDT_WSTR		0x04		/* Status reg */
++
++# define WCR_WT			(0xFF<<8)
++# define WCR_WDE		(1<<2)
++# define WCR_WDZST		(1<<0)
++#endif
++
++#define WDT_DEFAULT_TIME	10		/* seconds */
++#define WDT_SEQ1		0x5555
++#define WDT_SEQ2		0xAAAA
++
++static struct platform_device *imx_wdt_dev;
++
++struct imx_wdt_struct {
++	struct resource		*res;
++	struct device		*dev;
++	struct clk		*clk;
++	void __iomem		*base;
++	int			wdt_time;
++	int			nowayout;
++	unsigned long		status;
++};
++
++static unsigned int timeout = WDT_DEFAULT_TIME;
++
++static struct watchdog_info imx_wdt_info = {
++	.identity	= "imx watchdog",
++	.options	= WDIOF_KEEPALIVEPING
++#ifdef CONFIG_ARCH_MX1
++			| WDIOF_SETTIMEOUT
++#endif
++};
++
++/* Disable the watchdog. */
++static inline void imx_wdt_stop(struct imx_wdt_struct *imx_wdt)
++{
++	dev_dbg(imx_wdt->dev, "<%s>\n", __func__);
++
++#ifdef CONFIG_ARCH_MX1
++	__raw_writew(0, imx_wdt->base + IMX_WDT_WCR);
++#else
++	dev_info(imx_wdt->dev, "watchdog is unstoppable on i.MX2/3 !\n");
++#endif
++}
++
++/* Enable and reset the watchdog. */
++static inline void imx_wdt_start(struct imx_wdt_struct *imx_wdt)
++{
++	u16 temp;
++
++	dev_dbg(imx_wdt->dev, "<%s>\n", __func__);
++
++	temp = __raw_readw(imx_wdt->base + IMX_WDT_WCR);
++	temp |= imx_wdt->wdt_time << 8;
++	__raw_writew(temp, imx_wdt->base + IMX_WDT_WCR);
++
++#ifdef CONFIG_ARCH_MX1
++# ifndef CONFIG_WATCHDOG_NOWAYOUT
++	temp |= WCR_WDEC;
++	__raw_writew(temp, imx_wdt->base + IMX_WDT_WCR);
++# endif
++	temp |= WCR_WDE;
++	__raw_writew(temp, imx_wdt->base + IMX_WDT_WCR);
++#else
++	temp |= WCR_WDE | WCR_WDZST;
++	__raw_writew(temp, imx_wdt->base + IMX_WDT_WCR);
++#endif
++
++#ifdef CONFIG_ARCH_MX1
++	__raw_writew(WDT_SEQ1, imx_wdt->base + IMX_WDT_WSR);
++	__raw_writew(WDT_SEQ2, imx_wdt->base + IMX_WDT_WSR);
++#endif
++}
++
++/* Service the watchdog */
++static inline void imx_wdt_service(struct imx_wdt_struct *imx_wdt)
++{
++	dev_dbg(imx_wdt->dev, "<%s>\n", __func__);
++
++	__raw_writew(WDT_SEQ1, imx_wdt->base + IMX_WDT_WSR);
++	__raw_writew(WDT_SEQ2, imx_wdt->base + IMX_WDT_WSR);
++}
++
++/* Watchdog device is opened, and watchdog starts running. */
++static int imx_wdt_open(struct inode *inode, struct file *file)
++{
++	struct imx_wdt_struct *imx_wdt = platform_get_drvdata(imx_wdt_dev);
++
++	dev_dbg(imx_wdt->dev, "<%s>\n", __func__);
++
++	if (test_and_set_bit(0, &imx_wdt->status))
++		return -EBUSY;
++
++	file->private_data = imx_wdt;
++
++	imx_wdt_start(imx_wdt);
++	return nonseekable_open(inode, file);
++}
++
++/* Close the watchdog device. */
++static int imx_wdt_close(struct inode *inode, struct file *file)
++{
++	struct imx_wdt_struct *imx_wdt = file->private_data;
++
++	dev_dbg(imx_wdt->dev, "<%s>\n", __func__);
++
++	/* Disable the watchdog if possible */
++	if (!imx_wdt->nowayout)
++		imx_wdt_stop(imx_wdt);
++
++	clear_bit(0, &imx_wdt->status);
++	return 0;
++}
++
++#ifdef CONFIG_ARCH_MX1
++/* Change the watchdog time interval. */
++static int imx_wdt_settimeout(struct imx_wdt_struct *imx_wdt, int new_time)
++{
++	dev_dbg(imx_wdt->dev, "<%s>\n", __func__);
++
++	if ((new_time * 2 < 1) || (new_time * 2  > WDT_MAX_TIME))
++		return -EINVAL;
++
++	imx_wdt->wdt_time = new_time * 2;
++	return 0;
++}
++#endif
++
++/* Handle commands from user-space. */
++static int imx_wdt_ioctl(struct inode *inode, struct file *file,
++		unsigned int cmd, unsigned long arg)
++{
++	struct imx_wdt_struct *imx_wdt = file->private_data;
++
++	void __user *argp = (void __user *)arg;
++	int __user *p = argp;
++#ifdef CONFIG_ARCH_MX1
++	int new_value;
++#endif
++
++	dev_dbg(imx_wdt->dev, "<%s>\n", __func__);
++
++	switch (cmd) {
++	case WDIOC_KEEPALIVE:
++		imx_wdt_service(imx_wdt);
++		return 0;
++
++	case WDIOC_GETSUPPORT:
++		return copy_to_user(argp, &imx_wdt_info,
++			sizeof(imx_wdt_info)) ? -EFAULT : 0;
++#ifdef CONFIG_ARCH_MX1
++	case WDIOC_SETTIMEOUT:
++		if (get_user(new_value, p))
++			return -EFAULT;
++
++		if (imx_wdt_settimeout(imx_wdt, new_value))
++			return -EINVAL;
++
++		/* Enable new time value */
++		imx_wdt_start(imx_wdt);
++
++		/* Return current value */
++		return put_user(imx_wdt->wdt_time / 2, p);
++#endif
++	case WDIOC_GETTIMEOUT:
++		return put_user(imx_wdt->wdt_time / 2, p);
++
++	default:
++		return -ENOTTY;
++	}
++}
++
++/* Refresh the watchdog whenever device is written to. */
++static ssize_t imx_wdt_write(struct file *file, const char *data,
++						size_t len, loff_t *ppos)
++{
++	struct imx_wdt_struct *imx_wdt = file->private_data;
++
++	dev_dbg(imx_wdt->dev, "<%s>\n", __func__);
++
++	imx_wdt_service(imx_wdt);
++	return len;
++}
++
++static const struct file_operations imx_wdt_fops = {
++	.owner		= THIS_MODULE,
++	.llseek		= no_llseek,
++	.ioctl		= imx_wdt_ioctl,
++	.open		= imx_wdt_open,
++	.release	= imx_wdt_close,
++	.write		= imx_wdt_write,
++};
++
++static struct miscdevice imx_wdt_miscdev = {
++	.minor		= WATCHDOG_MINOR,
++	.name		= "watchdog",
++	.fops		= &imx_wdt_fops,
++};
++
++static void imx_wdt_shutdown(struct platform_device *pdev)
++{
++	struct imx_wdt_struct *imx_wdt = platform_get_drvdata(pdev);
++
++	dev_dbg(imx_wdt->dev, "<%s>\n", __func__);
++
++	imx_wdt_stop(imx_wdt);
++}
++
++static int __init imx_wdt_probe(struct platform_device *pdev)
++{
++	int ret;
++	int res_size;
++	struct resource *res;
++	void __iomem *base;
++	struct imx_wdt_struct *imx_wdt;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		dev_err(&pdev->dev, "can't get device resources\n");
++		return -ENODEV;
++	}
++
++	res_size = res->end - res->start + 1;
++	if (!request_mem_region(res->start, res_size, res->name)) {
++		dev_err(&pdev->dev, "can't allocate %d bytes at %d address\n",
++			res_size, res->start);
++		return -ENOMEM;
++	}
++
++	base = ioremap(res->start, res_size);
++	if (!base) {
++		dev_err(&pdev->dev, "ioremap failed\n");
++		ret = -EIO;
++		goto fail0;
++	}
++
++	imx_wdt = kzalloc(sizeof(struct imx_wdt_struct), GFP_KERNEL);
++	if (!imx_wdt) {
++		dev_err(&pdev->dev, "can't allocate interface\n");
++		ret = -ENOMEM;
++		goto fail1;
++	}
++
++	imx_wdt->clk = clk_get(&pdev->dev, NULL);
++	if (IS_ERR(imx_wdt->clk)) {
++		dev_err(&pdev->dev, "can't get Watchdog clock\n");
++		ret = PTR_ERR(imx_wdt->clk);
++		goto fail2;
++	}
++	clk_enable(imx_wdt->clk);
++
++	/* Setup imx_wdt driver structure */
++	imx_wdt->dev			= &pdev->dev;
++	imx_wdt->base			= base;
++	imx_wdt->res			= res;
++	imx_wdt->wdt_time		= timeout * 2;
++#ifdef CONFIG_WATCHDOG_NOWAYOUT
++	imx_wdt->nowayout		= 1;
++#else
++	imx_wdt->nowayout		= 0;
++#endif
++
++	/* Set up platform driver data */
++	platform_set_drvdata(pdev, imx_wdt);
++	imx_wdt_dev = pdev;
++
++	if (imx_wdt_miscdev.parent) {
++		ret = -EBUSY;
++		goto fail3;
++	}
++	imx_wdt_miscdev.parent = &pdev->dev;
++
++	ret = misc_register(&imx_wdt_miscdev);
++	if (ret)
++		goto fail3;
++
++	dev_dbg(&pdev->dev, "IMX Watchdog Timer enabled\n");
++	return 0;
++
++fail3:
++	clk_disable(imx_wdt->clk);
++	clk_put(imx_wdt->clk);
++fail2:
++	platform_set_drvdata(pdev, NULL);
++	kfree(imx_wdt);
++fail1:
++	iounmap(base);
++fail0:
++	release_mem_region(res->start, res_size);
++
++	return ret; /* Return error number */
++}
++
++static int __exit imx_wdt_remove(struct platform_device *pdev)
++{
++	struct imx_wdt_struct *imx_wdt = platform_get_drvdata(pdev);
++
++	dev_dbg(&pdev->dev, "IMX Watchdog Timer disabled\n");
++
++	platform_set_drvdata(pdev, NULL);
++	misc_deregister(&imx_wdt_miscdev);
++	imx_wdt_dev = NULL;
++	iounmap(imx_wdt->base);
++	release_mem_region(imx_wdt->res->start,
++		imx_wdt->res->end - imx_wdt->res->start + 1);
++
++	clk_disable(imx_wdt->clk);
++	clk_put(imx_wdt->clk);
++
++	kfree(imx_wdt);
++	return 0;
++}
++
++#ifdef CONFIG_PM
++
++static int imx_wdt_suspend(struct platform_device *pdev, pm_message_t message)
++{
++#ifdef CONFIG_ARCH_MX1
++	struct imx_wdt_struct *imx_wdt = platform_get_drvdata(pdev);
++
++	u32 temp = __raw_readw(imx_wdt->base + IMX_WDT_WCR);
++	__raw_writew(temp | WCR_WHALT, imx_wdt->base + IMX_WDT_WCR);
++#endif
++	return 0;
++}
++
++static int imx_wdt_resume(struct platform_device *pdev)
++{
++#ifdef CONFIG_ARCH_MX1
++	struct imx_wdt_struct *imx_wdt = platform_get_drvdata(pdev);
++	u32 temp;
++
++	if (imx_wdt->status) {
++		temp = __raw_readw(imx_wdt->base + IMX_WDT_WCR) & ~WCR_WHALT;
++		__raw_writew(temp, imx_wdt->base + IMX_WDT_WCR);
++	}
++#endif
++	return 0;
++}
++
++#else
++#define imx_wdt_suspend NULL
++#define imx_wdt_resume	NULL
++#endif
++
++static struct platform_driver imx_wdt_driver = {
++	.probe		= imx_wdt_probe,
++	.remove		= __exit_p(imx_wdt_remove),
++	.shutdown	= imx_wdt_shutdown,
++	.suspend	= imx_wdt_suspend,
++	.resume		= imx_wdt_resume,
++	.driver		= {
++		.name	= "imx-wdt",
++		.owner	= THIS_MODULE,
++	},
++};
++
++static int __init imx_wdt_init(void)
++{
++	return platform_driver_probe(&imx_wdt_driver, imx_wdt_probe);
++}
++
++static void __exit imx_wdt_exit(void)
++{
++	platform_driver_unregister(&imx_wdt_driver);
++}
++module_init(imx_wdt_init);
++module_exit(imx_wdt_exit);
++
++module_param(timeout, uint, 0);
++MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds");
++
++MODULE_AUTHOR("Darius Augulis");
++MODULE_DESCRIPTION("Watchdog driver for IMX");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
++MODULE_ALIAS("platform:imx-wdt");
diff --git a/recipes/linux/linux-2.6.31/pcm043/0066-HACK-increase-default-tx_queue_len-to-10000.patch b/recipes/linux/linux-2.6.31/pcm043/0066-HACK-increase-default-tx_queue_len-to-10000.patch
new file mode 100644
index 0000000..d0b9123
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0066-HACK-increase-default-tx_queue_len-to-10000.patch
@@ -0,0 +1,36 @@
+From c15a83d5d49ca36d827fd35faee8d9c0048e8053 Mon Sep 17 00:00:00 2001
+From: Marc Kleine-Budde <mkl at pengutronix.de>
+Date: Fri, 19 Dec 2008 14:32:42 +0100
+Subject: [PATCH 066/101] HACK: increase default tx_queue_len to 10000
+
+HACK HACK HACK
+
+Without this patch sending CAN packages faster then they could be
+send out on the wire results in -ENOBUF. This patch increases the
+default tx_queue_len to 10000 so that in this case the sender blocks.
+Thus the CAN socket just behaves like congested a TCP/IP socket.
+
+HACK HACK HACK
+
+Signed-off-by: Marc Kleine-Budde <mkl at pengutronix.de>
+
+rebased to  2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel at phytec.de>
+---
+
+ drivers/net/can/dev.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+Index: linux-2.6.31.6/drivers/net/can/dev.c
+===================================================================
+--- linux-2.6.31.6.orig/drivers/net/can/dev.c	2009-11-10 01:32:31.000000000 +0100
++++ linux-2.6.31.6/drivers/net/can/dev.c	2009-12-08 09:12:45.558976163 +0100
+@@ -420,7 +420,7 @@
+ 	dev->mtu = sizeof(struct can_frame);
+ 	dev->hard_header_len = 0;
+ 	dev->addr_len = 0;
+-	dev->tx_queue_len = 10;
++	dev->tx_queue_len = 10000;
+ 
+ 	/* New-style flags. */
+ 	dev->flags = IFF_NOARP;
diff --git a/recipes/linux/linux-2.6.31/pcm043/0084-i.MX35-clock-support-Add-USB-clocks.patch b/recipes/linux/linux-2.6.31/pcm043/0084-i.MX35-clock-support-Add-USB-clocks.patch
new file mode 100644
index 0000000..da33524
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0084-i.MX35-clock-support-Add-USB-clocks.patch
@@ -0,0 +1,30 @@
+From f46cfd74faf9b1644e9eefc1e7fa5541f17d1d32 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Tue, 17 Mar 2009 15:43:54 +0100
+Subject: [PATCH 084/101] i.MX35 clock support: Add USB clocks
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+
+rebased to  2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel at phytec.de>
+---
+ arch/arm/mach-mx3/clock-imx35.c |    6 ++++--
+ 1 files changed, 4 insertions(+), 2 deletions(-)
+
+Index: linux-2.6.31.6/arch/arm/mach-mx3/clock-imx35.c
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/mach-mx3/clock-imx35.c	2009-12-07 15:20:31.963944848 +0100
++++ linux-2.6.31.6/arch/arm/mach-mx3/clock-imx35.c	2009-12-08 09:39:04.798706951 +0100
+@@ -425,8 +425,10 @@
+ 	_REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
+ 	_REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
+ 	_REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
+-	_REGISTER_CLOCK(NULL, "usbotg", usbotg_clk)
+-	_REGISTER_CLOCK("mxc_wdt.0", NULL, wdog_clk)
++	_REGISTER_CLOCK("mxc-ehci.0", NULL, usbotg_clk)
++	_REGISTER_CLOCK("mxc-ehci.1", NULL, usbotg_clk)
++	_REGISTER_CLOCK("mxc-ehci.2", NULL, usbotg_clk)
++	_REGISTER_CLOCK("imx-wdt.0", NULL, wdog_clk)
+ 	_REGISTER_CLOCK(NULL, "max", max_clk)
+ 	_REGISTER_CLOCK(NULL, "audmux", audmux_clk)
+ 	_REGISTER_CLOCK(NULL, "csi", csi_clk)
diff --git a/recipes/linux/linux-2.6.31/pcm043/0088-ehci-mxc-Fix-clocks.patch b/recipes/linux/linux-2.6.31/pcm043/0088-ehci-mxc-Fix-clocks.patch
new file mode 100644
index 0000000..25143cb
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0088-ehci-mxc-Fix-clocks.patch
@@ -0,0 +1,33 @@
+From f5d7944a7257ffcf2aa7ee0736962e9b564837fd Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Wed, 8 Apr 2009 16:39:47 +0200
+Subject: [PATCH 088/101] ehci mxc: Fix clocks
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/mach-mx3/clock.c |    9 ++++++---
+ 1 files changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/mach-mx3/clock.c b/arch/arm/mach-mx3/clock.c
+index aee34ed..a08f2be 100644
+--- a/arch/arm/mach-mx3/clock.c
++++ b/arch/arm/mach-mx3/clock.c
+@@ -532,9 +532,12 @@ static struct clk_lookup lookups[] __initdata = {
+ 	_REGISTER_CLOCK("mx3_sdc_fb", NULL, ipu_clk)
+ 	_REGISTER_CLOCK(NULL, "kpp", kpp_clk)
+ 	/* FIXME: mxc-ehci now misses the secondary clock */
+-	_REGISTER_CLOCK("mxc-ehci.0", NULL, usb_clk1)
+-	_REGISTER_CLOCK("mxc-ehci.1", NULL, usb_clk1)
+-	_REGISTER_CLOCK("mxc-ehci.2", NULL, usb_clk1)
++	_REGISTER_CLOCK("mxc-ehci.0", "usb", usb_clk1)
++	_REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", usb_clk2)
++	_REGISTER_CLOCK("mxc-ehci.1", "usb", usb_clk1)
++	_REGISTER_CLOCK("mxc-ehci.1", "usb_ahb", usb_clk2)
++	_REGISTER_CLOCK("mxc-ehci.2", "usb", usb_clk1)
++	_REGISTER_CLOCK("mxc-ehci.2", "usb_ahb", usb_clk2)
+ 	_REGISTER_CLOCK("fsl-usb2-udc", "usb", usb_clk1)
+ 	_REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", usb_clk2)
+ 	_REGISTER_CLOCK("mx3-camera.0", NULL, csi_clk)
+-- 
+1.6.2.1
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0090-mx3x-Fixup-USB-base-addresses.patch b/recipes/linux/linux-2.6.31/pcm043/0090-mx3x-Fixup-USB-base-addresses.patch
new file mode 100644
index 0000000..61fe36c
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0090-mx3x-Fixup-USB-base-addresses.patch
@@ -0,0 +1,93 @@
+From c5ff90856d241112b588e091167e6fc69020d535 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Fri, 17 Apr 2009 16:52:25 +0200
+Subject: [PATCH 090/101] mx3x: Fixup USB base addresses
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+
+rebased to 2.6.31.6, but without pcm037.c changes
+Signed-off-by: Jan Weitzel <J.Weitzel at phytec.de>
+---
+ arch/arm/mach-mx3/devices.c           |   20 ++++++++++++++------
+ arch/arm/mach-mx3/pcm037.c            |   20 ++++++++++----------
+ arch/arm/plat-mxc/include/mach/mx31.h |    2 +-
+ arch/arm/plat-mxc/include/mach/mx35.h |    1 +
+ 4 files changed, 26 insertions(+), 17 deletions(-)
+
+Index: linux-2.6.31.6/arch/arm/mach-mx3/devices.c
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/mach-mx3/devices.c	2009-12-10 11:33:07.024614628 +0100
++++ linux-2.6.31.6/arch/arm/mach-mx3/devices.c	2009-12-10 11:33:10.356276214 +0100
+@@ -371,8 +371,8 @@
+ 
+ static struct resource otg_resources[] = {
+ 	{
+-		.start	= OTG_BASE_ADDR,
+-		.end	= OTG_BASE_ADDR + 0x1ff,
++		.start = MX31_OTG_BASE_ADDR,
++		.end = MX31_OTG_BASE_ADDR + 0x1ff,
+ 		.flags	= IORESOURCE_MEM,
+ 	}, {
+ 		.start	= MXC_INT_USB3,
+@@ -410,8 +410,8 @@
+ 
+ static struct resource mxc_usbh1_resources[] = {
+ 	{
+-		.start = OTG_BASE_ADDR + 0x200,
+-		.end = OTG_BASE_ADDR + 0x3ff,
++		.start = MX31_OTG_BASE_ADDR + 0x200,
++		.end = MX31_OTG_BASE_ADDR + 0x3ff,
+ 		.flags = IORESOURCE_MEM,
+ 	}, {
+ 		.start = MXC_INT_USB1,
+@@ -435,8 +435,8 @@
+ 
+ static struct resource mxc_usbh2_resources[] = {
+ 	{
+-		.start = OTG_BASE_ADDR + 0x400,
+-		.end = OTG_BASE_ADDR + 0x5ff,
++		.start = MX31_OTG_BASE_ADDR + 0x400,
++		.end = MX31_OTG_BASE_ADDR + 0x5ff,
+ 		.flags = IORESOURCE_MEM,
+ 	}, {
+ 		.start = MXC_INT_USB2,
+@@ -586,6 +586,14 @@
+ 	if (cpu_is_mx35()) {
+ 		mxc_nand_resources[0].start = MX35_NFC_BASE_ADDR;
+ 		mxc_nand_resources[0].end = MX35_NFC_BASE_ADDR + 0xfff;
++		otg_resources[0].start = MX35_OTG_BASE_ADDR;
++		otg_resources[0].end = MX35_OTG_BASE_ADDR + 0x1ff;
++		otg_resources[1].start = MXC_INT_USBOTG;
++		otg_resources[1].end = MXC_INT_USBOTG;
++		mxc_usbh1_resources[0].start = MX35_OTG_BASE_ADDR + 0x400;
++		mxc_usbh1_resources[0].end = MX35_OTG_BASE_ADDR + 0x5ff;
++		mxc_usbh1_resources[1].start = MXC_INT_USBHS;
++		mxc_usbh1_resources[1].end = MXC_INT_USBHS;
+ 		imx_ssi_resources0[1].start = MX35_INT_SSI1;
+ 		imx_ssi_resources0[1].end = MX35_INT_SSI1;
+ 		imx_ssi_resources1[1].start = MX35_INT_SSI2;
+Index: linux-2.6.31.6/arch/arm/plat-mxc/include/mach/mx31.h
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/plat-mxc/include/mach/mx31.h	2009-12-10 11:33:07.004682613 +0100
++++ linux-2.6.31.6/arch/arm/plat-mxc/include/mach/mx31.h	2009-12-10 11:33:10.356276214 +0100
+@@ -4,7 +4,7 @@
+ #define MX31_IRAM_BASE_ADDR		0x1FFC0000	/* internal ram */
+ #define MX31_IRAM_SIZE			SZ_16K
+ 
+-#define OTG_BASE_ADDR		(AIPS1_BASE_ADDR + 0x00088000)
++#define MX31_OTG_BASE_ADDR	(AIPS1_BASE_ADDR + 0x00088000)
+ #define ATA_BASE_ADDR		(AIPS1_BASE_ADDR + 0x0008C000)
+ #define UART4_BASE_ADDR 	(AIPS1_BASE_ADDR + 0x000B0000)
+ #define UART5_BASE_ADDR 	(AIPS1_BASE_ADDR + 0x000B4000)
+Index: linux-2.6.31.6/arch/arm/plat-mxc/include/mach/mx35.h
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/plat-mxc/include/mach/mx35.h	2009-12-10 11:33:07.014617995 +0100
++++ linux-2.6.31.6/arch/arm/plat-mxc/include/mach/mx35.h	2009-12-10 11:33:10.356276214 +0100
+@@ -5,6 +5,7 @@
+ #define MX35_IRAM_SIZE		SZ_128K
+ 
+ #define MXC_FEC_BASE_ADDR	0x50038000
++#define MX35_OTG_BASE_ADDR	0x53ff4000
+ #define MX35_NFC_BASE_ADDR	0xBB000000
+ 
+ /*
diff --git a/recipes/linux/linux-2.6.31/pcm043/0091-mx31-clock-remove-obsolete-FIXME-comment.patch b/recipes/linux/linux-2.6.31/pcm043/0091-mx31-clock-remove-obsolete-FIXME-comment.patch
new file mode 100644
index 0000000..40c9c63
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0091-mx31-clock-remove-obsolete-FIXME-comment.patch
@@ -0,0 +1,25 @@
+From 4ed32022da7583d8cf260809f41fb1bfcfb033a8 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Fri, 17 Apr 2009 16:52:55 +0200
+Subject: [PATCH 091/101] mx31 clock: remove obsolete FIXME comment
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ arch/arm/mach-mx3/clock.c |    1 -
+ 1 files changed, 0 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/mach-mx3/clock.c b/arch/arm/mach-mx3/clock.c
+index a08f2be..8ec45f6 100644
+--- a/arch/arm/mach-mx3/clock.c
++++ b/arch/arm/mach-mx3/clock.c
+@@ -531,7 +531,6 @@ static struct clk_lookup lookups[] __initdata = {
+ 	_REGISTER_CLOCK("ipu-core", NULL, ipu_clk)
+ 	_REGISTER_CLOCK("mx3_sdc_fb", NULL, ipu_clk)
+ 	_REGISTER_CLOCK(NULL, "kpp", kpp_clk)
+-	/* FIXME: mxc-ehci now misses the secondary clock */
+ 	_REGISTER_CLOCK("mxc-ehci.0", "usb", usb_clk1)
+ 	_REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", usb_clk2)
+ 	_REGISTER_CLOCK("mxc-ehci.1", "usb", usb_clk1)
+-- 
+1.6.2.1
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/0092-mx35-clock-give-ehci-clocks-names.patch b/recipes/linux/linux-2.6.31/pcm043/0092-mx35-clock-give-ehci-clocks-names.patch
new file mode 100644
index 0000000..91b27f9
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0092-mx35-clock-give-ehci-clocks-names.patch
@@ -0,0 +1,30 @@
+From 655b9879b22d1e2776c8df0a4fa77801a1b7fd97 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Fri, 17 Apr 2009 16:53:27 +0200
+Subject: [PATCH 092/101] mx35 clock: give ehci clocks names
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+
+rebased to  2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel at phytec.de>
+---
+ arch/arm/mach-mx3/clock-imx35.c |    6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
+
+Index: linux-2.6.31.6/arch/arm/mach-mx3/clock-imx35.c
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/mach-mx3/clock-imx35.c	2009-12-08 09:39:04.798706951 +0100
++++ linux-2.6.31.6/arch/arm/mach-mx3/clock-imx35.c	2009-12-08 09:49:47.949859691 +0100
+@@ -425,9 +425,9 @@
+ 	_REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
+ 	_REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
+ 	_REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
+-	_REGISTER_CLOCK("mxc-ehci.0", NULL, usbotg_clk)
+-	_REGISTER_CLOCK("mxc-ehci.1", NULL, usbotg_clk)
+-	_REGISTER_CLOCK("mxc-ehci.2", NULL, usbotg_clk)
++	_REGISTER_CLOCK("mxc-ehci.0", "usb", usbotg_clk)
++	_REGISTER_CLOCK("mxc-ehci.1", "usb", usbotg_clk)
++	_REGISTER_CLOCK("mxc-ehci.2", "usb", usbotg_clk)
+ 	_REGISTER_CLOCK("imx-wdt.0", NULL, wdog_clk)
+ 	_REGISTER_CLOCK(NULL, "max", max_clk)
+ 	_REGISTER_CLOCK(NULL, "audmux", audmux_clk)
diff --git a/recipes/linux/linux-2.6.31/pcm043/0096-i.MX35-implement-get_rate-for-usb-otg-clock.patch b/recipes/linux/linux-2.6.31/pcm043/0096-i.MX35-implement-get_rate-for-usb-otg-clock.patch
new file mode 100644
index 0000000..0190641
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0096-i.MX35-implement-get_rate-for-usb-otg-clock.patch
@@ -0,0 +1,54 @@
+From d7463937b967203cee097b96593ef46cb9ea23a7 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Tue, 21 Apr 2009 14:50:53 +0200
+Subject: [PATCH 096/101] i.MX35: implement get_rate for usb otg clock
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+
+rebased to  2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel at phytec.de>
+---
+ arch/arm/mach-mx3/clock-imx35.c |   16 +++++++++++++++-
+ 1 files changed, 15 insertions(+), 1 deletions(-)
+
+Index: linux-2.6.31.6/arch/arm/mach-mx3/clock-imx35.c
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/mach-mx3/clock-imx35.c	2009-12-08 09:49:47.949859691 +0100
++++ linux-2.6.31.6/arch/arm/mach-mx3/clock-imx35.c	2009-12-08 09:56:24.498623255 +0100
+@@ -273,6 +273,19 @@
+ 	return rate / get_3_3_div((pdr2 >> 16) & 0x3f);
+ }
+ 
++static unsigned long get_rate_otg(struct clk *clk)
++{
++	unsigned long pdr4 = __raw_readl(CCM_BASE + CCM_PDR4);
++	unsigned long rate;
++
++	if (pdr4 & (1 << 9))
++		rate = get_rate_arm();
++	else
++		rate = get_rate_ppll();
++
++	return rate / get_3_3_div((pdr4 >> 22) & 0x3f);
++}
++
+ static unsigned long get_rate_ipg_per(struct clk *clk)
+ {
+ 	unsigned long pdr0 = __raw_readl(CCM_BASE + CCM_PDR0);
+@@ -365,7 +378,7 @@
+ DEFINE_CLOCK(uart1_clk,  0, CCM_CGR2, 16, get_rate_uart, NULL);
+ DEFINE_CLOCK(uart2_clk,  1, CCM_CGR2, 18, get_rate_uart, NULL);
+ DEFINE_CLOCK(uart3_clk,  2, CCM_CGR2, 20, get_rate_uart, NULL);
+-DEFINE_CLOCK(usbotg_clk, 0, CCM_CGR2, 22, NULL, NULL);
++DEFINE_CLOCK(usbotg_clk, 0, CCM_CGR2, 22, get_rate_otg, NULL);
+ DEFINE_CLOCK(wdog_clk,   0, CCM_CGR2, 24, NULL, NULL);
+ DEFINE_CLOCK(max_clk,    0, CCM_CGR2, 26, NULL, NULL);
+ DEFINE_CLOCK(audmux_clk, 0, CCM_CGR2, 30, NULL, NULL);
+@@ -428,6 +441,7 @@
+ 	_REGISTER_CLOCK("mxc-ehci.0", "usb", usbotg_clk)
+ 	_REGISTER_CLOCK("mxc-ehci.1", "usb", usbotg_clk)
+ 	_REGISTER_CLOCK("mxc-ehci.2", "usb", usbotg_clk)
++	_REGISTER_CLOCK("fsl-usb2-udc", "usb", usbotg_clk)
+ 	_REGISTER_CLOCK("imx-wdt.0", NULL, wdog_clk)
+ 	_REGISTER_CLOCK(NULL, "max", max_clk)
+ 	_REGISTER_CLOCK(NULL, "audmux", audmux_clk)
diff --git a/recipes/linux/linux-2.6.31/pcm043/0097-fsl-udc-driver-add-mx35-support.patch b/recipes/linux/linux-2.6.31/pcm043/0097-fsl-udc-driver-add-mx35-support.patch
new file mode 100644
index 0000000..3467895
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/0097-fsl-udc-driver-add-mx35-support.patch
@@ -0,0 +1,83 @@
+From 56e08cdd4fde350a1e43c69b084fa618df1e2af7 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Tue, 21 Apr 2009 14:52:45 +0200
+Subject: [PATCH 097/101] fsl udc driver: add mx35 support
+
+Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
+---
+ drivers/usb/gadget/fsl_mx3_udc.c |   31 ++++++++++++++++++++-----------
+ 1 files changed, 20 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/usb/gadget/fsl_mx3_udc.c b/drivers/usb/gadget/fsl_mx3_udc.c
+index 4bc2bf3..20a802e 100644
+--- a/drivers/usb/gadget/fsl_mx3_udc.c
++++ b/drivers/usb/gadget/fsl_mx3_udc.c
+@@ -17,6 +17,8 @@
+ #include <linux/fsl_devices.h>
+ #include <linux/platform_device.h>
+ 
++#include <mach/hardware.h>
++
+ static struct clk *mxc_ahb_clk;
+ static struct clk *mxc_usb_clk;
+ 
+@@ -28,14 +30,16 @@ int fsl_udc_clk_init(struct platform_device *pdev)
+ 
+ 	pdata = pdev->dev.platform_data;
+ 
+-	mxc_ahb_clk = clk_get(&pdev->dev, "usb_ahb");
+-	if (IS_ERR(mxc_ahb_clk))
+-		return PTR_ERR(mxc_ahb_clk);
++	if (!cpu_is_mx35()) {
++		mxc_ahb_clk = clk_get(&pdev->dev, "usb_ahb");
++		if (IS_ERR(mxc_ahb_clk))
++			return PTR_ERR(mxc_ahb_clk);
+ 
+-	ret = clk_enable(mxc_ahb_clk);
+-	if (ret < 0) {
+-		dev_err(&pdev->dev, "clk_enable(\"usb_ahb\") failed\n");
+-		goto eenahb;
++		ret = clk_enable(mxc_ahb_clk);
++		if (ret < 0) {
++			dev_err(&pdev->dev, "clk_enable(\"usb_ahb\") failed\n");
++			goto eenahb;
++		}
+ 	}
+ 
+ 	/* make sure USB_CLK is running at 60 MHz +/- 1000 Hz */
+@@ -50,6 +54,7 @@ int fsl_udc_clk_init(struct platform_device *pdev)
+ 	if (pdata->phy_mode != FSL_USB2_PHY_ULPI &&
+ 	    (freq < 59999000 || freq > 60001000)) {
+ 		dev_err(&pdev->dev, "USB_CLK=%lu, should be 60MHz\n", freq);
++		ret = -EINVAL;
+ 		goto eclkrate;
+ 	}
+ 
+@@ -66,9 +71,11 @@ eclkrate:
+ 	clk_put(mxc_usb_clk);
+ 	mxc_usb_clk = NULL;
+ egusb:
+-	clk_disable(mxc_ahb_clk);
++	if (!cpu_is_mx35())
++		clk_disable(mxc_ahb_clk);
+ eenahb:
+-	clk_put(mxc_ahb_clk);
++	if (!cpu_is_mx35())
++		clk_put(mxc_ahb_clk);
+ 	return ret;
+ }
+ 
+@@ -90,6 +97,8 @@ void fsl_udc_clk_release(void)
+ 		clk_disable(mxc_usb_clk);
+ 		clk_put(mxc_usb_clk);
+ 	}
+-	clk_disable(mxc_ahb_clk);
+-	clk_put(mxc_ahb_clk);
++	if (!cpu_is_mx35()) {
++		clk_disable(mxc_ahb_clk);
++		clk_put(mxc_ahb_clk);
++	}
+ }
+-- 
+1.6.2.1
+
diff --git a/recipes/linux/linux-2.6.31/pcm043/Update-PCM043-board-support.patch b/recipes/linux/linux-2.6.31/pcm043/Update-PCM043-board-support.patch
new file mode 100644
index 0000000..117611e
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/Update-PCM043-board-support.patch
@@ -0,0 +1,134 @@
+Based on 
+From 0d4941a59648e16d99624cf16812d5ae83986187 Mon Sep 17 00:00:00 2001
+From: Sascha Hauer <s.hauer at pengutronix.de>
+Date: Fri, 6 Feb 2009 15:42:26 +0100
+Subject: [PATCH 026/101] [ARM] MX35: Add PCM043 board support
+
+add USB support
+
+Signed-off-by: Jan Weitzel <J.Weitzel at phytec.de>
+---
+Index: linux-2.6.31.6/arch/arm/mach-mx3/pcm043.c
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/mach-mx3/pcm043.c	2009-12-10 11:59:35.364772725 +0100
++++ linux-2.6.31.6/arch/arm/mach-mx3/pcm043.c	2009-12-10 13:45:21.484650731 +0100
+@@ -28,6 +28,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/i2c.h>
+ #include <linux/i2c/at24.h>
++#include <linux/fsl_devices.h>
+ #include <linux/delay.h>
+ 
+ #include <asm/mach-types.h>
+@@ -44,6 +45,7 @@
+ #include <mach/iomux-mx35.h>
+ #include <mach/ipu.h>
+ #include <mach/mx3fb.h>
++#include <mach/mxc_ehci.h>
+ #include <mach/audmux.h>
+ #include <mach/ssi.h>
+ 
+@@ -207,6 +209,9 @@
+ 	MX35_PAD_D3_REV__IPU_DISPB_D3_REV,
+ 	MX35_PAD_D3_CLS__IPU_DISPB_D3_CLS,
+ 	MX35_PAD_D3_SPL__IPU_DISPB_D3_SPL,
++	/* USB host */
++	MX35_PAD_I2C2_CLK__USB_TOP_USBH2_PWR,
++	MX35_PAD_I2C2_DAT__USB_TOP_USBH2_OC,
+ 	/* SSI */
+ 	MX35_PAD_STXFS4__AUDMUX_AUD4_TXFS,
+ 	MX35_PAD_STXD4__AUDMUX_AUD4_TXD,
+@@ -214,6 +219,66 @@
+ 	MX35_PAD_SCK4__AUDMUX_AUD4_TXC,
+ };
+ 
++static int pcm043_usbh1_init(struct platform_device *pdev)
++{
++	unsigned int tmp;
++
++	tmp = readl(IO_ADDRESS(MX35_OTG_BASE_ADDR) + 0x600);
++	tmp &= ~((3 << 21) | (1 << 2) | (1 << 16));
++	tmp |= (1 << 4) | (2 << 21) | (1 << 19) | (1 << 12) | (1 << 6) | (1 << 5);
++	writel(tmp, IO_ADDRESS(MX35_OTG_BASE_ADDR) + 0x600);
++
++	tmp = readl(IO_ADDRESS(MX35_OTG_BASE_ADDR) + 0x584);
++	tmp |= (3 << 30);
++	writel(tmp, IO_ADDRESS(MX35_OTG_BASE_ADDR) + 0x584);
++
++	return 0;
++}
++
++static struct mxc_usbh_platform_data usbh1_pdata = {
++	.init = pcm043_usbh1_init,
++};
++
++static int pcm043_otg_init(struct platform_device *pdev)
++{
++	unsigned int tmp;
++
++	tmp = readl(IO_ADDRESS(MX35_OTG_BASE_ADDR) + 0x600);
++	tmp &= ~(3 << 29);
++	tmp |= (2 << 29);
++	writel(tmp, IO_ADDRESS(MX35_OTG_BASE_ADDR) + 0x600);
++
++	tmp = readl(IO_ADDRESS(MX35_OTG_BASE_ADDR) + 0x184);
++	tmp &= ~(3 << 30);
++	writel(tmp, IO_ADDRESS(MX35_OTG_BASE_ADDR) + 0x184);
++
++	return 0;
++}
++
++static struct mxc_usbh_platform_data otg_pdata = {
++	.init = pcm043_otg_init,
++};
++
++static struct fsl_usb2_platform_data usb_data = {
++	.operating_mode	= FSL_USB2_DR_DEVICE,
++	.phy_mode	= FSL_USB2_PHY_UTMI,
++};
++
++static int otg_mode_host;
++
++static int __init pcm043_otg_mode(char *options)
++{
++	if (!strcmp(options, "host"))
++		otg_mode_host = 1;
++	else if (!strcmp(options, "device"))
++		otg_mode_host = 0;
++	else
++		pr_info("pcm043_otg_mode neither \"host\" nor \"device\". "
++			"Defaulting to device\n");
++	return 0;
++}
++__setup("pcm043_otg_mode=", pcm043_otg_mode);
++
+ #define AC97_GPIO_TXFS	(1 * 32 + 31)
+ #define AC97_GPIO_TXD	(1 * 32 + 28)
+ #define AC97_GPIO_RESET	(1 * 32 + 0)
+@@ -299,6 +364,8 @@
+  */
+ static void __init mxc_board_init(void)
+ {
++	unsigned int tmp;
++
+ 	mxc_iomux_v3_setup_multiple_pads(pcm043_pads, ARRAY_SIZE(pcm043_pads));
+ 
+ 	mxc_audmux_v2_configure_port(3,
+@@ -329,6 +396,17 @@
+ 
+ 	mxc_register_device(&mx3_ipu, &mx3_ipu_data);
+ 	mxc_register_device(&mx3_fb, &mx3fb_pdata);
++
++	tmp = readl(IO_ADDRESS(MX35_OTG_BASE_ADDR) + 0x600);
++	tmp &= ~(3 << 29);
++	tmp |= (2 << 29);
++	writel(tmp, IO_ADDRESS(MX35_OTG_BASE_ADDR) + 0x600);
++
++	mxc_register_device(&mxc_usbh1, &usbh1_pdata);
++	if (otg_mode_host)
++		mxc_register_device(&mxc_otg, &otg_pdata);
++	else
++		mxc_register_device(&mxc_otg_udc_device, &usb_data);
+ }
+ 
+ static void __init pcm043_timer_init(void)
diff --git a/recipes/linux/linux-2.6.31/pcm043/add-led-gpio.patch b/recipes/linux/linux-2.6.31/pcm043/add-led-gpio.patch
new file mode 100644
index 0000000..cbd096b
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/add-led-gpio.patch
@@ -0,0 +1,17 @@
+Add support for the LED on baseboard
+
+Signed-off-by: Jan Weitzel <J.Weitzel at phytec.de>
+---
+Index: linux-2.6.31.6/arch/arm/mach-mx3/pcm043.c
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/mach-mx3/pcm043.c	2009-12-11 13:56:03.526475695 +0100
++++ linux-2.6.31.6/arch/arm/mach-mx3/pcm043.c	2009-12-11 13:58:49.894701069 +0100
+@@ -250,6 +250,8 @@
+ 	MX35_PAD_SCK4__AUDMUX_AUD4_TXC,
+   	/* 1-Wire*/
+ 	MX35_PAD_GPIO1_0__OWIRE_LINE,
++	/* GPIO */
++	MX35_PAD_ATA_CS0__GPIO2_6,
+ 	/* CAN */
+         MX35_PAD_SD2_DATA2__CAN1_RXCAN,
+         MX35_PAD_SD2_DATA3__CAN1_TXCAN,
diff --git a/recipes/linux/linux-2.6.31/pcm043/add_mmc.diff b/recipes/linux/linux-2.6.31/pcm043/add_mmc.diff
new file mode 100644
index 0000000..fb3a3c7
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/add_mmc.diff
@@ -0,0 +1,1396 @@
+From: Wolfram Sang <w.sang at pengutronix.de>
+Subject: add preliminary MMC support to MX35
+
+WIP!
+
+This is the backported SDHCI-driver from top of tree with the modifications needed
+to make the esdhc-version from FSL work with it. There are still some issues left,
+especially stylewise, this is more a proof-of-concept for the approach.
+
+WIP!
+
+Not suitable for upstream (yet).
+
+Signed-off-by: Wolfram Sang <w.sang at pengutronix.de>
+---
+ arch/arm/mach-mx3/pcm043.c          |   30 ++++
+ drivers/mmc/host/Kconfig            |  137 +++++++++++++++++++--
+ drivers/mmc/host/Makefile           |   14 +-
+ drivers/mmc/host/sdhci-esdhc.c      |  215 +++++++++++++++++++++++++++++++++
+ drivers/mmc/host/sdhci-of-core.c    |  231 ++++++++++++++++++++++++++++++++++++
+ drivers/mmc/host/sdhci-of-hlwd.c    |   65 ++++++++++
+ drivers/mmc/host/sdhci-of.h         |   37 +++++
+ drivers/mmc/host/sdhci-pltfm-core.c |  187 +++++++++++++++++++++++++++++
+ drivers/mmc/host/sdhci.c            |   56 ++++----
+ drivers/mmc/host/sdhci.h            |   51 ++++---
+ 10 files changed, 964 insertions(+), 59 deletions(-)
+
+Index: drivers/mmc/host/Kconfig
+===================================================================
+--- drivers/mmc/host/Kconfig.orig
++++ drivers/mmc/host/Kconfig
+@@ -44,6 +44,19 @@ config MMC_SDHCI_IO_ACCESSORS
+ 	  This is silent Kconfig symbol that is selected by the drivers that
+ 	  need to overwrite SDHCI IO memory accessors.
+ 
++config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
++	bool
++	select MMC_SDHCI_IO_ACCESSORS
++	help
++	  This option is selected by drivers running on big endian hosts
++	  and performing I/O to a SDHCI controller through a bus that
++	  implements a hardware byte swapper using a 32-bit datum.
++	  This endian mapping mode is called "data invariance" and
++	  has the effect of scrambling the addresses and formats of data
++	  accessed in sizes other than the datum size.
++
++	  This is the case for the Freescale eSDHC and Nintendo Wii SDHCI.
++
+ config MMC_SDHCI_PCI
+ 	tristate "SDHCI support on PCI bus"
+ 	depends on MMC_SDHCI && PCI
+@@ -72,14 +85,33 @@ config MMC_RICOH_MMC
+ 
+ 	  If unsure, say Y.
+ 
++config MMC_SDHCI_ESDHC
++	bool "SDHCI support for the Freescale eSDHC controller"
++	depends on MMC_SDHCI_OF || MMC_SDHCI_PLTFM
++	select MMC_SDHCI_IO_ACCESSORS
++	select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER if MMC_SDHCI_OF
++	help
++	  This selects the Freescale eSDHC controller support.
++
++	  If unsure, say N.
++
+ config MMC_SDHCI_OF
+ 	tristate "SDHCI support on OpenFirmware platforms"
+ 	depends on MMC_SDHCI && PPC_OF
+-	select MMC_SDHCI_IO_ACCESSORS
+ 	help
+ 	  This selects the OF support for Secure Digital Host Controller
+-	  Interfaces. So far, only the Freescale eSDHC controller is known
+-	  to exist on OF platforms.
++	  Interfaces.
++
++	  If unsure, say N.
++
++config MMC_SDHCI_OF_HLWD
++	bool "SDHCI OF support for the Nintendo Wii SDHCI controllers"
++	depends on MMC_SDHCI_OF
++	select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
++	help
++	  This selects the Secure Digital Host Controller Interface (SDHCI)
++	  found in the "Hollywood" chipset of the Nintendo Wii video game
++	  console.
+ 
+ 	  If unsure, say N.
+ 
+@@ -132,11 +164,11 @@ config MMC_OMAP
+ 
+ config MMC_OMAP_HS
+ 	tristate "TI OMAP High Speed Multimedia Card Interface support"
+-	depends on ARCH_OMAP2430 || ARCH_OMAP3
++	depends on ARCH_OMAP2430 || ARCH_OMAP3 || ARCH_OMAP4
+ 	help
+ 	  This selects the TI OMAP High Speed Multimedia card Interface.
+-	  If you have an OMAP2430 or OMAP3 board with a Multimedia Card slot,
+-	  say Y or M here.
++	  If you have an OMAP2430 or OMAP3 board or OMAP4 board with a
++	  Multimedia Card slot, say Y or M here.
+ 
+ 	  If unsure, say N.
+ 
+@@ -160,6 +192,12 @@ config MMC_AU1X
+ 
+ 	  If unsure, say N.
+ 
++choice
++	prompt "Atmel SD/MMC Driver"
++	default MMC_ATMELMCI if AVR32
++	help
++	  Choose which driver to use for the Atmel MCI Silicon
++
+ config MMC_AT91
+ 	tristate "AT91 SD/MMC Card Interface support"
+ 	depends on ARCH_AT91
+@@ -170,17 +208,19 @@ config MMC_AT91
+ 
+ config MMC_ATMELMCI
+ 	tristate "Atmel Multimedia Card Interface support"
+-	depends on AVR32
++	depends on AVR32 || ARCH_AT91
+ 	help
+ 	  This selects the Atmel Multimedia Card Interface driver. If
+-	  you have an AT32 (AVR32) platform with a Multimedia Card
+-	  slot, say Y or M here.
++	  you have an AT32 (AVR32) or AT91 platform with a Multimedia
++	  Card slot, say Y or M here.
+ 
+ 	  If unsure, say N.
+ 
++endchoice
++
+ config MMC_ATMELMCI_DMA
+ 	bool "Atmel MCI DMA support (EXPERIMENTAL)"
+-	depends on MMC_ATMELMCI && DMA_ENGINE && EXPERIMENTAL
++	depends on MMC_ATMELMCI && AVR32 && DMA_ENGINE && EXPERIMENTAL
+ 	help
+ 	  Say Y here to have the Atmel MCI driver use a DMA engine to
+ 	  do data transfers and thus increase the throughput and
+@@ -199,6 +239,13 @@ config MMC_IMX
+ 
+ 	  If unsure, say N.
+ 
++config MMC_MSM7X00A
++	tristate "Qualcomm MSM 7X00A SDCC Controller Support"
++	depends on MMC && ARCH_MSM
++	help
++	  This provides support for the SD/MMC cell found in the
++          MSM 7X00A controllers from Qualcomm.
++
+ config MMC_MXC
+ 	tristate "Freescale i.MX2/3 Multimedia Card Interface support"
+ 	depends on ARCH_MXC
+@@ -236,6 +283,14 @@ config MMC_MVSDIO
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called mvsdio.
+ 
++config MMC_DAVINCI
++        tristate "TI DAVINCI Multimedia Card Interface support"
++        depends on ARCH_DAVINCI
++        help
++          This selects the TI DAVINCI Multimedia card Interface.
++          If you have an DAVINCI board with a Multimedia Card slot,
++          say Y or M here.  If unsure, say N.
++
+ config MMC_SPI
+ 	tristate "MMC/SD/SDIO over SPI"
+ 	depends on SPI_MASTER && !HIGHMEM && HAS_DMA
+@@ -261,6 +316,47 @@ config MMC_S3C
+ 
+ 	  If unsure, say N.
+ 
++config MMC_S3C_HW_SDIO_IRQ
++       bool "Hardware support for SDIO IRQ"
++       depends on MMC_S3C
++       help
++         Enable the hardware support for SDIO interrupts instead of using
++	 the generic polling code.
++
++choice
++	prompt "Samsung S3C SD/MMC transfer code"
++	depends on MMC_S3C
++
++config MMC_S3C_PIO
++	bool "Use PIO transfers only"
++	help
++	  Use PIO to transfer data between memory and the hardware.
++
++	  PIO is slower than DMA as it requires CPU instructions to
++	  move the data. This has been the traditional default for
++	  the S3C MCI driver.
++
++config MMC_S3C_DMA
++	bool "Use DMA transfers only (EXPERIMENTAL)"
++	depends on EXPERIMENTAL
++	help
++	  Use DMA to transfer data between memory and the hardare.
++
++	  Currently, the DMA support in this driver seems to not be
++	  working properly and needs to be debugged before this
++	  option is useful.
++
++config MMC_S3C_PIODMA
++	bool "Support for both PIO and DMA (EXPERIMENTAL)"
++	help
++	  Compile both the PIO and DMA transfer routines into the
++	  driver and let the platform select at run-time which one
++	  is best.
++
++	  See notes for the DMA option.
++
++endchoice
++
+ config MMC_SDRICOH_CS
+ 	tristate "MMC/SD driver for Ricoh Bay1Controllers (EXPERIMENTAL)"
+ 	depends on EXPERIMENTAL && PCI && PCMCIA
+@@ -273,7 +369,7 @@ config MMC_SDRICOH_CS
+ 
+ config MMC_TMIO
+ 	tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support"
+-	depends on MFD_TMIO || MFD_ASIC3
++	depends on MFD_TMIO || MFD_ASIC3 || SUPERH
+ 	help
+ 	  This provides support for the SD/MMC cell found in TC6393XB,
+ 	  T7L66XB and also HTC ASIC3
+@@ -301,3 +397,22 @@ config MMC_VIA_SDMMC
+ 	  If you have a controller with this interface, say Y or M here.
+ 
+ 	  If unsure, say N.
++
++config SDH_BFIN
++	tristate "Blackfin Secure Digital Host support"
++	depends on MMC && ((BF54x && !BF544) || (BF51x && !BF512))
++	help
++	  If you say yes here you will get support for the Blackfin on-chip
++	  Secure Digital Host interface.  This includes support for MMC and
++	  SD cards.
++
++	  To compile this driver as a module, choose M here: the
++	  module will be called bfin_sdh.
++
++	  If unsure, say N.
++
++config SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND
++	bool "Blackfin EZkit Missing SDH_CMD Pull Up Resistor Workaround"
++	depends on SDH_BFIN
++	help
++	  If you say yes here SD-Cards may work on the EZkit.
+Index: drivers/mmc/host/Makefile
+===================================================================
+--- drivers/mmc/host/Makefile.orig
++++ drivers/mmc/host/Makefile
+@@ -13,8 +13,6 @@ obj-$(CONFIG_MMC_MXC)		+= mxcmmc.o
+ obj-$(CONFIG_MMC_SDHCI)		+= sdhci.o
+ obj-$(CONFIG_MMC_SDHCI_PCI)	+= sdhci-pci.o
+ obj-$(CONFIG_MMC_RICOH_MMC)	+= ricoh_mmc.o
+-obj-$(CONFIG_MMC_SDHCI_OF)	+= sdhci-of.o
+-obj-$(CONFIG_MMC_SDHCI_PLTFM)	+= sdhci-pltfm.o
+ obj-$(CONFIG_MMC_SDHCI_S3C)	+= sdhci-s3c.o
+ obj-$(CONFIG_MMC_WBSD)		+= wbsd.o
+ obj-$(CONFIG_MMC_AU1X)		+= au1xmmc.o
+@@ -23,7 +21,9 @@ obj-$(CONFIG_MMC_OMAP_HS)	+= omap_hsmmc.
+ obj-$(CONFIG_MMC_AT91)		+= at91_mci.o
+ obj-$(CONFIG_MMC_ATMELMCI)	+= atmel-mci.o
+ obj-$(CONFIG_MMC_TIFM_SD)	+= tifm_sd.o
++obj-$(CONFIG_MMC_MSM7X00A)	+= msm_sdcc.o
+ obj-$(CONFIG_MMC_MVSDIO)	+= mvsdio.o
++obj-$(CONFIG_MMC_DAVINCI)       += davinci_mmc.o
+ obj-$(CONFIG_MMC_SPI)		+= mmc_spi.o
+ ifeq ($(CONFIG_OF),y)
+ obj-$(CONFIG_MMC_SPI)		+= of_mmc_spi.o
+@@ -33,6 +33,16 @@ obj-$(CONFIG_MMC_SDRICOH_CS)	+= sdricoh_
+ obj-$(CONFIG_MMC_TMIO)		+= tmio_mmc.o
+ obj-$(CONFIG_MMC_CB710)	+= cb710-mmc.o
+ obj-$(CONFIG_MMC_VIA_SDMMC)	+= via-sdmmc.o
++obj-$(CONFIG_SDH_BFIN)		+= bfin_sdh.o
++
++obj-$(CONFIG_MMC_SDHCI_OF)	+= sdhci-of.o
++sdhci-of-y				:= sdhci-of-core.o
++sdhci-of-$(CONFIG_MMC_SDHCI_ESDHC)	+= sdhci-esdhc.o
++sdhci-of-$(CONFIG_MMC_SDHCI_OF_HLWD)	+= sdhci-of-hlwd.o
++
++obj-$(CONFIG_MMC_SDHCI_PLTFM)	+= sdhci-pltfm.o
++sdhci-pltfm-y				:= sdhci-pltfm-core.o
++sdhci-pltfm-$(CONFIG_MMC_SDHCI_ESDHC)	+= sdhci-esdhc.o
+ 
+ ifeq ($(CONFIG_CB710_DEBUG),y)
+ 	CFLAGS-cb710-mmc	+= -DDEBUG
+Index: drivers/mmc/host/sdhci-esdhc.c
+===================================================================
+--- /dev/null
++++ drivers/mmc/host/sdhci-esdhc.c
+@@ -0,0 +1,215 @@
++/*
++ * Freescale eSDHC controller driver.
++ *
++ * Copyright (c) 2007 Freescale Semiconductor, Inc.
++ * Copyright (c) 2009 MontaVista Software, Inc.
++ *
++ * Authors: Xiaobo Xie <X.Xie at freescale.com>
++ *	    Anton Vorontsov <avorontsov at ru.mvista.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/io.h>
++#include <linux/delay.h>
++#include <linux/mmc/host.h>
++#include "sdhci-of.h"
++#include "sdhci.h"
++
++/*
++ * Ops and quirks for the Freescale eSDHC controller.
++ */
++
++#define ESDHC_DMA_SYSCTL	0x40c
++#define ESDHC_DMA_SNOOP		0x00000040
++
++#define ESDHC_SYSTEM_CONTROL	0x2c
++#define ESDHC_CLOCK_MASK	0x0000fff0
++#define ESDHC_PREDIV_SHIFT	8
++#define ESDHC_DIVIDER_SHIFT	4
++#define ESDHC_CLOCK_PEREN	0x00000004
++#define ESDHC_CLOCK_HCKEN	0x00000002
++#define ESDHC_CLOCK_IPGEN	0x00000001
++
++#define ESDHC_HOST_CONTROL_RES	0x05
++
++#ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
++
++static u16 esdhc_readw_be(struct sdhci_host *host, int reg)
++{
++	u16 ret;
++
++	if (unlikely(reg == SDHCI_HOST_VERSION))
++		ret = in_be16(host->ioaddr + reg);
++	else
++		ret = sdhci_be32bs_readw(host, reg);
++	return ret;
++}
++
++static void esdhc_writew_be(struct sdhci_host *host, u16 val, int reg)
++{
++	if (reg == SDHCI_BLOCK_SIZE) {
++		/*
++		 * Two last DMA bits are reserved, and first one is used for
++		 * non-standard blksz of 4096 bytes that we don't support
++		 * yet. So clear the DMA boundary bits.
++		 */
++		val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
++	}
++	sdhci_be32bs_writew(host, val, reg);
++}
++
++static void esdhc_writeb_be(struct sdhci_host *host, u8 val, int reg)
++{
++	/* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */
++	if (reg == SDHCI_HOST_CONTROL)
++		val &= ~ESDHC_HOST_CONTROL_RES;
++	sdhci_be32bs_writeb(host, val, reg);
++}
++
++static int esdhc_enable_dma(struct sdhci_host *host)
++{
++	u32 temp = sdhci_readl(host, ESDHC_DMA_SYSCTL);
++
++	temp |= ESDHC_DMA_SNOOP;
++	sdhci_writel(host, temp, ESDHC_DMA_SYSCTL);
++	return 0;
++}
++
++#else
++
++static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
++{
++	void __iomem *base = host->ioaddr + (reg & ~0x3);
++	u32 shift = (reg & 0x3) * 8;
++
++	writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
++}
++
++static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
++{
++	if (unlikely(reg == SDHCI_HOST_VERSION))
++		reg ^= 2;
++
++	return readw(host->ioaddr + reg);
++}
++
++static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
++{
++	static u16 ugh;
++
++	switch (reg) {
++	case SDHCI_TRANSFER_MODE:
++		/*
++		 * Postpone this write, we must do it together with a
++		 * command write that is down below.
++		 */
++		//of_host->xfer_mode_shadow = val;
++		ugh = val;
++		return;
++	case SDHCI_COMMAND:
++		writel(val << 16 | ugh, host->ioaddr + SDHCI_TRANSFER_MODE);
++		return;
++	case SDHCI_BLOCK_SIZE:
++		val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
++		break;
++	}
++	esdhc_clrset_le(host, 0xffff, val, reg);
++}
++
++static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
++{
++	switch (reg) {
++	case SDHCI_POWER_CONTROL:
++		/* FSL put the DMA bits there, so skip :( */
++		return;
++	case SDHCI_HOST_CONTROL:
++		val &= 0x07;
++		val |= 0x20;
++		break;
++	}
++	esdhc_clrset_le(host, 0xff, val, reg);
++}
++
++#endif /* CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER */
++
++static void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
++{
++	int pre_div = 2;
++	int div = 1;
++	u32 temp;
++
++	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
++	temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK);
++	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
++
++	if (clock == 0)
++		goto out;
++
++	while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
++		pre_div *= 2;
++
++	while (host->max_clk / pre_div / div > clock && div < 16)
++		div++;
++
++	dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d (%02x %02x)\n",
++		clock, host->max_clk / pre_div / div, pre_div, div);
++
++	pre_div >>= 1;
++	div--;
++
++	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
++	temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN |
++		  div << ESDHC_DIVIDER_SHIFT | pre_div << ESDHC_PREDIV_SHIFT);
++	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
++	mdelay(100);
++out:
++	host->clock = clock;
++}
++
++static unsigned int esdhc_get_max_clock(struct sdhci_host *host)
++{
++	struct sdhci_of_host *of_host = sdhci_priv(host);
++
++	return of_host->clock;
++}
++
++static unsigned int esdhc_get_min_clock(struct sdhci_host *host)
++{
++	struct sdhci_of_host *of_host = sdhci_priv(host);
++
++	return of_host->clock / 256 / 16;
++}
++
++struct sdhci_quirk_data sdhci_esdhc = {
++	.quirks = SDHCI_QUIRK_FORCE_BLK_SZ_2048 |
++		  SDHCI_QUIRK_BROKEN_CARD_DETECTION |
++		  SDHCI_QUIRK_NO_BUSY_IRQ |
++		  SDHCI_QUIRK_NONSTANDARD_CLOCK |
++		  SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
++		  SDHCI_QUIRK_PIO_NEEDS_DELAY |
++		  SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET |
++		   SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
++		  SDHCI_QUIRK_NO_CARD_NO_RESET,
++	.ops = {
++#ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
++		.custom_readl = sdhci_be32bs_readl,
++		.custom_readw = esdhc_readw_be,
++		.custom_readb = sdhci_be32bs_readb,
++		.custom_writel = sdhci_be32bs_writel,
++		.custom_writew = esdhc_writew_be,
++		.custom_writeb = esdhc_writeb_be,
++		.enable_dma = esdhc_enable_dma,
++#else
++		.custom_readw = esdhc_readw_le,
++		.custom_writew = esdhc_writew_le,
++		.custom_writeb = esdhc_writeb_le,
++#endif
++		.set_clock = esdhc_set_clock,
++		.get_max_clock = esdhc_get_max_clock,
++		.get_min_clock = esdhc_get_min_clock,
++	},
++};
+Index: drivers/mmc/host/sdhci-of-core.c
+===================================================================
+--- /dev/null
++++ drivers/mmc/host/sdhci-of-core.c
+@@ -0,0 +1,231 @@
++/*
++ * OpenFirmware bindings for Secure Digital Host Controller Interface.
++ *
++ * Copyright (c) 2007 Freescale Semiconductor, Inc.
++ * Copyright (c) 2009 MontaVista Software, Inc.
++ *
++ * Authors: Xiaobo Xie <X.Xie at freescale.com>
++ *	    Anton Vorontsov <avorontsov at ru.mvista.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/init.h>
++#include <linux/io.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/of.h>
++#include <linux/of_platform.h>
++#include <linux/mmc/host.h>
++#include <asm/machdep.h>
++#include "sdhci-of.h"
++#include "sdhci.h"
++
++#ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
++
++/*
++ * These accessors are designed for big endian hosts doing I/O to
++ * little endian controllers incorporating a 32-bit hardware byte swapper.
++ */
++
++u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg)
++{
++	return in_be32(host->ioaddr + reg);
++}
++
++u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg)
++{
++	return in_be16(host->ioaddr + (reg ^ 0x2));
++}
++
++u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg)
++{
++	return in_8(host->ioaddr + (reg ^ 0x3));
++}
++
++void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg)
++{
++	out_be32(host->ioaddr + reg, val);
++}
++
++void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg)
++{
++	struct sdhci_of_host *of_host = sdhci_priv(host);
++	int base = reg & ~0x3;
++	int shift = (reg & 0x2) * 8;
++
++	switch (reg) {
++	case SDHCI_TRANSFER_MODE:
++		/*
++		 * Postpone this write, we must do it together with a
++		 * command write that is down below.
++		 */
++		of_host->xfer_mode_shadow = val;
++		return;
++	case SDHCI_COMMAND:
++		sdhci_be32bs_writel(host, val << 16 | of_host->xfer_mode_shadow,
++				    SDHCI_TRANSFER_MODE);
++		return;
++	}
++	clrsetbits_be32(host->ioaddr + base, 0xffff << shift, val << shift);
++}
++
++void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg)
++{
++	int base = reg & ~0x3;
++	int shift = (reg & 0x3) * 8;
++
++	clrsetbits_be32(host->ioaddr + base , 0xff << shift, val << shift);
++}
++#endif /* CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER */
++
++#ifdef CONFIG_PM
++
++static int sdhci_of_suspend(struct of_device *ofdev, pm_message_t state)
++{
++	struct sdhci_host *host = dev_get_drvdata(&ofdev->dev);
++
++	return mmc_suspend_host(host->mmc, state);
++}
++
++static int sdhci_of_resume(struct of_device *ofdev)
++{
++	struct sdhci_host *host = dev_get_drvdata(&ofdev->dev);
++
++	return mmc_resume_host(host->mmc);
++}
++
++#else
++
++#define sdhci_of_suspend NULL
++#define sdhci_of_resume NULL
++
++#endif
++
++static bool __devinit sdhci_of_wp_inverted(struct device_node *np)
++{
++	if (of_get_property(np, "sdhci,wp-inverted", NULL))
++		return true;
++
++	/* Old device trees don't have the wp-inverted property. */
++	return machine_is(mpc837x_rdb) || machine_is(mpc837x_mds);
++}
++
++static int __devinit sdhci_of_probe(struct of_device *ofdev,
++				 const struct of_device_id *match)
++{
++	struct device_node *np = ofdev->node;
++	struct sdhci_quirk_data *sdhci_of_data = match->data;
++	struct sdhci_host *host;
++	struct sdhci_of_host *of_host;
++	const u32 *clk;
++	int size;
++	int ret;
++
++	if (!of_device_is_available(np))
++		return -ENODEV;
++
++	host = sdhci_alloc_host(&ofdev->dev, sizeof(*of_host));
++	if (IS_ERR(host))
++		return -ENOMEM;
++
++	of_host = sdhci_priv(host);
++	dev_set_drvdata(&ofdev->dev, host);
++
++	host->ioaddr = of_iomap(np, 0);
++	if (!host->ioaddr) {
++		ret = -ENOMEM;
++		goto err_addr_map;
++	}
++
++	host->irq = irq_of_parse_and_map(np, 0);
++	if (!host->irq) {
++		ret = -EINVAL;
++		goto err_no_irq;
++	}
++
++	host->hw_name = dev_name(&ofdev->dev);
++	if (sdhci_of_data) {
++		host->quirks = sdhci_of_data->quirks;
++		host->ops = &sdhci_of_data->ops;
++	}
++
++	if (of_get_property(np, "sdhci,1-bit-only", NULL))
++		host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
++
++	if (sdhci_of_wp_inverted(np))
++		host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
++
++	clk = of_get_property(np, "clock-frequency", &size);
++	if (clk && size == sizeof(*clk) && *clk)
++		of_host->clock = *clk;
++
++	ret = sdhci_add_host(host);
++	if (ret)
++		goto err_add_host;
++
++	return 0;
++
++err_add_host:
++	irq_dispose_mapping(host->irq);
++err_no_irq:
++	iounmap(host->ioaddr);
++err_addr_map:
++	sdhci_free_host(host);
++	return ret;
++}
++
++static int __devexit sdhci_of_remove(struct of_device *ofdev)
++{
++	struct sdhci_host *host = dev_get_drvdata(&ofdev->dev);
++
++	sdhci_remove_host(host, 0);
++	sdhci_free_host(host);
++	irq_dispose_mapping(host->irq);
++	iounmap(host->ioaddr);
++	return 0;
++}
++
++static const struct of_device_id sdhci_of_match[] = {
++#ifdef CONFIG_MMC_SDHCI_OF_ESDHC
++	{ .compatible = "fsl,mpc8379-esdhc", .data = &sdhci_esdhc, },
++	{ .compatible = "fsl,mpc8536-esdhc", .data = &sdhci_esdhc, },
++	{ .compatible = "fsl,esdhc", .data = &sdhci_esdhc, },
++#endif
++#ifdef CONFIG_MMC_SDHCI_OF_HLWD
++	{ .compatible = "nintendo,hollywood-sdhci", .data = &sdhci_hlwd, },
++#endif
++	{ .compatible = "generic-sdhci", },
++	{},
++};
++MODULE_DEVICE_TABLE(of, sdhci_of_match);
++
++static struct of_platform_driver sdhci_of_driver = {
++	.driver.name = "sdhci-of",
++	.match_table = sdhci_of_match,
++	.probe = sdhci_of_probe,
++	.remove = __devexit_p(sdhci_of_remove),
++	.suspend = sdhci_of_suspend,
++	.resume	= sdhci_of_resume,
++};
++
++static int __init sdhci_of_init(void)
++{
++	return of_register_platform_driver(&sdhci_of_driver);
++}
++module_init(sdhci_of_init);
++
++static void __exit sdhci_of_exit(void)
++{
++	of_unregister_platform_driver(&sdhci_of_driver);
++}
++module_exit(sdhci_of_exit);
++
++MODULE_DESCRIPTION("Secure Digital Host Controller Interface OF driver");
++MODULE_AUTHOR("Xiaobo Xie <X.Xie at freescale.com>, "
++	      "Anton Vorontsov <avorontsov at ru.mvista.com>");
++MODULE_LICENSE("GPL");
+Index: drivers/mmc/host/sdhci-of-hlwd.c
+===================================================================
+--- /dev/null
++++ drivers/mmc/host/sdhci-of-hlwd.c
+@@ -0,0 +1,65 @@
++/*
++ * drivers/mmc/host/sdhci-of-hlwd.c
++ *
++ * Nintendo Wii Secure Digital Host Controller Interface.
++ * Copyright (C) 2009 The GameCube Linux Team
++ * Copyright (C) 2009 Albert Herranz
++ *
++ * Based on sdhci-of-esdhc.c
++ *
++ * Copyright (c) 2007 Freescale Semiconductor, Inc.
++ * Copyright (c) 2009 MontaVista Software, Inc.
++ *
++ * Authors: Xiaobo Xie <X.Xie at freescale.com>
++ *	    Anton Vorontsov <avorontsov at ru.mvista.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/delay.h>
++#include <linux/mmc/host.h>
++#include "sdhci-of.h"
++#include "sdhci.h"
++
++/*
++ * Ops and quirks for the Nintendo Wii SDHCI controllers.
++ */
++
++/*
++ * We need a small delay after each write, or things go horribly wrong.
++ */
++#define SDHCI_HLWD_WRITE_DELAY	5 /* usecs */
++
++static void sdhci_hlwd_writel(struct sdhci_host *host, u32 val, int reg)
++{
++	sdhci_be32bs_writel(host, val, reg);
++	udelay(SDHCI_HLWD_WRITE_DELAY);
++}
++
++static void sdhci_hlwd_writew(struct sdhci_host *host, u16 val, int reg)
++{
++	sdhci_be32bs_writew(host, val, reg);
++	udelay(SDHCI_HLWD_WRITE_DELAY);
++}
++
++static void sdhci_hlwd_writeb(struct sdhci_host *host, u8 val, int reg)
++{
++	sdhci_be32bs_writeb(host, val, reg);
++	udelay(SDHCI_HLWD_WRITE_DELAY);
++}
++
++struct sdhci_quirk_data sdhci_hlwd = {
++	.quirks = SDHCI_QUIRK_32BIT_DMA_ADDR |
++		  SDHCI_QUIRK_32BIT_DMA_SIZE,
++	.ops = {
++		.readl = sdhci_be32bs_readl,
++		.readw = sdhci_be32bs_readw,
++		.readb = sdhci_be32bs_readb,
++		.writel = sdhci_hlwd_writel,
++		.writew = sdhci_hlwd_writew,
++		.writeb = sdhci_hlwd_writeb,
++	},
++};
+Index: drivers/mmc/host/sdhci-of.h
+===================================================================
+--- /dev/null
++++ drivers/mmc/host/sdhci-of.h
+@@ -0,0 +1,37 @@
++/*
++ * OpenFirmware bindings for Secure Digital Host Controller Interface.
++ *
++ * Copyright (c) 2007 Freescale Semiconductor, Inc.
++ * Copyright (c) 2009 MontaVista Software, Inc.
++ *
++ * Authors: Xiaobo Xie <X.Xie at freescale.com>
++ *	    Anton Vorontsov <avorontsov at ru.mvista.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or (at
++ * your option) any later version.
++ */
++
++#ifndef __SDHCI_OF_H
++#define __SDHCI_OF_H
++
++#include <linux/types.h>
++#include "sdhci.h"
++
++struct sdhci_of_host {
++	unsigned int clock;
++	u16 xfer_mode_shadow;
++};
++
++extern u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg);
++extern u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg);
++extern u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg);
++extern void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg);
++extern void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg);
++extern void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg);
++
++extern struct sdhci_quirk_data sdhci_esdhc;
++extern struct sdhci_quirk_data sdhci_hlwd;
++
++#endif /* __SDHCI_OF_H */
+Index: drivers/mmc/host/sdhci-pltfm-core.c
+===================================================================
+--- /dev/null
++++ drivers/mmc/host/sdhci-pltfm-core.c
+@@ -0,0 +1,187 @@
++/*
++ * sdhci-pltfm.c Support for SDHCI platform devices
++ * Copyright (c) 2009 Intel Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++/* Supports:
++ * SDHCI platform devices
++ *
++ * Inspired by sdhci-pci.c, by Pierre Ossman
++ */
++
++#include <linux/delay.h>
++#include <linux/highmem.h>
++#include <linux/platform_device.h>
++#include <linux/mmc/host.h>
++#include <linux/clk.h>
++#include <linux/io.h>
++
++#include "sdhci.h"
++#include "sdhci-of.h"
++
++/*****************************************************************************\
++ *                                                                           *
++ * Device probing/removal                                                    *
++ *                                                                           *
++\*****************************************************************************/
++
++static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
++{
++	struct sdhci_host *host;
++	struct resource *iomem;
++	struct sdhci_of_host *of_host;
++	struct clk *clk;
++	int ret;
++	struct sdhci_quirk_data *quirk = (struct sdhci_quirk_data *) 
++			platform_get_device_id(pdev)->driver_data;
++
++	BUG_ON(pdev == NULL);
++
++	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!iomem) {
++		ret = -ENOMEM;
++		goto err;
++	}
++
++	if (resource_size(iomem) != 0x100)
++		dev_err(&pdev->dev, "Invalid iomem size. You may "
++			"experience problems.\n");
++
++	if (pdev->dev.parent)
++		host = sdhci_alloc_host(pdev->dev.parent, sizeof(struct sdhci_of_host));
++	else
++		host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_of_host));
++
++	if (IS_ERR(host)) {
++		ret = PTR_ERR(host);
++		goto err;
++	}
++
++	of_host = sdhci_priv(host);
++	dev_set_drvdata(&pdev->dev, host);
++
++	host->hw_name = "platform";
++	host->irq = platform_get_irq(pdev, 0);
++
++	if (!request_mem_region(iomem->start, resource_size(iomem),
++		mmc_hostname(host->mmc))) {
++		dev_err(&pdev->dev, "cannot request region\n");
++		ret = -EBUSY;
++		goto err_request;
++	}
++
++	host->ioaddr = ioremap(iomem->start, resource_size(iomem));
++	if (!host->ioaddr) {
++		dev_err(&pdev->dev, "failed to remap registers\n");
++		ret = -ENOMEM;
++		goto err_remap;
++	}
++
++	if (quirk) {
++		host->quirks = quirk->quirks;
++		host->ops = &quirk->ops;
++	}
++
++	clk = clk_get(NULL, "sdhc");
++	if (IS_ERR(clk)) {
++		dev_err(&pdev->dev, "clk err\n");
++		return -ENODEV;
++	}
++	clk_enable(clk);
++	of_host->clock = clk_get_rate(clk);
++
++	ret = sdhci_add_host(host);
++	if (ret)
++		goto err_add_host;
++
++	platform_set_drvdata(pdev, host);
++	dev_info(&pdev->dev, "registered as %s\n", platform_get_device_id(pdev)->name);
++
++	return 0;
++
++err_add_host:
++	iounmap(host->ioaddr);
++err_remap:
++	release_mem_region(iomem->start, resource_size(iomem));
++err_request:
++	sdhci_free_host(host);
++err:
++	printk(KERN_ERR"Probing of sdhci-pltfm failed: %d\n", ret);
++	return ret;
++}
++
++static int __devexit sdhci_pltfm_remove(struct platform_device *pdev)
++{
++	struct sdhci_host *host = platform_get_drvdata(pdev);
++	struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	int dead;
++	u32 scratch;
++
++	dead = 0;
++	scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
++	if (scratch == (u32)-1)
++		dead = 1;
++
++	sdhci_remove_host(host, dead);
++	iounmap(host->ioaddr);
++	release_mem_region(iomem->start, resource_size(iomem));
++	sdhci_free_host(host);
++	platform_set_drvdata(pdev, NULL);
++
++	return 0;
++}
++
++static struct platform_device_id sdhci_id_table[] = {
++	{ "sdhci",		0, },
++#ifdef CONFIG_MMC_SDHCI_ESDHC
++	{ "sdhci-esdhc",	(kernel_ulong_t)&sdhci_esdhc, },
++#endif
++        { },
++};
++MODULE_DEVICE_TABLE(platform, sdhci_id_table);
++
++static struct platform_driver sdhci_pltfm_driver = {
++	.driver = {
++		.name	= "sdhci",
++		.owner	= THIS_MODULE,
++	},
++	.probe		= sdhci_pltfm_probe,
++	.remove		= __devexit_p(sdhci_pltfm_remove),
++	.id_table	= sdhci_id_table,
++};
++
++/*****************************************************************************\
++ *                                                                           *
++ * Driver init/exit                                                          *
++ *                                                                           *
++\*****************************************************************************/
++
++static int __init sdhci_drv_init(void)
++{
++	return platform_driver_register(&sdhci_pltfm_driver);
++}
++
++static void __exit sdhci_drv_exit(void)
++{
++	platform_driver_unregister(&sdhci_pltfm_driver);
++}
++
++module_init(sdhci_drv_init);
++module_exit(sdhci_drv_exit);
++
++MODULE_DESCRIPTION("Secure Digital Host Controller Interface platform driver");
++MODULE_AUTHOR("Mocean Laboratories <info at mocean-labs.com>");
++MODULE_LICENSE("GPL v2");
+Index: drivers/mmc/host/sdhci.c
+===================================================================
+--- drivers/mmc/host/sdhci.c.orig
++++ drivers/mmc/host/sdhci.c
+@@ -58,7 +58,7 @@ static void sdhci_dumpregs(struct sdhci_
+ 		sdhci_readw(host, SDHCI_TRANSFER_MODE));
+ 	printk(KERN_DEBUG DRIVER_NAME ": Present:  0x%08x | Host ctl: 0x%08x\n",
+ 		sdhci_readl(host, SDHCI_PRESENT_STATE),
+-		sdhci_readb(host, SDHCI_HOST_CONTROL));
++		sdhci_readl(host, SDHCI_HOST_CONTROL));
+ 	printk(KERN_DEBUG DRIVER_NAME ": Power:    0x%08x | Blk gap:  0x%08x\n",
+ 		sdhci_readb(host, SDHCI_POWER_CONTROL),
+ 		sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL));
+@@ -591,6 +591,9 @@ static u8 sdhci_calc_timeout(struct sdhc
+ 	target_timeout = data->timeout_ns / 1000 +
+ 		data->timeout_clks / host->clock;
+ 
++	if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
++		host->timeout_clk = host->clock / 1000;
++
+ 	/*
+ 	 * Figure out needed cycles.
+ 	 * We do this in steps in order to fit inside a 32 bit int.
+@@ -652,7 +655,7 @@ static void sdhci_prepare_data(struct sd
+ 	count = sdhci_calc_timeout(host, data);
+ 	sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
+ 
+-	if (host->flags & SDHCI_USE_DMA)
++	if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))
+ 		host->flags |= SDHCI_REQ_USE_DMA;
+ 
+ 	/*
+@@ -991,8 +994,8 @@ static void sdhci_set_clock(struct sdhci
+ 	clk |= SDHCI_CLOCK_INT_EN;
+ 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+ 
+-	/* Wait max 10 ms */
+-	timeout = 10;
++	/* Wait max 20 ms */
++	timeout = 20;
+ 	while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
+ 		& SDHCI_CLOCK_INT_STABLE)) {
+ 		if (timeout == 0) {
+@@ -1597,7 +1600,7 @@ int sdhci_resume_host(struct sdhci_host 
+ {
+ 	int ret;
+ 
+-	if (host->flags & SDHCI_USE_DMA) {
++	if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
+ 		if (host->ops->enable_dma)
+ 			host->ops->enable_dma(host);
+ 	}
+@@ -1678,23 +1681,20 @@ int sdhci_add_host(struct sdhci_host *ho
+ 	caps = sdhci_readl(host, SDHCI_CAPABILITIES);
+ 
+ 	if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
+-		host->flags |= SDHCI_USE_DMA;
+-	else if (!(caps & SDHCI_CAN_DO_DMA))
+-		DBG("Controller doesn't have DMA capability\n");
++		host->flags |= SDHCI_USE_SDMA;
++	else if (!(caps & SDHCI_CAN_DO_SDMA))
++		DBG("Controller doesn't have SDMA capability\n");
+ 	else
+-		host->flags |= SDHCI_USE_DMA;
++		host->flags |= SDHCI_USE_SDMA;
+ 
+ 	if ((host->quirks & SDHCI_QUIRK_BROKEN_DMA) &&
+-		(host->flags & SDHCI_USE_DMA)) {
++		(host->flags & SDHCI_USE_SDMA)) {
+ 		DBG("Disabling DMA as it is marked broken\n");
+-		host->flags &= ~SDHCI_USE_DMA;
++		host->flags &= ~SDHCI_USE_SDMA;
+ 	}
+ 
+-	if (host->flags & SDHCI_USE_DMA) {
+-		if ((host->version >= SDHCI_SPEC_200) &&
+-				(caps & SDHCI_CAN_DO_ADMA2))
+-			host->flags |= SDHCI_USE_ADMA;
+-	}
++	if ((host->version >= SDHCI_SPEC_200) && (caps & SDHCI_CAN_DO_ADMA2))
++		host->flags |= SDHCI_USE_ADMA;
+ 
+ 	if ((host->quirks & SDHCI_QUIRK_BROKEN_ADMA) &&
+ 		(host->flags & SDHCI_USE_ADMA)) {
+@@ -1702,13 +1702,14 @@ int sdhci_add_host(struct sdhci_host *ho
+ 		host->flags &= ~SDHCI_USE_ADMA;
+ 	}
+ 
+-	if (host->flags & SDHCI_USE_DMA) {
++	if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
+ 		if (host->ops->enable_dma) {
+ 			if (host->ops->enable_dma(host)) {
+ 				printk(KERN_WARNING "%s: No suitable DMA "
+ 					"available. Falling back to PIO.\n",
+ 					mmc_hostname(mmc));
+-				host->flags &= ~(SDHCI_USE_DMA | SDHCI_USE_ADMA);
++				host->flags &=
++					~(SDHCI_USE_SDMA | SDHCI_USE_ADMA);
+ 			}
+ 		}
+ 	}
+@@ -1736,7 +1737,7 @@ int sdhci_add_host(struct sdhci_host *ho
+ 	 * mask, but PIO does not need the hw shim so we set a new
+ 	 * mask here in that case.
+ 	 */
+-	if (!(host->flags & SDHCI_USE_DMA)) {
++	if (!(host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))) {
+ 		host->dma_mask = DMA_BIT_MASK(64);
+ 		mmc_dev(host->mmc)->dma_mask = &host->dma_mask;
+ 	}
+@@ -1757,13 +1758,15 @@ int sdhci_add_host(struct sdhci_host *ho
+ 	host->timeout_clk =
+ 		(caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
+ 	if (host->timeout_clk == 0) {
+-		if (!host->ops->get_timeout_clock) {
++		if (host->ops->get_timeout_clock) {
++			host->timeout_clk = host->ops->get_timeout_clock(host);
++		} else if (!(host->quirks &
++				SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
+ 			printk(KERN_ERR
+ 			       "%s: Hardware doesn't specify timeout clock "
+ 			       "frequency.\n", mmc_hostname(mmc));
+ 			return -ENODEV;
+ 		}
+-		host->timeout_clk = host->ops->get_timeout_clock(host);
+ 	}
+ 	if (caps & SDHCI_TIMEOUT_CLK_UNIT)
+ 		host->timeout_clk *= 1000;
+@@ -1772,7 +1775,8 @@ int sdhci_add_host(struct sdhci_host *ho
+ 	 * Set host parameters.
+ 	 */
+ 	mmc->ops = &sdhci_ops;
+-	if (host->ops->get_min_clock)
++	if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK &&
++			host->ops->set_clock && host->ops->get_min_clock)
+ 		mmc->f_min = host->ops->get_min_clock(host);
+ 	else
+ 		mmc->f_min = host->max_clk / 256;
+@@ -1810,7 +1814,7 @@ int sdhci_add_host(struct sdhci_host *ho
+ 	 */
+ 	if (host->flags & SDHCI_USE_ADMA)
+ 		mmc->max_hw_segs = 128;
+-	else if (host->flags & SDHCI_USE_DMA)
++	else if (host->flags & SDHCI_USE_SDMA)
+ 		mmc->max_hw_segs = 1;
+ 	else /* PIO */
+ 		mmc->max_hw_segs = 128;
+@@ -1893,10 +1897,10 @@ int sdhci_add_host(struct sdhci_host *ho
+ 
+ 	mmc_add_host(mmc);
+ 
+-	printk(KERN_INFO "%s: SDHCI controller on %s [%s] using %s%s\n",
++	printk(KERN_INFO "%s: SDHCI controller on %s [%s] using %s\n",
+ 		mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)),
+-		(host->flags & SDHCI_USE_ADMA)?"A":"",
+-		(host->flags & SDHCI_USE_DMA)?"DMA":"PIO");
++		(host->flags & SDHCI_USE_ADMA) ? "ADMA" :
++		(host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO");
+ 
+ 	sdhci_enable_card_detection(host);
+ 
+Index: drivers/mmc/host/sdhci.h
+===================================================================
+--- drivers/mmc/host/sdhci.h.orig
++++ drivers/mmc/host/sdhci.h
+@@ -8,6 +8,8 @@
+  * the Free Software Foundation; either version 2 of the License, or (at
+  * your option) any later version.
+  */
++#ifndef __SDHCI_H
++#define __SDHCI_H
+ 
+ #include <linux/scatterlist.h>
+ #include <linux/compiler.h>
+@@ -143,7 +145,7 @@
+ #define  SDHCI_CAN_DO_ADMA2	0x00080000
+ #define  SDHCI_CAN_DO_ADMA1	0x00100000
+ #define  SDHCI_CAN_DO_HISPD	0x00200000
+-#define  SDHCI_CAN_DO_DMA	0x00400000
++#define  SDHCI_CAN_DO_SDMA	0x00400000
+ #define  SDHCI_CAN_VDD_330	0x01000000
+ #define  SDHCI_CAN_VDD_300	0x02000000
+ #define  SDHCI_CAN_VDD_180	0x04000000
+@@ -232,6 +234,8 @@ struct sdhci_host {
+ #define SDHCI_QUIRK_FORCE_1_BIT_DATA			(1<<22)
+ /* Controller needs 10ms delay between applying power and clock */
+ #define SDHCI_QUIRK_DELAY_AFTER_POWER			(1<<23)
++/* Controller uses SDCLK instead of TMCLK for data timeouts */
++#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK		(1<<24)
+ 
+ 	int			irq;		/* Device IRQ */
+ 	void __iomem *		ioaddr;		/* Mapped address */
+@@ -250,7 +254,7 @@ struct sdhci_host {
+ 	spinlock_t		lock;		/* Mutex */
+ 
+ 	int			flags;		/* Host attributes */
+-#define SDHCI_USE_DMA		(1<<0)		/* Host is DMA capable */
++#define SDHCI_USE_SDMA		(1<<0)		/* Host is SDMA capable */
+ #define SDHCI_USE_ADMA		(1<<1)		/* Host is ADMA capable */
+ #define SDHCI_REQ_USE_DMA	(1<<2)		/* Use DMA for this req. */
+ #define SDHCI_DEVICE_DEAD	(1<<3)		/* Device unresponsive */
+@@ -290,12 +294,12 @@ struct sdhci_host {
+ 
+ struct sdhci_ops {
+ #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
+-	u32		(*readl)(struct sdhci_host *host, int reg);
+-	u16		(*readw)(struct sdhci_host *host, int reg);
+-	u8		(*readb)(struct sdhci_host *host, int reg);
+-	void		(*writel)(struct sdhci_host *host, u32 val, int reg);
+-	void		(*writew)(struct sdhci_host *host, u16 val, int reg);
+-	void		(*writeb)(struct sdhci_host *host, u8 val, int reg);
++	u32		(*custom_readl)(struct sdhci_host *host, int reg);
++	u16		(*custom_readw)(struct sdhci_host *host, int reg);
++	u8		(*custom_readb)(struct sdhci_host *host, int reg);
++	void		(*custom_writel)(struct sdhci_host *host, u32 val, int reg);
++	void		(*custom_writew)(struct sdhci_host *host, u16 val, int reg);
++	void		(*custom_writeb)(struct sdhci_host *host, u8 val, int reg);
+ #endif
+ 
+ 	void	(*set_clock)(struct sdhci_host *host, unsigned int clock);
+@@ -310,48 +314,48 @@ struct sdhci_ops {
+ 
+ static inline void sdhci_writel(struct sdhci_host *host, u32 val, int reg)
+ {
+-	if (unlikely(host->ops->writel))
+-		host->ops->writel(host, val, reg);
++	if (unlikely(host->ops->custom_writel))
++		host->ops->custom_writel(host, val, reg);
+ 	else
+ 		writel(val, host->ioaddr + reg);
+ }
+ 
+ static inline void sdhci_writew(struct sdhci_host *host, u16 val, int reg)
+ {
+-	if (unlikely(host->ops->writew))
+-		host->ops->writew(host, val, reg);
++	if (unlikely(host->ops->custom_writew))
++		host->ops->custom_writew(host, val, reg);
+ 	else
+ 		writew(val, host->ioaddr + reg);
+ }
+ 
+ static inline void sdhci_writeb(struct sdhci_host *host, u8 val, int reg)
+ {
+-	if (unlikely(host->ops->writeb))
+-		host->ops->writeb(host, val, reg);
++	if (unlikely(host->ops->custom_writeb))
++		host->ops->custom_writeb(host, val, reg);
+ 	else
+ 		writeb(val, host->ioaddr + reg);
+ }
+ 
+ static inline u32 sdhci_readl(struct sdhci_host *host, int reg)
+ {
+-	if (unlikely(host->ops->readl))
+-		return host->ops->readl(host, reg);
++	if (unlikely(host->ops->custom_readl))
++		return host->ops->custom_readl(host, reg);
+ 	else
+ 		return readl(host->ioaddr + reg);
+ }
+ 
+ static inline u16 sdhci_readw(struct sdhci_host *host, int reg)
+ {
+-	if (unlikely(host->ops->readw))
+-		return host->ops->readw(host, reg);
++	if (unlikely(host->ops->custom_readw))
++		return host->ops->custom_readw(host, reg);
+ 	else
+ 		return readw(host->ioaddr + reg);
+ }
+ 
+ static inline u8 sdhci_readb(struct sdhci_host *host, int reg)
+ {
+-	if (unlikely(host->ops->readb))
+-		return host->ops->readb(host, reg);
++	if (unlikely(host->ops->custom_readb))
++		return host->ops->custom_readb(host, reg);
+ 	else
+ 		return readb(host->ioaddr + reg);
+ }
+@@ -390,6 +394,11 @@ static inline u8 sdhci_readb(struct sdhc
+ 
+ #endif /* CONFIG_MMC_SDHCI_IO_ACCESSORS */
+ 
++struct sdhci_quirk_data {
++	unsigned int quirks;
++	struct sdhci_ops ops;
++};
++
+ extern struct sdhci_host *sdhci_alloc_host(struct device *dev,
+ 	size_t priv_size);
+ extern void sdhci_free_host(struct sdhci_host *host);
+@@ -406,3 +415,5 @@ extern void sdhci_remove_host(struct sdh
+ extern int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state);
+ extern int sdhci_resume_host(struct sdhci_host *host);
+ #endif
++
++#endif /* __SDHCI_H */
+Index: arch/arm/mach-mx3/pcm043.c
+===================================================================
+--- arch/arm/mach-mx3/pcm043.c.orig
++++ arch/arm/mach-mx3/pcm043.c
+@@ -279,6 +279,34 @@ static struct pad_desc pcm043_pads[] = {
+         MX35_PAD_SD2_DATA1__GPIO2_3,
+   	MX35_PAD_TX5_RX0__CAN2_TXCAN,
+   	MX35_PAD_TX4_RX1__CAN2_RXCAN,
++       /* esdhc */
++        MX35_PAD_SD1_CMD__ESDHC1_CMD,
++        MX35_PAD_SD1_CLK__ESDHC1_CLK,
++        MX35_PAD_SD1_DATA0__ESDHC1_DAT0,
++        MX35_PAD_SD1_DATA1__ESDHC1_DAT1,
++        MX35_PAD_SD1_DATA2__ESDHC1_DAT2,
++        MX35_PAD_SD1_DATA3__ESDHC1_DAT3,
++};
++
++#include <linux/mmc/host.h>
++
++static struct resource sdhci_resources[] = {
++       {
++               .start          = 0x53fb4000,
++               .end            = 0x53fb4000 + 0xff,
++               .flags          = IORESOURCE_MEM,
++       }, {
++               .start          = MX35_INT_MMC_SDHC1,
++               .end            = MX35_INT_MMC_SDHC1,
++               .flags          = IORESOURCE_IRQ,
++       },
++};
++
++static struct platform_device sdhci_device = {
++       .name           = "sdhci-esdhc",
++       .id             = 0,
++       .num_resources  = ARRAY_SIZE(sdhci_resources),
++       .resource       = sdhci_resources,
+ };
+ 
+ static int pcm043_usbh1_init(struct platform_device *pdev)
+@@ -516,6 +544,8 @@ static void __init mxc_board_init(void)
+         gpio_request (32 + 3, "can");
+         gpio_direction_output (32 + 3, 1);
+         gpio_set_value (32 + 3, 1);
++
++        platform_device_register(&sdhci_device);
+ }
+ 
+ static void __init pcm043_timer_init(void)
diff --git a/recipes/linux/linux-2.6.31/pcm043/fix_can.patch b/recipes/linux/linux-2.6.31/pcm043/fix_can.patch
new file mode 100644
index 0000000..c8ca166
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/fix_can.patch
@@ -0,0 +1,16 @@
+Fix problem with send and recive of can packets.
+
+Signed-off-by: Teresa Gámez <t.gamez at phytec.de>
+---
+Index: linux-2.6.31.6/drivers/net/can/flexcan/drv.c
+===================================================================
+--- linux-2.6.31.6.orig/drivers/net/can/flexcan/drv.c	2010-09-16 14:35:16.596367462 +0200
++++ linux-2.6.31.6/drivers/net/can/flexcan/drv.c	2010-09-16 14:36:07.946447792 +0200
+@@ -136,7 +136,6 @@
+ 		reg &= ~__MCR_AEN;
+ 
+ 	reg |= (flexcan->maxmb << __MCR_MAX_MB_OFFSET);
+-	reg |= __MCR_DOZE | __MCR_MAX_IDAM_C;
+ 	__raw_writel(reg, flexcan->io_base + CAN_HW_REG_MCR);
+ }
+ 
diff --git a/recipes/linux/linux-2.6.31/pcm043/fix_clock_calc.patch b/recipes/linux/linux-2.6.31/pcm043/fix_clock_calc.patch
new file mode 100644
index 0000000..244ab06
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/fix_clock_calc.patch
@@ -0,0 +1,27 @@
+Fix claculation, if "ARM sel" is set a 532Mhz PLL result to a 399MHz ARM clock
+Also th AHB clock is based on this ARM clock
+
+Signed-off-by: Jan Weitzel <J.Weitzel at phytec.de>
+---
+Index: linux-2.6.31.6/arch/arm/mach-mx3/clock-imx35.c
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/mach-mx3/clock-imx35.c	2009-12-15 13:15:35.335242329 +0100
++++ linux-2.6.31.6/arch/arm/mach-mx3/clock-imx35.c	2009-12-15 13:17:59.496030198 +0100
+@@ -155,7 +155,7 @@
+ 
+ 	aad = &clk_consumer[(pdr0 >> 16) & 0xf];
+ 	if (aad->sel)
+-		fref = fref * 2 / 3;
++		fref = fref * 3 / 4;
+ 
+ 	return fref / aad->arm;
+ }
+@@ -164,7 +164,7 @@
+ {
+ 	unsigned long pdr0 = __raw_readl(CCM_BASE + CCM_PDR0);
+ 	struct arm_ahb_div *aad;
+-	unsigned long fref = get_rate_mpll();
++	unsigned long fref = get_rate_arm();
+ 
+ 	aad = &clk_consumer[(pdr0 >> 16) & 0xf];
+ 
diff --git a/recipes/linux/linux-2.6.31/pcm043/fix_max7301.patch b/recipes/linux/linux-2.6.31/pcm043/fix_max7301.patch
new file mode 100644
index 0000000..a6854e1
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/fix_max7301.patch
@@ -0,0 +1,28 @@
+Fix wrong setting of portconfig register.
+mask size is 2bits, so shift must be twice offset
+direction input value is 2
+
+Signed-off-by: Jan Weitzel <J.Weitzel at phytec.de>
+---
+Index: linux-2.6.28/drivers/gpio/max7301.c
+===================================================================
+--- linux-2.6.28.orig/drivers/gpio/max7301.c
++++ linux-2.6.28/drivers/gpio/max7301.c
+@@ -123,7 +123,7 @@ static int max7301_direction_input(struc
+ 
+ 	/* Standard GPIO API doesn't support pull-ups, has to be extended.
+ 	 * Hard-coding no pollup for now. */
+-	*config = (*config & ~(3 << (offset & 3))) | (1 << (offset & 3));
++	*config = (*config & ~(3 << (2*(offset & 3)))) | (2 << (2*(offset & 3)));
+ 
+ 	ret = max7301_write(ts->spi, 0x08 + (offset >> 2), *config);
+ 
+@@ -157,7 +157,7 @@ static int max7301_direction_output(stru
+ 
+ 	mutex_lock(&ts->lock);
+ 
+-	*config = (*config & ~(3 << (offset & 3))) | (1 << (offset & 3));
++	*config = (*config & ~(3 << (2*(offset & 3)))) | (1 << (2*(offset & 3)));
+ 
+ 	ret = __max7301_set(ts, offset, value);
+ 
diff --git a/recipes/linux/linux-2.6.31/pcm043/fix_mmc_for_highspeed.diff b/recipes/linux/linux-2.6.31/pcm043/fix_mmc_for_highspeed.diff
new file mode 100644
index 0000000..2f1834b
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/fix_mmc_for_highspeed.diff
@@ -0,0 +1,63 @@
+From: Wolfram Sang <w.sang at pengutronix.de>
+Subject: fix esdhc-WIP for highspeed-cards
+
+Freescale has really messed up the control register, so we have to take care
+the SDHCI-core does not accidently set standard bits which have a different
+meaning here :( Previously highspeed (not necessarily HC) cards caused
+a wrong bus-width setting.
+
+Also, mark the ADMA-engine as broken because FSL themselves don't know yet if
+it is really working. Shouldn't harm much as MX35 has just ADMA1 anyway.
+
+Furthermore, disable multi-block accesses. This might affect the throughput,
+but this part seems to be broken, too, according to the errata. We better play
+safe here, it really helps with some cards.
+
+Signed-off-by: Wolfram Sang <w.sang at pengutronix.de>
+---
+ drivers/mmc/host/sdhci-esdhc.c |   11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+Index: linux-2.6.31.6/drivers/mmc/host/sdhci-esdhc.c
+===================================================================
+--- linux-2.6.31.6.orig/drivers/mmc/host/sdhci-esdhc.c	2010-09-13 11:13:43.476519017 +0200
++++ linux-2.6.31.6/drivers/mmc/host/sdhci-esdhc.c	2010-09-13 11:13:43.496492387 +0200
+@@ -34,6 +34,7 @@
+ #define ESDHC_CLOCK_HCKEN	0x00000002
+ #define ESDHC_CLOCK_IPGEN	0x00000001
+ 
++#define ESDHC_HOST_CONTROL_LE	0x20
+ #define ESDHC_HOST_CONTROL_RES	0x05
+ 
+ #ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
+@@ -127,8 +128,10 @@
+ 		/* FSL put the DMA bits there, so skip :( */
+ 		return;
+ 	case SDHCI_HOST_CONTROL:
+-		val &= 0x07;
+-		val |= 0x20;
++		/* FSL really messed up here, so we can just keep those */
++		val &= SDHCI_CTRL_LED | SDHCI_CTRL_4BITBUS;
++		/* and ensure the endianess */
++		val |= ESDHC_HOST_CONTROL_LE;
+ 		break;
+ 	}
+ 	esdhc_clrset_le(host, 0xff, val, reg);
+@@ -163,7 +166,7 @@
+ 
+ 	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+ 	temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN |
+-		  div << ESDHC_DIVIDER_SHIFT | pre_div << ESDHC_PREDIV_SHIFT);
++		  (div << ESDHC_DIVIDER_SHIFT) | (pre_div << ESDHC_PREDIV_SHIFT));
+ 	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+ 	mdelay(100);
+ out:
+@@ -193,6 +196,8 @@
+ 		  SDHCI_QUIRK_PIO_NEEDS_DELAY |
+ 		  SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET |
+ 		   SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
++		  SDHCI_QUIRK_NO_MULTIBLOCK |
++		  SDHCI_QUIRK_BROKEN_ADMA |
+ 		  SDHCI_QUIRK_NO_CARD_NO_RESET,
+ 	.ops = {
+ #ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
diff --git a/recipes/linux/linux-2.6.31/pcm043/fix_oob_layout.diff b/recipes/linux/linux-2.6.31/pcm043/fix_oob_layout.diff
new file mode 100644
index 0000000..d8e1b1d
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/fix_oob_layout.diff
@@ -0,0 +1,67 @@
+---
+ drivers/mtd/nand/mxc_nand_v2.c |   24 +++++++++++++++++++++---
+ 1 file changed, 21 insertions(+), 3 deletions(-)
+
+Index: drivers/mtd/nand/mxc_nand_v2.c
+===================================================================
+--- drivers/mtd/nand/mxc_nand_v2.c.orig
++++ drivers/mtd/nand/mxc_nand_v2.c
+@@ -1,6 +1,7 @@
+ /*
+  * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved.
+  * Copyright 2009 Sascha Hauer, kernel at pengutronix.de
++ * Copyright 2009 Juergen Beisert, kernel at pengutronix.de
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License
+@@ -130,6 +131,19 @@ struct mxc_nand_host {
+  *      User             ECC
+  *
+  * For pages larger than 512 bytes, n structures of this type will be used.
++ *
++ * Bad block detection:
++ * As long we do not overwrite the badblock_pattern structure member, the
++ * framework will use the description 'smallpage_flashbased' in file
++ * nand_bbt.c for page sizes with 512 bytes and description
++ * 'largepage_flashbased' in the same file for page sizes larger than
++ * 512 bytes.
++ *
++ * 'smallpage_flashbased' describes the bad block marker in the byte at offset
++ * five, 'largepage_flashbased' describes theses markers at offset 0 and 1
++ * in the OOB.
++ *
++ * So, we must keep these bytes free for bad block marker usage.
+  */
+ 
+ /* OOB description for 512 byte pages with 16 byte OOB */
+@@ -139,7 +153,9 @@ static struct nand_ecclayout nand_hw_ecc
+ 		 7,  8,  9, 10, 11, 12, 13, 14, 15
+ 	},
+ 	.oobfree = {
+-		{.offset = 0, .length = 7}
++		{.offset = 0, .length = 5},
++		/* keep offset 5 free for bad block marker usage */
++		{.offset = 6, .length = 1}
+ 	}
+ };
+ 
+@@ -153,7 +169,8 @@ static struct nand_ecclayout nand_hw_ecc
+ 		55, 56, 57, 58, 59, 60, 61, 62, 63
+ 	},
+ 	.oobfree = {
+-		{.offset = 0, .length = 7},
++		/* keep offset 0,1 free for bad block marker usage */
++		{.offset = 2, .length = 5},
+ 		{.offset = 16, .length = 7},
+ 		{.offset = 32, .length = 7},
+ 		{.offset = 48, .length = 7}
+@@ -175,7 +192,8 @@ static struct nand_ecclayout nand_hw_ecc
+ /*		119, 120, 121, 122, 123, 124, 125, 126, 127 */
+ 	},
+ 	.oobfree = {
+-		{.offset = 0, .length = 7},
++		/* keep offset 0,1 free for bad block marker usage */
++		{.offset = 2, .length = 5},
+ 		{.offset = 16, .length = 7},
+ 		{.offset = 32, .length = 7},
+ 		{.offset = 48, .length = 7},
diff --git a/recipes/linux/linux-2.6.31/pcm043/fix_owire_clk.patch b/recipes/linux/linux-2.6.31/pcm043/fix_owire_clk.patch
new file mode 100644
index 0000000..4d50ab4
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/fix_owire_clk.patch
@@ -0,0 +1,17 @@
+Fix the owire_clk dev_id
+
+Signed-off-by: Jan Weitzel <J.Weitzel at phytec.de>
+---
+Index: linux-2.6.31.6/arch/arm/mach-mx3/clock-imx35.c
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/mach-mx3/clock-imx35.c	2009-12-14 16:50:18.915973719 +0100
++++ linux-2.6.31.6/arch/arm/mach-mx3/clock-imx35.c	2009-12-14 16:51:06.835549332 +0100
+@@ -453,7 +453,7 @@
+ 	_REGISTER_CLOCK(NULL, "kpp", kpp_clk)
+ 	_REGISTER_CLOCK(NULL, "mlb", mlb_clk)
+ 	_REGISTER_CLOCK(NULL, "mshc", mshc_clk)
+-	_REGISTER_CLOCK("mxc_w1", NULL, owire_clk)
++	_REGISTER_CLOCK("mxc_w1.0", NULL, owire_clk)
+ 	_REGISTER_CLOCK(NULL, "pwm", pwm_clk)
+ 	_REGISTER_CLOCK(NULL, "rngc", rngc_clk)
+ 	_REGISTER_CLOCK(NULL, "rtc", rtc_clk)
diff --git a/recipes/linux/linux-2.6.31/pcm043/linux-2.6.31.6-flexcan.patch b/recipes/linux/linux-2.6.31/pcm043/linux-2.6.31.6-flexcan.patch
new file mode 100644
index 0000000..a3c37cb
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/linux-2.6.31.6-flexcan.patch
@@ -0,0 +1,2168 @@
+Add support for i.MX35 on-board CAN
+Signed-off-by: Sven Dyroff <s.dyroff at phytec.de>
+---
+Index: linux-2.6.31.6/drivers/net/can/flexcan/Makefile
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.31.6/drivers/net/can/flexcan/Makefile	2009-12-16 17:34:40.585687608 +0100
+@@ -0,0 +1,3 @@
++obj-$(CONFIG_CAN_FLEXCAN)	+= flexcan.o
++
++flexcan-y := dev.o drv.o mbm.o
+Index: linux-2.6.31.6/drivers/net/can/flexcan/dev.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.31.6/drivers/net/can/flexcan/dev.c	2009-12-16 17:34:40.585687608 +0100
+@@ -0,0 +1,675 @@
++/*
++ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file dev.c
++ *
++ * @brief Driver for Freescale CAN Controller FlexCAN.
++ *
++ * @ingroup can
++ */
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/errno.h>
++#include <linux/unistd.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/netdevice.h>
++#include <linux/spinlock.h>
++#include <linux/device.h>
++
++#include <linux/module.h>
++#include "flexcan.h"
++
++enum {
++//	FLEXCAN_ATTR_STATE = 0,
++//	FLEXCAN_ATTR_BITRATE,
++//	FLEXCAN_ATTR_BR_PRESDIV,
++//	FLEXCAN_ATTR_BR_RJW,
++//	FLEXCAN_ATTR_BR_PROPSEG,    ~~~~~sven~~~~~
++//	FLEXCAN_ATTR_BR_PSEG1,
++//	FLEXCAN_ATTR_BR_PSEG2,
++	FLEXCAN_ATTR_BR_CLKSRC = 0,
++	FLEXCAN_ATTR_MAXMB,
++	FLEXCAN_ATTR_XMIT_MAXMB,
++	FLEXCAN_ATTR_FIFO,
++	FLEXCAN_ATTR_WAKEUP,
++	FLEXCAN_ATTR_SRX_DIS,
++	FLEXCAN_ATTR_WAK_SRC,
++	FLEXCAN_ATTR_BCC,
++	FLEXCAN_ATTR_LOCAL_PRIORITY,
++	FLEXCAN_ATTR_ABORT,
++	FLEXCAN_ATTR_LOOPBACK,
++	FLEXCAN_ATTR_SMP,
++	FLEXCAN_ATTR_BOFF_REC,
++	FLEXCAN_ATTR_TSYN,
++	FLEXCAN_ATTR_LISTEN,
++	FLEXCAN_ATTR_EXTEND_MSG,
++	FLEXCAN_ATTR_STANDARD_MSG,
++#ifdef CONFIG_CAN_DEBUG_DEVICES
++	FLEXCAN_ATTR_DUMP_REG,
++	FLEXCAN_ATTR_DUMP_XMIT_MB,
++	FLEXCAN_ATTR_DUMP_RX_MB,
++#endif
++	FLEXCAN_ATTR_MAX
++};
++
++static ssize_t flexcan_show_attr(struct device *dev,
++				 struct device_attribute *attr, char *buf);
++static ssize_t flexcan_set_attr(struct device *dev,
++				struct device_attribute *attr, const char *buf,
++				size_t count);
++
++static struct device_attribute flexcan_dev_attr[FLEXCAN_ATTR_MAX] = {
++/*  ~~~~~sven~~~~~
++	[FLEXCAN_ATTR_STATE] = __ATTR(state, 0444, flexcan_show_attr, NULL),
++	[FLEXCAN_ATTR_BITRATE] =
++	    __ATTR(bitrate, 0644, flexcan_show_attr, flexcan_set_attr),
++	[FLEXCAN_ATTR_BR_PRESDIV] =
++	    __ATTR(br_presdiv, 0644, flexcan_show_attr, flexcan_set_attr),
++	[FLEXCAN_ATTR_BR_RJW] =
++	    __ATTR(br_rjw, 0644, flexcan_show_attr, flexcan_set_attr),
++	[FLEXCAN_ATTR_BR_PROPSEG] =
++	    __ATTR(br_propseg, 0644, flexcan_show_attr, flexcan_set_attr),
++	[FLEXCAN_ATTR_BR_PSEG1] =
++	    __ATTR(br_pseg1, 0644, flexcan_show_attr, flexcan_set_attr),
++	[FLEXCAN_ATTR_BR_PSEG2] =
++	    __ATTR(br_pseg2, 0644, flexcan_show_attr, flexcan_set_attr),
++*/
++	[FLEXCAN_ATTR_BR_CLKSRC] =
++	    __ATTR(br_clksrc, 0644, flexcan_show_attr, flexcan_set_attr),
++	[FLEXCAN_ATTR_MAXMB] =
++	    __ATTR(maxmb, 0644, flexcan_show_attr, flexcan_set_attr),
++	[FLEXCAN_ATTR_XMIT_MAXMB] =
++	    __ATTR(xmit_maxmb, 0644, flexcan_show_attr, flexcan_set_attr),
++	[FLEXCAN_ATTR_FIFO] =
++	    __ATTR(fifo, 0644, flexcan_show_attr, flexcan_set_attr),
++	[FLEXCAN_ATTR_WAKEUP] =
++	    __ATTR(wakeup, 0644, flexcan_show_attr, flexcan_set_attr),
++	[FLEXCAN_ATTR_SRX_DIS] =
++	    __ATTR(srx_dis, 0644, flexcan_show_attr, flexcan_set_attr),
++	[FLEXCAN_ATTR_WAK_SRC] =
++	    __ATTR(wak_src, 0644, flexcan_show_attr, flexcan_set_attr),
++	[FLEXCAN_ATTR_BCC] =
++	    __ATTR(bcc, 0644, flexcan_show_attr, flexcan_set_attr),
++	[FLEXCAN_ATTR_LOCAL_PRIORITY] =
++	    __ATTR(local_priority, 0644, flexcan_show_attr, flexcan_set_attr),
++	[FLEXCAN_ATTR_ABORT] =
++	    __ATTR(abort, 0644, flexcan_show_attr, flexcan_set_attr),
++	[FLEXCAN_ATTR_LOOPBACK] =
++	    __ATTR(loopback, 0644, flexcan_show_attr, flexcan_set_attr),
++	[FLEXCAN_ATTR_SMP] =
++	    __ATTR(smp, 0644, flexcan_show_attr, flexcan_set_attr),
++	[FLEXCAN_ATTR_BOFF_REC] =
++	    __ATTR(boff_rec, 0644, flexcan_show_attr, flexcan_set_attr),
++	[FLEXCAN_ATTR_TSYN] =
++	    __ATTR(tsyn, 0644, flexcan_show_attr, flexcan_set_attr),
++	[FLEXCAN_ATTR_LISTEN] =
++	    __ATTR(listen, 0644, flexcan_show_attr, flexcan_set_attr),
++	[FLEXCAN_ATTR_EXTEND_MSG] =
++	    __ATTR(ext_msg, 0644, flexcan_show_attr, flexcan_set_attr),
++	[FLEXCAN_ATTR_STANDARD_MSG] =
++	    __ATTR(std_msg, 0644, flexcan_show_attr, flexcan_set_attr),
++#ifdef CONFIG_CAN_DEBUG_DEVICES
++	[FLEXCAN_ATTR_DUMP_REG] =
++	    __ATTR(dump_reg, 0444, flexcan_show_attr, NULL),
++	[FLEXCAN_ATTR_DUMP_XMIT_MB] =
++	    __ATTR(dump_xmit_mb, 0444, flexcan_show_attr, NULL),
++	[FLEXCAN_ATTR_DUMP_RX_MB] =
++	    __ATTR(dump_rx_mb, 0444, flexcan_show_attr, NULL),
++#endif
++};
++
++//~~~~~~~~~~~~~~sven~~~~~~~~~~~~~~~~
++// static void flexcan_set_bitrate (struct flexcan_device *flexcan, int bitrate) {
++	/* TODO:: implement in future
++	 * based on the bitrate to get the timing of
++	 * presdiv, pseg1, pseg2, propseg
++	 */
++//}
++/*
++static void flexcan_update_bitrate (struct flexcan_device *flexcan) {
++        struct can_priv *priv = (can_priv *) flexcan;
++        struct can_bittiming *bt = &priv -> bittiming;
++
++        int rate, div;
++
++        if (flexcan -> br_clksrc)
++                rate = clk_get_rate (flexcan -> clk);
++        else {
++                struct clk *clk;
++                clk = clk_get (NULL, "ckih");
++                if (!clk)
++                        return;
++                rate = clk_get_rate (clk);
++                clk_put (clk);
++        }
++        if (!rate)
++                return;
++
++        div = (bt -> tq + 1);
++        div *= (bt -> prop_seg + bt -> phase_seg1 + bt -> phase_seg2 + 4);
++        bt -> bitrate = (rate + div - 1) / div;
++}
++*/
++//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++
++#ifdef CONFIG_CAN_DEBUG_DEVICES
++static int flexcan_dump_reg(struct flexcan_device *flexcan, char *buf)
++{
++	int ret = 0;
++	unsigned int reg;
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_MCR);
++	ret += sprintf(buf + ret, "MCR::0x%x\n", reg);
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_CTRL);
++	ret += sprintf(buf + ret, "CTRL::0x%x\n", reg);
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_RXGMASK);
++	ret += sprintf(buf + ret, "RXGMASK::0x%x\n", reg);
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_RX14MASK);
++	ret += sprintf(buf + ret, "RX14MASK::0x%x\n", reg);
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_RX15MASK);
++	ret += sprintf(buf + ret, "RX15MASK::0x%x\n", reg);
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_ECR);
++	ret += sprintf(buf + ret, "ECR::0x%x\n", reg);
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_ESR);
++	ret += sprintf(buf + ret, "ESR::0x%x\n", reg);
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_IMASK2);
++	ret += sprintf(buf + ret, "IMASK2::0x%x\n", reg);
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_IMASK1);
++	ret += sprintf(buf + ret, "IMASK1::0x%x\n", reg);
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_IFLAG2);
++	ret += sprintf(buf + ret, "IFLAG2::0x%x\n", reg);
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_IFLAG1);
++	ret += sprintf(buf + ret, "IFLAG1::0x%x\n", reg);
++	return ret;
++}
++
++static int flexcan_dump_xmit_mb(struct flexcan_device *flexcan, char *buf)
++{
++	int ret = 0, i;
++	i = flexcan->xmit_maxmb + 1;
++	for (; i <= flexcan->maxmb; i++)
++		ret +=
++		    sprintf(buf + ret,
++			    "mb[%d]::CS:0x%x ID:0x%x DATA[1~2]:0x%02x,0x%02x\n",
++			    i, flexcan->hwmb[i].mb_cs.data,
++			    flexcan->hwmb[i].mb_id, flexcan->hwmb[i].mb_data[1],
++			    flexcan->hwmb[i].mb_data[2]);
++	return ret;
++}
++
++static int flexcan_dump_rx_mb(struct flexcan_device *flexcan, char *buf)
++{
++	int ret = 0, i;
++	for (i = 0; i <= flexcan->xmit_maxmb; i++)
++		ret +=
++		    sprintf(buf + ret,
++			    "mb[%d]::CS:0x%x ID:0x%x DATA[1~2]:0x%02x,0x%02x\n",
++			    i, flexcan->hwmb[i].mb_cs.data,
++			    flexcan->hwmb[i].mb_id, flexcan->hwmb[i].mb_data[1],
++			    flexcan->hwmb[i].mb_data[2]);
++	return ret;
++}
++#endif
++
++//~~~~~~~~~~sven~~~~~~~~~
++static int flexcan_get_state (struct net_device *net, enum can_state *state) {
++        struct flexcan_device *flexcan = netdev_priv (net);
++        int esr;
++
++        *state = (netif_running (net) ? CAN_STATE_ERROR_ACTIVE : CAN_STATE_STOPPED);
++        if (netif_carrier_ok (net)) {
++                esr = __raw_readl (flexcan -> io_base + CAN_HW_REG_ESR);
++                switch ((esr & __ESR_FLT_CONF_MASK) >> __ESR_FLT_CONF_OFF) {
++                        case 0: break;
++                        case 1: *state = CAN_STATE_ERROR_PASSIVE; break;
++                        default: *state = CAN_STATE_BUS_OFF;
++                }
++        } else
++                *state = CAN_STATE_BUS_OFF;
++
++        return 0;
++}
++//~~~~~~~~~~~~~~~~~~~~~~~
++
++static ssize_t flexcan_show_attr(struct device *dev,
++				 struct device_attribute *attr, char *buf)
++{
++	int attr_id;
++	struct net_device *net;
++	struct flexcan_device *flexcan;
++
++	net = dev_get_drvdata(dev);
++	BUG_ON(!net);
++	flexcan = netdev_priv(net);
++	BUG_ON(!flexcan);
++
++	attr_id = attr - flexcan_dev_attr;
++	switch (attr_id) {
++/*    ~~~~~sven~~~~~
++	case FLEXCAN_ATTR_STATE:
++		return flexcan_show_state(net, buf);
++	case FLEXCAN_ATTR_BITRATE:
++		return sprintf(buf, "%d\n", flexcan->bitrate);
++	case FLEXCAN_ATTR_BR_PRESDIV:
++		return sprintf(buf, "%d\n", flexcan->br_presdiv + 1);
++	case FLEXCAN_ATTR_BR_RJW:
++		return sprintf(buf, "%d\n", flexcan->br_rjw);
++	case FLEXCAN_ATTR_BR_PROPSEG:
++		return sprintf(buf, "%d\n", flexcan->br_propseg + 1);
++	case FLEXCAN_ATTR_BR_PSEG1:
++		return sprintf(buf, "%d\n", flexcan->br_pseg1 + 1);
++	case FLEXCAN_ATTR_BR_PSEG2:
++		return sprintf(buf, "%d\n", flexcan->br_pseg2 + 1);
++*/
++	case FLEXCAN_ATTR_BR_CLKSRC:
++		return sprintf(buf, "%s\n", flexcan->br_clksrc ? "bus" : "osc");
++	case FLEXCAN_ATTR_MAXMB:
++		return sprintf(buf, "%d\n", flexcan->maxmb + 1);
++	case FLEXCAN_ATTR_XMIT_MAXMB:
++		return sprintf(buf, "%d\n", flexcan->xmit_maxmb + 1);
++	case FLEXCAN_ATTR_FIFO:
++		return sprintf(buf, "%d\n", flexcan->fifo);
++	case FLEXCAN_ATTR_WAKEUP:
++		return sprintf(buf, "%d\n", flexcan->wakeup);
++	case FLEXCAN_ATTR_SRX_DIS:
++		return sprintf(buf, "%d\n", flexcan->srx_dis);
++	case FLEXCAN_ATTR_WAK_SRC:
++		return sprintf(buf, "%d\n", flexcan->wak_src);
++	case FLEXCAN_ATTR_BCC:
++		return sprintf(buf, "%d\n", flexcan->bcc);
++	case FLEXCAN_ATTR_LOCAL_PRIORITY:
++		return sprintf(buf, "%d\n", flexcan->lprio);
++	case FLEXCAN_ATTR_ABORT:
++		return sprintf(buf, "%d\n", flexcan->abort);
++	case FLEXCAN_ATTR_LOOPBACK:
++		return sprintf(buf, "%d\n", flexcan->loopback);
++	case FLEXCAN_ATTR_SMP:
++		return sprintf(buf, "%d\n", flexcan->smp);
++	case FLEXCAN_ATTR_BOFF_REC:
++		return sprintf(buf, "%d\n", flexcan->boff_rec);
++	case FLEXCAN_ATTR_TSYN:
++		return sprintf(buf, "%d\n", flexcan->tsyn);
++	case FLEXCAN_ATTR_LISTEN:
++		return sprintf(buf, "%d\n", flexcan->listen);
++	case FLEXCAN_ATTR_EXTEND_MSG:
++		return sprintf(buf, "%d\n", flexcan->ext_msg);
++	case FLEXCAN_ATTR_STANDARD_MSG:
++		return sprintf(buf, "%d\n", flexcan->std_msg);
++#ifdef CONFIG_CAN_DEBUG_DEVICES
++	case FLEXCAN_ATTR_DUMP_REG:
++		return flexcan_dump_reg(flexcan, buf);
++	case FLEXCAN_ATTR_DUMP_XMIT_MB:
++		return flexcan_dump_xmit_mb(flexcan, buf);
++	case FLEXCAN_ATTR_DUMP_RX_MB:
++		return flexcan_dump_rx_mb(flexcan, buf);
++#endif
++	default:
++		return sprintf(buf, "%s:%p->%p\n", __func__, flexcan_dev_attr,
++			       attr);
++	}
++}
++
++static ssize_t flexcan_set_attr(struct device *dev,
++				struct device_attribute *attr, const char *buf,
++				size_t count)
++{
++	int attr_id, tmp;
++	struct net_device *net;
++	struct flexcan_device *flexcan;
++
++	net = dev_get_drvdata(dev);
++	BUG_ON(!net);
++	flexcan = netdev_priv(net);
++	BUG_ON(!flexcan);
++
++	attr_id = attr - flexcan_dev_attr;
++
++	if (mutex_lock_interruptible(&flexcan->mutex))
++		return count;
++
++	if (netif_running(net))
++		goto set_finish;
++
++	if (attr_id == FLEXCAN_ATTR_BR_CLKSRC) {
++		if (!strcasecmp(buf, "bus"))
++			flexcan->br_clksrc = 1;
++		else if (!strcasecmp(buf, "osc"))
++			flexcan->br_clksrc = 0;
++		goto set_finish;
++	}
++
++	tmp = simple_strtoul(buf, NULL, 0);
++	switch (attr_id) {
++/*    ~~~~~sven~~~~~
++	case FLEXCAN_ATTR_BITRATE:
++		flexcan_set_bitrate(flexcan, tmp);
++		break;
++	case FLEXCAN_ATTR_BR_PRESDIV:
++		if ((tmp > 0) && (tmp <= FLEXCAN_MAX_PRESDIV)) {
++			flexcan->br_presdiv = tmp - 1;
++			flexcan_update_bitrate(flexcan);
++		}
++		break;
++	case FLEXCAN_ATTR_BR_RJW:
++		if ((tmp > 0) && (tmp <= FLEXCAN_MAX_RJW))
++			flexcan->br_rjw = tmp - 1;
++		break;
++	case FLEXCAN_ATTR_BR_PROPSEG:
++		if ((tmp > 0) && (tmp <= FLEXCAN_MAX_PROPSEG)) {
++			flexcan->br_propseg = tmp - 1;
++			flexcan_update_bitrate(flexcan);
++		}
++		break;
++	case FLEXCAN_ATTR_BR_PSEG1:
++		if ((tmp > 0) && (tmp <= FLEXCAN_MAX_PSEG1)) {
++			flexcan->br_pseg1 = tmp - 1;
++			flexcan_update_bitrate(flexcan);
++		}
++		break;
++	case FLEXCAN_ATTR_BR_PSEG2:
++		if ((tmp > 0) && (tmp <= FLEXCAN_MAX_PSEG2)) {
++			flexcan->br_pseg2 = tmp - 1;
++			flexcan_update_bitrate(flexcan);
++		}
++		break;
++*/
++	case FLEXCAN_ATTR_MAXMB:
++		if ((tmp > 0) && (tmp <= FLEXCAN_MAX_MB)) {
++			if (flexcan->maxmb != (tmp - 1)) {
++				flexcan->maxmb = tmp - 1;
++				if (flexcan->xmit_maxmb < flexcan->maxmb)
++					flexcan->xmit_maxmb = flexcan->maxmb;
++			}
++		}
++		break;
++	case FLEXCAN_ATTR_XMIT_MAXMB:
++		if ((tmp > 0) && (tmp <= (flexcan->maxmb + 1))) {
++			if (flexcan->xmit_maxmb != (tmp - 1))
++				flexcan->xmit_maxmb = tmp - 1;
++		}
++		break;
++	case FLEXCAN_ATTR_FIFO:
++		flexcan->fifo = tmp ? 1 : 0;
++		break;
++	case FLEXCAN_ATTR_WAKEUP:
++		flexcan->wakeup = tmp ? 1 : 0;
++		break;
++	case FLEXCAN_ATTR_SRX_DIS:
++		flexcan->srx_dis = tmp ? 1 : 0;
++		break;
++	case FLEXCAN_ATTR_WAK_SRC:
++		flexcan->wak_src = tmp ? 1 : 0;
++		break;
++	case FLEXCAN_ATTR_BCC:
++		flexcan->bcc = tmp ? 1 : 0;
++		break;
++	case FLEXCAN_ATTR_LOCAL_PRIORITY:
++		flexcan->lprio = tmp ? 1 : 0;
++		break;
++	case FLEXCAN_ATTR_ABORT:
++		flexcan->abort = tmp ? 1 : 0;
++		break;
++	case FLEXCAN_ATTR_LOOPBACK:
++		flexcan->loopback = tmp ? 1 : 0;
++		break;
++	case FLEXCAN_ATTR_SMP:
++		flexcan->smp = tmp ? 1 : 0;
++		break;
++	case FLEXCAN_ATTR_BOFF_REC:
++		flexcan->boff_rec = tmp ? 1 : 0;
++		break;
++	case FLEXCAN_ATTR_TSYN:
++		flexcan->tsyn = tmp ? 1 : 0;
++		break;
++	case FLEXCAN_ATTR_LISTEN:
++		flexcan->listen = tmp ? 1 : 0;
++		break;
++	case FLEXCAN_ATTR_EXTEND_MSG:
++		flexcan->ext_msg = tmp ? 1 : 0;
++		break;
++	case FLEXCAN_ATTR_STANDARD_MSG:
++		flexcan->std_msg = tmp ? 1 : 0;
++		break;
++	}
++      set_finish:
++	mutex_unlock(&flexcan->mutex);
++	return count;
++}
++
++static void flexcan_device_default(struct flexcan_device *dev)
++{
++	dev->br_clksrc = 1;
++//        dev->br_rjw = 2;         ~~~~~sven~~~~~
++//        dev->br_presdiv = 6;     ~~~~~sven~~~~~
++//        dev->br_propseg = 4;     ~~~~~sven~~~~~
++//        dev->br_pseg1 = 4;       ~~~~~sven~~~~~
++//        dev->br_pseg2 = 7;       ~~~~~sven~~~~~
++
++	dev->bcc = 1;
++	dev->srx_dis = 1;
++	dev->smp = 1;
++	dev->boff_rec = 1;
++
++	dev->maxmb = FLEXCAN_MAX_MB - 1;
++	dev->xmit_maxmb = (FLEXCAN_MAX_MB >> 1) - 1;
++	dev->xmit_mb = dev->maxmb - dev->xmit_maxmb;
++
++	dev->ext_msg = 1;
++	dev->std_msg = 1;
++}
++
++static int flexcan_device_attach(struct flexcan_device *flexcan)
++{
++	int ret;
++	struct resource *res;
++#ifdef REGULATOR
++	struct platform_device *pdev = flexcan->dev;
++	struct flexcan_platform_data *plat_data = (pdev->dev).platform_data;
++#endif
++
++	res = platform_get_resource(flexcan->dev, IORESOURCE_MEM, 0);
++	if (!res)
++		return -ENODEV;
++
++	flexcan->io_base = ioremap(res->start, res->end - res->start + 1);
++	if (!flexcan->io_base)
++		return -ENOMEM;
++
++	flexcan->irq = platform_get_irq(flexcan->dev, 0);
++	if (!flexcan->irq) {
++		ret = -ENODEV;
++		goto no_irq_err;
++	}
++
++	ret = -EINVAL;
++#ifdef REGULATOR
++	if (plat_data) {
++		if (plat_data->core_reg) {
++			flexcan->core_reg = regulator_get(&pdev->dev,
++							  plat_data->core_reg);
++			if (!flexcan->core_reg)
++				goto plat_err;
++		}
++
++		if (plat_data->io_reg) {
++			flexcan->io_reg = regulator_get(&pdev->dev,
++							plat_data->io_reg);
++			if (!flexcan->io_reg)
++				goto plat_err;
++		}
++	}
++#endif
++	flexcan->clk = clk_get(&(flexcan->dev)->dev, "can_clk");
++	flexcan->hwmb = (struct can_hw_mb *)(flexcan->io_base + CAN_MB_BASE);
++	flexcan->rx_mask = (unsigned int *)(flexcan->io_base + CAN_RXMASK_BASE);
++	return 0;
++
++#ifdef REGULATOR
++      plat_err:
++	if (flexcan->core_reg) {
++		regulator_put(flexcan->core_reg, &pdev->dev);
++		flexcan->core_reg = NULL;
++	}
++#endif
++
++      no_irq_err:
++	if (flexcan->io_base)
++		iounmap(flexcan->io_base);
++	return ret;
++}
++
++static void flexcan_device_detach(struct flexcan_device *flexcan)
++{
++#ifdef REGULATOR
++	struct platform_device *pdev = flexcan->dev;
++#endif
++	if (flexcan->clk) {
++		clk_put(flexcan->clk);
++		flexcan->clk = NULL;
++	}
++#ifdef REGULATOR
++	if (flexcan->io_reg) {
++		regulator_put(flexcan->io_reg, &pdev->dev);
++		flexcan->io_reg = NULL;
++	}
++
++	if (flexcan->core_reg) {
++		regulator_put(flexcan->core_reg, &pdev->dev);
++		flexcan->core_reg = NULL;
++	}
++#endif
++
++	if (flexcan->io_base)
++		iounmap(flexcan->io_base);
++}
++
++
++//~~~~~~~~~~~~~~sven~~~~~~~~~~~~~~~~
++static struct can_bittiming_const flexcan_bittiming_const = {
++  .tseg1_min = 4,
++  .tseg1_max = 16,
++  .tseg2_min = 2,
++  .tseg2_max = 8,
++  .sjw_max = 4,
++  .brp_min = 1,
++  .brp_max = 256,
++  .brp_inc = 1,
++};
++//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++
++
++/*!
++ * @brief The function allocates can device.
++ *
++ * @param pdev	the pointer of platform device.
++ * @param setup	the initial function pointer of network device.
++ *
++ * @return none
++ */
++struct net_device *flexcan_device_alloc(struct platform_device *pdev,
++					void (*setup) (struct net_device *dev))
++{
++	struct flexcan_device *flexcan;
++	struct net_device *net;
++	int i, num;
++
++	net = alloc_netdev(sizeof(*flexcan), "can%d", setup);
++	if (net == NULL) {
++		printk(KERN_ERR "Allocate netdevice for FlexCAN fail!\n");
++		return NULL;
++	}
++	flexcan = netdev_priv(net);
++	memset(flexcan, 0, sizeof(*flexcan));
++
++	mutex_init(&flexcan->mutex);
++	init_timer(&flexcan->timer);
++
++	flexcan->dev = pdev;
++	if (flexcan_device_attach(flexcan)) {
++		printk(KERN_ERR "Attach FlexCAN fail!\n");
++		free_netdev(net);
++		return NULL;
++	}
++	flexcan_device_default(flexcan);
++//	flexcan_update_bitrate(flexcan);   ~~~~~sven~~~~~
++
++	num = ARRAY_SIZE(flexcan_dev_attr);
++
++	for (i = 0; i < num; i++) {
++		if (device_create_file(&pdev->dev, flexcan_dev_attr + i)) {
++			printk(KERN_ERR "Create attribute file fail!\n");
++			break;
++		}
++	}
++
++	if (i != num) {
++		for (; i >= 0; i--)
++			device_remove_file(&pdev->dev, flexcan_dev_attr + i);
++		free_netdev(net);
++		return NULL;
++	}
++	dev_set_drvdata(&pdev->dev, net);
++
++//~~~~~~~~~~~~~~sven~~~~~~~~~~~~~~~~
++
++        SET_NETDEV_DEV (net, &pdev -> dev);
++
++        flexcan -> can.bittiming_const = &flexcan_bittiming_const;
++        flexcan -> can.do_set_bittiming = flexcan_set_bittiming;
++        flexcan -> can.do_get_state = (void *) flexcan_get_state;
++
++        if (flexcan -> br_clksrc)
++                flexcan -> can.clock.freq = clk_get_rate (flexcan -> clk);
++        else {
++                struct clk *clk;
++                clk = clk_get (NULL, "ckih");
++                if (clk) {
++                        flexcan -> can.clock.freq = clk_get_rate (clk);
++                        clk_put (clk);
++                }
++        }
++
++        flexcan -> can.state = CAN_STATE_STOPPED;   // !!! Nur provisorisch !!!
++
++//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++
++	return net;
++}
++
++/*!
++ * @brief The function frees can device.
++ *
++ * @param pdev	the pointer of platform device.
++ *
++ * @return none
++ */
++void flexcan_device_free(struct platform_device *pdev)
++{
++	struct net_device *net;
++	struct flexcan_device *flexcan;
++	int i, num;
++	net = (struct net_device *)dev_get_drvdata(&pdev->dev);
++
++	unregister_candev(net);   // ~~~~~sven~~~~~
++	flexcan = netdev_priv(net);
++	del_timer(&flexcan->timer);
++
++	num = ARRAY_SIZE(flexcan_dev_attr);
++
++	for (i = 0; i < num; i++)
++		device_remove_file(&pdev->dev, flexcan_dev_attr + i);
++
++	flexcan_device_detach(netdev_priv(net));
++	free_netdev(net);
++}
+Index: linux-2.6.31.6/drivers/net/can/flexcan/drv.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.31.6/drivers/net/can/flexcan/drv.c	2009-12-16 17:34:40.585687608 +0100
+@@ -0,0 +1,657 @@
++/*
++ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file drv.c
++ *
++ * @brief Driver for Freescale CAN Controller FlexCAN.
++ *
++ * @ingroup can
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/netdevice.h>
++#include <linux/if_arp.h>
++#include <linux/if_ether.h>
++#include <linux/platform_device.h>
++#ifdef REGULATOR
++	#include <linux/regulator/regulator.h>
++#endif
++#include <linux/clk.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++//#include <mach/hardware.h>	//TBD asm/hardware.h
++#include <mach/mxc_flexcan.h>
++#include "flexcan.h"
++
++static void flexcan_hw_start(struct flexcan_device *flexcan)
++{
++	unsigned int reg;
++	if ((flexcan->maxmb + 1) > 32) {
++		__raw_writel(0xFFFFFFFF, flexcan->io_base + CAN_HW_REG_IMASK1);
++		reg = (1 << (flexcan->maxmb - 31)) - 1;
++		__raw_writel(reg, flexcan->io_base + CAN_HW_REG_IMASK2);
++	} else {
++		reg = (1 << (flexcan->maxmb + 1)) - 1;
++		__raw_writel(reg, flexcan->io_base + CAN_HW_REG_IMASK1);
++		__raw_writel(0, flexcan->io_base + CAN_HW_REG_IMASK2);
++	}
++
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_MCR) & (~__MCR_HALT);
++	__raw_writel(reg, flexcan->io_base + CAN_HW_REG_MCR);
++}
++
++static void flexcan_hw_stop(struct flexcan_device *flexcan)
++{
++	unsigned int reg;
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_MCR);
++	__raw_writel(reg | __MCR_HALT, flexcan->io_base + CAN_HW_REG_MCR);
++}
++
++static int flexcan_hw_reset(struct flexcan_device *flexcan)
++{
++	unsigned int reg;
++	int timeout = 100000;
++
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_MCR);
++	__raw_writel(reg | __MCR_MDIS, flexcan->io_base + CAN_HW_REG_MCR);
++
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_CTRL);
++	if (flexcan->br_clksrc)
++		reg |= __CTRL_CLK_SRC;
++	else
++		reg &= ~__CTRL_CLK_SRC;
++	__raw_writel(reg, flexcan->io_base + CAN_HW_REG_CTRL);
++
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_MCR) & (~__MCR_MDIS);
++	__raw_writel(reg, flexcan->io_base + CAN_HW_REG_MCR);
++	reg |= __MCR_SOFT_RST;
++	__raw_writel(reg, flexcan->io_base + CAN_HW_REG_MCR);
++
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_MCR);
++	while (reg & __MCR_SOFT_RST) {
++		if (--timeout <= 0) {
++			printk(KERN_ERR "Flexcan software Reset Timeouted\n");
++			return -1;
++		}
++		udelay(10);
++		reg = __raw_readl(flexcan->io_base + CAN_HW_REG_MCR);
++	}
++	return 0;
++}
++
++static inline void flexcan_mcr_setup(struct flexcan_device *flexcan)
++{
++	unsigned int reg;
++
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_MCR);
++	reg &= ~(__MCR_MAX_MB_MASK | __MCR_WAK_MSK | __MCR_MAX_IDAM_MASK);
++
++	if (flexcan->fifo)
++		reg |= __MCR_FEN;
++	else
++		reg &= ~__MCR_FEN;
++
++	if (flexcan->wakeup)
++		reg |= __MCR_SLF_WAK | __MCR_WAK_MSK;
++	else
++		reg &= ~(__MCR_SLF_WAK | __MCR_WAK_MSK);
++
++	if (flexcan->wak_src)
++		reg |= __MCR_WAK_SRC;
++	else
++		reg &= ~__MCR_WAK_SRC;
++
++	if (flexcan->srx_dis)
++		reg |= __MCR_SRX_DIS;
++	else
++		reg &= ~__MCR_SRX_DIS;
++
++	if (flexcan->bcc)
++		reg |= __MCR_BCC;
++	else
++		reg &= ~__MCR_BCC;
++
++	if (flexcan->lprio)
++		reg |= __MCR_LPRIO_EN;
++	else
++		reg &= ~__MCR_LPRIO_EN;
++
++	if (flexcan->abort)
++		reg |= __MCR_AEN;
++	else
++		reg &= ~__MCR_AEN;
++
++	reg |= (flexcan->maxmb << __MCR_MAX_MB_OFFSET);
++	reg |= __MCR_DOZE | __MCR_MAX_IDAM_C;
++	__raw_writel(reg, flexcan->io_base + CAN_HW_REG_MCR);
++}
++
++//~~~~~~~~~~~~~~sven~~~~~~~~~~~~~~~~
++static inline void flexcan_ctrl_setup (struct flexcan_device *flexcan) {
++        struct can_priv *priv = (struct can_priv *) flexcan;
++        struct can_bittiming *bt = &priv -> bittiming;
++
++        unsigned int reg;
++
++        reg = __raw_readl (flexcan -> io_base + CAN_HW_REG_CTRL);
++        reg &= ~(__CTRL_PRESDIV_MASK | __CTRL_RJW_MASK | __CTRL_PSEG1_MASK |
++                 __CTRL_PSEG2_MASK | __CTRL_PROPSEG_MASK);
++
++        if (flexcan -> loopback)
++                reg |= __CTRL_LPB;
++        else
++                reg &= ~__CTRL_LPB;
++
++        if (flexcan -> smp)
++                reg |= __CTRL_SMP;
++        else
++                reg &= ~__CTRL_SMP;
++
++        if (flexcan -> boff_rec)
++                reg |= __CTRL_BOFF_REC;
++        else
++                reg &= ~__CTRL_BOFF_REC;
++
++        if (flexcan -> tsyn)
++                reg |= __CTRL_TSYN;
++        else
++                reg &= ~__CTRL_TSYN;
++
++        if (flexcan -> listen)
++                reg |= __CTRL_LOM;
++        else
++                reg &= ~__CTRL_LOM;
++
++        reg |= ((bt -> brp - 1) << __CTRL_PRESDIV_OFFSET) |
++            ((bt -> sjw - 1) << __CTRL_RJW_OFFSET) |
++            ((bt -> phase_seg1 - 1) << __CTRL_PSEG1_OFFSET) |
++            ((bt -> phase_seg2 - 1) << __CTRL_PSEG2_OFFSET) |
++            ((bt -> prop_seg - 1) << __CTRL_PROPSEG_OFFSET);
++
++        reg &= ~__CTRL_LBUF;
++
++        reg |= __CTRL_TWRN_MSK | __CTRL_RWRN_MSK | __CTRL_BOFF_MSK |
++            __CTRL_ERR_MSK;
++
++        __raw_writel (reg, flexcan -> io_base + CAN_HW_REG_CTRL);
++}
++
++int flexcan_set_bittiming (struct net_device *dev) {
++        flexcan_ctrl_setup (netdev_priv (dev));
++        return 0;
++}
++
++EXPORT_SYMBOL (flexcan_set_bittiming);
++//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++
++static int flexcan_hw_restart(struct net_device *dev)
++{
++	unsigned int reg;
++	struct flexcan_device *flexcan = netdev_priv(dev);
++
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_MCR);
++	if (reg & __MCR_SOFT_RST)
++		return 1;
++
++	flexcan_mcr_setup(flexcan);
++
++	__raw_writel(0, flexcan->io_base + CAN_HW_REG_IMASK2);
++	__raw_writel(0, flexcan->io_base + CAN_HW_REG_IMASK1);
++
++	__raw_writel(0xFFFFFFFF, flexcan->io_base + CAN_HW_REG_IFLAG2);
++	__raw_writel(0xFFFFFFFF, flexcan->io_base + CAN_HW_REG_IFLAG1);
++
++	__raw_writel(0, flexcan->io_base + CAN_HW_REG_ECR);
++
++	flexcan_mbm_init(flexcan);
++	netif_carrier_on(dev);
++	flexcan_hw_start(flexcan);
++
++	if (netif_queue_stopped(dev))
++		netif_start_queue(dev);
++
++	return 0;
++}
++
++static void flexcan_hw_watch(unsigned long data)
++{
++	unsigned int reg, ecr;
++	struct net_device *dev = (struct net_device *)data;
++	struct flexcan_device *flexcan = dev ? netdev_priv(dev) : NULL;
++
++	BUG_ON(!flexcan);
++
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_MCR);
++	if (reg & __MCR_MDIS) {
++		if (flexcan_hw_restart(dev))
++			mod_timer(&flexcan->timer, HZ / 20);
++		return;
++	}
++	ecr = __raw_readl(flexcan->io_base + CAN_HW_REG_ECR);
++	if (flexcan->boff_rec) {
++		if (((reg & __ESR_FLT_CONF_MASK) >> __ESR_FLT_CONF_OFF) > 1) {
++			reg |= __MCR_SOFT_RST;
++			__raw_writel(reg, flexcan->io_base + CAN_HW_REG_MCR);
++			mod_timer(&flexcan->timer, HZ / 20);
++			return;
++		}
++		netif_carrier_on(dev);
++	}
++}
++
++static void flexcan_hw_busoff(struct net_device *dev)
++{
++	struct flexcan_device *flexcan = netdev_priv(dev);
++	unsigned int reg;
++
++	netif_carrier_off(dev);
++
++	flexcan->timer.function = flexcan_hw_watch;
++	flexcan->timer.data = (unsigned long)dev;
++
++	if (flexcan->boff_rec) {
++		mod_timer(&flexcan->timer, HZ / 10);
++		return;
++	}
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_MCR);
++	__raw_writel(reg | __MCR_SOFT_RST, flexcan->io_base + CAN_HW_REG_MCR);
++	mod_timer(&flexcan->timer, HZ / 20);
++}
++
++static int flexcan_hw_open (struct net_device *dev) {         // ~~~~~sven~~~~~
++        struct flexcan_device *flexcan = netdev_priv (dev);   // ~~~~~sven~~~~~
++	int err;                                              // ~~~~~sven~~~~~
++
++	if (flexcan_hw_reset(flexcan))
++		return -EFAULT;
++
++	flexcan_mcr_setup(flexcan);
++
++//~~~~~~~~~~~~~~sven~~~~~~~~~~~~~~~~
++
++        err = open_candev (dev);
++        if (err)
++                return err;
++
++        flexcan_ctrl_setup (netdev_priv (dev));    // determine and set bittime
++
++//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++
++	__raw_writel(0, flexcan->io_base + CAN_HW_REG_IMASK2);
++	__raw_writel(0, flexcan->io_base + CAN_HW_REG_IMASK1);
++
++	__raw_writel(0xFFFFFFFF, flexcan->io_base + CAN_HW_REG_IFLAG2);
++	__raw_writel(0xFFFFFFFF, flexcan->io_base + CAN_HW_REG_IFLAG1);
++
++	__raw_writel(0, flexcan->io_base + CAN_HW_REG_ECR);
++	return 0;
++}
++
++static void flexcan_err_handler(struct net_device *dev)
++{
++	struct flexcan_device *flexcan = netdev_priv(dev);
++	struct sk_buff *skb;
++	struct can_frame *frame;
++	unsigned int esr, ecr;
++
++	esr = __raw_readl(flexcan->io_base + CAN_HW_REG_ESR);
++	__raw_writel(esr & __ESR_INTERRUPTS, flexcan->io_base + CAN_HW_REG_ESR);
++
++	if (esr & __ESR_WAK_INT)
++		return;
++
++	skb = dev_alloc_skb(sizeof(struct can_frame));
++	if (!skb) {
++		printk(KERN_ERR "%s: allocates skb fail in\n", __func__);
++		return;
++	}
++	frame = (struct can_frame *)skb_put(skb, sizeof(*frame));
++	memset(frame, 0, sizeof(*frame));
++	frame->can_id = CAN_ERR_FLAG | CAN_ERR_CRTL;
++	frame->can_dlc = CAN_ERR_DLC;
++
++	if (esr & __ESR_TWRN_INT)
++		frame->data[1] |= CAN_ERR_CRTL_TX_WARNING;
++
++	if (esr & __ESR_RWRN_INT)
++		frame->data[1] |= CAN_ERR_CRTL_RX_WARNING;
++
++	if (esr & __ESR_BOFF_INT)
++		frame->can_id |= CAN_ERR_BUSOFF;
++
++	if (esr & __ESR_ERR_INT) {
++		if (esr & __ESR_BIT1_ERR)
++			frame->data[2] |= CAN_ERR_PROT_BIT1;
++
++		if (esr & __ESR_BIT0_ERR)
++			frame->data[2] |= CAN_ERR_PROT_BIT0;
++
++		if (esr & __ESR_ACK_ERR)
++			frame->can_id |= CAN_ERR_ACK;
++
++		/*TODO:// if (esr & __ESR_CRC_ERR) */
++
++		if (esr & __ESR_FRM_ERR)
++			frame->data[2] |= CAN_ERR_PROT_FORM;
++
++		if (esr & __ESR_STF_ERR)
++			frame->data[2] |= CAN_ERR_PROT_STUFF;
++
++		ecr = __raw_readl(flexcan->io_base + CAN_HW_REG_ECR);
++		switch ((esr & __ESR_FLT_CONF_MASK) >> __ESR_FLT_CONF_OFF) {
++		case 0:
++			if (__ECR_TX_ERR_COUNTER(ecr) >= __ECR_ACTIVE_THRESHOLD)
++				frame->data[1] |= CAN_ERR_CRTL_TX_WARNING;
++			if (__ECR_RX_ERR_COUNTER(ecr) >= __ECR_ACTIVE_THRESHOLD)
++				frame->data[1] |= CAN_ERR_CRTL_RX_WARNING;
++			break;
++		case 1:
++			if (__ECR_TX_ERR_COUNTER(ecr) >=
++			    __ECR_PASSIVE_THRESHOLD)
++				frame->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
++
++			if (__ECR_RX_ERR_COUNTER(ecr) >=
++			    __ECR_PASSIVE_THRESHOLD)
++				frame->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
++			break;
++		default:
++			frame->can_id |= CAN_ERR_BUSOFF;
++		}
++	}
++
++	if (frame->can_id & CAN_ERR_BUSOFF)
++		flexcan_hw_busoff(dev);
++
++	skb->dev = dev;
++	skb->ip_summed = CHECKSUM_UNNECESSARY;
++	netif_receive_skb(skb);
++}
++
++static irqreturn_t flexcan_irq_handler(int irq, void *data)
++{
++	struct net_device *dev = (struct net_device *)data;
++	struct flexcan_device *flexcan = dev ? netdev_priv(dev) : NULL;
++	unsigned int reg;
++
++	BUG_ON(!flexcan);
++
++	reg = __raw_readl(flexcan->io_base + CAN_HW_REG_ESR);
++	if (reg & __ESR_INTERRUPTS) {
++		flexcan_err_handler(dev);
++		return IRQ_HANDLED;
++	}
++
++	flexcan_mbm_isr(dev);
++	return IRQ_HANDLED;
++}
++
++static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++	struct can_frame *frame = (struct can_frame *) (skb -> data);
++	struct flexcan_device *flexcan = netdev_priv(dev);
++	struct net_device_stats *stats = (struct net_device_stats *) dev_get_stats (dev);    // ~~~~~~~sven~~~~~~~~
++
++	BUG_ON(!flexcan);
++
++	if (frame->can_dlc > 8)
++		return -EINVAL;
++
++	if (!flexcan_mbm_xmit(flexcan, frame)) {
++		dev_kfree_skb(skb);
++		stats->tx_bytes += frame->can_dlc;
++		stats->tx_packets++;
++		dev->trans_start = jiffies;
++		return NETDEV_TX_OK;
++	}
++	netif_stop_queue(dev);
++	return NETDEV_TX_BUSY;
++}
++
++static int flexcan_open(struct net_device *dev)
++{
++	struct flexcan_device *flexcan;
++	struct platform_device *pdev;
++	struct flexcan_platform_data *plat_data;
++
++	flexcan = netdev_priv(dev);
++	BUG_ON(!flexcan);
++
++	pdev = flexcan->dev;
++	plat_data = (pdev->dev).platform_data;
++	if (plat_data && plat_data->active)
++		plat_data->active(pdev->id);
++
++	if (flexcan->clk)
++		if (clk_enable(flexcan->clk))
++			goto clk_err;
++#ifdef REGULATOR
++	if (flexcan->core_reg)
++		if (regulator_enable(flexcan->core_reg))
++			goto core_reg_err;
++
++	if (flexcan->io_reg)
++		if (regulator_enable(flexcan->io_reg))
++			goto io_reg_err;
++#endif
++	if (plat_data && plat_data->xcvr_enable)
++		plat_data->xcvr_enable(pdev->id, 1);
++
++	if (request_irq(flexcan->irq, flexcan_irq_handler, IRQF_SAMPLE_RANDOM,
++			dev->name, dev))
++		goto irq_err;
++
++	if (flexcan_hw_open (dev))   // ~~~~~sven~~~~~
++		goto open_err;
++
++	flexcan_mbm_init(flexcan);
++	netif_carrier_on(dev);
++	flexcan_hw_start(flexcan);
++	return 0;
++      open_err:
++	free_irq(flexcan->irq, dev);
++      irq_err:
++	if (plat_data && plat_data->xcvr_enable)
++		plat_data->xcvr_enable(pdev->id, 0);
++#ifdef REGULATOR
++	if (flexcan->io_reg)
++		regulator_disable(flexcan->io_reg);
++      io_reg_err:
++	if (flexcan->core_reg)
++		regulator_disable(flexcan->core_reg);
++      core_reg_err:
++#endif
++	if (flexcan->clk)
++		clk_disable(flexcan->clk);
++      clk_err:
++	if (plat_data && plat_data->inactive)
++		plat_data->inactive(pdev->id);
++	return -ENODEV;
++}
++
++static int flexcan_stop(struct net_device *dev)
++{
++	struct flexcan_device *flexcan;
++	struct platform_device *pdev;
++	struct flexcan_platform_data *plat_data;
++
++	flexcan = netdev_priv(dev);
++
++	BUG_ON(!flexcan);
++
++	pdev = flexcan->dev;
++	plat_data = (pdev->dev).platform_data;
++
++	flexcan_hw_stop(flexcan);
++
++	free_irq(flexcan->irq, dev);
++
++	if (plat_data && plat_data->xcvr_enable)
++		plat_data->xcvr_enable(pdev->id, 0);
++
++#ifdef REGULATOR
++	if (flexcan->io_reg)
++		regulator_disable(flexcan->io_reg);
++	if (flexcan->core_reg)
++		regulator_disable(flexcan->core_reg);
++#endif
++	if (flexcan->clk)
++		clk_disable(flexcan->clk);
++	if (plat_data && plat_data->inactive)
++		plat_data->inactive(pdev->id);
++	return 0;
++}
++
++static const struct net_device_ops flexcan_netdev_ops = {
++       .ndo_open               = flexcan_open,
++       .ndo_stop               = flexcan_stop,
++       .ndo_start_xmit         = flexcan_start_xmit,
++};
++
++static void flexcan_setup(struct net_device *dev)
++{
++	dev->type = ARPHRD_CAN;
++	dev->mtu = sizeof(struct can_frame);
++	dev->hard_header_len = 0;
++	dev->addr_len = 0;
++	dev->tx_queue_len = FLEXCAN_MAX_MB;
++	dev->flags = IFF_NOARP;
++	dev->features = NETIF_F_NO_CSUM;
++
++        dev->netdev_ops = &flexcan_netdev_ops;
++}
++
++static int flexcan_probe(struct platform_device *pdev)
++{
++	struct net_device *net;
++	net = flexcan_device_alloc(pdev, flexcan_setup);
++	if (!net)
++		return -ENOMEM;
++
++	if (register_candev(net)) {   // ~~~~~sven~~~~~
++		flexcan_device_free(pdev);
++		return -ENODEV;
++	}
++	return 0;
++}
++
++static int flexcan_remove(struct platform_device *pdev)
++{
++	flexcan_device_free(pdev);
++	return 0;
++}
++
++static int flexcan_suspend(struct platform_device *pdev, pm_message_t state)
++{
++	struct net_device *net;
++	struct flexcan_device *flexcan;
++	struct flexcan_platform_data *plat_data;
++	net = (struct net_device *)dev_get_drvdata(&pdev->dev);
++	flexcan = netdev_priv(net);
++
++	BUG_ON(!flexcan);
++
++	if (!(net->flags & IFF_UP))
++		return 0;
++	if (flexcan->wakeup)
++		set_irq_wake(flexcan->irq, 1);
++	else {
++		plat_data = (pdev->dev).platform_data;
++
++		if (plat_data && plat_data->xcvr_enable)
++			plat_data->xcvr_enable(pdev->id, 0);
++#ifdef REGULATOR
++		if (flexcan->io_reg)
++			regulator_disable(flexcan->io_reg);
++		if (flexcan->core_reg)
++			regulator_disable(flexcan->core_reg);
++#endif
++		if (flexcan->clk)
++			clk_disable(flexcan->clk);
++		if (plat_data && plat_data->inactive)
++			plat_data->inactive(pdev->id);
++	}
++	return 0;
++}
++
++static int flexcan_resume(struct platform_device *pdev)
++{
++	struct net_device *net;
++	struct flexcan_device *flexcan;
++	struct flexcan_platform_data *plat_data;
++	net = (struct net_device *)dev_get_drvdata(&pdev->dev);
++	flexcan = netdev_priv(net);
++
++	BUG_ON(!flexcan);
++
++	if (!(net->flags & IFF_UP))
++		return 0;
++
++	if (flexcan->wakeup)
++		set_irq_wake(flexcan->irq, 0);
++	else {
++		plat_data = (pdev->dev).platform_data;
++		if (plat_data && plat_data->active)
++			plat_data->active(pdev->id);
++
++		if (flexcan->clk) {
++			if (clk_enable(flexcan->clk))
++				printk(KERN_ERR "%s:enable clock fail\n",
++				       __func__);
++		}
++#ifdef REGULATOR
++		if (flexcan->core_reg) {
++			if (regulator_enable(flexcan->core_reg))
++				printk(KERN_ERR "%s:enable core voltage\n",
++				       __func__);
++		}
++		if (flexcan->io_reg) {
++			if (regulator_enable(flexcan->io_reg))
++				printk(KERN_ERR "%s:enable io voltage\n",
++				       __func__);
++		}
++#endif
++		if (plat_data && plat_data->xcvr_enable)
++			plat_data->xcvr_enable(pdev->id, 1);
++	}
++	return 0;
++}
++
++static struct platform_driver flexcan_driver = {
++	.driver = {
++		   .name = FLEXCAN_DEVICE_NAME,
++		   },
++	.probe = flexcan_probe,
++	.remove = flexcan_remove,
++	.suspend = flexcan_suspend,
++	.resume = flexcan_resume,
++};
++
++static __init int flexcan_init(void)
++{
++	pr_info("Freescale FlexCAN Driver \n");
++	return platform_driver_register(&flexcan_driver);
++}
++
++static __exit void flexcan_exit(void)
++{
++	return platform_driver_unregister(&flexcan_driver);
++}
++
++module_init(flexcan_init);
++module_exit(flexcan_exit);
++
++MODULE_LICENSE("GPL");
+Index: linux-2.6.31.6/drivers/net/can/flexcan/flexcan.h
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.31.6/drivers/net/can/flexcan/flexcan.h	2009-12-16 17:34:40.585687608 +0100
+@@ -0,0 +1,230 @@
++/*
++ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file flexcan.h
++ *
++ * @brief FlexCan definitions.
++ *
++ * @ingroup can
++ */
++
++#ifndef __CAN_FLEXCAN_H__
++#define __CAN_FLEXCAN_H__
++
++#include <linux/list.h>
++#include <linux/platform_device.h>
++#ifdef REGULATOR
++	#include <linux/regulator/regulator.h>
++#endif
++#include <linux/clk.h>
++#include <linux/can.h>
++#include <linux/can/core.h>
++#include <linux/can/error.h>
++#include <linux/can/dev.h>
++
++#define FLEXCAN_DEVICE_NAME	"FlexCAN"
++
++struct can_mb_cs {
++	unsigned int time_stamp:16;
++	unsigned int length:4;
++	unsigned int rtr:1;
++	unsigned int ide:1;
++	unsigned int srr:1;
++	unsigned int nouse1:1;
++	unsigned int code:4;
++	unsigned int nouse2:4;
++};
++
++#define CAN_MB_RX_INACTIVE	0x0
++#define CAN_MB_RX_EMPTY		0x4
++#define CAN_MB_RX_FULL		0x2
++#define CAN_MB_RX_OVERRUN	0x6
++#define CAN_MB_RX_BUSY		0x1
++
++#define CAN_MB_TX_INACTIVE	0x8
++#define CAN_MB_TX_ABORT		0x9
++#define CAN_MB_TX_ONCE		0xC
++#define CAN_MB_TX_REMOTE	0xA
++
++struct can_hw_mb {
++	union {
++		struct can_mb_cs cs;
++		unsigned int data;
++	} mb_cs;
++	unsigned int mb_id;
++	unsigned char mb_data[8];
++};
++
++#define CAN_HW_REG_MCR		0x00
++#define CAN_HW_REG_CTRL		0x04
++#define CAN_HW_REG_TIMER	0x08
++#define CAN_HW_REG_RXGMASK	0x10
++#define CAN_HW_REG_RX14MASK	0x14
++#define CAN_HW_REG_RX15MASK	0x18
++#define CAN_HW_REG_ECR		0x1C
++#define CAN_HW_REG_ESR		0x20
++#define CAN_HW_REG_IMASK2	0x24
++#define CAN_HW_REG_IMASK1	0x28
++#define CAN_HW_REG_IFLAG2	0x2C
++#define CAN_HW_REG_IFLAG1	0x30
++
++#define CAN_MB_BASE	0x0080
++#define CAN_RXMASK_BASE	0x0880
++#define CAN_FIFO_BASE	0xE0
++
++#define __MCR_MDIS		(1 << 31)
++#define __MCR_FRZ		(1 << 30)
++#define __MCR_FEN		(1 << 29)
++#define __MCR_HALT		(1 << 28)
++#define __MCR_NOTRDY		(1 << 27)
++#define __MCR_WAK_MSK		(1 << 26)
++#define __MCR_SOFT_RST		(1 << 25)
++#define __MCR_FRZ_ACK		(1 << 24)
++#define __MCR_SLF_WAK		(1 << 22)
++#define __MCR_WRN_EN		(1 << 21)
++#define __MCR_LPM_ACK		(1 << 20)
++#define __MCR_WAK_SRC		(1 << 19)
++#define __MCR_DOZE		(1 << 18)
++#define __MCR_SRX_DIS		(1 << 17)
++#define __MCR_BCC		(1 << 16)
++#define __MCR_LPRIO_EN		(1 << 13)
++#define __MCR_AEN		(1 << 12)
++#define __MCR_MAX_IDAM_OFFSET 	8
++#define __MCR_MAX_IDAM_MASK 	(0x3 << __MCR_MAX_IDAM_OFFSET)
++#define __MCR_MAX_IDAM_A	(0x0 << __MCR_MAX_IDAM_OFFSET)
++#define __MCR_MAX_IDAM_B	(0x1 << __MCR_MAX_IDAM_OFFSET)
++#define __MCR_MAX_IDAM_C	(0x2 << __MCR_MAX_IDAM_OFFSET)
++#define __MCR_MAX_IDAM_D	(0x3 << __MCR_MAX_IDAM_OFFSET)
++#define __MCR_MAX_MB_OFFSET 	0
++#define __MCR_MAX_MB_MASK 	(0x3F)
++
++#define __CTRL_PRESDIV_OFFSET	24
++#define __CTRL_PRESDIV_MASK	(0xFF << __CTRL_PRESDIV_OFFSET)
++#define __CTRL_RJW_OFFSET	22
++#define __CTRL_RJW_MASK		(0x3 << __CTRL_RJW_OFFSET)
++#define __CTRL_PSEG1_OFFSET	19
++#define __CTRL_PSEG1_MASK	(0x7 << __CTRL_PSEG1_OFFSET)
++#define __CTRL_PSEG2_OFFSET	16
++#define __CTRL_PSEG2_MASK	(0x7 << __CTRL_PSEG2_OFFSET)
++#define __CTRL_BOFF_MSK		(0x1 << 15)
++#define __CTRL_ERR_MSK		(0x1 << 14)
++#define __CTRL_CLK_SRC		(0x1 << 13)
++#define __CTRL_LPB		(0x1 << 12)
++#define __CTRL_TWRN_MSK		(0x1 << 11)
++#define __CTRL_RWRN_MSK		(0x1 << 10)
++#define __CTRL_SMP		(0x1 << 7)
++#define __CTRL_BOFF_REC		(0x1 << 6)
++#define __CTRL_TSYN		(0x1 << 5)
++#define __CTRL_LBUF		(0x1 << 4)
++#define __CTRL_LOM		(0x1 << 3)
++#define __CTRL_PROPSEG_OFFSET	0
++#define __CTRL_PROPSEG_MASK	(0x7)
++
++#define __ECR_TX_ERR_COUNTER(x) ((x) & 0xFF)
++#define __ECR_RX_ERR_COUNTER(x) (((x) >> 8) & 0xFF)
++#define __ECR_PASSIVE_THRESHOLD	128
++#define __ECR_ACTIVE_THRESHOLD	96
++
++#define __ESR_TWRN_INT		(0x1 << 17)
++#define __ESR_RWRN_INT		(0x1 << 16)
++#define __ESR_BIT1_ERR		(0x1 << 15)
++#define __ESR_BIT0_ERR		(0x1 << 14)
++#define __ESR_ACK_ERR		(0x1 << 13)
++#define __ESR_CRC_ERR		(0x1 << 12)
++#define __ESR_FRM_ERR		(0x1 << 11)
++#define __ESR_STF_ERR		(0x1 << 10)
++#define __ESR_TX_WRN		(0x1 << 9)
++#define __ESR_RX_WRN		(0x1 << 8)
++#define __ESR_IDLE		(0x1 << 7)
++#define __ESR_TXRX		(0x1 << 6)
++#define __ESR_FLT_CONF_OFF	4
++#define __ESR_FLT_CONF_MASK	(0x3 << __ESR_FLT_CONF_OFF)
++#define __ESR_BOFF_INT		(0x1 << 2)
++#define __ESR_ERR_INT		(0x1 << 1)
++#define __ESR_WAK_INT		(0x1)
++
++#define __ESR_INTERRUPTS	(__ESR_WAK_INT | __ESR_ERR_INT | \
++				__ESR_BOFF_INT | __ESR_TWRN_INT | \
++				__ESR_RWRN_INT)
++
++#define __FIFO_OV_INT		0x0080
++#define __FIFO_WARN_INT		0x0040
++#define __FIFO_RDY_INT		0x0020
++
++struct flexcan_device {
++	struct can_priv can;    /* FIXME:new must be the first member! */
++	struct mutex mutex;
++	void *io_base;
++	struct can_hw_mb *hwmb;
++	unsigned int *rx_mask;
++	unsigned int xmit_mb;
++//        unsigned int bitrate;        ~~~~~sven~~~~~
++	/* word 1 */
++//        unsigned int br_presdiv:8;   ~~~~~sven~~~~~
++//        unsigned int br_rjw:2;       ~~~~~sven~~~~~
++//        unsigned int br_propseg:3;   ~~~~~sven~~~~~
++//        unsigned int br_pseg1:3;     ~~~~~sven~~~~~
++//        unsigned int br_pseg2:3;     ~~~~~sven~~~~~
++	unsigned int maxmb:6;
++	unsigned int xmit_maxmb:6;
++	unsigned int wd1_resv:1;
++
++	/* word 2 */
++	unsigned int fifo:1;
++	unsigned int wakeup:1;
++	unsigned int srx_dis:1;
++	unsigned int wak_src:1;
++	unsigned int bcc:1;
++	unsigned int lprio:1;
++	unsigned int abort:1;
++	unsigned int br_clksrc:1;
++	unsigned int loopback:1;
++	unsigned int smp:1;
++	unsigned int boff_rec:1;
++	unsigned int tsyn:1;
++	unsigned int listen:1;
++
++	unsigned int ext_msg:1;
++	unsigned int std_msg:1;
++
++	struct timer_list timer;
++	struct platform_device *dev;
++	struct regulator *core_reg;
++	struct regulator *io_reg;
++	struct clk *clk;
++	int irq;
++};
++
++#define FLEXCAN_MAX_FIFO_MB	8
++#define FLEXCAN_MAX_MB		64
++#define FLEXCAN_MAX_PRESDIV	256
++#define FLEXCAN_MAX_RJW		4
++#define FLEXCAN_MAX_PSEG1	8
++#define FLEXCAN_MAX_PSEG2	8
++#define FLEXCAN_MAX_PROPSEG	8
++#define FLEXCAN_MAX_BITRATE	1000000
++
++extern struct net_device *flexcan_device_alloc(struct platform_device *pdev,
++					       void (*setup) (struct net_device
++							      *dev));
++extern void flexcan_device_free(struct platform_device *pdev);
++
++extern void flexcan_mbm_init(struct flexcan_device *flexcan);
++extern void flexcan_mbm_isr(struct net_device *dev);
++extern int flexcan_mbm_xmit(struct flexcan_device *flexcan,
++			    struct can_frame *frame);
++
++extern int flexcan_set_bittiming (struct net_device *dev);      // ~~~~~sven~~~~~
++
++#endif				/* __CAN_FLEXCAN_H__ */
+Index: linux-2.6.31.6/drivers/net/can/flexcan/mbm.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.31.6/drivers/net/can/flexcan/mbm.c	2009-12-16 17:34:40.585687608 +0100
+@@ -0,0 +1,350 @@
++/*
++ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file mbm.c
++ *
++ * @brief Driver for Freescale CAN Controller FlexCAN.
++ *
++ * @ingroup can
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/netdevice.h>
++#include <linux/if_arp.h>
++#include <linux/if_ether.h>
++#include <linux/platform_device.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include "flexcan.h"
++
++#define flexcan_swab32(x)	\
++	(((x) << 24) | ((x) >> 24) |\
++		(((x) & (__u32)0x0000ff00UL) << 8) |\
++		(((x) & (__u32)0x00ff0000UL) >> 8))
++
++static inline void flexcan_memcpy(void *dst, void *src, int len)
++{
++	int i;
++	unsigned int *d = (unsigned int *)dst, *s = (unsigned int *)src;
++	len = (len + 3) >> 2;
++	for (i = 0; i < len; i++, s++, d++)
++		*d = flexcan_swab32(*s);
++}
++
++static void flexcan_mb_bottom(struct net_device *dev, int index)
++{
++	struct flexcan_device *flexcan = netdev_priv(dev);
++	struct net_device_stats *stats = (struct net_device_stats *) dev_get_stats (dev);  // ~~~~~sven~~~~~
++	struct can_hw_mb *hwmb;
++	struct can_frame *frame;
++	struct sk_buff *skb;
++	unsigned int tmp;
++
++	hwmb = flexcan->hwmb + index;
++	if (flexcan->fifo || (index >= (flexcan->maxmb - flexcan->xmit_maxmb))) {
++		if (hwmb->mb_cs.cs.code == CAN_MB_TX_ABORT)
++			hwmb->mb_cs.cs.code = CAN_MB_TX_INACTIVE;
++
++		if (hwmb->mb_cs.cs.code & CAN_MB_TX_INACTIVE) {
++			if (netif_queue_stopped(dev))
++				netif_start_queue(dev);
++			return;
++		}
++	}
++	skb = dev_alloc_skb(sizeof(struct can_frame));
++	if (skb) {
++		frame = (struct can_frame *)skb_put(skb, sizeof(*frame));
++		memset(frame, 0, sizeof(*frame));
++		if (hwmb->mb_cs.cs.ide)
++			frame->can_id =
++			    (hwmb->mb_id & CAN_EFF_MASK) | CAN_EFF_FLAG;
++		else
++			frame->can_id = (hwmb->mb_id >> 18) & CAN_SFF_MASK;
++
++		if (hwmb->mb_cs.cs.rtr)
++			frame->can_id |= CAN_RTR_FLAG;
++
++		frame->can_dlc = hwmb->mb_cs.cs.length;
++
++		if (frame->can_dlc && frame->can_dlc)
++			flexcan_memcpy(frame->data, hwmb->mb_data,
++				       frame->can_dlc);
++
++		if (flexcan->fifo
++		    || (index >= (flexcan->maxmb - flexcan->xmit_maxmb))) {
++			hwmb->mb_cs.cs.code = CAN_MB_TX_INACTIVE;
++			if (netif_queue_stopped(dev))
++				netif_start_queue(dev);
++		}
++
++		tmp = __raw_readl(flexcan->io_base + CAN_HW_REG_TIMER);
++
++		dev->last_rx = jiffies;
++		stats->rx_packets++;
++		stats->rx_bytes += frame->can_dlc;
++
++		skb->dev = dev;
++		skb->protocol = __constant_htons(ETH_P_CAN);
++		skb->ip_summed = CHECKSUM_UNNECESSARY;
++                // netif_receive_skb (skb);   ~~~~~sven~~~~~
++                netif_rx (skb);             //~~~~~sven~~~~~
++	} else {
++		tmp = hwmb->mb_cs.data;
++		tmp = hwmb->mb_id;
++		tmp = hwmb->mb_data[0];
++		if (flexcan->fifo
++		    || (index >= (flexcan->maxmb - flexcan->xmit_maxmb))) {
++
++			hwmb->mb_cs.cs.code = CAN_MB_TX_INACTIVE;
++			if (netif_queue_stopped(dev))
++				netif_start_queue(dev);
++		}
++		tmp = __raw_readl(flexcan->io_base + CAN_HW_REG_TIMER);
++		stats->rx_dropped++;
++	}
++}
++
++static void flexcan_fifo_isr(struct net_device *dev, unsigned int iflag1)
++{
++	struct flexcan_device *flexcan = dev ? netdev_priv(dev) : NULL;
++	struct net_device_stats *stats = (struct net_device_stats *) dev_get_stats (dev);  // ~~~~~sven~~~~~
++	struct sk_buff *skb;
++	struct can_hw_mb *hwmb = flexcan->hwmb;
++	struct can_frame *frame;
++	unsigned int tmp;
++
++	if (iflag1 & __FIFO_RDY_INT) {
++		skb = dev_alloc_skb(sizeof(struct can_frame));
++		if (skb) {
++			frame =
++			    (struct can_frame *)skb_put(skb, sizeof(*frame));
++			memset(frame, 0, sizeof(*frame));
++			if (hwmb->mb_cs.cs.ide)
++				frame->can_id =
++				    (hwmb->mb_id & CAN_EFF_MASK) | CAN_EFF_FLAG;
++			else
++				frame->can_id =
++				    (hwmb->mb_id >> 18) & CAN_SFF_MASK;
++
++			if (hwmb->mb_cs.cs.rtr)
++				frame->can_id |= CAN_RTR_FLAG;
++
++			frame->can_dlc = hwmb->mb_cs.cs.length;
++
++			if (frame->can_dlc && (frame->can_dlc <= 8))
++				flexcan_memcpy(frame->data, hwmb->mb_data,
++					       frame->can_dlc);
++			tmp = __raw_readl(flexcan->io_base + CAN_HW_REG_TIMER);
++
++			dev->last_rx = jiffies;
++
++			stats->rx_packets++;
++			stats->rx_bytes += frame->can_dlc;
++
++			skb->dev = dev;
++			skb->protocol = __constant_htons(ETH_P_CAN);
++			skb->ip_summed = CHECKSUM_UNNECESSARY;
++                        //netif_receive_skb (skb);   ~~~~~sven~~~~~
++                        netif_rx (skb);            //~~~~~sven~~~~~
++		} else {
++			tmp = hwmb->mb_cs.data;
++			tmp = hwmb->mb_id;
++			tmp = hwmb->mb_data[0];
++			tmp = __raw_readl(flexcan->io_base + CAN_HW_REG_TIMER);
++		}
++	}
++
++	if (iflag1 & (__FIFO_OV_INT | __FIFO_WARN_INT)) {
++		skb = dev_alloc_skb(sizeof(struct can_frame));
++		if (skb) {
++			frame =
++			    (struct can_frame *)skb_put(skb, sizeof(*frame));
++			memset(frame, 0, sizeof(*frame));
++			frame->can_id = CAN_ERR_FLAG | CAN_ERR_CRTL;
++			frame->can_dlc = CAN_ERR_DLC;
++			if (iflag1 & __FIFO_WARN_INT)
++				frame->data[1] |=
++				    CAN_ERR_CRTL_TX_WARNING |
++				    CAN_ERR_CRTL_RX_WARNING;
++			if (iflag1 & __FIFO_OV_INT)
++				frame->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
++
++			skb->dev = dev;
++			skb->protocol = __constant_htons(ETH_P_CAN);
++			skb->ip_summed = CHECKSUM_UNNECESSARY;
++                        //netif_receive_skb (skb);    ~~~~~sven~~~~~
++                        netif_rx (skb);             //~~~~~sven~~~~~
++		}
++	}
++}
++
++/*!
++ * @brief The function call by CAN ISR to handle mb events.
++ *
++ * @param dev		the pointer of network device.
++ *
++ * @return none
++ */
++void flexcan_mbm_isr(struct net_device *dev)
++{
++	int i, iflag1, iflag2, maxmb;
++	struct flexcan_device *flexcan = dev ? netdev_priv(dev) : NULL;
++
++	if (flexcan->maxmb > 31) {
++		maxmb = flexcan->maxmb + 1 - 32;
++		iflag1 = __raw_readl(flexcan->io_base + CAN_HW_REG_IFLAG1) &
++		    __raw_readl(flexcan->io_base + CAN_HW_REG_IMASK1);
++		iflag2 = __raw_readl(flexcan->io_base + CAN_HW_REG_IFLAG2) &
++		    __raw_readl(flexcan->io_base + CAN_HW_REG_IMASK2);
++		iflag2 &= (1 << maxmb) - 1;
++		maxmb = 32;
++	} else {
++		maxmb = flexcan->maxmb + 1;
++		iflag1 = __raw_readl(flexcan->io_base + CAN_HW_REG_IFLAG1) &
++		    __raw_readl(flexcan->io_base + CAN_HW_REG_IMASK1);
++		iflag1 &= (1 << maxmb) - 1;
++		iflag2 = 0;
++	}
++
++	__raw_writel(iflag1, flexcan->io_base + CAN_HW_REG_IFLAG1);
++	__raw_writel(iflag2, flexcan->io_base + CAN_HW_REG_IFLAG2);
++
++	if (flexcan->fifo) {
++		flexcan_fifo_isr(dev, iflag1);
++		iflag1 &= 0xFFFFFF00;
++	}
++	for (i = 0; iflag1 && (i < maxmb); i++) {
++		if (iflag1 & (1 << i)) {
++			iflag1 &= ~(1 << i);
++			flexcan_mb_bottom(dev, i);
++		}
++	}
++
++	for (i = maxmb; iflag2 && (i <= flexcan->maxmb); i++) {
++		if (iflag2 & (1 << (i - 32))) {
++			iflag2 &= ~(1 << (i - 32));
++			flexcan_mb_bottom(dev, i);
++		}
++	}
++}
++
++/*!
++ * @brief function to xmit message buffer
++ *
++ * @param flexcan	the pointer of can hardware device.
++ * @param frame		the pointer of can message frame.
++ *
++ * @return	Returns 0 if xmit is success. otherwise returns non-zero.
++ */
++int flexcan_mbm_xmit(struct flexcan_device *flexcan, struct can_frame *frame)
++{
++	int i = flexcan->xmit_mb;
++	struct can_hw_mb *hwmb = flexcan->hwmb;
++
++	do {
++		if (hwmb[i].mb_cs.cs.code == CAN_MB_TX_INACTIVE)
++			break;
++		if ((++i) > flexcan->maxmb) {
++			if (flexcan->fifo)
++				i = FLEXCAN_MAX_FIFO_MB;
++			else
++				i = flexcan->xmit_maxmb + 1;
++		}
++		if (i == flexcan->xmit_mb)
++			return -1;
++	} while (1);
++
++	flexcan->xmit_mb = i + 1;
++	if (flexcan->xmit_mb > flexcan->maxmb) {
++		if (flexcan->fifo)
++			flexcan->xmit_mb = FLEXCAN_MAX_FIFO_MB;
++		else
++			flexcan->xmit_mb = flexcan->xmit_maxmb + 1;
++	}
++
++	if (frame->can_id & CAN_RTR_FLAG)
++		hwmb[i].mb_cs.cs.rtr = 1;
++	else
++		hwmb[i].mb_cs.cs.rtr = 0;
++
++	if (frame->can_id & CAN_EFF_FLAG) {
++		hwmb[i].mb_cs.cs.ide = 1;
++		hwmb[i].mb_cs.cs.srr = 1;
++		hwmb[i].mb_id = frame->can_id & CAN_EFF_MASK;
++	} else {
++		hwmb[i].mb_cs.cs.ide = 0;
++		hwmb[i].mb_id = (frame->can_id & CAN_SFF_MASK) << 18;
++	}
++
++	hwmb[i].mb_cs.cs.length = frame->can_dlc;
++	flexcan_memcpy(hwmb[i].mb_data, frame->data, frame->can_dlc);
++	hwmb[i].mb_cs.cs.code = CAN_MB_TX_ONCE;
++	return 0;
++}
++
++/*!
++ * @brief function to initial message buffer
++ *
++ * @param flexcan	the pointer of can hardware device.
++ *
++ * @return	none
++ */
++void flexcan_mbm_init(struct flexcan_device *flexcan)
++{
++	struct can_hw_mb *hwmb;
++	int rx_mb, i;
++
++	/* Set global mask to receive all messages */
++	__raw_writel(0, flexcan->io_base + CAN_HW_REG_RXGMASK);
++	__raw_writel(0, flexcan->io_base + CAN_HW_REG_RX14MASK);
++	__raw_writel(0, flexcan->io_base + CAN_HW_REG_RX15MASK);
++
++	memset(flexcan->hwmb, 0, sizeof(*hwmb) * FLEXCAN_MAX_MB);
++	/* Set individual mask to receive all messages */
++	memset(flexcan->rx_mask, 0, sizeof(unsigned int) * FLEXCAN_MAX_MB);
++
++	if (flexcan->fifo)
++		rx_mb = FLEXCAN_MAX_FIFO_MB;
++	else
++		rx_mb = flexcan->maxmb - flexcan->xmit_maxmb;
++
++	hwmb = flexcan->hwmb;
++	if (flexcan->fifo) {
++		unsigned long *id_table = flexcan->io_base + CAN_FIFO_BASE;
++		for (i = 0; i < rx_mb; i++)
++			id_table[i] = 0;
++	} else {
++		for (i = 0; i < rx_mb; i++) {
++			hwmb[i].mb_cs.cs.code = CAN_MB_RX_EMPTY;
++			/*
++			 * IDE bit can not control by mask registers
++			 * So set message buffer to receive extend
++			 * or standard message.
++			 */
++			if (flexcan->ext_msg && flexcan->std_msg)
++				hwmb[i].mb_cs.cs.ide = i & 1;
++			else {
++				if (flexcan->ext_msg)
++					hwmb[i].mb_cs.cs.ide = 1;
++			}
++		}
++	}
++
++	for (; i <= flexcan->maxmb; i++)
++		hwmb[i].mb_cs.cs.code = CAN_MB_TX_INACTIVE;
++
++	flexcan->xmit_mb = rx_mb;
++}
+Index: linux-2.6.31.6/drivers/net/can/Kconfig
+===================================================================
+--- linux-2.6.31.6.orig/drivers/net/can/Kconfig	2009-11-10 01:32:31.000000000 +0100
++++ linux-2.6.31.6/drivers/net/can/Kconfig	2009-12-16 17:34:40.585687608 +0100
+@@ -84,4 +84,13 @@
+ 	  a problem with CAN support and want to see more of what is going
+ 	  on.
+ 
++config CAN_FLEXCAN
++	tristate "Freescale FlexCAN"
++	depends on CAN && ARCH_MX35
++	default m
++	---help---
++	  This select the support of Freescale CAN(FlexCAN).
++	  This driver can also be built as a module.
++	  If unsure, say N.
++
+ endmenu
+Index: linux-2.6.31.6/drivers/net/can/Makefile
+===================================================================
+--- linux-2.6.31.6.orig/drivers/net/can/Makefile	2009-11-10 01:32:31.000000000 +0100
++++ linux-2.6.31.6/drivers/net/can/Makefile	2009-12-16 17:34:40.585687608 +0100
+@@ -9,4 +9,6 @@
+ 
+ obj-$(CONFIG_CAN_SJA1000)	+= sja1000/
+ 
++obj-$(CONFIG_CAN_FLEXCAN)	+= flexcan/
++
+ ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
+Index: linux-2.6.31.6/arch/arm/plat-mxc/include/mach/mxc_flexcan.h
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.31.6/arch/arm/plat-mxc/include/mach/mxc_flexcan.h	2009-12-16 17:34:40.585687608 +0100
+@@ -0,0 +1,29 @@
++/*
++ *      Copyright (C) 2009 Jan Weitzel <armlinux at phytec.de>
++ *	Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ *      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.
++ */
++
++#ifndef __ASM_ARCH_MXC_FLEXCAN
++#define __ASM_ARCH_MXC_FLEXCAN
++
++struct flexcan_platform_data {
++#ifdef REGULATOR
++        char *core_reg;
++        char *io_reg;
++#endif
++        void (*xcvr_enable) (int id, int en);
++        void (*active) (int id);
++        void (*inactive) (int id);
++};
++
++#endif /* __ASM_ARCH_MXC_FLEXCAN  */
+Index: linux-2.6.31.6/arch/arm/mach-mx3/pcm043.c
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/mach-mx3/pcm043.c	2009-12-16 17:34:40.295686175 +0100
++++ linux-2.6.31.6/arch/arm/mach-mx3/pcm043.c	2009-12-17 12:45:43.254686159 +0100
+@@ -49,6 +49,7 @@
+ #include <mach/audmux.h>
+ #include <mach/ssi.h>
+ #include <mach/mxc_nand.h>
++#include <mach/mxc_flexcan.h>
+ 
+ #include "devices.h"
+ 
+@@ -150,6 +151,34 @@
+ 	&mxc_fec_device,
+ };
+ 
++static void flexcan_xcvr_enable(int id, int en)
++{
++	static int pwdn;
++
++	if (id < 0 || id > 1)
++		return;
++
++	if (en) {
++		if (!(pwdn++))
++			;//pmic_gpio_set_bit_val(MCU_GPIO_REG_GPIO_CONTROL_2, 1, 0);
++	} else {
++		if (!(--pwdn))
++			;//pmic_gpio_set_bit_val(MCU_GPIO_REG_GPIO_CONTROL_2, 1, 1);
++	}
++}
++
++struct flexcan_platform_data flexcan_data0 = {
++	.xcvr_enable = flexcan_xcvr_enable,
++//	.active = gpio_can_active,
++//	.inactive = gpio_can_inactive,
++};
++
++struct flexcan_platform_data flexcan_data1 = {
++	.xcvr_enable = flexcan_xcvr_enable,
++//	.active = gpio_can_active,
++//	.inactive = gpio_can_inactive,
++};
++
+ static struct pad_desc pcm043_pads[] = {
+ 	/* UART1 */
+ 	MX35_PAD_CTS1__UART1_CTS,
+@@ -218,6 +247,12 @@
+ 	MX35_PAD_STXD4__AUDMUX_AUD4_TXD,
+ 	MX35_PAD_SRXD4__AUDMUX_AUD4_RXD,
+ 	MX35_PAD_SCK4__AUDMUX_AUD4_TXC,
++  	/* CAN */
++        MX35_PAD_SD2_DATA2__CAN1_RXCAN,
++        MX35_PAD_SD2_DATA3__CAN1_TXCAN,
++        MX35_PAD_SD2_DATA1__GPIO2_3,
++  	MX35_PAD_TX5_RX0__CAN2_TXCAN,
++  	MX35_PAD_TX4_RX1__CAN2_RXCAN,
+ };
+ 
+ static int pcm043_usbh1_init(struct platform_device *pdev)
+@@ -414,6 +449,14 @@
+ 		mxc_register_device(&mxc_otg, &otg_pdata);
+ 	else
+ 		mxc_register_device(&mxc_otg_udc_device, &usb_data);
++
++ 	mxc_register_device (&flexcan_device0, &flexcan_data0);
++ 	mxc_register_device (&flexcan_device1, &flexcan_data1);
++
++        // Activate CAN-port on mapper
++        gpio_request (32 + 3, "can");
++        gpio_direction_output (32 + 3, 1);
++        gpio_set_value (32 + 3, 1);
+ }
+ 
+ static void __init pcm043_timer_init(void)
+Index: linux-2.6.31.6/arch/arm/mach-mx3/devices.c
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/mach-mx3/devices.c	2009-12-16 17:34:40.234637457 +0100
++++ linux-2.6.31.6/arch/arm/mach-mx3/devices.c	2009-12-16 17:34:40.595627212 +0100
+@@ -475,6 +475,46 @@
+ 	.num_resources = ARRAY_SIZE(mxc_fec_resources),
+ 	.resource = mxc_fec_resources,
+ };
++
++static struct resource flexcan0_resources[] = {
++	{
++		.start = MX35_CAN1_BASE_ADDR,
++		.end = MX35_CAN1_BASE_ADDR + 0x97F,
++		.flags = IORESOURCE_MEM
++	}, {
++		.start = MXC_INT_CAN1,
++		.end = MXC_INT_CAN1,
++		.flags = IORESOURCE_IRQ
++	}
++};
++
++static struct resource flexcan1_resources[] = {
++	{
++		.start = MX35_CAN2_BASE_ADDR,
++		.end = MX35_CAN2_BASE_ADDR + 0x97F,
++		.flags = IORESOURCE_MEM
++	}, {
++		.start = MXC_INT_CAN2,
++		.end = MXC_INT_CAN2,
++		.flags = IORESOURCE_IRQ
++	}
++};
++
++struct platform_device flexcan_device0 = {
++	.name = "FlexCAN",
++	.id = 0,
++	.num_resources = ARRAY_SIZE(flexcan0_resources),
++	.resource = flexcan0_resources,
++	//FIXME.dev = { .release = mxc_nop_release
++};
++
++struct platform_device flexcan_device1 = {
++	.name = "FlexCAN",
++	.id = 1,
++	.num_resources = ARRAY_SIZE(flexcan1_resources),
++	.resource = flexcan1_resources,
++};
++
+ #endif
+ 
+ static struct resource imx_ssi_resources0[] = {
+Index: linux-2.6.31.6/arch/arm/mach-mx3/devices.h
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/mach-mx3/devices.h	2009-12-16 17:34:39.985630161 +0100
++++ linux-2.6.31.6/arch/arm/mach-mx3/devices.h	2009-12-16 17:34:40.595627212 +0100
+@@ -25,3 +25,5 @@
+ extern struct platform_device imx_spi_device0;
+ extern struct platform_device imx_spi_device1;
+ extern struct platform_device imx_spi_device2;
++extern struct platform_device flexcan_device0;
++extern struct platform_device flexcan_device1;
+Index: linux-2.6.31.6/arch/arm/plat-mxc/include/mach/mx35.h
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/plat-mxc/include/mach/mx35.h	2009-12-16 17:34:40.055669053 +0100
++++ linux-2.6.31.6/arch/arm/plat-mxc/include/mach/mx35.h	2009-12-16 17:34:40.595627212 +0100
+@@ -7,6 +7,8 @@
+ #define MXC_FEC_BASE_ADDR	0x50038000
+ #define MX35_OTG_BASE_ADDR	0x53ff4000
+ #define MX35_NFC_BASE_ADDR	0xBB000000
++#define MX35_CAN1_BASE_ADDR     0x53FE4000
++#define MX35_CAN2_BASE_ADDR     0x53FE8000
+ 
+ /*
+  * Interrupt numbers
+Index: linux-2.6.31.6/arch/arm/mach-mx3/clock-imx35.c
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/mach-mx3/clock-imx35.c	2009-12-16 17:34:40.245728272 +0100
++++ linux-2.6.31.6/arch/arm/mach-mx3/clock-imx35.c	2009-12-17 12:46:53.565502506 +0100
+@@ -478,6 +478,8 @@
+ 	_REGISTER_CLOCK(NULL, "iim", iim_clk)
+ 	_REGISTER_CLOCK(NULL, "gpu2d", gpu2d_clk)
+ 	_REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk)
++ 	_REGISTER_CLOCK("FlexCAN.0", "can_clk", can1_clk)
++ 	_REGISTER_CLOCK("FlexCAN.1", "can_clk", can2_clk)
+ };
+ 
+ int __init mx35_clocks_init()
diff --git a/recipes/linux/linux-2.6.31/pcm043/linux-2.6.31.6-spi.patch b/recipes/linux/linux-2.6.31/pcm043/linux-2.6.31.6-spi.patch
new file mode 100644
index 0000000..a49f05b
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/linux-2.6.31.6-spi.patch
@@ -0,0 +1,116 @@
+Add support for SPI and MAX7301
+Signed-off-by: Sven Dyroff <s.dyroff at phytec.de>
+
+rebased to 2.6.31.6
+Signed-off-by: Andreas Adam <a.adam at phytec.de>
+---
+Index: linux-2.6.31.6/arch/arm/mach-mx3/pcm043.c
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/mach-mx3/pcm043.c	2009-12-11 13:58:49.894701069 +0100
++++ linux-2.6.31.6/arch/arm/mach-mx3/pcm043.c	2009-12-11 14:01:08.704700136 +0100
+@@ -30,6 +30,12 @@
+ #include <linux/i2c/at24.h>
+ #include <linux/fsl_devices.h>
+ #include <linux/delay.h>
++#ifdef CONFIG_SPI
++#include <linux/spi/spi.h>
++#endif
++#ifdef CONFIG_GPIO_MAX7301
++#include <linux/spi/max7301.h>
++#endif
+ 
+ #include <asm/mach-types.h>
+ #include <asm/mach/arch.h>
+@@ -42,6 +48,9 @@
+ #if defined CONFIG_I2C_IMX || defined CONFIG_I2C_IMX_MODULE
+ #include <mach/i2c.h>
+ #endif
++#ifdef CONFIG_SPI
++#include <mach/spi.h>
++#endif
+ #include <mach/iomux-mx35.h>
+ #include <mach/ipu.h>
+ #include <mach/mx3fb.h>
+@@ -243,6 +252,18 @@
+ 	/* USB host */
+ 	MX35_PAD_I2C2_CLK__USB_TOP_USBH2_PWR,
+ 	MX35_PAD_I2C2_DAT__USB_TOP_USBH2_OC,
++	/* SPI */
++	MX35_PAD_CSPI1_SS0__CSPI1_SS0,
++	MX35_PAD_CSPI1_SS1__CSPI1_SS1,
++	MX35_PAD_CSPI1_MISO__CSPI1_MISO,
++	MX35_PAD_CSPI1_MOSI__CSPI1_MOSI,
++	MX35_PAD_CSPI1_SCLK__CSPI1_SCLK,
++	MX35_PAD_CSPI1_SPI_RDY__CSPI1_RDY,
++	MX35_PAD_STXD5__CSPI2_MOSI,
++	MX35_PAD_SRXD5__CSPI2_MISO,
++	MX35_PAD_SCK5__CSPI2_SCLK,
++	MX35_PAD_STXFS5__CSPI2_RDY,
++	MX35_PAD_HCKR__CSPI2_SS0,
+ 	/* SSI */
+ 	MX35_PAD_STXFS4__AUDMUX_AUD4_TXFS,
+ 	MX35_PAD_STXD4__AUDMUX_AUD4_TXD,
+@@ -305,6 +326,33 @@
+ 	.phy_mode	= FSL_USB2_PHY_UTMI,
+ };
+ 
++#ifdef CONFIG_SPI
++static unsigned int pcm043_spi_cs [] = {MXC_SPI_CS(0), };
++
++static struct spi_imx_master pcm043_spi_1_data = {
++	.chipselect = pcm043_spi_cs,
++	.num_chipselect = ARRAY_SIZE (pcm043_spi_cs),
++};
++#endif /* CONFIG_SPI */
++
++#ifdef CONFIG_GPIO_MAX7301
++static struct max7301_platform_data max7301_info = {
++        .base = -1,
++};
++
++// bus_num must match id in imx_spi_device struct
++static struct spi_board_info spi_board_info [] __initdata = {
++        {
++                .modalias       = "max7301",
++                .platform_data  = &max7301_info,
++                .max_speed_hz   = 13000000,
++                .bus_num        = 1,
++                .chip_select    = 0,
++                .mode           = SPI_MODE_0,
++        },
++};
++#endif /* CONFIG_GPIO_MAX7301 */
++
+ static int otg_mode_host;
+ 
+ static int __init pcm043_otg_mode(char *options)
+@@ -454,7 +502,13 @@
+ 		mxc_register_device(&mxc_otg, &otg_pdata);
+ 	else
+ 		mxc_register_device(&mxc_otg_udc_device, &usb_data);
+-
++#ifdef CONFIG_SPI
++	mxc_register_device (&imx_spi_device1, &pcm043_spi_1_data);
++#endif
++#ifdef CONFIG_GPIO_MAX7301
++	spi_register_board_info (spi_board_info,
++				ARRAY_SIZE (spi_board_info));
++#endif
+  	mxc_register_device (&flexcan_device0, &flexcan_data0);
+  	mxc_register_device (&flexcan_device1, &flexcan_data1);
+ 
+Index: linux-2.6.31.6/arch/arm/plat-mxc/include/mach/mx3x.h
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/plat-mxc/include/mach/mx3x.h	2009-11-10 01:32:31.000000000 +0100
++++ linux-2.6.31.6/arch/arm/plat-mxc/include/mach/mx3x.h	2009-12-11 13:59:13.976022108 +0100
+@@ -279,8 +279,8 @@
+ 
+ /* Mandatory defines used globally */
+ 
+-/* this CPU supports up to 96 GPIOs */
+-#define ARCH_NR_GPIOS		96
++/* this CPU supports up to 96 GPIOs (don't forget the gpio expander!) */
++#define ARCH_NR_GPIOS		(96 + 28)
+ 
+ #if !defined(__ASSEMBLY__) && !defined(__MXC_BOOT_UNCOMPRESS)
+ 
diff --git a/recipes/linux/linux-2.6.31/pcm043/w1_master.patch b/recipes/linux/linux-2.6.31/pcm043/w1_master.patch
new file mode 100644
index 0000000..d16cc9c
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/w1_master.patch
@@ -0,0 +1,26 @@
+Add 1-wire
+Signed-off-by: Jan Weitzel <J.Weitzel at phytec.de>
+---
+Index: linux-2.6.31.6/arch/arm/mach-mx3/pcm043.c
+===================================================================
+--- linux-2.6.31.6.orig/arch/arm/mach-mx3/pcm043.c	2009-12-11 13:52:55.964646780 +0100
++++ linux-2.6.31.6/arch/arm/mach-mx3/pcm043.c	2009-12-11 13:55:28.858433047 +0100
+@@ -149,6 +149,7 @@
+ static struct platform_device *devices[] __initdata = {
+ 	&pcm043_flash,
+ 	&mxc_fec_device,
++	&mxc_w1_master_device,
+ };
+ 
+ static void flexcan_xcvr_enable(int id, int en)
+@@ -247,7 +248,9 @@
+ 	MX35_PAD_STXD4__AUDMUX_AUD4_TXD,
+ 	MX35_PAD_SRXD4__AUDMUX_AUD4_RXD,
+ 	MX35_PAD_SCK4__AUDMUX_AUD4_TXC,
+-  	/* CAN */
++  	/* 1-Wire*/
++	MX35_PAD_GPIO1_0__OWIRE_LINE,
++	/* CAN */
+         MX35_PAD_SD2_DATA2__CAN1_RXCAN,
+         MX35_PAD_SD2_DATA3__CAN1_TXCAN,
+         MX35_PAD_SD2_DATA1__GPIO2_3,
diff --git a/recipes/linux/linux/pcm043/defconfig b/recipes/linux/linux/pcm043/defconfig
new file mode 100644
index 0000000..72334d3
--- /dev/null
+++ b/recipes/linux/linux/pcm043/defconfig
@@ -0,0 +1,1659 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.31.6
+#
+CONFIG_ARM=y
+CONFIG_HAVE_PWM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_FIQ=y
+CONFIG_ARCH_MTD_XIP=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+# CONFIG_CLASSIC_RCU is not set
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Performance Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+# CONFIG_FREEZER is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+CONFIG_ARCH_MXC=y
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+
+#
+# Freescale MXC Implementations
+#
+# CONFIG_ARCH_MX1 is not set
+# CONFIG_ARCH_MX2 is not set
+CONFIG_ARCH_MX3=y
+CONFIG_ARCH_MX35=y
+
+#
+# MX3 platforms:
+#
+# CONFIG_MACH_MX31ADS is not set
+# CONFIG_MACH_PCM037 is not set
+# CONFIG_MACH_MX31LITE is not set
+# CONFIG_MACH_MX31_3DS is not set
+# CONFIG_MACH_MX31MOBOARD is not set
+# CONFIG_MACH_MX31LILLY is not set
+# CONFIG_MACH_QONG is not set
+CONFIG_MACH_PCM043=y
+# CONFIG_MACH_ARMADILLO5X0 is not set
+# CONFIG_MACH_MX35_3DS is not set
+# CONFIG_MXC_IRQ_PRIOR is not set
+CONFIG_MXC_PWM=y
+CONFIG_ARCH_MXC_IOMUX_V3=y
+CONFIG_ARCH_MXC_AUDMUX_V2=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_V6=y
+# CONFIG_CPU_32v6K is not set
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_OUTER_CACHE=y
+CONFIG_CACHE_L2X0=y
+# CONFIG_ARM_ERRATA_411920 is not set
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="noinitrd console=ttymxc0,115200 root=/dev/mtdblock2 rw ip=off"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_VFP=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_CAN=y
+CONFIG_CAN_RAW=y
+# CONFIG_CAN_BCM is not set
+
+#
+# CAN Device Drivers
+#
+# CONFIG_CAN_VCAN is not set
+CONFIG_CAN_DEV=y
+CONFIG_CAN_CALC_BITTIMING=y
+CONFIG_CAN_SJA1000=y
+CONFIG_CAN_SJA1000_PLATFORM=y
+# CONFIG_CAN_DEBUG_DEVICES is not set
+CONFIG_CAN_FLEXCAN=y
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_RAM=y
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_PLATRAM=y
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+CONFIG_MTD_NAND_MXC_V2=y
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+# CONFIG_BLK_DEV is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+CONFIG_EEPROM_AT24=y
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMC911X is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+CONFIG_FEC=y
+# CONFIG_FEC2 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_CDC_EEM is not set
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_SMSC95XX is not set
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+CONFIG_USB_NET_CDC_SUBSET=y
+# CONFIG_USB_ALI_M5632 is not set
+# CONFIG_USB_AN2720 is not set
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_KC2190 is not set
+CONFIG_USB_NET_ZAURUS=y
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_GPIO is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+CONFIG_TOUCHSCREEN_WM97XX=y
+# CONFIG_TOUCHSCREEN_WM9705 is not set
+CONFIG_TOUCHSCREEN_WM9712=y
+# CONFIG_TOUCHSCREEN_WM9713 is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_IMX=y
+CONFIG_SERIAL_IMX_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+# CONFIG_I2C_GPIO is not set
+CONFIG_I2C_IMX=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=y
+# CONFIG_SPI_GPIO is not set
+CONFIG_SPI_IMX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+CONFIG_W1=y
+
+#
+# 1-wire Bus Masters
+#
+# CONFIG_W1_MASTER_DS2490 is not set
+# CONFIG_W1_MASTER_DS2482 is not set
+CONFIG_W1_MASTER_MXC=y
+# CONFIG_W1_MASTER_DS1WM is not set
+# CONFIG_W1_MASTER_GPIO is not set
+
+#
+# 1-wire Slaves
+#
+CONFIG_W1_SLAVE_THERM=y
+# CONFIG_W1_SLAVE_SMEM is not set
+# CONFIG_W1_SLAVE_DS2431 is not set
+CONFIG_W1_SLAVE_DS2433=y
+# CONFIG_W1_SLAVE_DS2433_CRC is not set
+# CONFIG_W1_SLAVE_DS2760 is not set
+# CONFIG_W1_SLAVE_BQ27000 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+CONFIG_MFD_CORE=y
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_UCB1400_CORE is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+CONFIG_MFD_MC13783=y
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_TMIO is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+CONFIG_FB_MX3=y
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+# CONFIG_LOGO is not set
+CONFIG_SOUND=y
+# CONFIG_SOUND_OSS_CORE is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+# CONFIG_SND_DRIVERS is not set
+# CONFIG_SND_ARM is not set
+# CONFIG_SND_SPI is not set
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_AC97_BUS=y
+CONFIG_SND_IMX_SOC=y
+CONFIG_SND_MXC_SOC_SSI=y
+CONFIG_SND_SOC_PHYCORE_AC97=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+CONFIG_SND_SOC_WM9712=y
+# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=y
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+CONFIG_HID_DEBUG=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_MXC=y
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+CONFIG_USB_GADGET_FSL_USB2=y
+CONFIG_USB_FSL_USB2=y
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C_HSOTG is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_IO_ACCESSORS=y
+CONFIG_MMC_SDHCI_ESDHC=y
+CONFIG_MMC_SDHCI_PLTFM=y
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_ATMELMCI is not set
+# CONFIG_MMC_MXC is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+CONFIG_RTC_DRV_PCF8563=y
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_DMADEVICES=y
+
+#
+# DMA Devices
+#
+CONFIG_MX3_IPU=y
+CONFIG_MX3_IPU_IRQS=4
+CONFIG_DMA_ENGINE=y
+
+#
+# DMA Clients
+#
+# CONFIG_NET_DMA is not set
+# CONFIG_ASYNC_TX_DMA is not set
+# CONFIG_DMATEST is not set
+# CONFIG_AUXDISPLAY is not set
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=y
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_DETECT_HUNG_TASK is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_RATIONAL=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
-- 
1.7.3.4





More information about the Openembedded-devel mailing list