add rk29 sdio mmc
authorlhh <lhh@rock-chips.com>
Mon, 8 Nov 2010 04:05:18 +0000 (12:05 +0800)
committerlhh <lhh@rock-chips.com>
Mon, 8 Nov 2010 04:05:18 +0000 (12:05 +0800)
15 files changed:
arch/arm/configs/rk29_sdk_defconfig
arch/arm/mach-rk29/board-rk29sdk.c
arch/arm/mach-rk29/devices.c
arch/arm/mach-rk29/devices.h
arch/arm/mach-rk29/gpio.c
arch/arm/mach-rk29/include/mach/board.h
arch/arm/mach-rk29/include/mach/gpio.h
drivers/mmc/card/block.c
drivers/mmc/core/bus.c
drivers/mmc/core/core.c
drivers/mmc/core/mmc.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/rk2818-sdmmc.h
drivers/mmc/host/rk29_sdmmc.c [new file with mode: 0644]

index 1f464a8388ac45cffac7da9ba7a0ed3207c4fb5f..b6b6d5269af69fbd369909b997995359a215616e 100644 (file)
@@ -720,7 +720,34 @@ CONFIG_DUMMY_CONSOLE=y
 # CONFIG_SOUND is not set
 # CONFIG_HID_SUPPORT is not set
 # CONFIG_USB_SUPPORT is not set
-# CONFIG_MMC is not set
+CONFIG_MMC=y
+CONFIG_MMC_DEBUG=y
+# CONFIG_MMC_UNSAFE_RESUME is not set
+# CONFIG_MMC_EMBEDDED_SDIO is not set
+# CONFIG_MMC_PARANOID_SD_INIT is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_SDMMC_RK29=y
+
+#
+# Now, there are two SDMMC controllers selected, SDMMC0 and SDMMC1.
+#
+CONFIG_SDMMC0_RK29=y
+CONFIG_SDMMC1_RK29=y
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_ATMELMCI is not set
 # CONFIG_MEMSTICK is not set
 # CONFIG_NEW_LEDS is not set
 # CONFIG_SWITCH is not set
index 40d097a7bf5d191a3b04905c36f5cc7c1e60f6c1..afabec683d58fdc9f566c1626a67ddde782c827f 100755 (executable)
@@ -288,10 +288,107 @@ struct rk29fb_info rk29_fb_info = {
 };\r
 \r
 \r
+/*****************************************************************************************\r
+ * SDMMC devices\r
+*****************************************************************************************/\r
+#ifdef CONFIG_SDMMC0_RK29\r
+void rk29_sdmmc0_cfg_gpio(struct platform_device *dev)\r
+{\r
+       rk29_mux_api_set(GPIO1D1_SDMMC0CMD_NAME, GPIO1H_SDMMC0_CMD);\r
+       rk29_mux_api_set(GPIO1D0_SDMMC0CLKOUT_NAME, GPIO1H_SDMMC0_CLKOUT);\r
+       rk29_mux_api_set(GPIO1D2_SDMMC0DATA0_NAME, GPIO1H_SDMMC0_DATA0);\r
+       rk29_mux_api_set(GPIO1D3_SDMMC0DATA1_NAME, GPIO1H_SDMMC0_DATA1);\r
+       rk29_mux_api_set(GPIO1D4_SDMMC0DATA2_NAME, GPIO1H_SDMMC0_DATA2);\r
+       rk29_mux_api_set(GPIO1D5_SDMMC0DATA3_NAME, GPIO1H_SDMMC0_DATA3);\r
+       rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_SDMMC0_DETECT_N);\r
+}\r
+\r
+#define CONFIG_SDMMC0_USE_DMA\r
+struct rk29_sdmmc_platform_data default_sdmmc0_data = {\r
+       .num_slots              = 1,\r
+       .host_ocr_avail = (MMC_VDD_27_28|MMC_VDD_28_29|MMC_VDD_29_30|\r
+                                          MMC_VDD_30_31|MMC_VDD_31_32|MMC_VDD_32_33| \r
+                                          MMC_VDD_33_34|MMC_VDD_34_35| MMC_VDD_35_36),\r
+       .host_caps      = (MMC_CAP_4_BIT_DATA|MMC_CAP_MMC_HIGHSPEED|MMC_CAP_SD_HIGHSPEED),\r
+       .io_init = rk29_sdmmc0_cfg_gpio,\r
+       .dma_name = "sd_mmc",\r
+#ifdef CONFIG_SDMMC0_USE_DMA\r
+       .use_dma  = 1,\r
+#else\r
+       .use_dma = 0,\r
+#endif\r
+};\r
+#endif\r
+#ifdef CONFIG_SDMMC1_RK29\r
+#define CONFIG_SDMMC1_USE_DMA\r
+void rk29_sdmmc1_cfg_gpio(struct platform_device *dev)\r
+{\r
+       rk29_mux_api_set(GPIO1C2_SDMMC1CMD_NAME, GPIO1H_SDMMC1_CMD);\r
+       rk29_mux_api_set(GPIO1C7_SDMMC1CLKOUT_NAME, GPIO1H_SDMMC1_CLKOUT);\r
+       rk29_mux_api_set(GPIO1C3_SDMMC1DATA0_NAME, GPIO1H_SDMMC1_DATA0);\r
+       rk29_mux_api_set(GPIO1C4_SDMMC1DATA1_NAME, GPIO1H_SDMMC1_DATA1);\r
+       rk29_mux_api_set(GPIO1C5_SDMMC1DATA2_NAME, GPIO1H_SDMMC1_DATA2);\r
+       rk29_mux_api_set(GPIO1C6_SDMMC1DATA3_NAME, GPIO1H_SDMMC1_DATA3);\r
+}\r
+\r
+struct rk29_sdmmc_platform_data default_sdmmc1_data = {\r
+       .num_slots              = 1,\r
+       .host_ocr_avail = (MMC_VDD_26_27|MMC_VDD_27_28|MMC_VDD_28_29|\r
+                                          MMC_VDD_29_30|MMC_VDD_30_31|MMC_VDD_31_32|\r
+                                          MMC_VDD_32_33|MMC_VDD_33_34),\r
+       .host_caps      = (MMC_CAP_4_BIT_DATA|MMC_CAP_SDIO_IRQ|\r
+                                  MMC_CAP_MMC_HIGHSPEED|MMC_CAP_SD_HIGHSPEED),\r
+       .io_init = rk29_sdmmc1_cfg_gpio,\r
+       .dma_name = "sdio",\r
+#ifdef CONFIG_SDMMC1_USE_DMA\r
+       .use_dma  = 1,\r
+#else\r
+       .use_dma = 0,\r
+#endif\r
+};\r
+#endif\r
+static void __init rk29_board_iomux_init(void)\r
+{\r
+       #ifdef CONFIG_UART0_RK29        \r
+       rk29_mux_api_set(GPIO1B7_UART0SOUT_NAME, GPIO1L_UART0_SOUT);\r
+       rk29_mux_api_set(GPIO1B6_UART0SIN_NAME, GPIO1L_UART0_SIN);\r
+       #ifdef CONFIG_UART0_CTS_RTS_RK29\r
+       rk29_mux_api_set(GPIO1C1_UART0RTSN_SDMMC1WRITEPRT_NAME, GPIO1H_UART0_RTS_N);\r
+       rk29_mux_api_set(GPIO1C0_UART0CTSN_SDMMC1DETECTN_NAME, GPIO1H_UART0_CTS_N);\r
+       #endif\r
+       #endif\r
+       #ifdef CONFIG_UART1_RK29        \r
+       rk29_mux_api_set(GPIO2A5_UART1SOUT_NAME, GPIO2L_UART1_SOUT);\r
+       rk29_mux_api_set(GPIO2A4_UART1SIN_NAME, GPIO2L_UART1_SIN);\r
+       #endif\r
+       #ifdef CONFIG_UART2_RK29        \r
+       rk29_mux_api_set(GPIO2B1_UART2SOUT_NAME, GPIO2L_UART2_SOUT);\r
+       rk29_mux_api_set(GPIO2B0_UART2SIN_NAME, GPIO2L_UART2_SIN);\r
+       #ifdef CONFIG_UART2_CTS_RTS_RK29\r
+       rk29_mux_api_set(GPIO2A7_UART2RTSN_NAME, GPIO2L_UART2_RTS_N);\r
+       rk29_mux_api_set(GPIO2A6_UART2CTSN_NAME, GPIO2L_UART2_CTS_N);\r
+       #endif\r
+       #endif\r
+       #ifdef CONFIG_UART3_RK29        \r
+       rk29_mux_api_set(GPIO2B3_UART3SOUT_NAME, GPIO2L_UART3_SOUT);\r
+       rk29_mux_api_set(GPIO2B2_UART3SIN_NAME, GPIO2L_UART3_SIN);\r
+       #ifdef CONFIG_UART3_CTS_RTS_RK29\r
+       rk29_mux_api_set(GPIO2B5_UART3RTSN_I2C3SCL_NAME, GPIO2L_UART3_RTS_N);\r
+       rk29_mux_api_set(GPIO2B4_UART3CTSN_I2C3SDA_NAME, GPIO2L_UART3_CTS_N);\r
+       #endif\r
+       #endif\r
+}\r
+\r
 static struct platform_device *devices[] __initdata = {\r
 #ifdef CONFIG_UART1_RK29       \r
        &rk29_device_uart1,\r
 #endif \r
+#ifdef CONFIG_SDMMC0_RK29      \r
+       &rk29_device_sdmmc0,\r
+#endif\r
+#ifdef CONFIG_SDMMC1_RK29\r
+       &rk29_device_sdmmc1,\r
+#endif\r
 #ifdef CONFIG_MTD_NAND_RK29\r
        &rk29_device_nand,\r
 #endif\r
@@ -321,6 +418,7 @@ static void __init machine_rk29_init_irq(void)
 static void __init machine_rk29_board_init(void)\r
 { \r
        platform_add_devices(devices, ARRAY_SIZE(devices));     \r
+       rk29_board_iomux_init();\r
 }\r
 \r
 static void __init machine_rk29_mapio(void)\r
index 117d8891848d57e32cfb69e6bf4ed1cc44edafee..b62ba8979ee1696ae7021209f58e5677ad99666d 100755 (executable)
 #include <linux/delay.h>
 #include <mach/irqs.h>
 #include <mach/rk29_iomap.h>
-#include "devices.h" 
+#include "devices.h"
+
+#ifdef CONFIG_SDMMC0_RK29 
+static struct resource resources_sdmmc0[] = {
+       {
+               .start  = IRQ_SDMMC,
+               .end    = IRQ_SDMMC,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = RK29_SDMMC0_PHYS,
+               .end    = RK29_SDMMC0_PHYS + RK29_SDMMC0_SIZE -1,
+               .flags  = IORESOURCE_MEM,
+       }
+};
+#endif
+#ifdef CONFIG_SDMMC1_RK29
+static struct resource resources_sdmmc1[] = {
+       {
+               .start  = IRQ_SDIO,
+               .end    = IRQ_SDIO,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = RK29_SDMMC1_PHYS,
+               .end    = RK29_SDMMC1_PHYS + RK29_SDMMC1_SIZE -1,
+               .flags  = IORESOURCE_MEM,
+       }
+}; 
+#endif
+/* sdmmc */
+#ifdef CONFIG_SDMMC0_RK29
+struct platform_device rk29_device_sdmmc0 = {
+       .name                   = "rk29_sdmmc",
+       .id                             = 0,
+       .num_resources  = ARRAY_SIZE(resources_sdmmc0),
+       .resource               = resources_sdmmc0,
+       .dev                    = {
+               .platform_data = &default_sdmmc0_data,
+       },
+};
+#endif
+#ifdef CONFIG_SDMMC1_RK29
+struct platform_device rk29_device_sdmmc1 = {
+       .name                   = "rk29_sdmmc",
+       .id                             = 1,
+       .num_resources  = ARRAY_SIZE(resources_sdmmc1),
+       .resource               = resources_sdmmc1,
+       .dev                    = {
+               .platform_data = &default_sdmmc1_data,
+       },
+};
+#endif
 /*
  * rk29 4 uarts device
  */
@@ -34,7 +84,7 @@ static struct resource resources_uart0[] = {
        },
        {
                .start  = RK29_UART0_PHYS,
-               .end    = RK29_UART0_PHYS + SZ_1K - 1,
+               .end    = RK29_UART0_PHYS + RK29_UART0_SIZE - 1,
                .flags  = IORESOURCE_MEM,
        },
 };
@@ -48,7 +98,7 @@ static struct resource resources_uart1[] = {
        },
        {
                .start  = RK29_UART1_PHYS,
-               .end    = RK29_UART1_PHYS + SZ_1K - 1,
+               .end    = RK29_UART1_PHYS + RK29_UART1_SIZE - 1,
                .flags  = IORESOURCE_MEM,
        },
 };
@@ -62,7 +112,7 @@ static struct resource resources_uart2[] = {
        },
        {
                .start  = RK29_UART2_PHYS,
-               .end    = RK29_UART2_PHYS + SZ_1K - 1,
+               .end    = RK29_UART2_PHYS + RK29_UART2_SIZE - 1,
                .flags  = IORESOURCE_MEM,
        },
 };
@@ -76,7 +126,7 @@ static struct resource resources_uart3[] = {
        },
        {
                .start  = RK29_UART3_PHYS,
-               .end    = RK29_UART3_PHYS + SZ_1K - 1,
+               .end    = RK29_UART3_PHYS + RK29_UART3_SIZE - 1,
                .flags  = IORESOURCE_MEM,
        },
 };
index 134f662e9bbab5b1a23e4501e0e487066569f575..8d34b1f4e44fa21b1724d07ca277dc5c70462d2e 100755 (executable)
@@ -25,5 +25,9 @@ extern struct platform_device rk29_device_uart3;
 extern struct platform_device rk29_device_gpu;
 extern struct platform_device rk29_device_fb;
 extern struct platform_device rk29_device_nand;
+extern struct rk29_sdmmc_platform_data default_sdmmc0_data;
+extern struct rk29_sdmmc_platform_data default_sdmmc1_data;
+extern struct platform_device rk29_device_sdmmc0;
+extern struct platform_device rk29_device_sdmmc1;
 
 #endif
\ No newline at end of file
index 3135b6d19077db3500b39694d08661570ef2cbbd..b38b8fe37a7b0e364cf7cd56cb2ad5b22a62bb37 100644 (file)
@@ -500,7 +500,7 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
        unsigned char  __iomem  *gpioRegBase;
        u32             isr;
 
-       rk29_gpio = get_irq_chip_data(irq);
+       rk29_gpio = get_irq_chip_data(irq+14);
        gpioRegBase = rk29_gpio->regbase;
 
        //ÆÁ±ÎÖжÏ6»ò7
@@ -602,6 +602,7 @@ void __init rk29_gpio_irq_setup(void)
                                irq = IRQ_GPIO6;
                                break;          
                }
+               set_irq_chip_data(NR_AIC_IRQS+this->bank->id,this);
                set_irq_chained_handler(irq, gpio_irq_handler);
                this += 1; 
                pin += 32;
index 6598fc138fa5f9c4e81288f9d4b1890c2f35578d..bb575a0e2311241d177eaf311a1e124ffdb5ecc1 100755 (executable)
@@ -49,6 +49,18 @@ struct rk29fb_info{
     int (*io_deinit)(void);
 };
 
+struct rk29_sdmmc_platform_data {
+       unsigned int num_slots;
+       unsigned int host_caps;
+       unsigned int host_ocr_avail;
+       unsigned int use_dma:1;
+       char dma_name[8];
+       int (*io_init)(void);
+       int (*io_deinit)(void);
+       int (*status)(struct device *);
+       int (*register_status_notify)(void (*callback)(int card_present, void *dev_id), void *dev_id);
+};
+
 void __init rk29_map_common_io(void);
 void __init rk29_clock_init(void);
 
index ebcc601e82981dc9470081526176020b6c90cece..575f48f8594ff966a79099982ea4e757d6d2a4dd 100644 (file)
@@ -14,7 +14,8 @@
  */
 #ifndef __ARCH_ARM_MACH_RK29_GPIO_H
 #define __ARCH_ARM_MACH_RK29_GPIO_H
-
+#include <asm/irq.h>
 typedef enum eGPIOPinLevel
 {
        GPIO_LOW=0,
@@ -60,236 +61,236 @@ typedef enum GPIOIntType {
 #define PIN_BASE                               0
 #define MAX_BANK                               7
 
-#define        RK29_PIN0_PA0           (0*NUM_GROUP + PIN_BASE + 0);
-#define        RK29_PIN0_PA1           (0*NUM_GROUP + PIN_BASE + 1);
-#define        RK29_PIN0_PA2           (0*NUM_GROUP + PIN_BASE + 2);
-#define        RK29_PIN0_PA3           (0*NUM_GROUP + PIN_BASE + 3);
-#define        RK29_PIN0_PA4           (0*NUM_GROUP + PIN_BASE + 4);
-#define        RK29_PIN0_PA5           (0*NUM_GROUP + PIN_BASE + 5);
-#define        RK29_PIN0_PA6           (0*NUM_GROUP + PIN_BASE + 6);
-#define        RK29_PIN0_PA7           (0*NUM_GROUP + PIN_BASE + 7);
-#define        RK29_PIN0_PB0           (0*NUM_GROUP + PIN_BASE + 8);
-#define        RK29_PIN0_PB1           (0*NUM_GROUP + PIN_BASE + 9);
-#define        RK29_PIN0_PB2           (0*NUM_GROUP + PIN_BASE + 10);
-#define        RK29_PIN0_PB3           (0*NUM_GROUP + PIN_BASE + 11);
-#define        RK29_PIN0_PB4           (0*NUM_GROUP + PIN_BASE + 12);
-#define        RK29_PIN0_PB5           (0*NUM_GROUP + PIN_BASE + 13);
-#define        RK29_PIN0_PB6           (0*NUM_GROUP + PIN_BASE + 14);
-#define        RK29_PIN0_PB7           (0*NUM_GROUP + PIN_BASE + 15);
-#define        RK29_PIN0_PC0           (0*NUM_GROUP + PIN_BASE + 16);
-#define        RK29_PIN0_PC1           (0*NUM_GROUP + PIN_BASE + 17);
-#define        RK29_PIN0_PC2           (0*NUM_GROUP + PIN_BASE + 18);
-#define        RK29_PIN0_PC3           (0*NUM_GROUP + PIN_BASE + 19);
-#define        RK29_PIN0_PC4           (0*NUM_GROUP + PIN_BASE + 20);
-#define        RK29_PIN0_PC5           (0*NUM_GROUP + PIN_BASE + 21);
-#define        RK29_PIN0_PC6           (0*NUM_GROUP + PIN_BASE + 22);
-#define        RK29_PIN0_PC7           (0*NUM_GROUP + PIN_BASE + 23);
-#define        RK29_PIN0_PD0           (0*NUM_GROUP + PIN_BASE + 24);
-#define        RK29_PIN0_PD1           (0*NUM_GROUP + PIN_BASE + 25);
-#define        RK29_PIN0_PD2           (0*NUM_GROUP + PIN_BASE + 26);
-#define        RK29_PIN0_PD3           (0*NUM_GROUP + PIN_BASE + 27);
-#define        RK29_PIN0_PD4           (0*NUM_GROUP + PIN_BASE + 28);
-#define        RK29_PIN0_PD5           (0*NUM_GROUP + PIN_BASE + 29);
-#define        RK29_PIN0_PD6           (0*NUM_GROUP + PIN_BASE + 30);
-#define        RK29_PIN0_PD7           (0*NUM_GROUP + PIN_BASE + 31);
+#define        RK29_PIN0_PA0           (0*NUM_GROUP + PIN_BASE + 0)
+#define        RK29_PIN0_PA1           (0*NUM_GROUP + PIN_BASE + 1)
+#define        RK29_PIN0_PA2           (0*NUM_GROUP + PIN_BASE + 2)
+#define        RK29_PIN0_PA3           (0*NUM_GROUP + PIN_BASE + 3)
+#define        RK29_PIN0_PA4           (0*NUM_GROUP + PIN_BASE + 4)
+#define        RK29_PIN0_PA5           (0*NUM_GROUP + PIN_BASE + 5)
+#define        RK29_PIN0_PA6           (0*NUM_GROUP + PIN_BASE + 6)
+#define        RK29_PIN0_PA7           (0*NUM_GROUP + PIN_BASE + 7)
+#define        RK29_PIN0_PB0           (0*NUM_GROUP + PIN_BASE + 8)
+#define        RK29_PIN0_PB1           (0*NUM_GROUP + PIN_BASE + 9)
+#define        RK29_PIN0_PB2           (0*NUM_GROUP + PIN_BASE + 10)
+#define        RK29_PIN0_PB3           (0*NUM_GROUP + PIN_BASE + 11)
+#define        RK29_PIN0_PB4           (0*NUM_GROUP + PIN_BASE + 12)
+#define        RK29_PIN0_PB5           (0*NUM_GROUP + PIN_BASE + 13)
+#define        RK29_PIN0_PB6           (0*NUM_GROUP + PIN_BASE + 14)
+#define        RK29_PIN0_PB7           (0*NUM_GROUP + PIN_BASE + 15)
+#define        RK29_PIN0_PC0           (0*NUM_GROUP + PIN_BASE + 16)
+#define        RK29_PIN0_PC1           (0*NUM_GROUP + PIN_BASE + 17)
+#define        RK29_PIN0_PC2           (0*NUM_GROUP + PIN_BASE + 18)
+#define        RK29_PIN0_PC3           (0*NUM_GROUP + PIN_BASE + 19)
+#define        RK29_PIN0_PC4           (0*NUM_GROUP + PIN_BASE + 20)
+#define        RK29_PIN0_PC5           (0*NUM_GROUP + PIN_BASE + 21)
+#define        RK29_PIN0_PC6           (0*NUM_GROUP + PIN_BASE + 22)
+#define        RK29_PIN0_PC7           (0*NUM_GROUP + PIN_BASE + 23)
+#define        RK29_PIN0_PD0           (0*NUM_GROUP + PIN_BASE + 24)
+#define        RK29_PIN0_PD1           (0*NUM_GROUP + PIN_BASE + 25)
+#define        RK29_PIN0_PD2           (0*NUM_GROUP + PIN_BASE + 26)
+#define        RK29_PIN0_PD3           (0*NUM_GROUP + PIN_BASE + 27)
+#define        RK29_PIN0_PD4           (0*NUM_GROUP + PIN_BASE + 28)
+#define        RK29_PIN0_PD5           (0*NUM_GROUP + PIN_BASE + 29)
+#define        RK29_PIN0_PD6           (0*NUM_GROUP + PIN_BASE + 30)
+#define        RK29_PIN0_PD7           (0*NUM_GROUP + PIN_BASE + 31)
 
-#define        RK29_PIN1_PA0           (1*NUM_GROUP + PIN_BASE + 0); 
-#define        RK29_PIN1_PA1           (1*NUM_GROUP + PIN_BASE + 1); 
-#define        RK29_PIN1_PA2           (1*NUM_GROUP + PIN_BASE + 2); 
-#define        RK29_PIN1_PA3           (1*NUM_GROUP + PIN_BASE + 3); 
-#define        RK29_PIN1_PA4           (1*NUM_GROUP + PIN_BASE + 4); 
-#define        RK29_PIN1_PA5           (1*NUM_GROUP + PIN_BASE + 5); 
-#define        RK29_PIN1_PA6           (1*NUM_GROUP + PIN_BASE + 6); 
-#define        RK29_PIN1_PA7           (1*NUM_GROUP + PIN_BASE + 7); 
-#define        RK29_PIN1_PB0           (1*NUM_GROUP + PIN_BASE + 8); 
-#define        RK29_PIN1_PB1           (1*NUM_GROUP + PIN_BASE + 9); 
-#define        RK29_PIN1_PB2           (1*NUM_GROUP + PIN_BASE + 10);
-#define        RK29_PIN1_PB3           (1*NUM_GROUP + PIN_BASE + 11);
-#define        RK29_PIN1_PB4           (1*NUM_GROUP + PIN_BASE + 12);
-#define        RK29_PIN1_PB5           (1*NUM_GROUP + PIN_BASE + 13);
-#define        RK29_PIN1_PB6           (1*NUM_GROUP + PIN_BASE + 14);
-#define        RK29_PIN1_PB7           (1*NUM_GROUP + PIN_BASE + 15);
-#define        RK29_PIN1_PC0           (1*NUM_GROUP + PIN_BASE + 16);
-#define        RK29_PIN1_PC1           (1*NUM_GROUP + PIN_BASE + 17);
-#define        RK29_PIN1_PC2           (1*NUM_GROUP + PIN_BASE + 18);
-#define        RK29_PIN1_PC3           (1*NUM_GROUP + PIN_BASE + 19);
-#define        RK29_PIN1_PC4           (1*NUM_GROUP + PIN_BASE + 20);
-#define        RK29_PIN1_PC5           (1*NUM_GROUP + PIN_BASE + 21);
-#define        RK29_PIN1_PC6           (1*NUM_GROUP + PIN_BASE + 22);
-#define        RK29_PIN1_PC7           (1*NUM_GROUP + PIN_BASE + 23);
-#define        RK29_PIN1_PD0           (1*NUM_GROUP + PIN_BASE + 24);
-#define        RK29_PIN1_PD1           (1*NUM_GROUP + PIN_BASE + 25);
-#define        RK29_PIN1_PD2           (1*NUM_GROUP + PIN_BASE + 26);
-#define        RK29_PIN1_PD3           (1*NUM_GROUP + PIN_BASE + 27);
-#define        RK29_PIN1_PD4           (1*NUM_GROUP + PIN_BASE + 28);
-#define        RK29_PIN1_PD5           (1*NUM_GROUP + PIN_BASE + 29);
-#define        RK29_PIN1_PD6           (1*NUM_GROUP + PIN_BASE + 30);
-#define        RK29_PIN1_PD7           (1*NUM_GROUP + PIN_BASE + 31);
+#define        RK29_PIN1_PA0           (1*NUM_GROUP + PIN_BASE + 0) 
+#define        RK29_PIN1_PA1           (1*NUM_GROUP + PIN_BASE + 1) 
+#define        RK29_PIN1_PA2           (1*NUM_GROUP + PIN_BASE + 2) 
+#define        RK29_PIN1_PA3           (1*NUM_GROUP + PIN_BASE + 3) 
+#define        RK29_PIN1_PA4           (1*NUM_GROUP + PIN_BASE + 4) 
+#define        RK29_PIN1_PA5           (1*NUM_GROUP + PIN_BASE + 5) 
+#define        RK29_PIN1_PA6           (1*NUM_GROUP + PIN_BASE + 6) 
+#define        RK29_PIN1_PA7           (1*NUM_GROUP + PIN_BASE + 7) 
+#define        RK29_PIN1_PB0           (1*NUM_GROUP + PIN_BASE + 8) 
+#define        RK29_PIN1_PB1           (1*NUM_GROUP + PIN_BASE + 9) 
+#define        RK29_PIN1_PB2           (1*NUM_GROUP + PIN_BASE + 10)
+#define        RK29_PIN1_PB3           (1*NUM_GROUP + PIN_BASE + 11)
+#define        RK29_PIN1_PB4           (1*NUM_GROUP + PIN_BASE + 12)
+#define        RK29_PIN1_PB5           (1*NUM_GROUP + PIN_BASE + 13)
+#define        RK29_PIN1_PB6           (1*NUM_GROUP + PIN_BASE + 14)
+#define        RK29_PIN1_PB7           (1*NUM_GROUP + PIN_BASE + 15)
+#define        RK29_PIN1_PC0           (1*NUM_GROUP + PIN_BASE + 16)
+#define        RK29_PIN1_PC1           (1*NUM_GROUP + PIN_BASE + 17)
+#define        RK29_PIN1_PC2           (1*NUM_GROUP + PIN_BASE + 18)
+#define        RK29_PIN1_PC3           (1*NUM_GROUP + PIN_BASE + 19)
+#define        RK29_PIN1_PC4           (1*NUM_GROUP + PIN_BASE + 20)
+#define        RK29_PIN1_PC5           (1*NUM_GROUP + PIN_BASE + 21)
+#define        RK29_PIN1_PC6           (1*NUM_GROUP + PIN_BASE + 22)
+#define        RK29_PIN1_PC7           (1*NUM_GROUP + PIN_BASE + 23)
+#define        RK29_PIN1_PD0           (1*NUM_GROUP + PIN_BASE + 24)
+#define        RK29_PIN1_PD1           (1*NUM_GROUP + PIN_BASE + 25)
+#define        RK29_PIN1_PD2           (1*NUM_GROUP + PIN_BASE + 26)
+#define        RK29_PIN1_PD3           (1*NUM_GROUP + PIN_BASE + 27)
+#define        RK29_PIN1_PD4           (1*NUM_GROUP + PIN_BASE + 28)
+#define        RK29_PIN1_PD5           (1*NUM_GROUP + PIN_BASE + 29)
+#define        RK29_PIN1_PD6           (1*NUM_GROUP + PIN_BASE + 30)
+#define        RK29_PIN1_PD7           (1*NUM_GROUP + PIN_BASE + 31)
 
-#define        RK29_PIN2_PA0           (2*NUM_GROUP + PIN_BASE + 0)
-#define        RK29_PIN2_PA1           (2*NUM_GROUP + PIN_BASE + 1)
-#define        RK29_PIN2_PA2           (2*NUM_GROUP + PIN_BASE + 2)
-#define        RK29_PIN2_PA3           (2*NUM_GROUP + PIN_BASE + 3)
-#define        RK29_PIN2_PA4           (2*NUM_GROUP + PIN_BASE + 4)
-#define        RK29_PIN2_PA5           (2*NUM_GROUP + PIN_BASE + 5)
-#define        RK29_PIN2_PA6           (2*NUM_GROUP + PIN_BASE + 6)
-#define        RK29_PIN2_PA7           (2*NUM_GROUP + PIN_BASE + 7)
-#define        RK29_PIN2_PB0           (2*NUM_GROUP + PIN_BASE + 8)
-#define        RK29_PIN2_PB1           (2*NUM_GROUP + PIN_BASE + 9)
-#define        RK29_PIN2_PB2           (2*NUM_GROUP + PIN_BASE + 10);
-#define        RK29_PIN2_PB3           (2*NUM_GROUP + PIN_BASE + 11);
-#define        RK29_PIN2_PB4           (2*NUM_GROUP + PIN_BASE + 12);
-#define        RK29_PIN2_PB5           (2*NUM_GROUP + PIN_BASE + 13);
-#define        RK29_PIN2_PB6           (2*NUM_GROUP + PIN_BASE + 14);
-#define        RK29_PIN2_PB7           (2*NUM_GROUP + PIN_BASE + 15);
-#define        RK29_PIN2_PC0           (2*NUM_GROUP + PIN_BASE + 16);
-#define        RK29_PIN2_PC1           (2*NUM_GROUP + PIN_BASE + 17);
-#define        RK29_PIN2_PC2           (2*NUM_GROUP + PIN_BASE + 18);
-#define        RK29_PIN2_PC3           (2*NUM_GROUP + PIN_BASE + 19);
-#define        RK29_PIN2_PC4           (2*NUM_GROUP + PIN_BASE + 20);
-#define        RK29_PIN2_PC5           (2*NUM_GROUP + PIN_BASE + 21);
-#define        RK29_PIN2_PC6           (2*NUM_GROUP + PIN_BASE + 22);
-#define        RK29_PIN2_PC7           (2*NUM_GROUP + PIN_BASE + 23);
-#define        RK29_PIN2_PD0           (2*NUM_GROUP + PIN_BASE + 24);
-#define        RK29_PIN2_PD1           (2*NUM_GROUP + PIN_BASE + 25);
-#define        RK29_PIN2_PD2           (2*NUM_GROUP + PIN_BASE + 26);
-#define        RK29_PIN2_PD3           (2*NUM_GROUP + PIN_BASE + 27);
-#define        RK29_PIN2_PD4           (2*NUM_GROUP + PIN_BASE + 28);
-#define        RK29_PIN2_PD5           (2*NUM_GROUP + PIN_BASE + 29);
-#define        RK29_PIN2_PD6           (2*NUM_GROUP + PIN_BASE + 30);
-#define        RK29_PIN2_PD7           (2*NUM_GROUP + PIN_BASE + 31);
+#define        RK29_PIN2_PA0           (2*NUM_GROUP + PIN_BASE + 0)
+#define        RK29_PIN2_PA1           (2*NUM_GROUP + PIN_BASE + 1)
+#define        RK29_PIN2_PA2           (2*NUM_GROUP + PIN_BASE + 2)
+#define        RK29_PIN2_PA3           (2*NUM_GROUP + PIN_BASE + 3)
+#define        RK29_PIN2_PA4           (2*NUM_GROUP + PIN_BASE + 4)
+#define        RK29_PIN2_PA5           (2*NUM_GROUP + PIN_BASE + 5)
+#define        RK29_PIN2_PA6           (2*NUM_GROUP + PIN_BASE + 6)
+#define        RK29_PIN2_PA7           (2*NUM_GROUP + PIN_BASE + 7)
+#define        RK29_PIN2_PB0           (2*NUM_GROUP + PIN_BASE + 8)
+#define        RK29_PIN2_PB1           (2*NUM_GROUP + PIN_BASE + 9)
+#define        RK29_PIN2_PB2           (2*NUM_GROUP + PIN_BASE + 10)
+#define        RK29_PIN2_PB3           (2*NUM_GROUP + PIN_BASE + 11)
+#define        RK29_PIN2_PB4           (2*NUM_GROUP + PIN_BASE + 12)
+#define        RK29_PIN2_PB5           (2*NUM_GROUP + PIN_BASE + 13)
+#define        RK29_PIN2_PB6           (2*NUM_GROUP + PIN_BASE + 14)
+#define        RK29_PIN2_PB7           (2*NUM_GROUP + PIN_BASE + 15)
+#define        RK29_PIN2_PC0           (2*NUM_GROUP + PIN_BASE + 16)
+#define        RK29_PIN2_PC1           (2*NUM_GROUP + PIN_BASE + 17)
+#define        RK29_PIN2_PC2           (2*NUM_GROUP + PIN_BASE + 18)
+#define        RK29_PIN2_PC3           (2*NUM_GROUP + PIN_BASE + 19)
+#define        RK29_PIN2_PC4           (2*NUM_GROUP + PIN_BASE + 20)
+#define        RK29_PIN2_PC5           (2*NUM_GROUP + PIN_BASE + 21)
+#define        RK29_PIN2_PC6           (2*NUM_GROUP + PIN_BASE + 22)
+#define        RK29_PIN2_PC7           (2*NUM_GROUP + PIN_BASE + 23)
+#define        RK29_PIN2_PD0           (2*NUM_GROUP + PIN_BASE + 24)
+#define        RK29_PIN2_PD1           (2*NUM_GROUP + PIN_BASE + 25)
+#define        RK29_PIN2_PD2           (2*NUM_GROUP + PIN_BASE + 26)
+#define        RK29_PIN2_PD3           (2*NUM_GROUP + PIN_BASE + 27)
+#define        RK29_PIN2_PD4           (2*NUM_GROUP + PIN_BASE + 28)
+#define        RK29_PIN2_PD5           (2*NUM_GROUP + PIN_BASE + 29)
+#define        RK29_PIN2_PD6           (2*NUM_GROUP + PIN_BASE + 30)
+#define        RK29_PIN2_PD7           (2*NUM_GROUP + PIN_BASE + 31)
 
-#define        RK29_PIN3_PA0           (3*NUM_GROUP + PIN_BASE + 0); 
-#define        RK29_PIN3_PA1           (3*NUM_GROUP + PIN_BASE + 1); 
-#define        RK29_PIN3_PA2           (3*NUM_GROUP + PIN_BASE + 2); 
-#define        RK29_PIN3_PA3           (3*NUM_GROUP + PIN_BASE + 3); 
-#define        RK29_PIN3_PA4           (3*NUM_GROUP + PIN_BASE + 4); 
-#define        RK29_PIN3_PA5           (3*NUM_GROUP + PIN_BASE + 5); 
-#define        RK29_PIN3_PA6           (3*NUM_GROUP + PIN_BASE + 6); 
-#define        RK29_PIN3_PA7           (3*NUM_GROUP + PIN_BASE + 7); 
-#define        RK29_PIN3_PB0           (3*NUM_GROUP + PIN_BASE + 8); 
-#define        RK29_PIN3_PB1           (3*NUM_GROUP + PIN_BASE + 9); 
-#define        RK29_PIN3_PB2           (3*NUM_GROUP + PIN_BASE + 10);
-#define        RK29_PIN3_PB3           (3*NUM_GROUP + PIN_BASE + 11);
-#define        RK29_PIN3_PB4           (3*NUM_GROUP + PIN_BASE + 12);
-#define        RK29_PIN3_PB5           (3*NUM_GROUP + PIN_BASE + 13);
-#define        RK29_PIN3_PB6           (3*NUM_GROUP + PIN_BASE + 14);
-#define        RK29_PIN3_PB7           (3*NUM_GROUP + PIN_BASE + 15);
-#define        RK29_PIN3_PC0           (3*NUM_GROUP + PIN_BASE + 16);
-#define        RK29_PIN3_PC1           (3*NUM_GROUP + PIN_BASE + 17);
-#define        RK29_PIN3_PC2           (3*NUM_GROUP + PIN_BASE + 18);
-#define        RK29_PIN3_PC3           (3*NUM_GROUP + PIN_BASE + 19);
-#define        RK29_PIN3_PC4           (3*NUM_GROUP + PIN_BASE + 20);
-#define        RK29_PIN3_PC5           (3*NUM_GROUP + PIN_BASE + 21);
-#define        RK29_PIN3_PC6           (3*NUM_GROUP + PIN_BASE + 22);
-#define        RK29_PIN3_PC7           (3*NUM_GROUP + PIN_BASE + 23);
-#define        RK29_PIN3_PD0           (3*NUM_GROUP + PIN_BASE + 24);
-#define        RK29_PIN3_PD1           (3*NUM_GROUP + PIN_BASE + 25);
-#define        RK29_PIN3_PD2           (3*NUM_GROUP + PIN_BASE + 26);
-#define        RK29_PIN3_PD3           (3*NUM_GROUP + PIN_BASE + 27);
-#define        RK29_PIN3_PD4           (3*NUM_GROUP + PIN_BASE + 28);
-#define        RK29_PIN3_PD5           (3*NUM_GROUP + PIN_BASE + 29);
-#define        RK29_PIN3_PD6           (3*NUM_GROUP + PIN_BASE + 30);
-#define        RK29_PIN3_PD7           (3*NUM_GROUP + PIN_BASE + 31);
+#define        RK29_PIN3_PA0           (3*NUM_GROUP + PIN_BASE + 0) 
+#define        RK29_PIN3_PA1           (3*NUM_GROUP + PIN_BASE + 1) 
+#define        RK29_PIN3_PA2           (3*NUM_GROUP + PIN_BASE + 2) 
+#define        RK29_PIN3_PA3           (3*NUM_GROUP + PIN_BASE + 3) 
+#define        RK29_PIN3_PA4           (3*NUM_GROUP + PIN_BASE + 4) 
+#define        RK29_PIN3_PA5           (3*NUM_GROUP + PIN_BASE + 5) 
+#define        RK29_PIN3_PA6           (3*NUM_GROUP + PIN_BASE + 6) 
+#define        RK29_PIN3_PA7           (3*NUM_GROUP + PIN_BASE + 7) 
+#define        RK29_PIN3_PB0           (3*NUM_GROUP + PIN_BASE + 8) 
+#define        RK29_PIN3_PB1           (3*NUM_GROUP + PIN_BASE + 9) 
+#define        RK29_PIN3_PB2           (3*NUM_GROUP + PIN_BASE + 10)
+#define        RK29_PIN3_PB3           (3*NUM_GROUP + PIN_BASE + 11)
+#define        RK29_PIN3_PB4           (3*NUM_GROUP + PIN_BASE + 12)
+#define        RK29_PIN3_PB5           (3*NUM_GROUP + PIN_BASE + 13)
+#define        RK29_PIN3_PB6           (3*NUM_GROUP + PIN_BASE + 14)
+#define        RK29_PIN3_PB7           (3*NUM_GROUP + PIN_BASE + 15)
+#define        RK29_PIN3_PC0           (3*NUM_GROUP + PIN_BASE + 16)
+#define        RK29_PIN3_PC1           (3*NUM_GROUP + PIN_BASE + 17)
+#define        RK29_PIN3_PC2           (3*NUM_GROUP + PIN_BASE + 18)
+#define        RK29_PIN3_PC3           (3*NUM_GROUP + PIN_BASE + 19)
+#define        RK29_PIN3_PC4           (3*NUM_GROUP + PIN_BASE + 20)
+#define        RK29_PIN3_PC5           (3*NUM_GROUP + PIN_BASE + 21)
+#define        RK29_PIN3_PC6           (3*NUM_GROUP + PIN_BASE + 22)
+#define        RK29_PIN3_PC7           (3*NUM_GROUP + PIN_BASE + 23)
+#define        RK29_PIN3_PD0           (3*NUM_GROUP + PIN_BASE + 24)
+#define        RK29_PIN3_PD1           (3*NUM_GROUP + PIN_BASE + 25)
+#define        RK29_PIN3_PD2           (3*NUM_GROUP + PIN_BASE + 26)
+#define        RK29_PIN3_PD3           (3*NUM_GROUP + PIN_BASE + 27)
+#define        RK29_PIN3_PD4           (3*NUM_GROUP + PIN_BASE + 28)
+#define        RK29_PIN3_PD5           (3*NUM_GROUP + PIN_BASE + 29)
+#define        RK29_PIN3_PD6           (3*NUM_GROUP + PIN_BASE + 30)
+#define        RK29_PIN3_PD7           (3*NUM_GROUP + PIN_BASE + 31)
 
-#define        RK29_PIN4_PA0           (4*NUM_GROUP + PIN_BASE + 0); 
-#define        RK29_PIN4_PA1           (4*NUM_GROUP + PIN_BASE + 1); 
-#define        RK29_PIN4_PA2           (4*NUM_GROUP + PIN_BASE + 2); 
-#define        RK29_PIN4_PA3           (4*NUM_GROUP + PIN_BASE + 3); 
-#define        RK29_PIN4_PA4           (4*NUM_GROUP + PIN_BASE + 4); 
-#define        RK29_PIN4_PA5           (4*NUM_GROUP + PIN_BASE + 5); 
-#define        RK29_PIN4_PA6           (4*NUM_GROUP + PIN_BASE + 6); 
-#define        RK29_PIN4_PA7           (4*NUM_GROUP + PIN_BASE + 7); 
-#define        RK29_PIN4_PB0           (4*NUM_GROUP + PIN_BASE + 8); 
-#define        RK29_PIN4_PB1           (4*NUM_GROUP + PIN_BASE + 9); 
-#define        RK29_PIN4_PB2           (4*NUM_GROUP + PIN_BASE + 10);
-#define        RK29_PIN4_PB3           (4*NUM_GROUP + PIN_BASE + 11);
-#define        RK29_PIN4_PB4           (4*NUM_GROUP + PIN_BASE + 12);
-#define        RK29_PIN4_PB5           (4*NUM_GROUP + PIN_BASE + 13);
-#define        RK29_PIN4_PB6           (4*NUM_GROUP + PIN_BASE + 14);
-#define        RK29_PIN4_PB7           (4*NUM_GROUP + PIN_BASE + 15);
-#define        RK29_PIN4_PC0           (4*NUM_GROUP + PIN_BASE + 16);
-#define        RK29_PIN4_PC1           (4*NUM_GROUP + PIN_BASE + 17);
-#define        RK29_PIN4_PC2           (4*NUM_GROUP + PIN_BASE + 18);
-#define        RK29_PIN4_PC3           (4*NUM_GROUP + PIN_BASE + 19);
-#define        RK29_PIN4_PC4           (4*NUM_GROUP + PIN_BASE + 20);
-#define        RK29_PIN4_PC5           (4*NUM_GROUP + PIN_BASE + 21);
-#define        RK29_PIN4_PC6           (4*NUM_GROUP + PIN_BASE + 22);
-#define        RK29_PIN4_PC7           (4*NUM_GROUP + PIN_BASE + 23);
-#define        RK29_PIN4_PD0           (4*NUM_GROUP + PIN_BASE + 24);
-#define        RK29_PIN4_PD1           (4*NUM_GROUP + PIN_BASE + 25);
-#define        RK29_PIN4_PD2           (4*NUM_GROUP + PIN_BASE + 26);
-#define        RK29_PIN4_PD3           (4*NUM_GROUP + PIN_BASE + 27);
-#define        RK29_PIN4_PD4           (4*NUM_GROUP + PIN_BASE + 28);
-#define        RK29_PIN4_PD5           (4*NUM_GROUP + PIN_BASE + 29);
-#define        RK29_PIN4_PD6           (4*NUM_GROUP + PIN_BASE + 30);
-#define        RK29_PIN4_PD7           (4*NUM_GROUP + PIN_BASE + 31);
+#define        RK29_PIN4_PA0           (4*NUM_GROUP + PIN_BASE + 0) 
+#define        RK29_PIN4_PA1           (4*NUM_GROUP + PIN_BASE + 1) 
+#define        RK29_PIN4_PA2           (4*NUM_GROUP + PIN_BASE + 2) 
+#define        RK29_PIN4_PA3           (4*NUM_GROUP + PIN_BASE + 3) 
+#define        RK29_PIN4_PA4           (4*NUM_GROUP + PIN_BASE + 4) 
+#define        RK29_PIN4_PA5           (4*NUM_GROUP + PIN_BASE + 5) 
+#define        RK29_PIN4_PA6           (4*NUM_GROUP + PIN_BASE + 6) 
+#define        RK29_PIN4_PA7           (4*NUM_GROUP + PIN_BASE + 7) 
+#define        RK29_PIN4_PB0           (4*NUM_GROUP + PIN_BASE + 8) 
+#define        RK29_PIN4_PB1           (4*NUM_GROUP + PIN_BASE + 9) 
+#define        RK29_PIN4_PB2           (4*NUM_GROUP + PIN_BASE + 10)
+#define        RK29_PIN4_PB3           (4*NUM_GROUP + PIN_BASE + 11)
+#define        RK29_PIN4_PB4           (4*NUM_GROUP + PIN_BASE + 12)
+#define        RK29_PIN4_PB5           (4*NUM_GROUP + PIN_BASE + 13)
+#define        RK29_PIN4_PB6           (4*NUM_GROUP + PIN_BASE + 14)
+#define        RK29_PIN4_PB7           (4*NUM_GROUP + PIN_BASE + 15)
+#define        RK29_PIN4_PC0           (4*NUM_GROUP + PIN_BASE + 16)
+#define        RK29_PIN4_PC1           (4*NUM_GROUP + PIN_BASE + 17)
+#define        RK29_PIN4_PC2           (4*NUM_GROUP + PIN_BASE + 18)
+#define        RK29_PIN4_PC3           (4*NUM_GROUP + PIN_BASE + 19)
+#define        RK29_PIN4_PC4           (4*NUM_GROUP + PIN_BASE + 20)
+#define        RK29_PIN4_PC5           (4*NUM_GROUP + PIN_BASE + 21)
+#define        RK29_PIN4_PC6           (4*NUM_GROUP + PIN_BASE + 22)
+#define        RK29_PIN4_PC7           (4*NUM_GROUP + PIN_BASE + 23)
+#define        RK29_PIN4_PD0           (4*NUM_GROUP + PIN_BASE + 24)
+#define        RK29_PIN4_PD1           (4*NUM_GROUP + PIN_BASE + 25)
+#define        RK29_PIN4_PD2           (4*NUM_GROUP + PIN_BASE + 26)
+#define        RK29_PIN4_PD3           (4*NUM_GROUP + PIN_BASE + 27)
+#define        RK29_PIN4_PD4           (4*NUM_GROUP + PIN_BASE + 28)
+#define        RK29_PIN4_PD5           (4*NUM_GROUP + PIN_BASE + 29)
+#define        RK29_PIN4_PD6           (4*NUM_GROUP + PIN_BASE + 30)
+#define        RK29_PIN4_PD7           (4*NUM_GROUP + PIN_BASE + 31)
 
-#define        RK29_PIN5_PA0           (5*NUM_GROUP + PIN_BASE + 0)
-#define        RK29_PIN5_PA1           (5*NUM_GROUP + PIN_BASE + 1)
-#define        RK29_PIN5_PA2           (5*NUM_GROUP + PIN_BASE + 2)
-#define        RK29_PIN5_PA3           (5*NUM_GROUP + PIN_BASE + 3)
-#define        RK29_PIN5_PA4           (5*NUM_GROUP + PIN_BASE + 4)
-#define        RK29_PIN5_PA5           (5*NUM_GROUP + PIN_BASE + 5)
-#define        RK29_PIN5_PA6           (5*NUM_GROUP + PIN_BASE + 6)
-#define        RK29_PIN5_PA7           (5*NUM_GROUP + PIN_BASE + 7)
-#define        RK29_PIN5_PB0           (5*NUM_GROUP + PIN_BASE + 8)
-#define        RK29_PIN5_PB1           (5*NUM_GROUP + PIN_BASE + 9)
-#define        RK29_PIN5_PB2           (5*NUM_GROUP + PIN_BASE + 10);
-#define        RK29_PIN5_PB3           (5*NUM_GROUP + PIN_BASE + 11);
-#define        RK29_PIN5_PB4           (5*NUM_GROUP + PIN_BASE + 12);
-#define        RK29_PIN5_PB5           (5*NUM_GROUP + PIN_BASE + 13);
-#define        RK29_PIN5_PB6           (5*NUM_GROUP + PIN_BASE + 14);
-#define        RK29_PIN5_PB7           (5*NUM_GROUP + PIN_BASE + 15);
-#define        RK29_PIN5_PC0           (5*NUM_GROUP + PIN_BASE + 16);
-#define        RK29_PIN5_PC1           (5*NUM_GROUP + PIN_BASE + 17);
-#define        RK29_PIN5_PC2           (5*NUM_GROUP + PIN_BASE + 18);
-#define        RK29_PIN5_PC3           (5*NUM_GROUP + PIN_BASE + 19);
-#define        RK29_PIN5_PC4           (5*NUM_GROUP + PIN_BASE + 20);
-#define        RK29_PIN5_PC5           (5*NUM_GROUP + PIN_BASE + 21);
-#define        RK29_PIN5_PC6           (5*NUM_GROUP + PIN_BASE + 22);
-#define        RK29_PIN5_PC7           (5*NUM_GROUP + PIN_BASE + 23);
-#define        RK29_PIN5_PD0           (5*NUM_GROUP + PIN_BASE + 24);
-#define        RK29_PIN5_PD1           (5*NUM_GROUP + PIN_BASE + 25);
-#define        RK29_PIN5_PD2           (5*NUM_GROUP + PIN_BASE + 26);
-#define        RK29_PIN5_PD3           (5*NUM_GROUP + PIN_BASE + 27);
-#define        RK29_PIN5_PD4           (5*NUM_GROUP + PIN_BASE + 28);
-#define        RK29_PIN5_PD5           (5*NUM_GROUP + PIN_BASE + 29);
-#define        RK29_PIN5_PD6           (5*NUM_GROUP + PIN_BASE + 30);
-#define        RK29_PIN5_PD7           (5*NUM_GROUP + PIN_BASE + 31);
+#define        RK29_PIN5_PA0           (5*NUM_GROUP + PIN_BASE + 0)
+#define        RK29_PIN5_PA1           (5*NUM_GROUP + PIN_BASE + 1)
+#define        RK29_PIN5_PA2           (5*NUM_GROUP + PIN_BASE + 2)
+#define        RK29_PIN5_PA3           (5*NUM_GROUP + PIN_BASE + 3)
+#define        RK29_PIN5_PA4           (5*NUM_GROUP + PIN_BASE + 4)
+#define        RK29_PIN5_PA5           (5*NUM_GROUP + PIN_BASE + 5)
+#define        RK29_PIN5_PA6           (5*NUM_GROUP + PIN_BASE + 6)
+#define        RK29_PIN5_PA7           (5*NUM_GROUP + PIN_BASE + 7)
+#define        RK29_PIN5_PB0           (5*NUM_GROUP + PIN_BASE + 8)
+#define        RK29_PIN5_PB1           (5*NUM_GROUP + PIN_BASE + 9)
+#define        RK29_PIN5_PB2           (5*NUM_GROUP + PIN_BASE + 10)
+#define        RK29_PIN5_PB3           (5*NUM_GROUP + PIN_BASE + 11)
+#define        RK29_PIN5_PB4           (5*NUM_GROUP + PIN_BASE + 12)
+#define        RK29_PIN5_PB5           (5*NUM_GROUP + PIN_BASE + 13)
+#define        RK29_PIN5_PB6           (5*NUM_GROUP + PIN_BASE + 14)
+#define        RK29_PIN5_PB7           (5*NUM_GROUP + PIN_BASE + 15)
+#define        RK29_PIN5_PC0           (5*NUM_GROUP + PIN_BASE + 16)
+#define        RK29_PIN5_PC1           (5*NUM_GROUP + PIN_BASE + 17)
+#define        RK29_PIN5_PC2           (5*NUM_GROUP + PIN_BASE + 18)
+#define        RK29_PIN5_PC3           (5*NUM_GROUP + PIN_BASE + 19)
+#define        RK29_PIN5_PC4           (5*NUM_GROUP + PIN_BASE + 20)
+#define        RK29_PIN5_PC5           (5*NUM_GROUP + PIN_BASE + 21)
+#define        RK29_PIN5_PC6           (5*NUM_GROUP + PIN_BASE + 22)
+#define        RK29_PIN5_PC7           (5*NUM_GROUP + PIN_BASE + 23)
+#define        RK29_PIN5_PD0           (5*NUM_GROUP + PIN_BASE + 24)
+#define        RK29_PIN5_PD1           (5*NUM_GROUP + PIN_BASE + 25)
+#define        RK29_PIN5_PD2           (5*NUM_GROUP + PIN_BASE + 26)
+#define        RK29_PIN5_PD3           (5*NUM_GROUP + PIN_BASE + 27)
+#define        RK29_PIN5_PD4           (5*NUM_GROUP + PIN_BASE + 28)
+#define        RK29_PIN5_PD5           (5*NUM_GROUP + PIN_BASE + 29)
+#define        RK29_PIN5_PD6           (5*NUM_GROUP + PIN_BASE + 30)
+#define        RK29_PIN5_PD7           (5*NUM_GROUP + PIN_BASE + 31)
 
-#define        RK29_PIN6_PA0           (6*NUM_GROUP + PIN_BASE + 0); 
-#define        RK29_PIN6_PA1           (6*NUM_GROUP + PIN_BASE + 1); 
-#define        RK29_PIN6_PA2           (6*NUM_GROUP + PIN_BASE + 2); 
-#define        RK29_PIN6_PA3           (6*NUM_GROUP + PIN_BASE + 3); 
-#define        RK29_PIN6_PA4           (6*NUM_GROUP + PIN_BASE + 4); 
-#define        RK29_PIN6_PA5           (6*NUM_GROUP + PIN_BASE + 5); 
-#define        RK29_PIN6_PA6           (6*NUM_GROUP + PIN_BASE + 6); 
-#define        RK29_PIN6_PA7           (6*NUM_GROUP + PIN_BASE + 7); 
-#define        RK29_PIN6_PB0           (6*NUM_GROUP + PIN_BASE + 8); 
-#define        RK29_PIN6_PB1           (6*NUM_GROUP + PIN_BASE + 9); 
-#define        RK29_PIN6_PB2           (6*NUM_GROUP + PIN_BASE + 10);
-#define        RK29_PIN6_PB3           (6*NUM_GROUP + PIN_BASE + 11);
-#define        RK29_PIN6_PB4           (6*NUM_GROUP + PIN_BASE + 12);
-#define        RK29_PIN6_PB5           (6*NUM_GROUP + PIN_BASE + 13);
-#define        RK29_PIN6_PB6           (6*NUM_GROUP + PIN_BASE + 14);
-#define        RK29_PIN6_PB7           (6*NUM_GROUP + PIN_BASE + 15);
-#define        RK29_PIN6_PC0           (6*NUM_GROUP + PIN_BASE + 16);
-#define        RK29_PIN6_PC1           (6*NUM_GROUP + PIN_BASE + 17);
-#define        RK29_PIN6_PC2           (6*NUM_GROUP + PIN_BASE + 18);
-#define        RK29_PIN6_PC3           (6*NUM_GROUP + PIN_BASE + 19);
-#define        RK29_PIN6_PC4           (6*NUM_GROUP + PIN_BASE + 20);
-#define        RK29_PIN6_PC5           (6*NUM_GROUP + PIN_BASE + 21);
-#define        RK29_PIN6_PC6           (6*NUM_GROUP + PIN_BASE + 22);
-#define        RK29_PIN6_PC7           (6*NUM_GROUP + PIN_BASE + 23);
-#define        RK29_PIN6_PD0           (6*NUM_GROUP + PIN_BASE + 24);
-#define        RK29_PIN6_PD1           (6*NUM_GROUP + PIN_BASE + 25);
-#define        RK29_PIN6_PD2           (6*NUM_GROUP + PIN_BASE + 26);
-#define        RK29_PIN6_PD3           (6*NUM_GROUP + PIN_BASE + 27);
-#define        RK29_PIN6_PD4           (6*NUM_GROUP + PIN_BASE + 28);
-#define        RK29_PIN6_PD5           (6*NUM_GROUP + PIN_BASE + 29);
-#define        RK29_PIN6_PD6           (6*NUM_GROUP + PIN_BASE + 30);
-#define        RK29_PIN6_PD7           (6*NUM_GROUP + PIN_BASE + 31);
+#define        RK29_PIN6_PA0           (6*NUM_GROUP + PIN_BASE + 0) 
+#define        RK29_PIN6_PA1           (6*NUM_GROUP + PIN_BASE + 1) 
+#define        RK29_PIN6_PA2           (6*NUM_GROUP + PIN_BASE + 2) 
+#define        RK29_PIN6_PA3           (6*NUM_GROUP + PIN_BASE + 3) 
+#define        RK29_PIN6_PA4           (6*NUM_GROUP + PIN_BASE + 4) 
+#define        RK29_PIN6_PA5           (6*NUM_GROUP + PIN_BASE + 5) 
+#define        RK29_PIN6_PA6           (6*NUM_GROUP + PIN_BASE + 6) 
+#define        RK29_PIN6_PA7           (6*NUM_GROUP + PIN_BASE + 7) 
+#define        RK29_PIN6_PB0           (6*NUM_GROUP + PIN_BASE + 8) 
+#define        RK29_PIN6_PB1           (6*NUM_GROUP + PIN_BASE + 9) 
+#define        RK29_PIN6_PB2           (6*NUM_GROUP + PIN_BASE + 10)
+#define        RK29_PIN6_PB3           (6*NUM_GROUP + PIN_BASE + 11)
+#define        RK29_PIN6_PB4           (6*NUM_GROUP + PIN_BASE + 12)
+#define        RK29_PIN6_PB5           (6*NUM_GROUP + PIN_BASE + 13)
+#define        RK29_PIN6_PB6           (6*NUM_GROUP + PIN_BASE + 14)
+#define        RK29_PIN6_PB7           (6*NUM_GROUP + PIN_BASE + 15)
+#define        RK29_PIN6_PC0           (6*NUM_GROUP + PIN_BASE + 16)
+#define        RK29_PIN6_PC1           (6*NUM_GROUP + PIN_BASE + 17)
+#define        RK29_PIN6_PC2           (6*NUM_GROUP + PIN_BASE + 18)
+#define        RK29_PIN6_PC3           (6*NUM_GROUP + PIN_BASE + 19)
+#define        RK29_PIN6_PC4           (6*NUM_GROUP + PIN_BASE + 20)
+#define        RK29_PIN6_PC5           (6*NUM_GROUP + PIN_BASE + 21)
+#define        RK29_PIN6_PC6           (6*NUM_GROUP + PIN_BASE + 22)
+#define        RK29_PIN6_PC7           (6*NUM_GROUP + PIN_BASE + 23)
+#define        RK29_PIN6_PD0           (6*NUM_GROUP + PIN_BASE + 24)
+#define        RK29_PIN6_PD1           (6*NUM_GROUP + PIN_BASE + 25)
+#define        RK29_PIN6_PD2           (6*NUM_GROUP + PIN_BASE + 26)
+#define        RK29_PIN6_PD3           (6*NUM_GROUP + PIN_BASE + 27)
+#define        RK29_PIN6_PD4           (6*NUM_GROUP + PIN_BASE + 28)
+#define        RK29_PIN6_PD5           (6*NUM_GROUP + PIN_BASE + 29)
+#define        RK29_PIN6_PD6           (6*NUM_GROUP + PIN_BASE + 30)
+#define        RK29_PIN6_PD7           (6*NUM_GROUP + PIN_BASE + 31)
                                            
 #define ARCH_NR_GPIOS          (NUM_GROUP*MAX_BANK)
                                            
@@ -317,12 +318,12 @@ extern void __init rk29_gpio_irq_setup(void);
 
 static inline int gpio_to_irq(unsigned gpio)
 {
-       return gpio;
+       return (gpio + NR_AIC_IRQS);
 }
 
 static inline int irq_to_gpio(unsigned irq)
 {
-       return irq;       
+       return (irq - NR_AIC_IRQS);       
 }
 
 #endif /* __ASSEMBLY__ */     
index a73fe94bb0d48fb3b43841d1dd26ad06b62f9938..8d2bd242ac63eec01b938286f1b9b37da4a213e2 100644 (file)
@@ -235,11 +235,9 @@ static u32 get_card_status(struct mmc_card *card, struct request *req)
                cmd.arg = card->rca << 16;
        cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
        err = mmc_wait_for_cmd(card->host, &cmd, 0);
-       #if 0 //[xjh] not printk,save time
        if (err)
                printk(KERN_ERR "%s: error %d sending status comand",
                       req->rq_disk->disk_name, err);
-       #endif
        return cmd.resp[0];
 }
 
@@ -378,9 +376,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                 * until later as we need to wait for the card to leave
                 * programming mode even when things go wrong.
                 */
-               #if 1/*[xjh] do not retry with cmd17*/
                if (brq.cmd.error || brq.data.error || brq.stop.error) {
-                       
                        if (brq.data.blocks > 1 && rq_data_dir(req) == READ) {
                                /* Redo read one sector at a time */
                                printk(KERN_WARNING "%s: retrying using single "
@@ -388,14 +384,11 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                                disable_multi = 1;
                                continue;
                        }
-                       
                        status = get_card_status(card, req);
                } else if (disable_multi == 1) {
                        disable_multi = 0;
                }
-               #endif
 
-               #if 0 //[xjh] not printk,save time
                if (brq.cmd.error) {
                        printk(KERN_ERR "%s: error %d sending read/write "
                               "command, response %#x, card status %#x\n",
@@ -420,7 +413,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                               req->rq_disk->disk_name, brq.stop.error,
                               brq.stop.resp[0], status);
                }
-               #endif 
 
                if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
                        do {
@@ -453,7 +445,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                }
 
                if (brq.cmd.error || brq.stop.error || brq.data.error) {
-                       #if 1/*[xjh] do not retry with cmd17*/
                        if (rq_data_dir(req) == READ) {
                                /*
                                 * After an error, we redo I/O one sector at a
@@ -465,7 +456,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                                spin_unlock_irq(&md->lock);
                                continue;
                        }
-                       #endif
                        goto cmd_err;
                }
 
index 602b150163eebcbe87fd93ccdf0d1e4565d70a92..bdb165f93046f9cdce780a614ddafcc41f3cab91 100644 (file)
@@ -268,7 +268,6 @@ int mmc_add_card(struct mmc_card *card)
        return 0;
 }
 
-extern int sdmmc0_disable_Irq_ForRemoval;
 /*
  * Unregister a new MMC card with the driver model, and
  * (eventually) free it.
@@ -278,7 +277,6 @@ void mmc_remove_card(struct mmc_card *card)
 #ifdef CONFIG_DEBUG_FS
        mmc_remove_card_debugfs(card);
 #endif
-       unsigned long flags;
 
        if (mmc_card_present(card)) {
                if (mmc_host_is_spi(card->host)) {
@@ -288,13 +286,6 @@ void mmc_remove_card(struct mmc_card *card)
                        printk(KERN_INFO "%s: card %04x removed\n",
                                mmc_hostname(card->host), card->rca);
                }
-
-        if( !strncmp( mmc_hostname(card->host) ,"mmc0" , strlen("mmc0")) )
-        {
-                       local_irq_save(flags);
-            sdmmc0_disable_Irq_ForRemoval = 1; //close the IRQ for insertion or removal  
-            local_irq_restore(flags);
-        }
                device_del(&card->dev);
        }
 
index 231439a961e26cdc7e4b849ba4fee91d6919e2fe..fb25fd001f4a33672885789d0dbc7cd068af7391 100644 (file)
@@ -1059,7 +1059,7 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay)
 
 EXPORT_SYMBOL(mmc_detect_change);
 
-#if 0
+
 void mmc_rescan(struct work_struct *work)
 {
        struct mmc_host *host =
@@ -1154,102 +1154,6 @@ out:
        if (host->caps & MMC_CAP_NEEDS_POLL)
                mmc_schedule_delayed_work(&host->detect, HZ);
 }
-#else
-void mmc_rescan(struct work_struct *work)
-{
-       struct mmc_host *host =
-               container_of(work, struct mmc_host, detect.work);
-       u32 ocr;
-       int err;
-       int extend_wakelock = 0;
-
-       mmc_bus_get(host);
-       if(host->bus_ops == NULL)
-       {
-               /* detect a newly inserted card */
-
-               /*
-                * Only we can add a new handler, so it's safe to
-                * release the lock here.
-                */
-               mmc_bus_put(host);
-
-               if (host->ops->get_cd && host->ops->get_cd(host) == 0)
-                       goto out;
-
-               mmc_claim_host(host);
-
-               mmc_power_up(host);
-               mmc_go_idle(host);
-
-               mmc_send_if_cond(host, host->ocr_avail);
-
-               /*
-                * First we search for SDIO...
-                */
-               err = mmc_send_io_op_cond(host, 0, &ocr);
-               if (!err) {
-                       if (mmc_attach_sdio(host, ocr))
-                               mmc_power_off(host);
-                       extend_wakelock = 1;
-                       goto out;
-               }
-
-               /*
-                * ...then normal SD...
-                */
-               err = mmc_send_app_op_cond(host, 0, &ocr);
-               if (!err) {
-                       if (mmc_attach_sd(host, ocr))
-                               mmc_power_off(host);
-                       extend_wakelock = 1;
-                       goto out;
-               }
-
-               /*
-                * ...and finally MMC.
-                */
-               err = mmc_send_op_cond(host, 0, &ocr);
-               if (!err) {
-                       if (mmc_attach_mmc(host, ocr))
-                               mmc_power_off(host);
-                       extend_wakelock = 1;
-                       goto out;
-               }
-
-               mmc_release_host(host);
-               mmc_power_off(host);
-               
-       }
-       else
-       {
-               /* if there is a card registered, check whether it is still present */
-               if ((host->bus_ops != NULL) && host->bus_ops->detect && !host->bus_dead)
-                       host->bus_ops->detect(host);
-
-               /* If the card was removed the bus will be marked
-                * as dead - extend the wakelock so userspace
-                * can respond */
-               if (host->bus_dead)
-                       extend_wakelock = 1;
-
-               mmc_bus_put(host);
-               
-       }
-       
-
-
-out:
-       if (extend_wakelock)
-               wake_lock_timeout(&mmc_delayed_work_wake_lock, HZ / 2);
-       else
-               wake_unlock(&mmc_delayed_work_wake_lock);
-
-       if (host->caps & MMC_CAP_NEEDS_POLL)
-               mmc_schedule_delayed_work(&host->detect, HZ);
-}
-
-#endif
 
 void mmc_start_host(struct mmc_host *host)
 {
index 33747f583df89f8abf88b41eef123630b4aed22d..32af45c419f449d2f1cc9f07d058d667306a61a8 100644 (file)
@@ -660,9 +660,6 @@ static void mmc_attach_bus_ops(struct mmc_host *host)
 int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
 {
        int err;
-       
-       unsigned long flags;
-       extern int sdmmc0_disable_Irq_ForRemoval;
 
        BUG_ON(!host);
        WARN_ON(!host->claimed);
@@ -711,10 +708,6 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
        err = mmc_add_card(host->card);
        if (err)
                goto remove_card;
-       
-       local_irq_save(flags);
-       sdmmc0_disable_Irq_ForRemoval = 0; //close the IRQ for insertion or removal  
-       local_irq_restore(flags);
 
        return 0;
 
index c58ddc0eecc1a5e7ebc25f02cedaff43a5311710..0aa0cf0dde249e1431a0b824a4aab506bab9f5ff 100644 (file)
@@ -27,6 +27,29 @@ if SDMMC_RK2818
                        This supports the use of the SDMMC1 controller on rk2818 processors.
 endif
 
+config SDMMC_RK29
+       tristate "RK29 SDMMC controller suppport"
+       depends on ARCH_RK29
+       help
+               This selects the RK29 SDMMC controller.
+               SDMMC0 used for sd/mmc card, and SDMMC1 used for sdio.
+if SDMMC_RK29
+    comment "Now, there are two SDMMC controllers selected, SDMMC0 and SDMMC1."
+       config SDMMC0_RK29
+               tristate "RK29 SDMMC0 controller support(sdmmc)"
+               default y
+               depends on ARCH_RK29
+               help
+                       This supports the use of the SDMMC0 controller on Rk29 processors.
+       
+       config SDMMC1_RK29
+               tristate "RK29 SDMMC1 controller support(sdio)"
+               default y
+               depends on ARCH_RK29
+               help
+                       This supports the use of the SDMMC1 controller on Rk29 processors.
+endif
+
 config MMC_ARMMMCI
        tristate "ARM AMBA Multimedia Card Interface support"
        depends on ARM_AMBA
index cf31850676a4cfa7f50abd742ee8996e84932f7b..8230c5f949b1908db5fd4956d88ebd47e521148a 100644 (file)
@@ -6,6 +6,7 @@ ifeq ($(CONFIG_MMC_DEBUG),y)
        EXTRA_CFLAGS            += -DDEBUG
 endif
 
+obj-$(CONFIG_SDMMC_RK29)       += rk29_sdmmc.o
 obj-$(CONFIG_SDMMC_RK2818)     += rk2818-sdmmc.o
 obj-$(CONFIG_MMC_ARMMMCI)      += mmci.o
 obj-$(CONFIG_MMC_PXA)          += pxamci.o
index 15a12f4a5d55a5bf78813d45058a5ea1575eeccc..2422958b6fe65a06e2ca8c2993724f2573a7c27d 100755 (executable)
 
 /* Specifies how often in millisecs to poll for card removal-insertion changes
  * when the timer switch is open */
-#define RK28_SDMMC0_SWITCH_POLL_DELAY 3500
+#define RK_SDMMC0_SWITCH_POLL_DELAY 3500
 
 
 #endif
diff --git a/drivers/mmc/host/rk29_sdmmc.c b/drivers/mmc/host/rk29_sdmmc.c
new file mode 100644 (file)
index 0000000..6e1339e
--- /dev/null
@@ -0,0 +1,1484 @@
+/* drivers/mmc/host/rk29_sdmmc.c
+ *
+ * Copyright (C) 2010 ROCKCHIP, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+#include <linux/blkdev.h>
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <linux/seq_file.h>
+#include <linux/stat.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+
+#include <mach/board.h>
+#include <mach/rk29_iomap.h>
+#include <mach/gpio.h>
+#include <asm/dma.h>
+#include <mach/rk29-dma-pl330.h>
+#include <asm/scatterlist.h>
+
+#include "rk2818-sdmmc.h"
+
+#if 0
+#define DBG(x...) printk(KERN_INFO x)
+#else
+#define DBG(x...) do { } while (0)
+#endif
+
+#define RK29_SDMMC_DATA_ERROR_FLAGS    (SDMMC_INT_DTO | SDMMC_INT_DCRC | SDMMC_INT_HTO | SDMMC_INT_SBE | SDMMC_INT_EBE)
+#define RK29_SDMMC_CMD_ERROR_FLAGS     (SDMMC_INT_RTO | SDMMC_INT_RCRC | SDMMC_INT_RE | SDMMC_INT_HLE)
+#define RK29_SDMMC_ERROR_FLAGS         (RK29_SDMMC_DATA_ERROR_FLAGS | RK29_SDMMC_CMD_ERROR_FLAGS | SDMMC_INT_HLE)
+#define RK29_SDMMC_SEND_STATUS         1
+#define RK29_SDMMC_RECV_STATUS         2
+#define RK29_SDMMC_DMA_THRESHOLD       16
+
+enum {
+       EVENT_CMD_COMPLETE = 0,
+       EVENT_XFER_COMPLETE,
+       EVENT_DATA_COMPLETE,
+       EVENT_DATA_ERROR,
+       EVENT_XFER_ERROR
+};
+
+enum rk29_sdmmc_state {
+       STATE_IDLE = 0,
+       STATE_SENDING_CMD,
+       STATE_SENDING_DATA,
+       STATE_DATA_BUSY,
+       STATE_SENDING_STOP,
+       STATE_DATA_ERROR,
+};
+
+static struct rk29_dma_client rk29_dma_sdmmc0_client = {
+        .name = "rk29-dma-sdmmc0",
+};
+
+static struct rk29_dma_client rk29_dma_sdio1_client = {
+        .name = "rk29-dma-sdio1",
+};
+
+struct rk29_sdmmc {
+       spinlock_t              lock;
+       void __iomem            *regs;
+       struct clk              *clk;
+       struct scatterlist      *sg;
+       unsigned int            pio_offset;
+       struct mmc_request      *mrq;
+       struct mmc_request      *curr_mrq;
+       struct mmc_command      *cmd;
+       struct mmc_data         *data;
+       int                     dma_chn;
+       //dma_addr_t            sg_dma;
+       //dma_sg_ll_t           *sg_cpu;
+       unsigned int    use_dma:1;
+       char                    dma_name[8];
+       u32                     cmd_status;
+       u32                     data_status;
+       u32                     stop_cmdr;
+       u32                     dir_status;
+       struct tasklet_struct   tasklet;
+       unsigned long           pending_events;
+       unsigned long           completed_events;
+       enum rk29_sdmmc_state   state;
+       struct list_head        queue;
+       u32                     bus_hz;
+       u32                     current_speed;
+       struct platform_device  *pdev;
+       struct mmc_host         *mmc;
+       u32                     ctype;
+       struct list_head        queue_node;
+       unsigned int            clock;
+       unsigned long           flags;
+#define RK29_SDMMC_CARD_PRESENT        0
+#define RK29_SDMMC_CARD_NEED_INIT      1
+#define RK29_SDMMC_SHUTDOWN            2
+       int                     id;
+       int                     irq;
+       struct timer_list       detect_timer;
+};
+
+#define rk29_sdmmc_test_and_clear_pending(host, event)         \
+       test_and_clear_bit(event, &host->pending_events)
+#define rk29_sdmmc_set_completed(host, event)                  \
+       set_bit(event, &host->completed_events)
+
+#define rk29_sdmmc_set_pending(host, event)                            \
+       set_bit(event, &host->pending_events)
+
+static void rk29_sdmmc_write(unsigned char  __iomem    *regbase, unsigned int regOff,unsigned int val)
+{
+       __raw_writel(val,regbase + regOff);
+}
+
+static unsigned int rk29_sdmmc_read(unsigned char  __iomem     *regbase, unsigned int regOff)
+{
+       return __raw_readl(regbase + regOff);
+}
+
+
+#if defined (CONFIG_DEBUG_FS)
+/*
+ * The debugfs stuff below is mostly optimized away when
+ * CONFIG_DEBUG_FS is not set.
+ */
+static int rk29_sdmmc_req_show(struct seq_file *s, void *v)
+{
+       struct rk29_sdmmc       *host = s->private;
+       struct mmc_request      *mrq;
+       struct mmc_command      *cmd;
+       struct mmc_command      *stop;
+       struct mmc_data         *data;
+
+       /* Make sure we get a consistent snapshot */
+       spin_lock(&host->lock);
+       mrq = host->mrq;
+
+       if (mrq) {
+               cmd = mrq->cmd;
+               data = mrq->data;
+               stop = mrq->stop;
+
+               if (cmd)
+                       seq_printf(s,
+                               "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
+                               cmd->opcode, cmd->arg, cmd->flags,
+                               cmd->resp[0], cmd->resp[1], cmd->resp[2],
+                               cmd->resp[2], cmd->error);
+               if (data)
+                       seq_printf(s, "DATA %u / %u * %u flg %x err %d\n",
+                               data->bytes_xfered, data->blocks,
+                               data->blksz, data->flags, data->error);
+               if (stop)
+                       seq_printf(s,
+                               "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
+                               stop->opcode, stop->arg, stop->flags,
+                               stop->resp[0], stop->resp[1], stop->resp[2],
+                               stop->resp[2], stop->error);
+       }
+
+       spin_unlock(&host->lock);
+
+       return 0;
+}
+
+static int rk29_sdmmc_req_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, rk29_sdmmc_req_show, inode->i_private);
+}
+
+static const struct file_operations rk29_sdmmc_req_fops = {
+       .owner          = THIS_MODULE,
+       .open           = rk29_sdmmc_req_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+#define SDMMC_CTRL            (0x000)
+#define SDMMC_PWREN           (0x004)
+#define SDMMC_CLKDIV          (0x008)
+#define SDMMC_CLKSRC          (0x00c)
+#define SDMMC_CLKENA          (0x010)
+#define SDMMC_TMOUT           (0x014)
+#define SDMMC_CTYPE           (0x018)
+#define SDMMC_BLKSIZ          (0x01c)
+#define SDMMC_BYTCNT          (0x020)
+#define SDMMC_INTMASK         (0x024)
+#define SDMMC_CMDARG          (0x028)
+#define SDMMC_CMD             (0x02c)
+#define SDMMC_RESP0           (0x030)
+#define SDMMC_RESP1           (0x034)
+#define SDMMC_RESP2           (0x038)
+#define SDMMC_RESP3           (0x03c)
+#define SDMMC_MINTSTS         (0x040)
+#define SDMMC_RINTSTS         (0x044)
+#define SDMMC_STATUS          (0x048)
+#define SDMMC_FIFOTH          (0x04c)
+#define SDMMC_CDETECT         (0x050)
+#define SDMMC_WRTPRT          (0x054)
+#define SDMMC_TCBCNT          (0x05c)
+#define SDMMC_TBBCNT          (0x060)
+#define SDMMC_DEBNCE          (0x064)
+static int rk29_sdmmc_regs_show(struct seq_file *s, void *v)
+{
+       struct rk29_sdmmc       *host = s->private;
+
+       seq_printf(s, "SDMMC_CTRL:   \t0x%08x\n", SDMMC_CTRL);
+       seq_printf(s, "SDMMC_PWREN:  \t0x%08x\n", SDMMC_PWREN);
+       seq_printf(s, "SDMMC_CLKDIV: \t0x%08x\n", SDMMC_CLKDIV);
+       seq_printf(s, "SDMMC_CLKSRC: \t0x%08x\n", SDMMC_CLKSRC);
+       seq_printf(s, "SDMMC_CLKENA: \t0x%08x\n", SDMMC_CLKENA);
+       seq_printf(s, "SDMMC_TMOUT:  \t0x%08x\n", SDMMC_TMOUT);
+       seq_printf(s, "SDMMC_CTYPE:  \t0x%08x\n", SDMMC_CTYPE);
+       seq_printf(s, "SDMMC_BLKSIZ: \t0x%08x\n", SDMMC_BLKSIZ);
+       seq_printf(s, "SDMMC_BYTCNT: \t0x%08x\n", SDMMC_BYTCNT);
+       seq_printf(s, "SDMMC_INTMASK:\t0x%08x\n", SDMMC_INTMASK);
+       seq_printf(s, "SDMMC_CMDARG: \t0x%08x\n", SDMMC_CMDARG);
+       seq_printf(s, "SDMMC_CMD:    \t0x%08x\n", SDMMC_CMD);
+       seq_printf(s, "SDMMC_RESP0:  \t0x%08x\n", SDMMC_RESP0);
+       seq_printf(s, "SDMMC_RESP1:  \t0x%08x\n", SDMMC_RESP1);
+       seq_printf(s, "SDMMC_RESP2:  \t0x%08x\n", SDMMC_RESP2);
+       seq_printf(s, "SDMMC_RESP3:  \t0x%08x\n", SDMMC_RESP3);
+       seq_printf(s, "SDMMC_MINTSTS:\t0x%08x\n", SDMMC_MINTSTS);
+       seq_printf(s, "SDMMC_RINTSTS:\t0x%08x\n", SDMMC_RINTSTS);
+       seq_printf(s, "SDMMC_STATUS: \t0x%08x\n", SDMMC_STATUS);
+       seq_printf(s, "SDMMC_FIFOTH: \t0x%08x\n", SDMMC_FIFOTH);
+       seq_printf(s, "SDMMC_CDETECT:\t0x%08x\n", SDMMC_CDETECT);
+       seq_printf(s, "SDMMC_WRTPRT: \t0x%08x\n", SDMMC_WRTPRT);
+       seq_printf(s, "SDMMC_TCBCNT: \t0x%08x\n", SDMMC_TCBCNT);
+       seq_printf(s, "SDMMC_TBBCNT: \t0x%08x\n", SDMMC_TBBCNT);
+       seq_printf(s, "SDMMC_DEBNCE: \t0x%08x\n", SDMMC_DEBNCE);
+
+       return 0;
+}
+
+static int rk29_sdmmc_regs_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, rk29_sdmmc_regs_show, inode->i_private);
+}
+
+static const struct file_operations rk29_sdmmc_regs_fops = {
+       .owner          = THIS_MODULE,
+       .open           = rk29_sdmmc_regs_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static void rk29_sdmmc_init_debugfs(struct rk29_sdmmc *host)
+{
+       struct mmc_host         *mmc = host->mmc;
+       struct dentry           *root;
+       struct dentry           *node;
+
+       root = mmc->debugfs_root;
+       if (!root)
+               return;
+
+       node = debugfs_create_file("regs", S_IRUSR, root, host,
+                       &rk29_sdmmc_regs_fops);
+       if (IS_ERR(node))
+               return;
+       if (!node)
+               goto err;
+
+       node = debugfs_create_file("req", S_IRUSR, root, host, &rk29_sdmmc_req_fops);
+       if (!node)
+               goto err;
+
+       node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
+       if (!node)
+               goto err;
+
+       node = debugfs_create_x32("pending_events", S_IRUSR, root,
+                                    (u32 *)&host->pending_events);
+       if (!node)
+               goto err;
+
+       node = debugfs_create_x32("completed_events", S_IRUSR, root,
+                                    (u32 *)&host->completed_events);
+       if (!node)
+               goto err;
+
+       return;
+
+err:
+       dev_err(&mmc->class_dev, "failed to initialize debugfs for host\n");
+}
+#endif
+
+static inline unsigned ns_to_clocks(unsigned clkrate, unsigned ns)
+{
+       u32 clks;
+       if (clkrate > 1000000)
+               clks =  (ns * (clkrate / 1000000) + 999) / 1000;
+       else
+               clks =  ((ns/1000) * (clkrate / 1000) + 999) / 1000;
+
+       return clks;
+}
+
+static void rk29_sdmmc_set_timeout(struct rk29_sdmmc *host,struct mmc_data *data)
+{
+       unsigned timeout;
+
+       timeout = ns_to_clocks(host->clock, data->timeout_ns) + data->timeout_clks;
+
+       rk29_sdmmc_write(host->regs, SDMMC_TMOUT, (timeout << 8) | (70));
+}
+
+static u32 rk29_sdmmc_prepare_command(struct mmc_host *mmc,
+                                struct mmc_command *cmd)
+{
+       struct mmc_data *data;
+       u32             cmdr;
+       
+       cmd->error = -EINPROGRESS;
+       cmdr = cmd->opcode;
+
+       if(cmdr == 12) 
+               cmdr |= SDMMC_CMD_STOP;
+       else 
+               cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
+
+       if (cmd->flags & MMC_RSP_PRESENT) {
+               cmdr |= SDMMC_CMD_RESP_EXP; // expect the respond, need to set this bit
+               if (cmd->flags & MMC_RSP_136) 
+                       cmdr |= SDMMC_CMD_RESP_LONG; // expect long respond
+               
+               if(cmd->flags & MMC_RSP_CRC) 
+                       cmdr |= SDMMC_CMD_RESP_CRC;
+       }
+
+       data = cmd->data;
+       if (data) {
+               cmdr |= SDMMC_CMD_DAT_EXP;
+               if (data->flags & MMC_DATA_STREAM) 
+                       cmdr |= SDMMC_CMD_STRM_MODE; //  set stream mode
+               if (data->flags & MMC_DATA_WRITE) 
+                   cmdr |= SDMMC_CMD_DAT_WR;
+       }
+       return cmdr;
+}
+
+
+static void rk29_sdmmc_start_command(struct rk29_sdmmc *host,
+               struct mmc_command *cmd, u32 cmd_flags)
+{
+       int tmo = 50;
+       host->cmd = cmd;
+       dev_vdbg(&host->pdev->dev,
+                       "start cmd:%d ARGR=0x%08x CMDR=0x%08x\n",
+                       cmd->opcode, cmd->arg, cmd_flags);
+       rk29_sdmmc_write(host->regs, SDMMC_CMDARG, cmd->arg); // write to SDMMC_CMDARG register
+       rk29_sdmmc_write(host->regs, SDMMC_CMD, cmd_flags | SDMMC_CMD_START); // write to SDMMC_CMD register
+
+       /* wait until CIU accepts the command */
+       while (--tmo && (rk29_sdmmc_read(host->regs, SDMMC_CMD) & SDMMC_CMD_START)) 
+               cpu_relax();
+}
+
+static void send_stop_cmd(struct rk29_sdmmc *host, struct mmc_data *data)
+{
+       rk29_sdmmc_start_command(host, data->stop, host->stop_cmdr);
+}
+
+
+#ifdef USE_DMA
+
+static void rk29_sdmmc_dma_cleanup(struct rk29_sdmmc *host)
+{
+       struct mmc_data                 *data = host->data;
+
+       if (data) 
+               dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len,
+                    ((data->flags & MMC_DATA_WRITE)
+                     ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
+}
+
+static void rk29_sdmmc_stop_dma(struct rk29_sdmmc *host)
+{
+       if (host->dma_chn > 0) {
+               dma_stop_channel(host->dma_chn);
+               rk29_sdmmc_dma_cleanup(host);
+       } else {
+               /* Data transfer was stopped by the interrupt handler */
+               rk29_sdmmc_set_pending(host, EVENT_XFER_COMPLETE);
+       }
+}
+
+/* This function is called by the DMA driver from tasklet context. */
+static void rk29_sdmmc_dma_complete(int chn, dma_irq_type_t type, void *arg)
+{
+       struct rk29_sdmmc       *host = arg;
+       struct mmc_data         *data = host->data;
+
+       dev_vdbg(&host->pdev->dev, "DMA complete\n");
+
+       spin_lock(&host->lock);
+       rk29_sdmmc_dma_cleanup(host);
+
+       /*
+        * If the card was removed, data will be NULL. No point trying
+        * to send the stop command or waiting for NBUSY in this case.
+        */
+       if (data) {
+               rk29_sdmmc_set_pending(host, EVENT_XFER_COMPLETE);
+               tasklet_schedule(&host->tasklet);
+       }
+       spin_unlock(&host->lock);
+}
+
+static int rk29_sdmmc_submit_data_dma(struct rk29_sdmmc *host, struct mmc_data *data)
+{
+       struct scatterlist              *sg;
+       unsigned int                    i, direction, sg_len;
+       unsigned int                    j, trans_len;
+
+       /* If we don't have a channel, we can't do DMA */
+       if (host->dma_chn < 0)
+               return -ENODEV;
+
+       /*
+        * We don't do DMA on "complex" transfers, i.e. with
+        * non-word-aligned buffers or lengths. Also, we don't bother
+        * with all the DMA setup overhead for short transfers.
+        */
+       if (data->blocks * data->blksz < RK29_SDMMC_DMA_THRESHOLD)
+               return -EINVAL;
+       if (data->blksz & 3)
+               return -EINVAL;
+
+       for_each_sg(data->sg, sg, data->sg_len, i) {
+               if (sg->offset & 3 || sg->length & 3)
+                       return -EINVAL;
+       }
+
+       if (data->flags & MMC_DATA_READ)
+               direction = DMA_FROM_DEVICE;
+       else
+               direction = DMA_TO_DEVICE;
+
+       sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len,
+                                  direction);
+
+       dev_vdbg(&host->pdev->dev, "sd sg_cpu: 0x%08x sg_dma:0x%08x sg_len:%d \n",
+               (u32)host->sg_cpu, (u32)host->sg_dma, sg_len);
+
+       for (i = 0, j = 0; i < sg_len; i++) {
+               unsigned int length = sg_dma_len(&data->sg[i]);
+               u32 mem_addr = sg_dma_address(&data->sg[i]);
+
+               while (length) {
+
+                       host->sg_cpu[j].setup.cfg = DMA_CFG_CMP_CH_EN | DMA_CFG_CMP_CH_NR(host->dma_chn);
+
+                       if (data->flags & MMC_DATA_READ) {
+                               host->sg_cpu[j].setup.src_address = SDMMC_DATA_ADR;
+                               host->sg_cpu[j].setup.dest_address = mem_addr;
+                               host->sg_cpu[j].setup.cfg |= DMA_CFG_RD_SLV_NR(DMA_SLV_SDMMC);
+                       } else {
+                               host->sg_cpu[j].setup.src_address = mem_addr;
+                               host->sg_cpu[j].setup.dest_address = SDMMC_DATA_ADR;
+                               host->sg_cpu[j].setup.cfg |= DMA_CFG_WR_SLV_NR(DMA_SLV_SDMMC);
+                       }
+                       host->sg_cpu[j].next_entry = host->sg_dma + (j + 1) *
+                                               sizeof(dma_sg_ll_t);
+
+                       if (trans_len > DMA_MAX_TRANSFERS) {
+                               trans_len = DMA_MAX_TRANSFERS;
+                               length -= (DMA_MAX_TRANSFERS + 1) << 2;
+                               mem_addr += ((DMA_MAX_TRANSFERS + 1) << 2);
+                       }
+                       else {
+                               length = 0;
+                       }
+
+                       host->sg_cpu[j].setup.trans_length = trans_len;
+
+                       dev_vdbg(&host->pdev->dev, "sd src: 0x%08x dest:0x%08x cfg:0x%08x nxt:0x%08x len:%d \n",
+                               host->sg_cpu[j].setup.src_address, host->sg_cpu[j].setup.dest_address,
+                               host->sg_cpu[j].setup.cfg, host->sg_cpu[j].next_entry,
+                               host->sg_cpu[j].setup.trans_length);
+
+                       /* move to next transfer descriptor */
+                       j++;
+               }
+       }
+       host->sg_cpu[j].setup.src_address = host->sg_dma;
+       host->sg_cpu[j].setup.dest_address = DMACH_SOFT_INT_PHYS;
+       host->sg_cpu[j].setup.trans_length = 1;
+       host->sg_cpu[j].setup.cfg = 0;
+       // disable irq of RX & TX, let DMA handle it
+       //SDMMC_INTMASK &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR);
+       ///SDMMC_CTRL |= SDMMC_CTRL_DMA_ENABLE; // enable dma
+       rk29_sdmmc_write(host->regs, SDMMC_CTRL, (rk29_sdmmc_read(host->regs, SDMMC_CTRL))|SDMMC_CTRL_DMA_ENABLE);
+       dma_prog_sg_channel(host->dma_chn, host->sg_dma);
+       wmb();
+       /* Go! */
+       dma_start_channel(host->dma_chn);
+
+       return 0;
+}
+
+#else
+static int rk29_sdmmc_submit_data_dma(struct rk29_sdmmc *host, struct mmc_data *data)
+{
+       return -ENOSYS;
+}
+
+static void rk29_sdmmc_stop_dma(struct rk29_sdmmc *host)
+{
+       /* Data transfer was stopped by the interrupt handler */
+       rk29_sdmmc_set_pending(host, EVENT_XFER_COMPLETE);
+       
+}
+#endif
+
+static void rk29_sdmmc_submit_data(struct rk29_sdmmc *host, struct mmc_data *data)
+{
+       data->error = -EINPROGRESS;
+
+       WARN_ON(host->data);
+       host->sg = NULL;
+       host->data = data;
+
+       if (rk29_sdmmc_submit_data_dma(host, data)) {
+               host->sg = data->sg;
+               host->pio_offset = 0;
+               if (data->flags & MMC_DATA_READ)
+                       host->dir_status = RK29_SDMMC_RECV_STATUS;
+               else 
+                       host->dir_status = RK29_SDMMC_SEND_STATUS;
+
+               rk29_sdmmc_write(host->regs, SDMMC_CTRL, (rk29_sdmmc_read(host->regs, SDMMC_CTRL))&(~SDMMC_CTRL_DMA_ENABLE));
+       }
+
+}
+
+static void sdmmc_send_cmd(struct rk29_sdmmc *host, unsigned int cmd, int arg)
+{
+       int tmo = 10000;
+       
+       rk29_sdmmc_write(host->regs, SDMMC_CMDARG, arg);
+       rk29_sdmmc_write(host->regs, SDMMC_CMD, SDMMC_CMD_START | cmd);         
+       while (--tmo && readl(host->regs + SDMMC_CMD) & SDMMC_CMD_START); 
+       if(!tmo) {
+               printk("%s %d set cmd register timeout error!!!\n",__FUNCTION__,__LINE__);
+       }
+}
+
+void rk29_sdmmc_setup_bus(struct rk29_sdmmc *host)
+{
+       u32 div;
+
+       if (host->clock != host->current_speed) {
+               div  = (((host->bus_hz + (host->bus_hz / 5)) / host->clock)) >> 1;
+               
+               /* store the actual clock for calculations */
+               host->clock = (host->bus_hz / div) >> 1;
+               /* disable clock */
+               rk29_sdmmc_write(host->regs, SDMMC_CLKENA, 0);
+               rk29_sdmmc_write(host->regs, SDMMC_CLKSRC,0);
+               /* inform CIU */
+               sdmmc_send_cmd(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
+               /* set clock to desired speed */
+               rk29_sdmmc_write(host->regs, SDMMC_CLKDIV, div);
+               /* inform CIU */
+               sdmmc_send_cmd(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
+               /* enable clock */
+               rk29_sdmmc_write(host->regs, SDMMC_CLKENA, SDMMC_CLKEN_ENABLE);
+               /* inform CIU */
+               sdmmc_send_cmd(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
+
+               host->current_speed = host->clock;
+       }
+
+       /* Set the current  bus width */
+       rk29_sdmmc_write(host->regs, SDMMC_CTYPE, host->ctype);
+}
+
+static void rk29_sdmmc_start_request(struct rk29_sdmmc *host)
+{
+       struct mmc_request      *mrq;
+       struct mmc_command      *cmd;
+       struct mmc_data         *data;
+       u32                     cmdflags;
+
+       mrq = host->curr_mrq;
+
+       /* Slot specific timing and width adjustment */
+       rk29_sdmmc_setup_bus(host);
+       host->pending_events = 0;
+       host->completed_events = 0;
+       host->data_status = 0;
+
+       data = mrq->data;
+       if (data) {
+               rk29_sdmmc_set_timeout(host,data);
+               rk29_sdmmc_write(host->regs, SDMMC_BYTCNT,data->blksz*data->blocks);
+               rk29_sdmmc_write(host->regs, SDMMC_BLKSIZ,data->blksz);
+       }
+
+       cmd = mrq->cmd;
+       cmdflags = rk29_sdmmc_prepare_command(host->mmc, cmd);
+
+       if (unlikely(test_and_clear_bit(RK29_SDMMC_CARD_NEED_INIT, &host->flags))) 
+           cmdflags |= SDMMC_CMD_INIT; //this is the first command, let set send the initializtion clock
+       
+       if (data) //we may need to move this code to mci_start_command
+               rk29_sdmmc_submit_data(host, data);
+
+       rk29_sdmmc_start_command(host, cmd, cmdflags);
+
+       if (mrq->stop) 
+               host->stop_cmdr = rk29_sdmmc_prepare_command(host->mmc, mrq->stop);
+       
+}
+
+static void rk29_sdmmc_queue_request(struct rk29_sdmmc *host,struct mmc_request *mrq)
+{
+       spin_lock(&host->lock);
+       host->mrq = mrq;
+       if (host->state == STATE_IDLE) {
+               host->state = STATE_SENDING_CMD;
+               rk29_sdmmc_start_request(host);
+       } else {
+               list_add_tail(&host->queue_node, &host->queue);
+       }
+       spin_unlock(&host->lock);
+}
+
+
+static void rk29_sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       struct rk29_sdmmc *host = mmc_priv(mmc);
+
+       WARN_ON(host->mrq);
+
+       if (!test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags)) {
+               mrq->cmd->error = -ENOMEDIUM;
+               mmc_request_done(mmc, mrq);
+               return;
+       }
+
+       rk29_sdmmc_queue_request(host,mrq);
+}
+
+static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct rk29_sdmmc *host = mmc_priv(mmc);;
+
+       host->ctype = 0; // set default 1 bit mode
+       switch (ios->bus_width) {
+       case MMC_BUS_WIDTH_1:
+               host->ctype = 0;
+               break;
+       case MMC_BUS_WIDTH_4:
+               host->ctype = SDMMC_CTYPE_4BIT;
+               break;
+       }
+
+       if (ios->clock) {
+               spin_lock(&host->lock);
+               /*
+                * Use mirror of ios->clock to prevent race with mmc
+                * core ios update when finding the minimum.
+                */
+               host->clock = ios->clock;
+
+               spin_unlock(&host->lock);
+       } else {
+               spin_lock(&host->lock);
+               host->clock = 0;
+               spin_unlock(&host->lock);
+       }
+
+       switch (ios->power_mode) {
+       case MMC_POWER_UP:
+               set_bit(RK29_SDMMC_CARD_NEED_INIT, &host->flags);
+               rk29_sdmmc_write(host->regs, SDMMC_PWREN, 1);
+               break;
+       default:
+               break;
+       }
+}
+
+static int rk29_sdmmc_get_ro(struct mmc_host *mmc)
+{
+       struct rk29_sdmmc *host = mmc_priv(mmc);
+       u32 wrtprt = rk29_sdmmc_read(host->regs, SDMMC_WRTPRT);
+
+       return (wrtprt & SDMMC_WRITE_PROTECT)?1:0;
+}
+
+
+static int rk29_sdmmc_get_cd(struct mmc_host *mmc)
+{
+       struct rk29_sdmmc *host = mmc_priv(mmc);
+       u32 cdetect = rk29_sdmmc_read(host->regs, SDMMC_CDETECT);
+
+       return (cdetect & SDMMC_CARD_DETECT_N)?0:1;
+}
+
+static void rk29_sdmmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+       u32 intmask;
+       unsigned long flags;
+       struct rk29_sdmmc *host = mmc_priv(mmc);
+       
+       spin_lock_irqsave(&host->lock, flags);
+       intmask = rk29_sdmmc_read(host->regs, SDMMC_INTMASK);
+       if(enable)
+               rk29_sdmmc_write(host->regs, SDMMC_INTMASK, intmask | SDMMC_INT_SDIO);
+       else
+               rk29_sdmmc_write(host->regs, SDMMC_INTMASK, intmask & ~SDMMC_INT_SDIO);
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static const struct mmc_host_ops rk29_sdmmc_ops[] = {
+       {
+               .request        = rk29_sdmmc_request,
+               .set_ios        = rk29_sdmmc_set_ios,
+               .get_ro         = rk29_sdmmc_get_ro,
+               .get_cd         = rk29_sdmmc_get_cd,
+       },
+       {
+               .request        = rk29_sdmmc_request,
+               .set_ios        = rk29_sdmmc_set_ios,
+               .enable_sdio_irq = rk29_sdmmc_enable_sdio_irq,
+       },
+};
+
+static void rk29_sdmmc_request_end(struct rk29_sdmmc *host, struct mmc_request *mrq)
+       __releases(&host->lock)
+       __acquires(&host->lock)
+{
+       struct mmc_host         *prev_mmc = host->mmc;
+       
+       WARN_ON(host->cmd || host->data);
+       host->curr_mrq = NULL;
+       if (!list_empty(&host->queue)) {
+               host = list_entry(host->queue.next,
+                               struct rk29_sdmmc, queue_node);
+               list_del(&host->queue_node);
+               host->state = STATE_SENDING_CMD;
+               rk29_sdmmc_start_request(host);
+       } else {
+               dev_vdbg(&host->pdev->dev, "list empty\n");
+               host->state = STATE_IDLE;
+       }
+
+       spin_unlock(&host->lock);
+       mmc_request_done(prev_mmc, mrq);
+
+       spin_lock(&host->lock);
+}
+
+static void rk29_sdmmc_command_complete(struct rk29_sdmmc *host,
+                       struct mmc_command *cmd)
+{
+       u32             status = host->cmd_status;
+
+       host->cmd_status = 0;
+
+       if(cmd->flags & MMC_RSP_PRESENT) {
+
+           if(cmd->flags & MMC_RSP_136) {
+
+               /* Read the response from the card (up to 16 bytes).
+                * RK29 SDMMC controller saves bits 127-96 in SDMMC_RESP3
+                * for easy parsing. But the UNSTUFF_BITS macro in core/mmc.c
+                * core/sd.c expect those bits be in resp[0]. Hence
+                * reverse the response word order.
+                */
+               cmd->resp[3] = rk29_sdmmc_read(host->regs, SDMMC_RESP0);
+               cmd->resp[2] = rk29_sdmmc_read(host->regs, SDMMC_RESP1);
+               cmd->resp[1] = rk29_sdmmc_read(host->regs, SDMMC_RESP2);
+               cmd->resp[0] = rk29_sdmmc_read(host->regs, SDMMC_RESP3);
+           } else {
+               cmd->resp[0] = rk29_sdmmc_read(host->regs, SDMMC_RESP0);
+               cmd->resp[1] = 0;
+               cmd->resp[2] = 0;
+               cmd->resp[3] = 0;
+           }
+       }
+
+       if (status & SDMMC_INT_RTO)
+               cmd->error = -ETIMEDOUT;
+       else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC))
+               cmd->error = -EILSEQ;
+       else if (status & SDMMC_INT_RE)
+               cmd->error = -EIO;
+       else
+               cmd->error = 0;
+
+       if (cmd->error) {
+               dev_vdbg(&host->pdev->dev,
+                       "command error: status=0x%08x resp=0x%08x\n"
+                       "cmd=0x%08x arg=0x%08x flg=0x%08x err=%d\n", 
+                       status, cmd->resp[0], 
+                       cmd->opcode, cmd->arg, cmd->flags, cmd->error);
+
+               if (cmd->data) {
+                       host->data = NULL;
+                       rk29_sdmmc_stop_dma(host);
+               }
+       } 
+}
+
+static void rk29_sdmmc_tasklet_func(unsigned long priv)
+{
+       struct rk29_sdmmc       *host = (struct rk29_sdmmc *)priv;
+       struct mmc_request      *mrq = host->curr_mrq;
+       struct mmc_data         *data = host->data;
+       struct mmc_command      *cmd = host->cmd;
+       enum rk29_sdmmc_state   state = host->state;
+       enum rk29_sdmmc_state   prev_state;
+       u32                     status;
+
+       spin_lock(&host->lock);
+
+       state = host->state;
+
+       do {
+               prev_state = state;
+
+               switch (state) {
+               case STATE_IDLE:
+                       break;
+
+               case STATE_SENDING_CMD:
+                       if (!rk29_sdmmc_test_and_clear_pending(host,
+                                               EVENT_CMD_COMPLETE))
+                               break;
+
+                       host->cmd = NULL;
+                       rk29_sdmmc_set_completed(host, EVENT_CMD_COMPLETE);
+                       rk29_sdmmc_command_complete(host, mrq->cmd);
+                       if (!mrq->data || cmd->error) {
+                               rk29_sdmmc_request_end(host, host->curr_mrq);
+                               goto unlock;
+                       }
+
+                       prev_state = state = STATE_SENDING_DATA;
+                       /* fall through */
+
+               case STATE_SENDING_DATA:
+                       if (rk29_sdmmc_test_and_clear_pending(host,
+                                               EVENT_DATA_ERROR)) {
+                               rk29_sdmmc_stop_dma(host);
+                               if (data->stop)
+                                       send_stop_cmd(host, data);
+                               state = STATE_DATA_ERROR;
+                               break;
+                       }
+
+                       if (!rk29_sdmmc_test_and_clear_pending(host,
+                                               EVENT_XFER_COMPLETE))
+                               break;
+
+                       rk29_sdmmc_set_completed(host, EVENT_XFER_COMPLETE);
+                       prev_state = state = STATE_DATA_BUSY;
+                       /* fall through */
+
+               case STATE_DATA_BUSY:
+                       if (!rk29_sdmmc_test_and_clear_pending(host,
+                                               EVENT_DATA_COMPLETE))
+                               break;
+
+                       host->data = NULL;
+                       rk29_sdmmc_set_completed(host, EVENT_DATA_COMPLETE);
+                       status = host->data_status;
+
+                       if (unlikely(status & RK29_SDMMC_DATA_ERROR_FLAGS)) {
+                               if (status & SDMMC_INT_DTO) {
+                                       dev_err(&host->pdev->dev,
+                                                       "data timeout error\n");
+                                       data->error = -ETIMEDOUT;
+                               } else if (status & SDMMC_INT_DCRC) {
+                                       dev_err(&host->pdev->dev,
+                                                       "data CRC error\n");
+                                       data->error = -EILSEQ;
+                               } else {
+                                       dev_err(&host->pdev->dev,
+                                               "data FIFO error (status=%08x)\n",
+                                               status);
+                                       data->error = -EIO;
+                               }
+                       }
+                       else {
+                               data->bytes_xfered = data->blocks * data->blksz;
+                               data->error = 0;
+                       }
+
+                       if (!data->stop) {
+                               rk29_sdmmc_request_end(host, host->curr_mrq);
+                               goto unlock;
+                       }
+
+                       prev_state = state = STATE_SENDING_STOP;
+                       if (!data->error)
+                               send_stop_cmd(host, data);
+                       /* fall through */
+
+               case STATE_SENDING_STOP:
+                       if (!rk29_sdmmc_test_and_clear_pending(host,
+                                               EVENT_CMD_COMPLETE))
+                               break;
+
+                       host->cmd = NULL;
+                       rk29_sdmmc_command_complete(host, mrq->stop);
+                       rk29_sdmmc_request_end(host, host->curr_mrq);
+                       goto unlock;
+               case STATE_DATA_ERROR:
+                       if (!rk29_sdmmc_test_and_clear_pending(host,
+                                               EVENT_XFER_COMPLETE))
+                               break;
+
+                       state = STATE_DATA_BUSY;
+                       break;
+               }
+       } while (state != prev_state);
+
+       host->state = state;
+
+unlock:
+       spin_unlock(&host->lock);
+
+}
+
+
+
+inline static void rk29_sdmmc_push_data(struct rk29_sdmmc *host, void *buf,int cnt)
+{
+    u32* pData = (u32*)buf;
+
+    if (cnt % 4 != 0) 
+           printk("error not align 4\n");
+
+    cnt = cnt >> 2;
+    while (cnt > 0) {
+        rk29_sdmmc_write(host->regs, SDMMC_DATA,*pData++);
+        cnt--;
+    }
+}
+
+inline static void rk29_sdmmc_pull_data(struct rk29_sdmmc *host,void *buf,int cnt)
+{
+    u32* pData = (u32*)buf;
+
+    if (cnt % 4 != 0) 
+           printk("error not align 4\n");
+    cnt = cnt >> 2;
+    while (cnt > 0) {
+        *pData++ = rk29_sdmmc_read(host->regs, SDMMC_DATA);
+        cnt--;
+    }
+}
+
+static void rk29_sdmmc_read_data_pio(struct rk29_sdmmc *host)
+{
+       struct scatterlist      *sg = host->sg;
+       void                    *buf = sg_virt(sg);
+       unsigned int            offset = host->pio_offset;
+       struct mmc_data         *data = host->data;
+       u32                     status;
+       unsigned int            nbytes = 0,len,old_len,count =0;
+
+       do {
+               len = SDMMC_GET_FCNT(rk29_sdmmc_read(host->regs, SDMMC_STATUS)) << 2;
+               if(count == 0) 
+                       old_len = len;
+               if (likely(offset + len <= sg->length)) {
+                       rk29_sdmmc_pull_data(host, (void *)(buf + offset),len);
+
+                       offset += len;
+                       nbytes += len;
+
+                       if (offset == sg->length) {
+                               flush_dcache_page(sg_page(sg));
+                               host->sg = sg = sg_next(sg);
+                               if (!sg)
+                                       goto done;
+                               offset = 0;
+                               buf = sg_virt(sg);
+                       }
+               } else {
+                       unsigned int remaining = sg->length - offset;
+                       rk29_sdmmc_pull_data(host, (void *)(buf + offset),remaining);
+                       nbytes += remaining;
+
+                       flush_dcache_page(sg_page(sg));
+                       host->sg = sg = sg_next(sg);
+                       if (!sg)
+                               goto done;
+                       offset = len - remaining;
+                       buf = sg_virt(sg);
+                       rk29_sdmmc_pull_data(host, buf,offset);
+                       nbytes += offset;
+               }
+
+               status = rk29_sdmmc_read(host->regs, SDMMC_MINTSTS);
+               rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_RXDR); // clear RXDR interrupt
+               if (status & RK29_SDMMC_DATA_ERROR_FLAGS) {
+                       host->data_status = status;
+                       data->bytes_xfered += nbytes;
+                       smp_wmb();
+                       rk29_sdmmc_set_pending(host, EVENT_DATA_ERROR);
+                       tasklet_schedule(&host->tasklet);
+                       return;
+               }
+               count ++;
+       } while (status & SDMMC_INT_RXDR); // if the RXDR is ready let read again
+       len = SDMMC_GET_FCNT(rk29_sdmmc_read(host->regs, SDMMC_STATUS));
+       host->pio_offset = offset;
+       data->bytes_xfered += nbytes;
+       return;
+
+done:
+       data->bytes_xfered += nbytes;
+       smp_wmb();
+       rk29_sdmmc_set_pending(host, EVENT_XFER_COMPLETE);
+}
+
+static void rk29_sdmmc_write_data_pio(struct rk29_sdmmc *host)
+{
+       struct scatterlist      *sg = host->sg;
+       void                    *buf = sg_virt(sg);
+       unsigned int            offset = host->pio_offset;
+       struct mmc_data         *data = host->data;
+       u32                     status;
+       unsigned int            nbytes = 0,len;
+
+       do {
+
+               len = SDMMC_FIFO_SZ - (SDMMC_GET_FCNT(rk29_sdmmc_read(host->regs, SDMMC_STATUS)) << 2);
+               if (likely(offset + len <= sg->length)) {
+                       rk29_sdmmc_push_data(host, (void *)(buf + offset),len);
+
+                       offset += len;
+                       nbytes += len;
+                       if (offset == sg->length) {
+                               host->sg = sg = sg_next(sg);
+                               if (!sg)
+                                       goto done;
+
+                               offset = 0;
+                               buf = sg_virt(sg);
+                       }
+               } else {
+                       unsigned int remaining = sg->length - offset;
+
+                       rk29_sdmmc_push_data(host, (void *)(buf + offset), remaining);
+                       nbytes += remaining;
+
+                       host->sg = sg = sg_next(sg);
+                       if (!sg) {
+                               goto done;
+                       }
+
+                       offset = len - remaining;
+                       buf = sg_virt(sg);
+                       rk29_sdmmc_push_data(host, (void *)buf, offset);
+                       nbytes += offset;
+               }
+
+               status = rk29_sdmmc_read(host->regs, SDMMC_MINTSTS);
+               rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_TXDR); // clear RXDR interrupt
+               if (status & RK29_SDMMC_DATA_ERROR_FLAGS) {
+                       host->data_status = status;
+                       data->bytes_xfered += nbytes;
+                       smp_wmb();
+                       rk29_sdmmc_set_pending(host, EVENT_DATA_ERROR);
+                       tasklet_schedule(&host->tasklet);
+                       return;
+               }
+       } while (status & SDMMC_INT_TXDR); // if TXDR, let write again
+
+       host->pio_offset = offset;
+       data->bytes_xfered += nbytes;
+
+       return;
+
+done:
+       data->bytes_xfered += nbytes;
+       smp_wmb();
+       rk29_sdmmc_set_pending(host, EVENT_XFER_COMPLETE);
+}
+
+static void rk29_sdmmc_cmd_interrupt(struct rk29_sdmmc *host, u32 status)
+{
+       if(!host->cmd_status) 
+               host->cmd_status = status;
+
+       smp_wmb();
+       rk29_sdmmc_set_pending(host, EVENT_CMD_COMPLETE);
+       tasklet_schedule(&host->tasklet);
+}
+
+static irqreturn_t rk29_sdmmc_interrupt(int irq, void *dev_id)
+{
+       struct rk29_sdmmc       *host = dev_id;
+       u32                     status,  pending;
+       unsigned int            pass_count = 0;
+       bool present;
+       bool present_old;
+               
+       spin_lock(&host->lock);
+       do {
+               status = rk29_sdmmc_read(host->regs, SDMMC_RINTSTS);
+               pending = rk29_sdmmc_read(host->regs, SDMMC_MINTSTS);// read only mask reg
+               if (!pending)
+                       break;
+               if(pending & SDMMC_INT_CD) {
+                   writel(SDMMC_INT_CD, host->regs + SDMMC_RINTSTS);  // clear sd detect int
+       
+                       present = rk29_sdmmc_get_cd(host->mmc);
+                       present_old = test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags);
+                       if(present != present_old) {
+                               
+                               if (present != 0) {
+                                       set_bit(RK29_SDMMC_CARD_PRESENT, &host->flags);
+                               } else {
+                                       clear_bit(RK29_SDMMC_CARD_PRESENT, &host->flags);
+                               }                       
+                               if(host->pdev->id ==0) {        //sdmmc0                                
+                                               mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(RK_SDMMC0_SWITCH_POLL_DELAY));
+                               } else {        //sdio
+                                               mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(20));
+                               }
+                       }
+               }       
+               if(pending & RK29_SDMMC_CMD_ERROR_FLAGS) {
+                   rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,RK29_SDMMC_CMD_ERROR_FLAGS);  //  clear interrupt
+                   host->cmd_status = status;
+                   smp_wmb();
+                   rk29_sdmmc_set_pending(host, EVENT_CMD_COMPLETE);
+                   tasklet_schedule(&host->tasklet);
+               }
+
+               if (pending & RK29_SDMMC_DATA_ERROR_FLAGS) { // if there is an error, let report DATA_ERROR
+                       rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,RK29_SDMMC_DATA_ERROR_FLAGS);  // clear interrupt
+                       host->data_status = status;
+                       smp_wmb();
+                       rk29_sdmmc_set_pending(host, EVENT_DATA_ERROR);
+                       tasklet_schedule(&host->tasklet);
+               }
+
+
+               if(pending & SDMMC_INT_DTO) {
+                   rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_DTO);  // clear interrupt
+                   if (!host->data_status)
+                       host->data_status = status;
+                   smp_wmb();
+                   if(host->dir_status == RK29_SDMMC_RECV_STATUS) {
+                       if(host->sg != NULL) 
+                               rk29_sdmmc_read_data_pio(host);
+                   }
+                   rk29_sdmmc_set_pending(host, EVENT_DATA_COMPLETE);
+                   tasklet_schedule(&host->tasklet);
+               }
+
+               if (pending & SDMMC_INT_RXDR) {
+                   rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_RXDR);  //  clear interrupt
+                   if(host->sg) 
+                           rk29_sdmmc_read_data_pio(host);
+               }
+
+               if (pending & SDMMC_INT_TXDR) {
+                   rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_TXDR);  //  clear interrupt
+                   if(host->sg) {
+                       rk29_sdmmc_write_data_pio(host);
+                   }
+               }
+
+               if (pending & SDMMC_INT_CMD_DONE) {
+                   rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_CMD_DONE);  //  clear interrupt
+                   rk29_sdmmc_cmd_interrupt(host, status);
+               }
+       } while (pass_count++ < 5);
+       
+       spin_unlock(&host->lock);
+
+       return pass_count ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/*
+ *
+ * MMC card detect thread, kicked off from detect interrupt, 1 timer 
+ *
+ */
+static void rk29_sdmmc_detect_change(unsigned long data)
+{
+       struct mmc_request *mrq;
+       struct rk29_sdmmc *host = (struct rk29_sdmmc *)data;;
+               
+       smp_rmb();
+       if (test_bit(RK29_SDMMC_SHUTDOWN, &host->flags))
+               return; 
+       spin_lock(&host->lock); 
+       /* Clean up queue if present */
+               mrq = host->mrq;
+               if (mrq) {
+                       if (mrq == host->curr_mrq) {
+                               /* reset all blocks */
+                               rk29_sdmmc_write(host->regs, SDMMC_CTRL, (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET));
+                               /* wait till resets clear */
+                               while (rk29_sdmmc_read(host->regs, SDMMC_CTRL) & (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET));
+                               rk29_sdmmc_write(host->regs, SDMMC_CTRL, SDMMC_CTRL_INT_ENABLE);
+                               host->data = NULL;
+                               host->cmd = NULL;
+
+                               switch (host->state) {
+                               case STATE_IDLE:
+                                       break;
+                               case STATE_SENDING_CMD:
+                                       mrq->cmd->error = -ENOMEDIUM;
+                                       if (!mrq->data)
+                                               break;
+                                       /* fall through */
+                               case STATE_SENDING_DATA:
+                                       mrq->data->error = -ENOMEDIUM;
+                                       rk29_sdmmc_stop_dma(host);
+                                       break;
+                               case STATE_DATA_BUSY:
+                               case STATE_DATA_ERROR:
+                                       if (mrq->data->error == -EINPROGRESS)
+                                               mrq->data->error = -ENOMEDIUM;
+                                       if (!mrq->stop)
+                                               break;
+                                       /* fall through */
+                               case STATE_SENDING_STOP:
+                                       mrq->stop->error = -ENOMEDIUM;
+                                       break;
+                               }
+
+                               rk29_sdmmc_request_end(host, mrq);
+                       } else {
+                               list_del(&host->queue_node);
+                               mrq->cmd->error = -ENOMEDIUM;
+                               if (mrq->data)
+                                       mrq->data->error = -ENOMEDIUM;
+                               if (mrq->stop)
+                                       mrq->stop->error = -ENOMEDIUM;
+
+                               spin_unlock(&host->lock);
+                               mmc_request_done(host->mmc, mrq);
+                               spin_lock(&host->lock);
+                       }
+
+               }       
+       mmc_detect_change(host->mmc, 0);
+}
+
+static int rk29_sdmmc_probe(struct platform_device *pdev)
+{
+       struct mmc_host                 *mmc;
+       struct rk29_sdmmc               *host;
+       struct resource                 *regs;
+       struct rk29_sdmmc_platform_data *pdata;
+       int                             irq;
+       int                             ret = 0;
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!regs)
+               return -ENXIO;
+
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+
+       mmc = mmc_alloc_host(sizeof(struct rk29_sdmmc), &pdev->dev);
+       if (!mmc)
+               return -ENOMEM;
+               
+       host = mmc_priv(mmc);
+       host->mmc = mmc;
+       host->pdev = pdev;
+       pdata = pdev->dev.platform_data;
+       if (!pdata) {
+               dev_err(&pdev->dev, "Platform data missing\n");
+               ret = -ENODEV;
+               goto err_freehost;
+       }
+
+       spin_lock_init(&host->lock);
+       INIT_LIST_HEAD(&host->queue);
+
+       ret = -ENOMEM;
+       host->regs = ioremap(regs->start, regs->end - regs->start);
+       if (!host->regs)
+           goto err_freehost;
+
+#ifdef USE_DMA
+       if((strncmp(host->dma_name, "sdio", strlen("sdio")) == 1)
+               host->dma_chn = rk29_dma_request(DMACH_SDIO, &rk29_dma_sdio1_client, NULL);
+       if((strncmp(host->dma_name, "sd_mmc", strlen("sd_mmc")) == 1)   
+               host->dma_chn = rk29_dma_request(DMACH_SDMMC, &rk29_dma_sdmmc0_client, NULL);
+       rk29_dma_config(host->dma_chn, 16);
+       rk29_dma_set_buffdone_fn(host->dma_chn, rk29_sdmmc_dma_complete)        
+#endif
+       host->bus_hz = 25000000;  ////cgu_get_clk_freq(CGU_SB_SD_MMC_CCLK_IN_ID); 
+
+       /* reset all blocks */
+       rk29_sdmmc_write(host->regs, SDMMC_CTRL,(SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET));
+       /* wait till resets clear */
+       while (rk29_sdmmc_read(host->regs, SDMMC_CTRL) & (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET));
+
+        /* Clear the interrupts for the host controller */
+       rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFF);
+       rk29_sdmmc_write(host->regs, SDMMC_INTMASK, 0); // disable all mmc interrupt first
+
+       /* Put in max timeout */
+       rk29_sdmmc_write(host->regs, SDMMC_TMOUT, 0xFFFFFFFF);
+
+       /* FIFO threshold settings  */
+       rk29_sdmmc_write(host->regs, SDMMC_FIFOTH, ((0x3 << 28) | (0x0f << 16) | (0x10 << 0))); // RXMark = 15, TXMark = 16, DMA Size = 16
+
+       /* disable clock to CIU */
+       rk29_sdmmc_write(host->regs, SDMMC_CLKENA,0);
+       rk29_sdmmc_write(host->regs, SDMMC_CLKSRC,0);
+       rk29_sdmmc_write(host->regs, SDMMC_PWREN, 1);
+       tasklet_init(&host->tasklet, rk29_sdmmc_tasklet_func, (unsigned long)host);
+       
+       ret = request_irq(irq, rk29_sdmmc_interrupt, 0, dev_name(&pdev->dev), host);
+       if (ret)
+           goto err_dmaunmap;
+
+       platform_set_drvdata(pdev, host);
+       memcpy(host->dma_name, pdata->dma_name, 8);
+       mmc->ops = &rk29_sdmmc_ops[pdev->id];
+       mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510);
+       mmc->f_max = host->bus_hz/2; //max f is clock to mmc_clk/2
+       mmc->ocr_avail = pdata->host_ocr_avail;
+       mmc->caps = pdata->host_caps;
+       mmc->max_phys_segs = 64;
+       mmc->max_hw_segs = 64;
+       mmc->max_blk_size = 65536; /* SDMMC_BLKSIZ is 16 bits*/
+       mmc->max_blk_count = 512;
+       mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+       mmc->max_seg_size = mmc->max_req_size;  
+       
+       /* Assume card is present initially */
+       if(!rk29_sdmmc_get_cd(host->mmc))
+               set_bit(RK29_SDMMC_CARD_PRESENT, &host->flags);
+       else
+               clear_bit(RK29_SDMMC_CARD_PRESENT, &host->flags);
+
+       mmc_add_host(mmc);
+
+
+#if defined (CONFIG_DEBUG_FS)
+       rk29_sdmmc_init_debugfs(host);
+#endif
+
+       /* Create card detect handler thread  */
+       setup_timer(&host->detect_timer, rk29_sdmmc_detect_change,(unsigned long)host);
+       
+       // enable interrupt for command done, data over, data empty, receive ready and error such as transmit, receive timeout, crc error
+       rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFF);
+       rk29_sdmmc_write(host->regs, SDMMC_INTMASK,SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_TXDR | SDMMC_INT_RXDR | RK29_SDMMC_ERROR_FLAGS);
+       rk29_sdmmc_write(host->regs, SDMMC_CTRL,SDMMC_CTRL_INT_ENABLE); // enable mci interrupt
+
+
+       dev_info(&pdev->dev, "RK29 SDMMC controller at irq %d\n", irq);
+
+       return 0;
+err_dmaunmap:
+#ifdef USE_DMA
+       if((strncmp(host->dma_name, "sdio", strlen("sdio")) == 1)
+               rk29_dma_free(DMACH_SDIO, &rk29_dma_sdio1_client);
+       if((strncmp(host->dma_name, "sd_mmc", strlen("sd_mmc")) == 1)   
+               rk29_dma_free(DMACH_SDMMC, &rk29_dma_sdmmc0_client);
+err_freemap:
+#endif
+       iounmap(host->regs);
+err_freehost:
+       kfree(host);
+       return ret;
+}
+
+
+
+static int __exit rk29_sdmmc_remove(struct platform_device *pdev)
+{
+       struct rk29_sdmmc *host = platform_get_drvdata(pdev);
+
+       rk29_sdmmc_write(host->regs, SDMMC_RINTSTS, 0xFFFFFFFF);
+       rk29_sdmmc_write(host->regs, SDMMC_INTMASK, 0); // disable all mmc interrupt first
+       
+       /* Shutdown detect IRQ and kill detect thread */
+       del_timer_sync(&host->detect_timer);
+
+       /* Debugfs stuff is cleaned up by mmc core */
+       set_bit(RK29_SDMMC_SHUTDOWN, &host->flags);
+       smp_wmb();
+       mmc_remove_host(host->mmc);
+       mmc_free_host(host->mmc);
+
+       /* disable clock to CIU */
+       rk29_sdmmc_write(host->regs, SDMMC_CLKENA,0);
+       rk29_sdmmc_write(host->regs, SDMMC_CLKSRC,0);
+       
+       free_irq(platform_get_irq(pdev, 0), host);
+#ifdef USE_DMA
+       if((strncmp(host->dma_name, "sdio", strlen("sdio")) == 1)
+               rk29_dma_free(DMACH_SDIO, &rk29_dma_sdio1_client);
+       if((strncmp(host->dma_name, "sd_mmc", strlen("sd_mmc")) == 1)   
+               rk29_dma_free(DMACH_SDMMC, &rk29_dma_sdmmc0_client);
+#endif
+       iounmap(host->regs);
+
+       kfree(host);
+       return 0;
+}
+
+static int rk29_sdmmc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+#ifdef CONFIG_PM
+       struct rk29_sdmmc *host = platform_get_drvdata(pdev);
+       rk29_sdmmc_write(host->regs, SDMMC_CLKENA, 0);
+       clk_disable(host->clk);
+#endif
+       return 0;
+}
+
+static int rk29_sdmmc_resume(struct platform_device *pdev)
+{
+#ifdef CONFIG_PM
+       struct rk29_sdmmc *host = platform_get_drvdata(pdev);
+       clk_enable(host->clk);
+#endif
+       return 0;
+}
+
+static struct platform_driver rk29_sdmmc_driver = {
+       .suspend    = rk29_sdmmc_suspend,
+       .resume     = rk29_sdmmc_resume,
+       .remove         = __exit_p(rk29_sdmmc_remove),
+       .driver         = {
+               .name           = "rk29_sdmmc",
+       },
+};
+
+static int __init rk29_sdmmc_init(void)
+{
+       return platform_driver_probe(&rk29_sdmmc_driver, rk29_sdmmc_probe);
+}
+
+static void __exit rk29_sdmmc_exit(void)
+{
+       platform_driver_unregister(&rk29_sdmmc_driver);
+}
+
+module_init(rk29_sdmmc_init);
+module_exit(rk29_sdmmc_exit);
+
+MODULE_DESCRIPTION("Rk29 Multimedia Card Interface driver");
+MODULE_AUTHOR("Rockchips");
+MODULE_LICENSE("GPL v2");
\ No newline at end of file