[PATCH 80/133] [Jaunty SRU] ARM.imx51 Freescale:ENGR00070770 MX51 SIM driver

Brad Figg brad.figg at canonical.com
Thu Jul 9 16:49:10 UTC 2009


Enable MXC SIM module driver

Signed-off-by: Richard Zhu <r65037 at freescale.com>
Signed-off-by: Brad Figg <brad.figg at canonical.com>
---
 arch/arm/configs/imx51_defconfig      |    7 +-
 arch/arm/mach-mx51/clock.c            |   88 ++
 arch/arm/mach-mx51/mx51_3stack.c      |   55 ++
 arch/arm/mach-mx51/mx51_3stack_gpio.c |   39 +
 arch/arm/plat-mxc/include/mach/mxc.h  |    9 +
 debian/config/armel/config.imx51      |    1 +
 drivers/char/Kconfig                  |    6 +
 drivers/char/Makefile                 |    1 +
 drivers/char/imx_sim.c                | 1473 +++++++++++++++++++++++++++++++++
 drivers/mmc/host/mx_sdhci.c           |    6 +-
 include/linux/mxc_sim_interface.h     |  108 +++
 11 files changed, 1790 insertions(+), 3 deletions(-)
 create mode 100644 drivers/char/imx_sim.c
 create mode 100644 include/linux/mxc_sim_interface.h

diff --git a/arch/arm/configs/imx51_defconfig b/arch/arm/configs/imx51_defconfig
index aa6ec98..ce06361 100644
--- a/arch/arm/configs/imx51_defconfig
+++ b/arch/arm/configs/imx51_defconfig
@@ -741,7 +741,12 @@ CONFIG_FM_SI4702=m
 CONFIG_MXC_IIM=y
 
 #
-# Serial drivers
+# IMX SIM support
+#
+CONFIG_IMX_SIM=m
+
+#
+ Serial drivers
 #
 # CONFIG_SERIAL_8250 is not set
 
diff --git a/arch/arm/mach-mx51/clock.c b/arch/arm/mach-mx51/clock.c
index 52b8b37..9300a7e 100644
--- a/arch/arm/mach-mx51/clock.c
+++ b/arch/arm/mach-mx51/clock.c
@@ -2324,6 +2324,92 @@ static struct clk esdhc4_clk[] = {
 	 },
 };
 
+static int _clk_sim_set_parent(struct clk *clk, struct clk *parent)
+{
+	u32 reg, mux;
+
+	mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, NULL);
+	reg = __raw_readl(MXC_CCM_CSCMR2) & ~MXC_CCM_CSCMR2_SIM_CLK_SEL_MASK;
+	reg |= mux << MXC_CCM_CSCMR2_SIM_CLK_SEL_OFFSET;
+	__raw_writel(reg, MXC_CCM_CSCMR2);
+
+	return 0;
+}
+
+static void _clk_sim_recalc(struct clk *clk)
+{
+	u32 reg, pred, podf;
+
+	reg = __raw_readl(MXC_CCM_CSCDR2);
+	pred = ((reg & MXC_CCM_CSCDR2_SIM_CLK_PRED_MASK) >>
+		MXC_CCM_CSCDR2_SIM_CLK_PRED_OFFSET) + 1;
+	podf = ((reg & MXC_CCM_CSCDR2_SIM_CLK_PODF_MASK) >>
+		MXC_CCM_CSCDR2_SIM_CLK_PODF_OFFSET) + 1;
+	clk->rate = clk->parent->rate / (pred * podf);
+}
+
+static unsigned long _clk_sim_round_rate(struct clk *clk, unsigned long rate)
+{
+	u32 pre, post;
+	u32 div = clk->parent->rate / rate;
+	if (clk->parent->rate % rate)
+		div++;
+
+	__calc_pre_post_dividers(div, &pre, &post);
+
+	return clk->parent->rate / (pre * post);
+}
+
+static int _clk_sim_set_rate(struct clk *clk, unsigned long rate)
+{
+	u32 reg;
+	u32 div;
+	u32 pre, post;
+
+	div = clk->parent->rate / rate;
+
+	if ((clk->parent->rate / div) != rate)
+		return -EINVAL;
+
+	__calc_pre_post_dividers(div, &pre, &post);
+
+	/* Set SIM clock divider */
+	reg = __raw_readl(MXC_CCM_CSCDR2) &
+	    ~(MXC_CCM_CSCDR2_SIM_CLK_PRED_MASK |
+	      MXC_CCM_CSCDR2_SIM_CLK_PODF_MASK);
+	reg |= (post - 1) << MXC_CCM_CSCDR2_SIM_CLK_PODF_OFFSET;
+	reg |= (pre - 1) << MXC_CCM_CSCDR2_SIM_CLK_PRED_OFFSET;
+	__raw_writel(reg, MXC_CCM_CSCDR2);
+
+	clk->rate = rate;
+	return 0;
+
+}
+
+static struct clk sim_clk[] = {
+	{
+	 .name = "sim_clk",
+	 .parent = &pll3_sw_clk,
+	 .set_parent = _clk_sim_set_parent,
+	 .secondary = &sim_clk[1],
+	 .recalc = _clk_sim_recalc,
+	 .round_rate = _clk_sim_round_rate,
+	 .set_rate = _clk_sim_set_rate,
+	 .enable = _clk_enable,
+	 .enable_reg = MXC_CCM_CCGR4,
+	 .enable_shift = MXC_CCM_CCGR4_CG2_OFFSET,
+	 .disable = _clk_disable,
+	 },
+	{
+	 .name = "sim_ipg_clk",
+	 .parent = &ipg_clk,
+	 .enable = _clk_enable,
+	 .enable_reg = MXC_CCM_CCGR4,
+	 .enable_shift = MXC_CCM_CCGR4_CG1_OFFSET,
+	 .disable = _clk_disable,
+	 },
+};
+
 static void _clk_nfc_recalc(struct clk *clk)
 {
 	u32 reg, div;
@@ -2844,6 +2930,8 @@ static struct clk *mxc_clks[] = {
 	&esdhc4_clk[0],
 	&esdhc4_clk[1],
 	&esdhc_dep_clks,
+	&sim_clk[0],
+	&sim_clk[1],
 	&emi_slow_clk,
 	&ddr_clk,
 	&emi_enfc_clk,
diff --git a/arch/arm/mach-mx51/mx51_3stack.c b/arch/arm/mach-mx51/mx51_3stack.c
index 27dd653..9b29dbc 100644
--- a/arch/arm/mach-mx51/mx51_3stack.c
+++ b/arch/arm/mach-mx51/mx51_3stack.c
@@ -444,6 +444,60 @@ static inline void mxc_init_enet(void)
 }
 #endif
 
+#if defined(CONFIG_IMX_SIM) || defined(CONFIG_IMX_SIM_MODULE)
+/* Used to configure the SIM bus */
+static struct mxc_sim_platform_data sim_data = {
+	.clk_rate = 4000000,
+	.clock_sim = "sim_clk",
+	.power_sim = NULL,
+	.init = NULL,
+	.exit = NULL,
+	.detect = 0,
+};
+
+/*!
+ * Resource definition for the SIM
+ */
+static struct resource mxc_sim_resources[] = {
+	[0] = {
+	       .start = SIM_BASE_ADDR,
+	       .end = SIM_BASE_ADDR + SZ_4K - 1,
+	       .flags = IORESOURCE_MEM,
+	       },
+	[1] = {
+	       .start = MXC_INT_SIM_IPB,
+	       .end = MXC_INT_SIM_IPB,
+	       .flags = IORESOURCE_IRQ,
+	       },
+	[2] = {
+	       .start = MXC_INT_SIM_DAT,
+	       .end = MXC_INT_SIM_DAT,
+	       .flags = IORESOURCE_IRQ,
+	       },
+};
+
+/*! Device Definition for IMX SIM */
+static struct platform_device mxc_sim_device = {
+	.name = "mxc_sim",
+	.id = 0,
+	.dev = {
+		.release = mxc_nop_release,
+		.platform_data = &sim_data,
+		},
+	.num_resources = ARRAY_SIZE(mxc_sim_resources),
+	.resource = mxc_sim_resources,
+};
+
+static inline void mxc_init_sim(void)
+{
+	(void)platform_device_register(&mxc_sim_device);
+}
+#else
+static inline void mxc_init_sim(void)
+{
+}
+#endif
+
 #if defined(CONFIG_MMC_IMX_ESDHCI) || defined(CONFIG_MMC_IMX_ESDHCI_MODULE)
 /*!
  * Get WP pin value to detect write protection
@@ -1018,6 +1072,7 @@ static void __init mxc_board_init(void)
 	mxc_init_keypad();
 	mxc_init_nand_mtd();
 	mxc_init_mmc();
+	mxc_init_sim();
 	mxc_init_srpgconfig();
 	mx51_3stack_init_mc13892();
 
diff --git a/arch/arm/mach-mx51/mx51_3stack_gpio.c b/arch/arm/mach-mx51/mx51_3stack_gpio.c
index dde9f09..3064d1f 100644
--- a/arch/arm/mach-mx51/mx51_3stack_gpio.c
+++ b/arch/arm/mach-mx51/mx51_3stack_gpio.c
@@ -601,6 +601,33 @@ static struct mxc_iomux_pin_cfg __initdata nand_iomux_pins[] = {
 	 },
 };
 
+static struct mxc_iomux_pin_cfg __initdata sim_iomux_pins[] = {
+	{
+	 MX51_PIN_NANDF_CS4, IOMUX_CONFIG_ALT6,
+	 PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH |
+	 PAD_CTL_HYS_NONE | PAD_CTL_47K_PU |
+	 PAD_CTL_PUE_KEEPER | PAD_CTL_ODE_OPENDRAIN_NONE | PAD_CTL_PKE_ENABLE,
+	 },
+	{
+	 MX51_PIN_NANDF_CS5, IOMUX_CONFIG_ALT6,
+	 PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH |
+	 PAD_CTL_HYS_NONE | PAD_CTL_47K_PU |
+	 PAD_CTL_PUE_KEEPER | PAD_CTL_ODE_OPENDRAIN_NONE | PAD_CTL_PKE_ENABLE,
+	 },
+	{
+	 MX51_PIN_NANDF_CS6, IOMUX_CONFIG_ALT6,
+	 PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH |
+	 PAD_CTL_HYS_NONE | PAD_CTL_100K_PD |
+	 PAD_CTL_PUE_PULL | PAD_CTL_ODE_OPENDRAIN_NONE | PAD_CTL_PKE_ENABLE,
+	 },
+	{
+	 MX51_PIN_NANDF_CS7, IOMUX_CONFIG_ALT6,
+	 PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH |
+	 PAD_CTL_HYS_NONE | PAD_CTL_22K_PU |
+	 PAD_CTL_PUE_PULL | PAD_CTL_ODE_OPENDRAIN_NONE | PAD_CTL_PKE_ENABLE,
+	 },
+};
+
 static int __initdata enable_ata = { 0 };
 static int __init ata_setup(char *__unused)
 {
@@ -610,6 +637,15 @@ static int __init ata_setup(char *__unused)
 
 __setup("ata", ata_setup);
 
+static int __initdata enable_sim = { 0 };
+static int __init sim_setup(char *__unused)
+{
+	enable_sim = 1;
+	return 1;
+}
+
+__setup("sim", sim_setup);
+
 void __init mx51_3stack_io_init(void)
 {
 	int i, num;
@@ -629,6 +665,9 @@ void __init mx51_3stack_io_init(void)
 	if (enable_ata) {
 		pin_ptr = ata_iomux_pins;
 		num = ARRAY_SIZE(ata_iomux_pins);
+	} else if (enable_sim) {
+		pin_ptr = sim_iomux_pins;
+		num = ARRAY_SIZE(sim_iomux_pins);
 	} else {
 		pin_ptr = nand_iomux_pins;
 		num = ARRAY_SIZE(nand_iomux_pins);
diff --git a/arch/arm/plat-mxc/include/mach/mxc.h b/arch/arm/plat-mxc/include/mach/mxc.h
index 860bcad..8318ddd 100644
--- a/arch/arm/plat-mxc/include/mach/mxc.h
+++ b/arch/arm/plat-mxc/include/mach/mxc.h
@@ -349,6 +349,15 @@ void mxc_pg_disable(struct platform_device *pdev);
 
 struct mxc_unifi_platform_data *get_unifi_plat_data(void);
 
+struct mxc_sim_platform_data {
+	unsigned int clk_rate;
+	char *clock_sim;
+	char *power_sim;
+	int (*init)(struct platform_device *pdev);
+	void (*exit)(void);
+	unsigned int detect; /* 1 have detect pin, 0 not */
+};
+
 #endif				/* __ASSEMBLY__ */
 
 #define MUX_IO_P		29
diff --git a/debian/config/armel/config.imx51 b/debian/config/armel/config.imx51
index bf2472b..25bf06f 100644
--- a/debian/config/armel/config.imx51
+++ b/debian/config/armel/config.imx51
@@ -496,6 +496,7 @@ CONFIG_I2C_MXC_SELECT2=y
 CONFIG_IFB=m
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
+# CONFIG_IMX_SIM is not set
 CONFIG_INET6_AH=m
 CONFIG_INET6_ESP=m
 CONFIG_INET6_IPCOMP=m
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 43d6ba8..782f4a5 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -418,6 +418,12 @@ config SGI_MBCS
          If you have an SGI Altix with an attached SABrick
          say Y or M here, otherwise say N.
 
+config IMX_SIM
+	tristate "IMX SIM support"
+	depends on ARCH_MX51
+	---help---
+         Say Y to enable the SIM driver support.
+
 source "drivers/serial/Kconfig"
 
 config UNIX98_PTYS
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 438f713..e4ae86e 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -11,6 +11,7 @@ obj-y	 += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o t
 
 obj-$(CONFIG_LEGACY_PTYS)	+= pty.o
 obj-$(CONFIG_UNIX98_PTYS)	+= pty.o
+obj-$(CONFIG_IMX_SIM) 		+= imx_sim.o
 obj-y				+= misc.o
 obj-$(CONFIG_VT)		+= vt_ioctl.o vc_screen.o selection.o keyboard.o
 obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o
diff --git a/drivers/char/imx_sim.c b/drivers/char/imx_sim.c
new file mode 100644
index 0000000..22d4677
--- /dev/null
+++ b/drivers/char/imx_sim.c
@@ -0,0 +1,1473 @@
+/*
+ * Copyright 2008-2009 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 mxc_sim.c
+ *
+ * @brief Driver for Freescale IMX SIM interface
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#include <linux/clk.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/mxc_sim_interface.h>
+
+#include <asm/io.h>
+
+#define SIM_INTERNAL_CLK  0
+#define SIM_RFU          -1
+
+/* Default communication parameters: FI=372, DI=1, PI1=5V, II=50mA, WWT=10 */
+#define SIM_PARAM_DEFAULT { 0, 1, 1, 5, 1, 0, 0, 0, 10 }
+
+/* Transmit and receive buffer sizes */
+#define SIM_XMT_BUFFER_SIZE 256
+#define SIM_RCV_BUFFER_SIZE 256
+
+/* Interface character references */
+#define SIM_IFC_TXI(letter, number) (letter + number * 4)
+#define SIM_IFC_TA1   SIM_IFC_TXI(0, 0)
+#define SIM_IFC_TB1   SIM_IFC_TXI(0, 1)
+#define SIM_IFC_TC1   SIM_IFC_TXI(0, 2)
+#define SIM_IFC_TD1   SIM_IFC_TXI(0, 3)
+#define SIM_IFC_TA2   SIM_IFC_TXI(1, 0)
+#define SIM_IFC_TB2   SIM_IFC_TXI(1, 1)
+#define SIM_IFC_TC2   SIM_IFC_TXI(1, 2)
+#define SIM_IFC_TD2   SIM_IFC_TXI(1, 3)
+#define SIM_IFC_TA3   SIM_IFC_TXI(2, 0)
+#define SIM_IFC_TB3   SIM_IFC_TXI(2, 1)
+#define SIM_IFC_TC3   SIM_IFC_TXI(2, 2)
+#define SIM_IFC_TD3   SIM_IFC_TXI(2, 3)
+#define SIM_IFC_TA4   SIM_IFC_TXI(3, 0)
+#define SIM_IFC_TB4   SIM_IFC_TXI(3, 1)
+#define SIM_IFC_TC4   SIM_IFC_TXI(3, 2)
+#define SIM_IFC_TD4   SIM_IFC_TXI(3, 3)
+
+/* ATR and OPS states */
+#define SIM_STATE_REMOVED              0
+#define SIM_STATE_OPERATIONAL_IDLE     1
+#define SIM_STATE_OPERATIONAL_COMMAND  2
+#define SIM_STATE_OPERATIONAL_RESPONSE 3
+#define SIM_STATE_OPERATIONAL_STATUS1  4
+#define SIM_STATE_OPERATIONAL_STATUS2  5
+#define SIM_STATE_OPERATIONAL_PTS      6
+#define SIM_STATE_DETECTED_ATR_T0       7
+#define SIM_STATE_DETECTED_ATR_TS       8
+#define SIM_STATE_DETECTED_ATR_TXI      9
+#define SIM_STATE_DETECTED_ATR_THB      10
+#define SIM_STATE_DETECTED_ATR_TCK      11
+
+/* Definitions of the offset of the SIM hardware registers */
+#define PORT1_CNTL 	0x00	/* 00 */
+#define SETUP 		0x04	/* 04 */
+#define PORT1_DETECT 	0x08	/* 08 */
+#define PORT1_XMT_BUF 	0x0C	/* 0c */
+#define PORT1_RCV_BUF 	0x10	/* 10 */
+#define PORT0_CNTL 	0x14	/* 14 */
+#define CNTL 		0x18	/* 18 */
+#define CLK_PRESCALER 	0x1C	/* 1c */
+#define RCV_THRESHOLD 	0x20	/* 20 */
+#define ENABLE 		0x24	/* 24 */
+#define XMT_STATUS 	0x28	/* 28 */
+#define RCV_STATUS 	0x2C	/* 2c */
+#define INT_MASK 	0x30	/* 30 */
+#define PORTO_XMT_BUF 	0x34	/* 34 */
+#define PORT0_RCV_BUF 	0x38	/* 38 */
+#define PORT0_DETECT 	0x3C	/* 3c */
+#define DATA_FORMAT 	0x40	/* 40 */
+#define XMT_THRESHOLD 	0x44	/* 44 */
+#define GUARD_CNTL 	0x48	/* 48 */
+#define OD_CONFIG 	0x4C	/* 4c */
+#define RESET_CNTL 	0x50	/* 50 */
+#define CHAR_WAIT 	0x54	/* 54 */
+#define GPCNT 		0x58	/* 58 */
+#define DIVISOR 	0x5C	/* 5c */
+#define BWT 		0x60	/* 60 */
+#define BGT 		0x64	/* 64 */
+#define BWT_H 		0x68	/* 68 */
+#define XMT_FIFO_STAT 	0x6C	/* 6c */
+#define RCV_FIFO_CNT 	0x70	/* 70 */
+#define RCV_FIFO_WPTR 	0x74	/* 74 */
+#define RCV_FIFO_RPTR 	0x78	/* 78 */
+
+/* SIM port[0|1]_cntl register bits */
+#define SIM_PORT_CNTL_SFPD   (1<<7)
+#define SIM_PORT_CNTL_3VOLT  (1<<6)
+#define SIM_PORT_CNTL_SCSP   (1<<5)
+#define SIM_PORT_CNTL_SCEN   (1<<4)
+#define SIM_PORT_CNTL_SRST   (1<<3)
+#define SIM_PORT_CNTL_STEN   (1<<2)
+#define SIM_PORT_CNTL_SVEN   (1<<1)
+#define SIM_PORT_CNTL_SAPD   (1<<0)
+
+/* SIM od_config register bits */
+#define SIM_OD_CONFIG_OD_P1  (1<<1)
+#define SIM_OD_CONFIG_OD_P0  (1<<0)
+
+/* SIM enable register bits */
+#define SIM_ENABLE_XMTEN     (1<<1)
+#define SIM_ENABLE_RCVEN     (1<<0)
+
+/* SIM int_mask register bits */
+#define SIM_INT_MASK_RFEM    (1<<13)
+#define SIM_INT_MASK_BGTM    (1<<12)
+#define SIM_INT_MASK_BWTM    (1<<11)
+#define SIM_INT_MASK_RTM     (1<<10)
+#define SIM_INT_MASK_CWTM    (1<<9)
+#define SIM_INT_MASK_GPCM    (1<<8)
+#define SIM_INT_MASK_TDTFM   (1<<7)
+#define SIM_INT_MASK_TFOM    (1<<6)
+#define SIM_INT_MASK_XTM     (1<<5)
+#define SIM_INT_MASK_TFEIM   (1<<4)
+#define SIM_INT_MASK_ETCIM   (1<<3)
+#define SIM_INT_MASK_OIM     (1<<2)
+#define SIM_INT_MASK_TCIM    (1<<1)
+#define SIM_INT_MASK_RIM     (1<<0)
+
+/* SIM xmt_status register bits */
+#define SIM_XMT_STATUS_GPCNT (1<<8)
+#define SIM_XMT_STATUS_TDTF  (1<<7)
+#define SIM_XMT_STATUS_TFO   (1<<6)
+#define SIM_XMT_STATUS_TC    (1<<5)
+#define SIM_XMT_STATUS_ETC   (1<<4)
+#define SIM_XMT_STATUS_TFE   (1<<3)
+#define SIM_XMT_STATUS_XTE   (1<<0)
+
+/* SIM rcv_status register bits */
+#define SIM_RCV_STATUS_BGT   (1<<11)
+#define SIM_RCV_STATUS_BWT   (1<<10)
+#define SIM_RCV_STATUS_RTE   (1<<9)
+#define SIM_RCV_STATUS_CWT   (1<<8)
+#define SIM_RCV_STATUS_CRCOK (1<<7)
+#define SIM_RCV_STATUS_LRCOK (1<<6)
+#define SIM_RCV_STATUS_RDRF  (1<<5)
+#define SIM_RCV_STATUS_RFD   (1<<4)
+#define SIM_RCV_STATUS_RFE   (1<<1)
+#define SIM_RCV_STATUS_OEF   (1<<0)
+
+/* SIM cntl register bits */
+#define SIM_CNTL_BWTEN       (1<<15)
+#define SIM_CNTL_XMT_CRC_LRC (1<<14)
+#define SIM_CNTL_CRCEN       (1<<13)
+#define SIM_CNTL_LRCEN       (1<<12)
+#define SIM_CNTL_CWTEN       (1<<11)
+#define SIM_CNTL_SAMPLE12    (1<<4)
+#define SIM_CNTL_ONACK       (1<<3)
+#define SIM_CNTL_ANACK       (1<<2)
+#define SIM_CNTL_ICM         (1<<1)
+#define SIM_CNTL_GPCNT_CLK_SEL(x)   ((x&0x03)<<9)
+#define SIM_CNTL_GPCNT_CLK_SEL_MASK     (0x03<<9)
+#define SIM_CNTL_BAUD_SEL(x)        ((x&0x07)<<6)
+#define SIM_CNTL_BAUD_SEL_MASK          (0x07<<6)
+
+/* SIM rcv_threshold register bits */
+#define SIM_RCV_THRESHOLD_RTH(x)    ((x&0x0f)<<9)
+#define SIM_RCV_THRESHOLD_RTH_MASK      (0x0f<<9)
+#define SIM_RCV_THRESHOLD_RDT(x)   ((x&0x1ff)<<0)
+#define SIM_RCV_THRESHOLD_RDT_MASK     (0x1ff<<0)
+
+/* SIM xmt_threshold register bits */
+#define SIM_XMT_THRESHOLD_XTH(x)    ((x&0x0f)<<4)
+#define SIM_XMT_THRESHOLD_XTH_MASK      (0x0f<<4)
+#define SIM_XMT_THRESHOLD_TDT(x)    ((x&0x0f)<<0)
+#define SIM_XMT_THRESHOLD_TDT_MASK      (0x0f<<0)
+
+/* SIM guard_cntl register bits */
+#define SIM_GUARD_CNTL_RCVR11              (1<<8)
+#define SIM_GIARD_CNTL_GETU(x)           (x&0xff)
+#define SIM_GIARD_CNTL_GETU_MASK           (0xff)
+
+/* SIM port[0|]_detect register bits */
+#define SIM_PORT_DETECT_SPDS  (1<<3)
+#define SIM_PORT_DETECT_SPDP  (1<<2)
+#define SIM_PORT_DETECT_SDI   (1<<1)
+#define SIM_PORT_DETECT_SDIM  (1<<0)
+
+/* END of REGS definitions */
+
+/* ATR parser data (the parser state is stored in the main device structure) */
+typedef struct {
+	uint8_t T0;		/* ATR T0 */
+	uint8_t TS;		/* ATR TS */
+	/* ATR TA1, TB1, TC1, TD1, TB1, ... , TD4 */
+	uint8_t TXI[16];
+	uint8_t THB[15];	/* ATR historical bytes */
+	uint8_t TCK;		/* ATR checksum */
+	uint16_t ifc_valid;	/* valid interface characters */
+	uint8_t ifc_current_valid;	/* calid ifcs in the current batch */
+	uint8_t cnt;		/* number of current batch */
+	uint8_t num_hb;		/* number of historical bytes */
+} sim_atrparser_t;
+
+/* Main SIM driver structure */
+typedef struct {
+	/* card inserted = 1, ATR received = 2, card removed = 0 */
+	int present;
+	/* current ATR or OPS state */
+	int state;
+	/* current power state */
+	int power;
+	/* error code occured during transfer */
+	int errval;
+	struct clk *clk;	/* Clock id */
+	uint8_t clk_flag;
+	struct resource *res;	/* IO map memory */
+	void __iomem *ioaddr;	/* Mapped address */
+	int ipb_irq;		/* sim ipb IRQ num */
+	int dat_irq;		/* sim dat IRQ num */
+	/* parser for incoming ATR stream */
+	sim_atrparser_t atrparser;
+	/* raw ATR stream received */
+	sim_atr_t atr;
+	/* communication parameters according to ATR */
+	sim_param_t param_atr;
+	/* current communication parameters */
+	sim_param_t param;
+	/* current TPDU or PTS transfer */
+	sim_xfer_t xfer;
+	/* transfer is on the way = 1, idle = 2 */
+	int xfer_ongoing;
+	/* remaining bytes to transmit for the current transfer */
+	int xmt_remaining;
+	/* transmit position */
+	int xmt_pos;
+	/* receive position / number of bytes received */
+	int rcv_count;
+	uint8_t rcv_buffer[SIM_RCV_BUFFER_SIZE];
+	uint8_t xmt_buffer[SIM_XMT_BUFFER_SIZE];
+	/* transfer completion notifier */
+	struct completion xfer_done;
+	/* async notifier for card and ATR detection */
+	struct fasync_struct *fasync;
+	/* Platform specific data */
+	struct mxc_sim_platform_data *plat_data;
+} sim_t;
+
+static int sim_param_F[] = {
+	SIM_INTERNAL_CLK, 372, 558, 744, 1116, 1488, 1860, SIM_RFU,
+	SIM_RFU, 512, 768, 1024, 1536, 2048, SIM_RFU, SIM_RFU
+};
+
+static int sim_param_D[] = {
+	SIM_RFU, 64 * 1, 64 * 2, 64 * 4, 64 * 8, 64 * 16, SIM_RFU, SIM_RFU,
+	SIM_RFU, SIM_RFU, 64 * 1 / 2, 64 * 1 / 4, 64 * 1 / 8, 64 * 1 / 16,
+	64 * 1 / 32, 64 * 1 / 64
+};
+
+static struct miscdevice sim_dev;
+
+/* Function: sim_calc_param
+ *
+ * Description: determine register values depending on communication parameters
+ *
+ * Parameters:
+ * uint32_t fi             ATR frequency multiplier index
+ * uint32_t di             ATR frequency divider index
+ * uint32_t* ptr_divisor   location to store divisor result
+ * uint32_t* ptr_sample12  location to store sample12 result
+ *
+ * Return Values:
+ *  SIM_OK                          calculation finished without errors
+ * -SIM_E_PARAM_DIVISOR_RANGE       calculated divisor > 255
+ * -SIM_E_PARAM_FBYD_NOTDIVBY8OR12  F/D not divisable by 12 (as required)
+ * -SIM_E_PARAM_FBYD_WITHFRACTION   F/D has a remainder
+ * -SIM_E_PARAM_DI_INVALID          frequency multiplyer index not supported
+ * -SIM_E_PARAM_FI_INVALID          frequency divider index not supported
+ */
+
+static int sim_calc_param(uint32_t fi, uint32_t di, uint32_t *ptr_divisor,
+			  uint32_t *ptr_sample12)
+{
+	int32_t errval = SIM_OK;
+	int32_t f = sim_param_F[fi];
+	int32_t d = sim_param_D[di];
+	int32_t stage2_fra = (64 * f) % d;
+	int32_t stage2_div = (64 * f) / d;
+	uint32_t sample12 = 1;
+	uint32_t divisor = 31;
+
+	if ((f > 0) || (d > 0)) {
+		if (stage2_fra == 0) {
+			if ((stage2_div % 12) == 0) {
+				sample12 = 1;
+				divisor = stage2_div / 12;
+			} else if ((stage2_div % 8) == 0) {
+				sample12 = 0;
+				divisor = stage2_div / 8;
+			} else
+				sample12 = -1;
+			if (sample12 >= 0) {
+				if (divisor < 256) {
+					pr_debug("fi=%i", fi);
+					pr_debug("di=%i", di);
+					pr_debug("f=%i", f);
+					pr_debug("d=%i/64", d);
+					pr_debug("div=%i", stage2_div);
+					pr_debug("divisor=%i", divisor);
+					pr_debug("sample12=%i\n", sample12);
+
+					*ptr_divisor = divisor;
+					*ptr_sample12 = sample12;
+					errval = SIM_OK;
+				} else
+					errval = -SIM_E_PARAM_DIVISOR_RANGE;
+			} else
+				errval = -SIM_E_PARAM_FBYD_NOTDIVBY8OR12;
+		} else
+			errval = -SIM_E_PARAM_FBYD_WITHFRACTION;
+	} else
+		errval = -SIM_E_PARAM_FI_INVALID;
+
+	return errval;
+};
+
+/* Function: sim_set_param
+ *
+ * Description: apply communication parameters (setup devisor and sample12)
+ *
+ * Parameters:
+ * sim_t* sim              pointer to SIM device handler
+ * sim_param_t* param      pointer to communication parameters
+ *
+ * Return Values:
+ * see function sim_calc_param
+ */
+
+static int sim_set_param(sim_t *sim, sim_param_t *param)
+{
+	uint32_t divisor, sample12, reg_data;
+	int errval;
+
+	errval = sim_calc_param(param->FI, param->DI, &divisor, &sample12);
+	if (errval == SIM_OK) {
+		__raw_writel(divisor, sim->ioaddr + DIVISOR);
+		if (sample12) {
+			reg_data = __raw_readl(sim->ioaddr + CNTL);
+			reg_data |= SIM_CNTL_SAMPLE12;
+			__raw_writel(reg_data, sim->ioaddr + CNTL);
+		} else {
+			reg_data = __raw_readl(sim->ioaddr + CNTL);
+			reg_data &= ~SIM_CNTL_SAMPLE12;
+			__raw_writel(reg_data, sim->ioaddr + CNTL);
+		}
+	}
+
+	return errval;
+};
+
+/* Function: sim_atr_received
+ *
+ * Description: this function is called whenever a valid ATR has been received.
+ * It determines the communication parameters from the ATR received and notifies
+ * the user space application with SIGIO.
+ *
+ * Parameters:
+ * sim_t* sim              pointer to SIM device handler
+ */
+
+static void sim_atr_received(sim_t *sim)
+{
+	sim_param_t param_default = SIM_PARAM_DEFAULT;
+	sim->param_atr = param_default;
+
+	if (sim->atrparser.ifc_valid & (1 << (SIM_IFC_TA1))) {
+		sim->param_atr.FI = sim->atrparser.TXI[SIM_IFC_TA1] >> 4;
+		sim->param_atr.DI = sim->atrparser.TXI[SIM_IFC_TA1] & 0x0f;
+	}
+	if (sim->atrparser.ifc_valid & (1 << (SIM_IFC_TB1))) {
+		sim->param_atr.PI1 = (sim->atrparser.TXI[SIM_IFC_TB1] >> 4)
+		    & 0x07;
+		sim->param_atr.II = sim->atrparser.TXI[SIM_IFC_TB1] & 0x07f;
+	}
+	if (sim->atrparser.ifc_valid & (1 << (SIM_IFC_TC1)))
+		sim->param_atr.N = sim->atrparser.TXI[SIM_IFC_TC1];
+
+	if (sim->atrparser.ifc_valid & (1 << (SIM_IFC_TD1)))
+		sim->param_atr.T = sim->atrparser.TXI[SIM_IFC_TD1] & 0x0f;
+
+	if (sim->atrparser.ifc_valid & (1 << (SIM_IFC_TB2)))
+		sim->param_atr.PI2 = sim->atrparser.TXI[SIM_IFC_TB2];
+
+	if (sim->atrparser.ifc_valid & (1 << (SIM_IFC_TC2)))
+		sim->param_atr.WWT = sim->atrparser.TXI[SIM_IFC_TC2];
+
+	if (sim->fasync)
+		kill_fasync(&sim->fasync, SIGIO, POLL_IN);
+
+};
+
+/* Function: sim_xmt_fill
+ *
+ * Description: fill the transmit FIFO until the FIFO is full or
+ * the end of the transmission has been reached.
+ *
+ * Parameters:
+ * sim_t* sim              pointer to SIM device handler
+ */
+
+static void sim_xmt_fill(sim_t *sim)
+{
+	uint32_t reg_data;
+	int bytesleft;
+
+	reg_data = __raw_readl(sim->ioaddr + XMT_FIFO_STAT);
+	bytesleft = 16 - ((reg_data >> 8) & 0x0f);
+
+	pr_debug("txfill: remaining=%i bytesleft=%i\n",
+		 sim->xmt_remaining, bytesleft);
+	if (bytesleft > sim->xmt_remaining)
+		bytesleft = sim->xmt_remaining;
+
+	sim->xmt_remaining -= bytesleft;
+	for (; bytesleft > 0; bytesleft--) {
+		__raw_writel(sim->xmt_buffer[sim->xmt_pos],
+			     sim->ioaddr + PORT1_XMT_BUF);
+		sim->xmt_pos++;
+	};
+/* FIXME: optimization - keep filling until fifo full */
+};
+
+/* Function: sim_xmt_start
+ *
+ * Description: initiate a transfer
+ *
+ * Parameters:
+ * sim_t* sim              pointer to SIM device handler
+ * int pos                 position in the xfer transmit buffer
+ * int count               number of bytes to be transmitted
+ */
+
+static void sim_xmt_start(sim_t *sim, int pos, int count)
+{
+	uint32_t reg_data;
+
+	pr_debug("tx\n");
+	sim->xmt_remaining = count;
+	sim->xmt_pos = pos;
+	sim_xmt_fill(sim);
+
+	if (sim->xmt_remaining) {
+		reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+		reg_data &= ~SIM_INT_MASK_TDTFM;
+		__raw_writel(reg_data, sim->ioaddr + INT_MASK);
+	} else {
+		reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+		reg_data &= ~SIM_INT_MASK_TCIM;
+		__raw_writel(reg_data, sim->ioaddr + INT_MASK);
+		__raw_writel(SIM_XMT_STATUS_TC | SIM_XMT_STATUS_TDTF,
+			     sim->ioaddr + XMT_STATUS);
+		reg_data = __raw_readl(sim->ioaddr + ENABLE);
+		reg_data |= SIM_ENABLE_XMTEN;
+		__raw_writel(reg_data, sim->ioaddr + ENABLE);
+	}
+};
+
+/* Function: sim_atr_add
+ *
+ * Description: add a byte to the raw ATR string
+ *
+ * Parameters:
+ * sim_t* sim              pointer to SIM device handler
+ * uint8_t data            byte to be added
+ */
+
+static void sim_atr_add(sim_t *sim, uint8_t data)
+{
+	if (sim->atr.size < SIM_ATR_LENGTH_MAX)
+		sim->atr.t[sim->atr.size++] = data;
+	else
+		printk(KERN_ERR "sim.c: ATR received is too big!\n");
+};
+
+/* Function: sim_fsm
+ *
+ * Description: main finite state machine running in ISR context.
+ *
+ * Parameters:
+ * sim_t* sim              pointer to SIM device handler
+ * uint8_t data            byte received
+ */
+
+static void sim_fsm(sim_t *sim, uint16_t data)
+{
+	uint32_t temp, i = 0;
+	switch (sim->state) {
+
+		pr_debug("%s stat is %d \n", __func__, sim->state);
+		/* OPS FSM */
+
+	case SIM_STATE_OPERATIONAL_IDLE:
+		printk(KERN_INFO "data received unexpectidly (%04x)\n", data);
+		break;
+
+	case SIM_STATE_OPERATIONAL_COMMAND:
+		if (data == sim->xmt_buffer[1]) {
+			if (sim->xfer.rcv_length) {
+				sim->state = SIM_STATE_OPERATIONAL_RESPONSE;
+			} else {
+				sim->state = SIM_STATE_OPERATIONAL_STATUS1;
+				if (sim->xfer.xmt_length > 5)
+					sim_xmt_start(sim, 5,
+						      sim->xfer.xmt_length - 5);
+			};
+		} else if (((data & 0xf0) == 0x60) | ((data & 0xf0) == 0x90)) {
+			sim->xfer.sw1 = data;
+			sim->state = SIM_STATE_OPERATIONAL_STATUS2;
+		} else {
+			sim->errval = -SIM_E_NACK;
+			complete(&sim->xfer_done);
+		};
+		break;
+
+	case SIM_STATE_OPERATIONAL_RESPONSE:
+		sim->rcv_buffer[sim->rcv_count] = data;
+		sim->rcv_count++;
+		if (sim->rcv_count == sim->xfer.rcv_length)
+			sim->state = SIM_STATE_OPERATIONAL_STATUS1;
+		break;
+
+	case SIM_STATE_OPERATIONAL_STATUS1:
+		sim->xfer.sw1 = data;
+		sim->state = SIM_STATE_OPERATIONAL_STATUS2;
+		break;
+
+	case SIM_STATE_OPERATIONAL_STATUS2:
+		sim->xfer.sw2 = data;
+		sim->state = SIM_STATE_OPERATIONAL_IDLE;
+		complete(&sim->xfer_done);
+		break;
+
+	case SIM_STATE_OPERATIONAL_PTS:
+		sim->rcv_buffer[sim->rcv_count] = data;
+		sim->rcv_count++;
+		if (sim->rcv_count == sim->xfer.rcv_length)
+			sim->state = SIM_STATE_OPERATIONAL_IDLE;
+		break;
+
+		/* ATR FSM */
+
+	case SIM_STATE_DETECTED_ATR_T0:
+		sim_atr_add(sim, data);
+		pr_debug("T0 %02x\n", data);
+		sim->atrparser.T0 = data;
+		sim->state = SIM_STATE_DETECTED_ATR_TS;
+		break;
+
+	case SIM_STATE_DETECTED_ATR_TS:
+		sim_atr_add(sim, data);
+		pr_debug("TS %02x\n", data);
+		sim->atrparser.TS = data;
+		if (data & 0xf0) {
+			sim->atrparser.ifc_current_valid = (data >> 4) & 0x0f;
+			sim->atrparser.num_hb = data & 0x0f;
+			sim->atrparser.ifc_valid = 0;
+			sim->state = SIM_STATE_DETECTED_ATR_TXI;
+			sim->atrparser.cnt = 0;
+		} else {
+			goto sim_fsm_atr_thb;
+		};
+		break;
+
+	case SIM_STATE_DETECTED_ATR_TXI:
+		sim_atr_add(sim, data);
+		i = ffs(sim->atrparser.ifc_current_valid) - 1;
+		pr_debug("T%c%i %02x\n", 'A' + i, sim->atrparser.cnt + 1, data);
+		sim->atrparser.TXI[SIM_IFC_TXI(i, sim->atrparser.cnt)] = data;
+		sim->atrparser.ifc_valid |= 1 << SIM_IFC_TXI(i,
+							     sim->atrparser.
+							     cnt);
+		sim->atrparser.ifc_current_valid &= ~(1 << i);
+
+		if (sim->atrparser.ifc_current_valid == 0) {
+			if (i == 3) {
+				sim->atrparser.ifc_current_valid = (data >> 4)
+				    & 0x0f;
+				sim->atrparser.cnt++;
+
+				if (sim->atrparser.cnt >= 4) {
+					/* error */
+					printk(KERN_ERR "ERROR !\n");
+					break;
+				};
+			} else {
+sim_fsm_atr_thb:
+				if (sim->atrparser.num_hb) {
+					sim->state = SIM_STATE_DETECTED_ATR_THB;
+					sim->atrparser.cnt = 0;
+				} else {
+					goto sim_fsm_atr_tck;
+				};
+			};
+		};
+		break;
+
+	case SIM_STATE_DETECTED_ATR_THB:
+		sim_atr_add(sim, data);
+		pr_debug("THB%i %02x\n", i, data);
+		sim->atrparser.THB[sim->atrparser.cnt] = data;
+		sim->atrparser.cnt++;
+
+		if (sim->atrparser.cnt == sim->atrparser.num_hb) {
+sim_fsm_atr_tck:
+			i = sim->atrparser.ifc_valid & (1 << (SIM_IFC_TD1));
+			temp = sim->atrparser.TXI[SIM_IFC_TD1] & 0x0f;
+			if ((i && temp) == SIM_PROTOCOL_T1)
+				sim->state = SIM_STATE_DETECTED_ATR_TCK;
+			else
+				goto sim_fsm_atr_received;
+		};
+		break;
+
+	case SIM_STATE_DETECTED_ATR_TCK:
+		sim_atr_add(sim, data);
+		/* checksum not required for T=0 */
+		sim->atrparser.TCK = data;
+sim_fsm_atr_received:
+		sim->state = SIM_STATE_OPERATIONAL_IDLE;
+		sim->present = SIM_PRESENT_OPERATIONAL;
+		sim_atr_received(sim);
+		break;
+	};
+};
+
+/* Function: sim_irq_handler
+ *
+ * Description: interrupt service routine.
+ *
+ * Parameters:
+ * int irq                 interrupt number
+ * void *dev_id            pointer to SIM device handler
+ *
+ * Return values:
+ * IRQ_HANDLED             OS specific
+ */
+
+static irqreturn_t sim_irq_handler(int irq, void *dev_id)
+{
+	uint32_t reg_data, reg_data0, reg_data1;
+
+	sim_t *sim = (sim_t *) dev_id;
+
+	pr_debug("%s entering\n", __func__);
+
+	reg_data0 = __raw_readl(sim->ioaddr + XMT_STATUS);
+	reg_data1 = __raw_readl(sim->ioaddr + INT_MASK);
+	if ((reg_data0 & SIM_XMT_STATUS_TC)
+	    && (!(reg_data1 & SIM_INT_MASK_TCIM))) {
+		pr_debug("TC_IRQ\n");
+		__raw_writel(SIM_XMT_STATUS_TC, sim->ioaddr + XMT_STATUS);
+		reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+		reg_data |= SIM_INT_MASK_TCIM;
+		__raw_writel(reg_data, sim->ioaddr + INT_MASK);
+		reg_data = __raw_readl(sim->ioaddr + ENABLE);
+		reg_data &= ~SIM_ENABLE_XMTEN;
+		__raw_writel(reg_data, sim->ioaddr + ENABLE);
+	};
+
+	reg_data0 = __raw_readl(sim->ioaddr + XMT_STATUS);
+	reg_data1 = __raw_readl(sim->ioaddr + INT_MASK);
+	if ((reg_data0 & SIM_XMT_STATUS_TDTF)
+	    && (!(reg_data1 & SIM_INT_MASK_TDTFM))) {
+		pr_debug("TDTF_IRQ\n");
+		__raw_writel(SIM_XMT_STATUS_TDTF, sim->ioaddr + XMT_STATUS);
+		sim_xmt_fill(sim);
+
+		if (sim->xmt_remaining == 0) {
+			__raw_writel(SIM_XMT_STATUS_TC,
+				     sim->ioaddr + XMT_STATUS);
+			reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+			reg_data &= ~SIM_INT_MASK_TCIM;
+			reg_data |= SIM_INT_MASK_TDTFM;
+			__raw_writel(reg_data, sim->ioaddr + INT_MASK);
+		};
+	};
+
+	reg_data0 = __raw_readl(sim->ioaddr + RCV_STATUS);
+	reg_data1 = __raw_readl(sim->ioaddr + INT_MASK);
+	if ((reg_data0 & SIM_RCV_STATUS_RDRF)
+	    && (!(reg_data1 & SIM_INT_MASK_RIM))) {
+		pr_debug("%s RDRF_IRQ\n", __func__);
+		__raw_writel(SIM_RCV_STATUS_RDRF, sim->ioaddr + RCV_STATUS);
+
+		while (__raw_readl(sim->ioaddr + RCV_FIFO_CNT)) {
+			uint32_t data;
+			data = __raw_readl(sim->ioaddr + PORT1_RCV_BUF);
+			pr_debug("RX = %02x state = %i\n", data, sim->state);
+			if (data & 0x700) {
+				if (sim->xfer_ongoing) {
+					/* error */
+					printk(KERN_ERR "ERROR !\n");
+					return IRQ_HANDLED;
+				};
+			} else
+				sim_fsm(sim, data);
+		};
+	};
+
+	reg_data0 = __raw_readl(sim->ioaddr + PORT0_DETECT);
+	if (reg_data0 & SIM_PORT_DETECT_SDI) {
+		pr_debug("%s PD_IRQ\n", __func__);
+		reg_data = __raw_readl(sim->ioaddr + PORT0_DETECT);
+		reg_data |= SIM_PORT_DETECT_SDI;
+		__raw_writel(reg_data, sim->ioaddr + PORT0_DETECT);
+
+		reg_data0 = __raw_readl(sim->ioaddr + PORT0_DETECT);
+		if (reg_data0 & SIM_PORT_DETECT_SPDP) {
+			reg_data = __raw_readl(sim->ioaddr + PORT0_DETECT);
+			reg_data &= ~SIM_PORT_DETECT_SPDS;
+			__raw_writel(reg_data, sim->ioaddr + PORT0_DETECT);
+
+			if (sim->present != SIM_PRESENT_REMOVED) {
+				pr_debug("Removed sim card\n");
+				sim->present = SIM_PRESENT_REMOVED;
+				sim->state = SIM_STATE_REMOVED;
+
+				if (sim->fasync)
+					kill_fasync(&sim->fasync,
+						    SIGIO, POLL_IN);
+			};
+		} else {
+			reg_data = __raw_readl(sim->ioaddr + PORT0_DETECT);
+			reg_data |= SIM_PORT_DETECT_SPDS;
+			__raw_writel(reg_data, sim->ioaddr + PORT0_DETECT);
+
+			if (sim->present == SIM_PRESENT_REMOVED) {
+				pr_debug("Inserted sim card\n");
+				sim->state = SIM_STATE_DETECTED_ATR_T0;
+				sim->present = SIM_PRESENT_DETECTED;
+
+				if (sim->fasync)
+					kill_fasync(&sim->fasync,
+						    SIGIO, POLL_IN);
+			};
+		};
+	};
+
+	return IRQ_HANDLED;
+};
+
+/* Function: sim_power_on
+ *
+ * Description: run the power on sequence
+ *
+ * Parameters:
+ * sim_t* sim              pointer to SIM device handler
+ */
+
+static void sim_power_on(sim_t *sim)
+{
+	uint32_t reg_data;
+
+	/* power on sequence */
+	reg_data = __raw_readl(sim->ioaddr + PORT0_CNTL);
+	reg_data |= SIM_PORT_CNTL_SVEN;
+	__raw_writel(reg_data, sim->ioaddr + PORT0_CNTL);
+	msleep(10);
+	reg_data = __raw_readl(sim->ioaddr + PORT0_CNTL);
+	reg_data |= SIM_PORT_CNTL_SCEN;
+	__raw_writel(reg_data, sim->ioaddr + PORT0_CNTL);
+	msleep(10);
+	reg_data = SIM_RCV_THRESHOLD_RTH(0) | SIM_RCV_THRESHOLD_RDT(1);
+	__raw_writel(reg_data, sim->ioaddr + RCV_THRESHOLD);
+	__raw_writel(SIM_RCV_STATUS_RDRF, sim->ioaddr + RCV_STATUS);
+	reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+	reg_data &= ~SIM_INT_MASK_RIM;
+	__raw_writel(reg_data, sim->ioaddr + INT_MASK);
+	__raw_writel(31, sim->ioaddr + DIVISOR);
+	reg_data = __raw_readl(sim->ioaddr + CNTL);
+	reg_data |= SIM_CNTL_SAMPLE12;
+	__raw_writel(reg_data, sim->ioaddr + CNTL);
+	reg_data = __raw_readl(sim->ioaddr + ENABLE);
+	reg_data |= SIM_ENABLE_RCVEN;
+	__raw_writel(reg_data, sim->ioaddr + ENABLE);
+	reg_data = __raw_readl(sim->ioaddr + PORT0_CNTL);
+	reg_data |= SIM_PORT_CNTL_SRST;
+	__raw_writel(reg_data, sim->ioaddr + PORT0_CNTL);
+	sim->power = SIM_POWER_ON;
+};
+
+/* Function: sim_power_off
+ *
+ * Description: run the power off sequence
+ *
+ * Parameters:
+ * sim_t* sim              pointer to SIM device handler
+ */
+
+static void sim_power_off(sim_t *sim)
+{
+	uint32_t reg_data;
+
+	/* sim_power_off sequence */
+	reg_data = __raw_readl(sim->ioaddr + PORT0_CNTL);
+	reg_data &= ~SIM_PORT_CNTL_SCEN;
+	__raw_writel(reg_data, sim->ioaddr + PORT0_CNTL);
+	reg_data = __raw_readl(sim->ioaddr + ENABLE);
+	reg_data &= ~SIM_ENABLE_RCVEN;
+	__raw_writel(reg_data, sim->ioaddr + ENABLE);
+	reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+	reg_data |= SIM_INT_MASK_RIM;
+	__raw_writel(reg_data, sim->ioaddr + INT_MASK);
+	__raw_writel(0, sim->ioaddr + RCV_THRESHOLD);
+	reg_data = __raw_readl(sim->ioaddr + PORT0_CNTL);
+	reg_data &= ~SIM_PORT_CNTL_SRST;
+	__raw_writel(reg_data, sim->ioaddr + PORT0_CNTL);
+	reg_data = __raw_readl(sim->ioaddr + PORT0_CNTL);
+	reg_data &= ~SIM_PORT_CNTL_SVEN;
+	__raw_writel(reg_data, sim->ioaddr + PORT0_CNTL);
+	sim->power = SIM_POWER_OFF;
+};
+
+/* Function: sim_start
+ *
+ * Description: ramp up the SIM interface
+ *
+ * Parameters:
+ * sim_t* sim              pointer to SIM device handler
+ */
+
+static void sim_start(sim_t *sim)
+{
+	uint32_t reg_data, clk_rate, clk_div = 0;
+
+	/* Configuring SIM for Operation */
+	reg_data = SIM_XMT_THRESHOLD_XTH(0) | SIM_XMT_THRESHOLD_TDT(4);
+	__raw_writel(reg_data, sim->ioaddr + XMT_THRESHOLD);
+	__raw_writel(0, sim->ioaddr + SETUP);
+	/* ~ 4 MHz */
+	clk_rate = clk_get_rate(sim->clk);
+	clk_div = clk_rate / sim->plat_data->clk_rate;
+	if (clk_rate % sim->plat_data->clk_rate)
+		clk_div++;
+	__raw_writel(clk_div, sim->ioaddr + CLK_PRESCALER);
+
+	reg_data = SIM_CNTL_GPCNT_CLK_SEL(0) | SIM_CNTL_BAUD_SEL(7)
+	    | SIM_CNTL_SAMPLE12 | SIM_CNTL_ANACK | SIM_CNTL_ICM;
+	__raw_writel(reg_data, sim->ioaddr + CNTL);
+	__raw_writel(31, sim->ioaddr + DIVISOR);
+	reg_data = __raw_readl(sim->ioaddr + OD_CONFIG);
+	reg_data |= SIM_OD_CONFIG_OD_P0;
+	__raw_writel(reg_data, sim->ioaddr + OD_CONFIG);
+	reg_data = __raw_readl(sim->ioaddr + PORT0_CNTL);
+	reg_data |= SIM_PORT_CNTL_3VOLT | SIM_PORT_CNTL_STEN;
+	__raw_writel(reg_data, sim->ioaddr + PORT0_CNTL);
+
+	/* presense detect */
+	pr_debug("%s p0_det is 0x%x \n", __func__,
+		 __raw_readl(sim->ioaddr + PORT0_DETECT));
+	if (__raw_readl(sim->ioaddr + PORT0_DETECT) & SIM_PORT_DETECT_SPDP) {
+		pr_debug("%s card removed \n", __func__);
+		reg_data = __raw_readl(sim->ioaddr + PORT0_DETECT);
+		reg_data &= ~SIM_PORT_DETECT_SPDS;
+		__raw_writel(reg_data, sim->ioaddr + PORT0_DETECT);
+		sim->present = SIM_PRESENT_REMOVED;
+		sim->state = SIM_STATE_REMOVED;
+	} else {
+		pr_debug("%s card inserted \n", __func__);
+		reg_data = __raw_readl(sim->ioaddr + PORT0_DETECT);
+		reg_data |= SIM_PORT_DETECT_SPDS;
+		__raw_writel(reg_data, sim->ioaddr + PORT0_DETECT);
+		sim->present = SIM_PRESENT_DETECTED;
+		sim->state = SIM_STATE_DETECTED_ATR_T0;
+	};
+	reg_data = __raw_readl(sim->ioaddr + PORT0_DETECT);
+	reg_data |= SIM_PORT_DETECT_SDI;
+	reg_data &= ~SIM_PORT_DETECT_SDIM;
+	__raw_writel(reg_data, sim->ioaddr + PORT0_DETECT);
+
+	/*
+	 * Since there is no PD0 layout on MX51, assume
+	 * that there is a SIM card in slot defaulty.
+	 * */
+	if (0 == (sim->plat_data->detect)) {
+		reg_data = __raw_readl(sim->ioaddr + PORT0_DETECT);
+		reg_data |= SIM_PORT_DETECT_SPDS;
+		__raw_writel(reg_data, sim->ioaddr + PORT0_DETECT);
+		sim->present = SIM_PRESENT_DETECTED;
+		sim->state = SIM_STATE_DETECTED_ATR_T0;
+	}
+
+	if (sim->present == SIM_PRESENT_DETECTED)
+		sim_power_on(sim);
+
+};
+
+/* Function: sim_stop
+ *
+ * Description: shut down the SIM interface
+ *
+ * Parameters:
+ * sim_t* sim              pointer to SIM device handler
+ */
+
+static void sim_stop(sim_t *sim)
+{
+	__raw_writel(0, sim->ioaddr + SETUP);
+	__raw_writel(0, sim->ioaddr + ENABLE);
+	__raw_writel(0, sim->ioaddr + PORT0_CNTL);
+	__raw_writel(0x06, sim->ioaddr + CNTL);
+	__raw_writel(0, sim->ioaddr + CLK_PRESCALER);
+	__raw_writel(0, sim->ioaddr + SETUP);
+	__raw_writel(0, sim->ioaddr + OD_CONFIG);
+	__raw_writel(0, sim->ioaddr + XMT_THRESHOLD);
+	__raw_writel(0xb8, sim->ioaddr + XMT_STATUS);
+	__raw_writel(4, sim->ioaddr + RESET_CNTL);
+	mdelay(1);
+};
+
+/* Function: sim_data_reset
+ *
+ * Description: reset a SIM structure to default values
+ *
+ * Parameters:
+ * sim_t* sim              pointer to SIM device handler
+ */
+
+static void sim_data_reset(sim_t *sim)
+{
+	sim_param_t param_default = SIM_PARAM_DEFAULT;
+	sim->present = SIM_PRESENT_REMOVED;
+	sim->state = SIM_STATE_REMOVED;
+	sim->power = SIM_POWER_OFF;
+	sim->errval = SIM_OK;
+	memset(&sim->atrparser, 0, sizeof(sim->atrparser));
+	memset(&sim->atr, 0, sizeof(sim->atr));
+	sim->param_atr = param_default;
+	memset(&sim->param, 0, sizeof(sim->param));
+	memset(&sim->xfer, 0, sizeof(sim->xfer));
+	sim->xfer_ongoing = 0;
+	sim->xmt_remaining = 0;
+	sim->xmt_pos = 0;
+	sim->rcv_count = 0;
+	memset(sim->rcv_buffer, 0, SIM_RCV_BUFFER_SIZE);
+	memset(sim->xmt_buffer, 0, SIM_XMT_BUFFER_SIZE);
+};
+
+/* Function: sim_cold_reset
+ *
+ * Description: cold reset the SIM interface, including card
+ * power down and interface hardware reset.
+ *
+ * Parameters:
+ * sim_t* sim              pointer to SIM device handler
+ */
+
+static void sim_cold_reset(sim_t *sim)
+{
+	if (sim->present != SIM_PRESENT_REMOVED) {
+		sim_power_off(sim);
+		sim_stop(sim);
+		sim_data_reset(sim);
+		sim->state = SIM_STATE_DETECTED_ATR_T0;
+		sim->present = SIM_PRESENT_DETECTED;
+		msleep(50);
+		sim_start(sim);
+		sim_power_on(sim);
+	};
+};
+
+/* Function: sim_warm_reset
+ *
+ * Description: warm reset the SIM interface: just invoke the
+ * reset signal and reset the SIM structure for the interface.
+ *
+ * Parameters:
+ * sim_t* sim              pointer to SIM device handler
+ */
+
+static void sim_warm_reset(sim_t *sim)
+{
+	uint32_t reg_data;
+
+	if (sim->present != SIM_PRESENT_REMOVED) {
+		reg_data = __raw_readl(sim->ioaddr + PORT0_CNTL);
+		reg_data |= SIM_PORT_CNTL_SRST;
+		__raw_writel(reg_data, sim->ioaddr + PORT0_CNTL);
+		sim_data_reset(sim);
+		msleep(50);
+		reg_data = __raw_readl(sim->ioaddr + PORT0_CNTL);
+		reg_data &= ~SIM_PORT_CNTL_SRST;
+		__raw_writel(reg_data, sim->ioaddr + PORT0_CNTL);
+	};
+};
+
+/* Function: sim_card_lock
+ *
+ * Description: physically lock the SIM card.
+ *
+ * Parameters:
+ * sim_t* sim              pointer to SIM device handler
+ */
+
+static int sim_card_lock(sim_t *sim)
+{
+	int errval;
+
+	/* place holder for true physcial locking */
+	if (sim->present != SIM_PRESENT_REMOVED)
+		errval = SIM_OK;
+	else
+		errval = -SIM_E_NOCARD;
+	return errval;
+};
+
+/* Function: sim_card_eject
+ *
+ * Description: physically unlock and eject the SIM card.
+ *
+ * Parameters:
+ * sim_t* sim              pointer to SIM device handler
+ */
+
+static int sim_card_eject(sim_t *sim)
+{
+	int errval;
+
+	/* place holder for true physcial locking */
+	if (sim->present != SIM_PRESENT_REMOVED)
+		errval = SIM_OK;
+	else
+		errval = -SIM_E_NOCARD;
+	return errval;
+};
+
+/* Function: sim_ioctl
+ *
+ * Description: handle ioctl calls
+ *
+ * Parameters: OS specific
+ */
+
+static int sim_ioctl(struct inode *inode, struct file *file,
+		     unsigned int cmd, unsigned long arg)
+{
+	int ret, errval = SIM_OK;
+	unsigned long timeout;
+
+	sim_t *sim = (sim_t *) file->private_data;
+
+	switch (cmd) {
+		pr_debug("ioctl cmd %d is issued...\n", cmd);
+
+	case SIM_IOCTL_GET_ATR:
+		if (sim->present != SIM_PRESENT_OPERATIONAL) {
+			errval = -SIM_E_NOCARD;
+			break;
+		};
+		ret = copy_to_user((sim_atr_t *) arg, &sim->atr,
+				   sizeof(sim_atr_t));
+		if (ret)
+			errval = -SIM_E_ACCESS;
+		break;
+
+	case SIM_IOCTL_GET_PARAM_ATR:
+		if (sim->present != SIM_PRESENT_OPERATIONAL) {
+			errval = -SIM_E_NOCARD;
+			break;
+		};
+		ret = copy_to_user((sim_param_t *) arg, &sim->param_atr,
+				   sizeof(sim_param_t));
+		if (ret)
+			errval = -SIM_E_ACCESS;
+		break;
+
+	case SIM_IOCTL_GET_PARAM:
+		ret = copy_to_user((sim_param_t *) arg, &sim->param,
+				   sizeof(sim_param_t));
+		if (ret)
+			errval = -SIM_E_ACCESS;
+		break;
+
+	case SIM_IOCTL_SET_PARAM:
+		ret = copy_from_user(&sim->param, (sim_param_t *) arg,
+				     sizeof(sim_param_t));
+		if (ret)
+			errval = -SIM_E_ACCESS;
+		else
+			errval = sim_set_param(sim, &sim->param);
+		break;
+
+	case SIM_IOCTL_POWER_ON:
+		if (sim->power == SIM_POWER_ON) {
+			errval = -SIM_E_POWERED_ON;
+			break;
+		};
+		sim_power_on(sim);
+		break;
+
+	case SIM_IOCTL_POWER_OFF:
+		if (sim->power == SIM_POWER_OFF) {
+			errval = -SIM_E_POWERED_OFF;
+			break;
+		};
+		sim_power_off(sim);
+		break;
+
+	case SIM_IOCTL_COLD_RESET:
+		if (sim->power == SIM_POWER_OFF) {
+			errval = -SIM_E_POWERED_OFF;
+			break;
+		};
+		sim_cold_reset(sim);
+		break;
+
+	case SIM_IOCTL_WARM_RESET:
+		sim_warm_reset(sim);
+		if (sim->power == SIM_POWER_OFF) {
+			errval = -SIM_E_POWERED_OFF;
+			break;
+		};
+		break;
+
+	case SIM_IOCTL_XFER:
+		if (sim->present != SIM_PRESENT_OPERATIONAL) {
+			errval = -SIM_E_NOCARD;
+			break;
+		};
+
+		ret = copy_from_user(&sim->xfer, (sim_xfer_t *) arg,
+				     sizeof(sim_xfer_t));
+		if (ret) {
+			errval = -SIM_E_ACCESS;
+			break;
+		};
+
+		ret = copy_from_user(sim->xmt_buffer, sim->xfer.xmt_buffer,
+				     sim->xfer.xmt_length);
+		if (ret) {
+			errval = -SIM_E_ACCESS;
+			break;
+		};
+
+		sim->rcv_count = 0;
+		sim->xfer.sw1 = 0;
+		sim->xfer.sw2 = 0;
+
+		if (sim->xfer.type == SIM_XFER_TYPE_TPDU) {
+			if (sim->xfer.xmt_length < 5) {
+				errval = -SIM_E_TPDUSHORT;
+				break;
+			}
+			sim->state = SIM_STATE_OPERATIONAL_COMMAND;
+		} else if (sim->xfer.type == SIM_XFER_TYPE_PTS) {
+			if (sim->xfer.xmt_length == 0) {
+				errval = -SIM_E_PTSEMPTY;
+				break;
+			}
+			sim->state = SIM_STATE_OPERATIONAL_PTS;
+		} else {
+			errval = -SIM_E_INVALIDXFERTYPE;
+			break;
+		};
+
+		if (sim->xfer.xmt_length > SIM_XMT_BUFFER_SIZE) {
+			errval = -SIM_E_INVALIDXMTLENGTH;
+			break;
+		};
+
+		if (sim->xfer.rcv_length > SIM_XMT_BUFFER_SIZE) {
+			errval = -SIM_E_INVALIDRCVLENGTH;
+			break;
+		};
+
+		sim->errval = 0;
+		sim->xfer_ongoing = 1;
+		init_completion(&sim->xfer_done);
+		sim_xmt_start(sim, 0, 5);
+		timeout =
+		    wait_for_completion_interruptible_timeout(&sim->xfer_done,
+							      sim->xfer.
+							      timeout);
+		sim->xfer_ongoing = 0;
+
+		if (sim->errval) {
+			errval = sim->errval;
+			break;
+		};
+
+		if (timeout == 0) {
+			errval = -SIM_E_TIMEOUT;
+			break;
+		}
+
+		ret = copy_to_user(sim->xfer.rcv_buffer, sim->rcv_buffer,
+				   sim->xfer.rcv_length);
+		if (ret) {
+			errval = -SIM_E_ACCESS;
+			break;
+		};
+
+		ret = copy_to_user((sim_xfer_t *) arg, &sim->xfer,
+				   sizeof(sim_xfer_t));
+		if (ret)
+			errval = -SIM_E_ACCESS;
+		break;
+
+	case SIM_IOCTL_GET_PRESENSE:
+		if (put_user(sim->present, (int *)arg))
+			errval = -SIM_E_ACCESS;
+		break;
+
+	case SIM_IOCTL_CARD_LOCK:
+		errval = sim_card_lock(sim);
+		break;
+
+	case SIM_IOCTL_CARD_EJECT:
+		errval = sim_card_eject(sim);
+		break;
+
+	};
+
+	return errval;
+};
+
+/* Function: sim_fasync
+ *
+ * Description: async handler
+ *
+ * Parameters: OS specific
+ */
+
+static int sim_fasync(int fd, struct file *file, int mode)
+{
+	sim_t *sim = (sim_t *) file->private_data;
+	return fasync_helper(fd, file, mode, &sim->fasync);
+}
+
+/* Function: sim_open
+ *
+ * Description: ramp up interface when being opened
+ *
+ * Parameters: OS specific
+ */
+
+static int sim_open(struct inode *inode, struct file *file)
+{
+	int errval = SIM_OK;
+
+	sim_t *sim = dev_get_drvdata(sim_dev.parent);
+	file->private_data = sim;
+
+	if (!sim->ioaddr) {
+		errval = -ENOMEM;
+		return errval;
+	}
+
+	if (!(sim->clk_flag)) {
+		pr_debug("\n%s enable the clock\n", __func__);
+		clk_enable(sim->clk);
+		sim->clk_flag = 1;
+	}
+
+	sim_start(sim);
+
+	return errval;
+};
+
+/* Function: sim_release
+ *
+ * Description: shut down interface when being closed
+ *
+ * Parameters: OS specific
+ */
+
+static int sim_release(struct inode *inode, struct file *file)
+{
+	uint32_t reg_data;
+
+	sim_t *sim = (sim_t *) file->private_data;
+
+	if (sim->clk_flag) {
+		pr_debug("\n%s disable the clock\n", __func__);
+		clk_disable(sim->clk);
+		sim->clk_flag = 0;
+	}
+
+	/* disable presense detection */
+	reg_data = __raw_readl(sim->ioaddr + PORT0_DETECT);
+	__raw_writel(reg_data | SIM_PORT_DETECT_SDIM,
+		     sim->ioaddr + PORT0_DETECT);
+
+	if (sim->present != SIM_PRESENT_REMOVED) {
+		sim_power_off(sim);
+		if (sim->fasync)
+			kill_fasync(&sim->fasync, SIGIO, POLL_IN);
+	};
+
+	sim_stop(sim);
+
+	sim_fasync(-1, file, 0);
+
+	pr_debug("exit\n");
+	return 0;
+};
+
+static const struct file_operations sim_fops = {
+	.open = sim_open,
+	.ioctl = sim_ioctl,
+	.fasync = sim_fasync,
+	.release = sim_release
+};
+
+static struct miscdevice sim_dev = {
+	MISC_DYNAMIC_MINOR,
+	"mxc_sim",
+	&sim_fops
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Driver init/exit                                                          *
+ *                                                                           *
+\*****************************************************************************/
+
+static int sim_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct mxc_sim_platform_data *sim_plat = pdev->dev.platform_data;
+
+	sim_t *sim = kzalloc(sizeof(sim_t), GFP_KERNEL);
+
+	if (sim == 0) {
+		ret = -ENOMEM;
+		printk(KERN_ERR "Can't get the MEMORY\n");
+		return ret;
+	};
+
+	BUG_ON(pdev == NULL);
+
+	sim->plat_data = sim_plat;
+	sim->clk_flag = 0;
+
+	sim->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!sim->res) {
+		ret = -ENOMEM;
+		printk(KERN_ERR "Can't get the MEMORY\n");
+		goto out;
+	}
+
+	/* request the sim clk and sim_serial_clk */
+	sim->clk = clk_get(NULL, sim->plat_data->clock_sim);
+	if (IS_ERR(sim->clk)) {
+		ret = PTR_ERR(sim->clk);
+		printk(KERN_ERR "Get CLK ERROR !\n");
+		goto out;
+	}
+	pr_debug("sim clock:%lu\n", clk_get_rate(sim->clk));
+
+	sim->ipb_irq = platform_get_irq(pdev, 0);
+	if (!sim->ipb_irq) {
+		ret = -ENOMEM;
+		goto out1;
+	}
+
+	sim->dat_irq = platform_get_irq(pdev, 1);
+	if (!sim->dat_irq) {
+		ret = -ENOMEM;
+		goto out1;
+	}
+
+	if (!request_mem_region(sim->res->start,
+				sim->res->end -
+				sim->res->start + 1, pdev->name)) {
+		printk(KERN_ERR "request_mem_region failed\n");
+		ret = -ENOMEM;
+		goto out1;
+	}
+
+	sim->ioaddr = (void *)ioremap(sim->res->start, sim->res->end -
+				       sim->res->start + 1);
+
+	ret = request_irq(sim->ipb_irq, sim_irq_handler,
+			  0, "mxc_sim_ipb", sim);
+	ret |= request_irq(sim->dat_irq, sim_irq_handler,
+			   0, "mxc_sim_dat", sim);
+
+	if (ret) {
+		printk(KERN_ERR "Can't get the irq\n");
+		goto out2;
+	};
+
+	platform_set_drvdata(pdev, sim);
+	sim_dev.parent = &(pdev->dev);
+
+	misc_register(&sim_dev);
+
+	return ret;
+out2:
+	free_irq(sim->ipb_irq, sim);
+	free_irq(sim->dat_irq, sim);
+	release_mem_region(sim->res->start,
+			   sim->res->end - sim->res->start + 1);
+out1:
+	clk_put(sim->clk);
+out:
+	kfree(sim);
+	return ret;
+}
+
+static int sim_remove(struct platform_device *pdev)
+{
+	sim_t *sim = platform_get_drvdata(pdev);
+
+	clk_put(sim->clk);
+
+	free_irq(sim->ipb_irq, sim);
+	free_irq(sim->dat_irq, sim);
+
+	iounmap(sim->ioaddr);
+
+	kfree(sim);
+	release_mem_region(sim->res->start,
+			   sim->res->end - sim->res->start + 1);
+
+	misc_deregister(&sim_dev);
+	return 0;
+}
+
+static struct platform_driver sim_driver = {
+	.driver = {
+		   .name = "mxc_sim",
+		   },
+	.probe = sim_probe,
+	.remove = sim_remove,
+	.suspend = NULL,
+	.resume = NULL,
+};
+
+static int __init sim_drv_init(void)
+{
+	return platform_driver_register(&sim_driver);
+}
+
+static void __exit sim_drv_exit(void)
+{
+	platform_driver_unregister(&sim_driver);
+}
+
+module_init(sim_drv_init);
+module_exit(sim_drv_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXC SIM Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/mx_sdhci.c b/drivers/mmc/host/mx_sdhci.c
index 986338f..e156ae9 100644
--- a/drivers/mmc/host/mx_sdhci.c
+++ b/drivers/mmc/host/mx_sdhci.c
@@ -901,7 +901,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 			}
 		}
 	}
-	spin_unlock_irqrestore(&host->lock, flags);
 	host->mrq = mrq;
 	if (!(host->flags & SDHCI_CD_PRESENT)) {
 		host->mrq->cmd->error = -ENOMEDIUM;
@@ -909,6 +908,8 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 	} else
 		sdhci_send_command(host, mrq->cmd);
 
+	spin_unlock_irqrestore(&host->lock, flags);
+
 	mmiowb();
 }
 
@@ -1491,7 +1492,8 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 			     SDHCI_TRNS_READ))
 				intmask &= ~SDHCI_INT_DATA_END_BIT;
 		}
-		sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
+		if (intmask & SDHCI_INT_DATA_MASK)
+			sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
 	}
 
 	intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
diff --git a/include/linux/mxc_sim_interface.h b/include/linux/mxc_sim_interface.h
new file mode 100644
index 0000000..ee6e50c
--- /dev/null
+++ b/include/linux/mxc_sim_interface.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2008-2009 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 mxc_sim_interface.h
+ *
+ * @brief Driver for Freescale IMX SIM interface
+ *
+ */
+
+#ifndef MXC_SIM_INTERFACE_H
+#define MXC_SIM_INTERFACE_H
+
+#define SIM_ATR_LENGTH_MAX 32
+
+/* Raw ATR SIM_IOCTL_GET_ATR */
+typedef struct {
+	uint32_t size;		/* length of ATR received */
+	uint8_t t[SIM_ATR_LENGTH_MAX];	/* raw ATR string received */
+} sim_atr_t;
+
+/* Communication parameters for SIM_IOCTL_[GET|SET]_PARAM */
+typedef struct {
+	uint8_t convention;	/* direct = 0, indirect = 1 */
+	uint8_t FI, DI;		/* frequency multiplier and devider indices */
+	uint8_t PI1, II;	/* programming voltage and current indices */
+	uint8_t N;		/* extra guard time */
+	uint8_t T;		/* protocol type: T0 = 0, T1 = 1 */
+	uint8_t PI2;		/* programming voltage 2 value */
+	uint8_t WWT;		/* working wait time */
+} sim_param_t;
+
+/* ISO7816-3 protocols */
+#define SIM_PROTOCOL_T0  0
+#define SIM_PROTOCOL_T1  1
+
+/* Transfer data for SIM_IOCTL_XFER */
+typedef struct {
+	uint8_t *xmt_buffer;	/* transmit buffer pointer */
+	int32_t xmt_length;	/* transmit buffer length */
+	uint8_t *rcv_buffer;	/* receive buffer pointer */
+	int32_t rcv_length;	/* receive buffer length */
+	int type;		/* transfer type: TPDU = 0, PTS = 1 */
+	int timeout;		/* transfer timeout in milliseconds */
+	uint8_t sw1;		/* status word 1 */
+	uint8_t sw2;		/* status word 2 */
+} sim_xfer_t;
+
+/* Transfer types for SIM_IOCTL_XFER */
+#define SIM_XFER_TYPE_TPDU 0
+#define SIM_XFER_TYPE_PTS  1
+
+/* Interface power states */
+#define SIM_POWER_OFF 0
+#define SIM_POWER_ON  1
+
+/* Return values for SIM_IOCTL_GET_PRESENSE */
+#define SIM_PRESENT_REMOVED     0
+#define SIM_PRESENT_DETECTED    1
+#define SIM_PRESENT_OPERATIONAL 2
+
+/* Return values for SIM_IOCTL_GET_ERROR */
+#define SIM_OK                         0
+#define SIM_E_ACCESS                   1
+#define SIM_E_TPDUSHORT                2
+#define SIM_E_PTSEMPTY                 3
+#define SIM_E_INVALIDXFERTYPE          4
+#define SIM_E_INVALIDXMTLENGTH         5
+#define SIM_E_INVALIDRCVLENGTH         6
+#define SIM_E_NACK                     7
+#define SIM_E_TIMEOUT                  8
+#define SIM_E_NOCARD                   9
+#define SIM_E_PARAM_FI_INVALID         10
+#define SIM_E_PARAM_DI_INVALID         11
+#define SIM_E_PARAM_FBYD_WITHFRACTION  12
+#define SIM_E_PARAM_FBYD_NOTDIVBY8OR12 13
+#define SIM_E_PARAM_DIVISOR_RANGE      14
+#define SIM_E_MALLOC                   15
+#define SIM_E_IRQ                      16
+#define SIM_E_POWERED_ON               17
+#define SIM_E_POWERED_OFF              18
+
+/* ioctl encodings */
+#define SIM_IOCTL_BASE 0xc0
+#define SIM_IOCTL_GET_PRESENSE   _IOR(SIM_IOCTL_BASE, 1, int)
+#define SIM_IOCTL_GET_ATR        _IOR(SIM_IOCTL_BASE, 2, sim_atr_t)
+#define SIM_IOCTL_GET_PARAM_ATR  _IOR(SIM_IOCTL_BASE, 3, sim_param_t)
+#define SIM_IOCTL_GET_PARAM      _IOR(SIM_IOCTL_BASE, 4, sim_param_t)
+#define SIM_IOCTL_SET_PARAM      _IOW(SIM_IOCTL_BASE, 5, sim_param_t)
+#define SIM_IOCTL_XFER           _IOR(SIM_IOCTL_BASE, 6, sim_xfer_t)
+#define SIM_IOCTL_POWER_ON       _IO(SIM_IOCTL_BASE, 7)
+#define SIM_IOCTL_POWER_OFF      _IO(SIM_IOCTL_BASE, 8)
+#define SIM_IOCTL_WARM_RESET     _IO(SIM_IOCTL_BASE, 9)
+#define SIM_IOCTL_COLD_RESET     _IO(SIM_IOCTL_BASE, 10)
+#define SIM_IOCTL_CARD_LOCK      _IO(SIM_IOCTL_BASE, 11)
+#define SIM_IOCTL_CARD_EJECT     _IO(SIM_IOCTL_BASE, 12)
+
+#endif
-- 
1.6.0.4





More information about the kernel-team mailing list