summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Kobler <eng1@koblersystems.de>2011-03-01 14:01:38 +0100
committerTom Rini <tom_rini@mentor.com>2011-03-01 11:26:09 -0700
commit1840fd720b423ed4245a4fdb511170ae33dfde80 (patch)
tree92ec149ed37bf1981debf236649546c96c1024e4
parentaffc152bd4df73fd3892eb09cab0a331fd282866 (diff)
downloadopenembedded-1840fd720b423ed4245a4fdb511170ae33dfde80.tar.gz
linux-2.6.31 config and patch files for pcm043
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@koblersystems.de> Signed-off-by: Tom Rini <tom_rini@mentor.com>
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0001-mxcv2-nand-driver.patch1130
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0001-spi-add-SPI-driver-for-most-known-i.MX-SoCs.patch2337
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0002-MXC-NFC-Remove-useless-structure-member.patch45
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0002-mfd-Add-Freescale-MC13783-driver.patch984
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0002-mxc_nand-cleanup-eccoob-descriptions.patch111
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0003-MXC-NFC-Add-a-real-NAND-flash-data-width-setup-func.patch51
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0003-mx3-Add-SSI-pins-to-iomux-table.patch48
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0003-mxc_nand-cleanup-initialization.patch124
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0004-MXC-NFC-Use-generic-bad-block-detection.patch148
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0004-mxc-iomux-v3-remove-resource-handling.patch111
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0004-mxc_nand-merge-send_read_page-and-send_prog_page.patch104
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0005-MXC-NFC-Divide-flash-device-detection-into-two-step.patch48
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0005-i.MX31-clock-rename-SSI-clocks-to-driver-name.patch28
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0005-mxc_nand-introduce-mxc_do_addr_cycle.patch122
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0006-MXC-NFC-Reorder-structure-setup-to-use-NAND-informa.patch129
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0006-i.MX2-Add-sound-ssi-resources.patch132
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0006-mxc-nand-remove-debug-param.patch82
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0007-MXC-NFC-Fix-OOB-layout.patch104
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0007-i.MX3-Add-sound-ssi-resources.patch101
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0007-mxc-nand-remove-dead-code.patch41
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0008-MXC-Add-a-digital-audio-multiplexer-driver.patch281
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0008-MXC-NFC-The-i.MX35-CPU-also-uses-a-V2.1-NFC.patch26
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0008-mxc-nand-use-resource_size.patch26
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0009-MX31-Fix-spi-clock-names.patch32
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0009-MXC-NFC-Fix-NFC-s-address-area-on-i.MX35.patch28
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0009-mxc-nand-use-buffers.patch473
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0010-MXC-NFC-Add-the-clock-resource-to-support-NFC-in-i.patch61
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0010-i.MX35-Fix-audmux-clock.patch52
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0010-mxc-nand-simplify-command-processing.patch143
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0011-MX31-add-spi-controller-devices-resources.patch97
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0011-MXC-NFC-Fix-NFC-s-clock-name.patch28
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0011-mxc-nand-modify-send_page-to-send-all-pages-not-on.patch87
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0012-MXC-NFC-i.MX35-can-work-with-the-v2-not-with-v1-of.patch34
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0012-i.MX27-clock-rename-spi-clocks-to-match-device.patch30
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0012-mxc_nand-remove-unused-defines.patch31
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0013-MXC-NFC-Add-the-cpu_is_mx25-macro.patch38
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0013-add-a-mc13783-codec-driver.patch834
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0013-mxc_nand-Make-main-spare-areas-runtime-configurable.patch142
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0014-MXC-NFC-Add-NAND-device-to-the-pcm043-platform.patch47
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0014-imx-ssi-sound-driver.patch1911
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0014-mxc_nand-Get-rid-of-pagesize_2k-flag.patch128
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0015-MXC-NFC-unlock_addr-is-only-used-while-__init-pha.patch28
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0015-add-phycore-ac97-sound-support.patch140
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0015-mxc_nand-Add-NFC-V2-support.patch191
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0016-add-phycore-mc13783-sound-support.patch211
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0016-mxc_nand-disable-sp_en-bit-only-once.patch66
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0017-mxc_nand-Allow-flash-based-bbt.patch79
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0017-pcm043-add-sound-support.patch161
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0018-mxc_nand-remove-TROP_US_DELAY.patch88
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0018-pcm038-Add-SPI-MC13783-support.patch146
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0019-mx27-add-support-for-phytec-pca100-phyCARD-s-board.patch293
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0019-mxc_nand-use-DRIVER_NAME-where-appropriate.patch35
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0020-MX2-Add-SPI-devices-resources.patch92
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0021-Early-printk.patch106
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0021-mxc-mx1-mx2-DMA-add-a-possibility-to-create-an-endle.patch50
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0022-ASoC-Allow-32-bit-registers-for-DAPM.patch203
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0023-pca100-add-sound-support.patch99
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0024-MX31-Clock-updates.patch40
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0024-pcm038-add-sound-support.patch72
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0025-pcm037-Add-sound-support.patch144
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0026-imx-ssi-Fix-AC97-rates.patch37
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0027-Add-EHCI-support-for-MX27-and-MX31-based-boards.patch347
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0027-imx-ssi-flush-fifos.patch29
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0028-imx-ssi-Fix-occasional-AC97-reset-failure.patch37
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0029-MX31-Add-USB-platform-devices-and-resources.patch100
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0053-Watchdog-driver-for-IMX-MXC.patch490
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0066-HACK-increase-default-tx_queue_len-to-10000.patch36
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0084-i.MX35-clock-support-Add-USB-clocks.patch30
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0088-ehci-mxc-Fix-clocks.patch33
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0090-mx3x-Fixup-USB-base-addresses.patch93
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0091-mx31-clock-remove-obsolete-FIXME-comment.patch25
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0092-mx35-clock-give-ehci-clocks-names.patch30
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0096-i.MX35-implement-get_rate-for-usb-otg-clock.patch54
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/0097-fsl-udc-driver-add-mx35-support.patch83
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/Update-PCM043-board-support.patch134
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/add-led-gpio.patch17
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/add_mmc.diff1396
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/fix_can.patch16
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/fix_clock_calc.patch27
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/fix_max7301.patch28
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/fix_mmc_for_highspeed.diff63
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/fix_oob_layout.diff67
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/fix_owire_clk.patch17
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/linux-2.6.31.6-flexcan.patch2168
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/linux-2.6.31.6-spi.patch116
-rw-r--r--recipes/linux/linux-2.6.31/pcm043/w1_master.patch26
-rw-r--r--recipes/linux/linux/pcm043/defconfig1659
87 files changed, 19911 insertions, 0 deletions
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 0000000000..fbbf023fcb
--- /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@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@pengutronix.de>
+
+rebased to 2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel@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@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 0000000000..19981d68e0
--- /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@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@pengutronix.de>
+Tested-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+Acked-by: David Brownell <david-b@pacbell.net>
+Cc: Andrea Paterniani <a.paterniani@swapp-eng.it>
+Cc: Russell King <rmk@arm.linux.org.uk>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@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@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@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 0000000000..1cad5b583f
--- /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@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@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 0000000000..c97566688c
--- /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@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@pengutronix.de>
+Signed-off-by: Samuel Ortiz <sameo@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@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@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@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@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 0000000000..f8258ac2b1
--- /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@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@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 0000000000..5a526fa865
--- /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@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@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 0000000000..c1e9ab0c1d
--- /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@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@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 0000000000..f437724622
--- /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@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@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 0000000000..2c5c37fd1c
--- /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@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@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 0000000000..5f04c346bb
--- /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@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@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 0000000000..656e680d20
--- /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@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@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 0000000000..2a6d1103b2
--- /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@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@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 0000000000..dce0282b1a
--- /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@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@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 0000000000..539408ec90
--- /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@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@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 0000000000..ba7598694d
--- /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@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@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 0000000000..9de57cf9d9
--- /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@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@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 0000000000..0829ae0e09
--- /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@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@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 0000000000..0aa5cc63dc
--- /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@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@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 0000000000..10eb2dc574
--- /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@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@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 0000000000..218b1033db
--- /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@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@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 0000000000..65c7339847
--- /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@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@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@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@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 0000000000..8d2a3c7247
--- /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@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@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 0000000000..ab3b1a30c3
--- /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@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@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 0000000000..f59d12723d
--- /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@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@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 0000000000..18096a4c35
--- /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@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@pengutronix.de>
+
+rebased to 2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel@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 0000000000..e48ff64f56
--- /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@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@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 0000000000..294acbc5f3
--- /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@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@pengutronix.de>
+
+rebased to 2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel@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 0000000000..765c783442
--- /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@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@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 0000000000..a7d5cda821
--- /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@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@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 0000000000..66e425bac5
--- /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@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@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 0000000000..a2e1d28e71
--- /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@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@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 0000000000..80979a897e
--- /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@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@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 0000000000..9a88af093b
--- /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@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@pengutronix.de>
+
+rebased to 2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel@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 0000000000..db2474ca72
--- /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@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@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 0000000000..8b4a438111
--- /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@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@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 0000000000..9fec47bf0b
--- /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@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@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 0000000000..c89b83d34b
--- /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@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@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@pengutronix.de
++ * Copyright 2009 Sascha Hauer, s.hauer@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@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@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 0000000000..96d2586b07
--- /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@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@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 0000000000..967b3ba8dd
--- /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@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@pengutronix.de>
+
+rebased to 2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel@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 0000000000..3b935c9615
--- /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@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@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@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@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@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@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@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@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 0000000000..e0c02260ca
--- /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@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@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 0000000000..6c1b6a00d4
--- /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@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@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 0000000000..2a588aa7c1
--- /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@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@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@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@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 0000000000..a600e7871c
--- /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@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@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 0000000000..629f551bfa
--- /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@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@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@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@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 0000000000..f926c8fd0c
--- /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@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@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 0000000000..1f3f9eede4
--- /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@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@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 0000000000..d4c1527ac2
--- /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@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@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 0000000000..9d8d26654b
--- /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@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@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 0000000000..447936a87a
--- /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@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@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 0000000000..fbada0b075
--- /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@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@pengutronix.de>
+Signed-off-by: Sascha Hauer <s.hauer@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@pengutronix.de>, Pengutronix
++ * Copyright (C) 2009 Sascha Hauer (kernel@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 0000000000..919ea3c7c8
--- /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@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@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 0000000000..45142f7131
--- /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@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@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 0000000000..24f2264588
--- /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@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@pengutronix.de>
+Date: Thu Jan 29 16:32:30 2009 +0100
+
+ [ARM] Add an early debug console
+
+ Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
+
+rebased to 2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel@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@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 0000000000..026d9d59bc
--- /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@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@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 0000000000..af342096e1
--- /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@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@gmail.com>
+Signed-off-by: Mark Brown <broonie@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 0000000000..623d80ab31
--- /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@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@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 0000000000..9bb85dd53b
--- /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@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@pengutronix.de>
+
+rebased to 2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel@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 0000000000..bebcb3af40
--- /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@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@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 0000000000..cba390ce85
--- /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@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@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 0000000000..53b1a60131
--- /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@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@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 0000000000..1c60690b89
--- /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@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@pengutronix.de>
+
+rebased to 2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel@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@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 0000000000..56fcd9e6f1
--- /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@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@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 0000000000..fcb26ac189
--- /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@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@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 0000000000..63eef36c25
--- /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@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@pengutronix.de>
+
+rebased to 2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel@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 0000000000..2f19c1c6b7
--- /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@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@gmail.com>
+
+rebased to 2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel@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@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 0000000000..d0b9123576
--- /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@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@pengutronix.de>
+
+rebased to 2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel@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 0000000000..da33524b96
--- /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@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@pengutronix.de>
+
+rebased to 2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel@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 0000000000..25143cb0e9
--- /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@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@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 0000000000..61fe36c6ea
--- /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@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@pengutronix.de>
+
+rebased to 2.6.31.6, but without pcm037.c changes
+Signed-off-by: Jan Weitzel <J.Weitzel@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 0000000000..40c9c632d4
--- /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@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@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 0000000000..91b27f9890
--- /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@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@pengutronix.de>
+
+rebased to 2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel@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 0000000000..0190641ce2
--- /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@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@pengutronix.de>
+
+rebased to 2.6.31.6
+Signed-off-by: Jan Weitzel <J.Weitzel@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 0000000000..3467895ba8
--- /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@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@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 0000000000..117611e920
--- /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@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@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 0000000000..cbd096b2e3
--- /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@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 0000000000..fb3a3c77f5
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/add_mmc.diff
@@ -0,0 +1,1396 @@
+From: Wolfram Sang <w.sang@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@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@freescale.com>
++ * Anton Vorontsov <avorontsov@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@freescale.com>
++ * Anton Vorontsov <avorontsov@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@freescale.com>, "
++ "Anton Vorontsov <avorontsov@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@freescale.com>
++ * Anton Vorontsov <avorontsov@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@freescale.com>
++ * Anton Vorontsov <avorontsov@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@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 0000000000..c8ca166f99
--- /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@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 0000000000..244ab06565
--- /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@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 0000000000..a6854e1feb
--- /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@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 0000000000..2f1834b038
--- /dev/null
+++ b/recipes/linux/linux-2.6.31/pcm043/fix_mmc_for_highspeed.diff
@@ -0,0 +1,63 @@
+From: Wolfram Sang <w.sang@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@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 0000000000..d8e1b1d22f
--- /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@pengutronix.de
++ * Copyright 2009 Juergen Beisert, kernel@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 0000000000..4d50ab4739
--- /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@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 0000000000..a3c37cb8e2
--- /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@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@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 0000000000..a49f05b2ec
--- /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@phytec.de>
+
+rebased to 2.6.31.6
+Signed-off-by: Andreas Adam <a.adam@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 0000000000..d16cc9c806
--- /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@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 0000000000..72334d3897
--- /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