From: lhh Date: Mon, 8 Nov 2010 04:05:18 +0000 (+0800) Subject: add rk29 sdio mmc X-Git-Tag: firefly_0821_release~11032^2~5 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=c4c8e2fde08182c1dd701267e79ca8fc2fc71be0;p=firefly-linux-kernel-4.4.55.git add rk29 sdio mmc --- diff --git a/arch/arm/configs/rk29_sdk_defconfig b/arch/arm/configs/rk29_sdk_defconfig index 1f464a8388ac..b6b6d5269af6 100644 --- a/arch/arm/configs/rk29_sdk_defconfig +++ b/arch/arm/configs/rk29_sdk_defconfig @@ -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 diff --git a/arch/arm/mach-rk29/board-rk29sdk.c b/arch/arm/mach-rk29/board-rk29sdk.c index 40d097a7bf5d..afabec683d58 100755 --- a/arch/arm/mach-rk29/board-rk29sdk.c +++ b/arch/arm/mach-rk29/board-rk29sdk.c @@ -288,10 +288,107 @@ struct rk29fb_info rk29_fb_info = { }; +/***************************************************************************************** + * SDMMC devices +*****************************************************************************************/ +#ifdef CONFIG_SDMMC0_RK29 +void rk29_sdmmc0_cfg_gpio(struct platform_device *dev) +{ + rk29_mux_api_set(GPIO1D1_SDMMC0CMD_NAME, GPIO1H_SDMMC0_CMD); + rk29_mux_api_set(GPIO1D0_SDMMC0CLKOUT_NAME, GPIO1H_SDMMC0_CLKOUT); + rk29_mux_api_set(GPIO1D2_SDMMC0DATA0_NAME, GPIO1H_SDMMC0_DATA0); + rk29_mux_api_set(GPIO1D3_SDMMC0DATA1_NAME, GPIO1H_SDMMC0_DATA1); + rk29_mux_api_set(GPIO1D4_SDMMC0DATA2_NAME, GPIO1H_SDMMC0_DATA2); + rk29_mux_api_set(GPIO1D5_SDMMC0DATA3_NAME, GPIO1H_SDMMC0_DATA3); + rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_SDMMC0_DETECT_N); +} + +#define CONFIG_SDMMC0_USE_DMA +struct rk29_sdmmc_platform_data default_sdmmc0_data = { + .num_slots = 1, + .host_ocr_avail = (MMC_VDD_27_28|MMC_VDD_28_29|MMC_VDD_29_30| + MMC_VDD_30_31|MMC_VDD_31_32|MMC_VDD_32_33| + MMC_VDD_33_34|MMC_VDD_34_35| MMC_VDD_35_36), + .host_caps = (MMC_CAP_4_BIT_DATA|MMC_CAP_MMC_HIGHSPEED|MMC_CAP_SD_HIGHSPEED), + .io_init = rk29_sdmmc0_cfg_gpio, + .dma_name = "sd_mmc", +#ifdef CONFIG_SDMMC0_USE_DMA + .use_dma = 1, +#else + .use_dma = 0, +#endif +}; +#endif +#ifdef CONFIG_SDMMC1_RK29 +#define CONFIG_SDMMC1_USE_DMA +void rk29_sdmmc1_cfg_gpio(struct platform_device *dev) +{ + rk29_mux_api_set(GPIO1C2_SDMMC1CMD_NAME, GPIO1H_SDMMC1_CMD); + rk29_mux_api_set(GPIO1C7_SDMMC1CLKOUT_NAME, GPIO1H_SDMMC1_CLKOUT); + rk29_mux_api_set(GPIO1C3_SDMMC1DATA0_NAME, GPIO1H_SDMMC1_DATA0); + rk29_mux_api_set(GPIO1C4_SDMMC1DATA1_NAME, GPIO1H_SDMMC1_DATA1); + rk29_mux_api_set(GPIO1C5_SDMMC1DATA2_NAME, GPIO1H_SDMMC1_DATA2); + rk29_mux_api_set(GPIO1C6_SDMMC1DATA3_NAME, GPIO1H_SDMMC1_DATA3); +} + +struct rk29_sdmmc_platform_data default_sdmmc1_data = { + .num_slots = 1, + .host_ocr_avail = (MMC_VDD_26_27|MMC_VDD_27_28|MMC_VDD_28_29| + MMC_VDD_29_30|MMC_VDD_30_31|MMC_VDD_31_32| + MMC_VDD_32_33|MMC_VDD_33_34), + .host_caps = (MMC_CAP_4_BIT_DATA|MMC_CAP_SDIO_IRQ| + MMC_CAP_MMC_HIGHSPEED|MMC_CAP_SD_HIGHSPEED), + .io_init = rk29_sdmmc1_cfg_gpio, + .dma_name = "sdio", +#ifdef CONFIG_SDMMC1_USE_DMA + .use_dma = 1, +#else + .use_dma = 0, +#endif +}; +#endif +static void __init rk29_board_iomux_init(void) +{ + #ifdef CONFIG_UART0_RK29 + rk29_mux_api_set(GPIO1B7_UART0SOUT_NAME, GPIO1L_UART0_SOUT); + rk29_mux_api_set(GPIO1B6_UART0SIN_NAME, GPIO1L_UART0_SIN); + #ifdef CONFIG_UART0_CTS_RTS_RK29 + rk29_mux_api_set(GPIO1C1_UART0RTSN_SDMMC1WRITEPRT_NAME, GPIO1H_UART0_RTS_N); + rk29_mux_api_set(GPIO1C0_UART0CTSN_SDMMC1DETECTN_NAME, GPIO1H_UART0_CTS_N); + #endif + #endif + #ifdef CONFIG_UART1_RK29 + rk29_mux_api_set(GPIO2A5_UART1SOUT_NAME, GPIO2L_UART1_SOUT); + rk29_mux_api_set(GPIO2A4_UART1SIN_NAME, GPIO2L_UART1_SIN); + #endif + #ifdef CONFIG_UART2_RK29 + rk29_mux_api_set(GPIO2B1_UART2SOUT_NAME, GPIO2L_UART2_SOUT); + rk29_mux_api_set(GPIO2B0_UART2SIN_NAME, GPIO2L_UART2_SIN); + #ifdef CONFIG_UART2_CTS_RTS_RK29 + rk29_mux_api_set(GPIO2A7_UART2RTSN_NAME, GPIO2L_UART2_RTS_N); + rk29_mux_api_set(GPIO2A6_UART2CTSN_NAME, GPIO2L_UART2_CTS_N); + #endif + #endif + #ifdef CONFIG_UART3_RK29 + rk29_mux_api_set(GPIO2B3_UART3SOUT_NAME, GPIO2L_UART3_SOUT); + rk29_mux_api_set(GPIO2B2_UART3SIN_NAME, GPIO2L_UART3_SIN); + #ifdef CONFIG_UART3_CTS_RTS_RK29 + rk29_mux_api_set(GPIO2B5_UART3RTSN_I2C3SCL_NAME, GPIO2L_UART3_RTS_N); + rk29_mux_api_set(GPIO2B4_UART3CTSN_I2C3SDA_NAME, GPIO2L_UART3_CTS_N); + #endif + #endif +} + static struct platform_device *devices[] __initdata = { #ifdef CONFIG_UART1_RK29 &rk29_device_uart1, #endif +#ifdef CONFIG_SDMMC0_RK29 + &rk29_device_sdmmc0, +#endif +#ifdef CONFIG_SDMMC1_RK29 + &rk29_device_sdmmc1, +#endif #ifdef CONFIG_MTD_NAND_RK29 &rk29_device_nand, #endif @@ -321,6 +418,7 @@ static void __init machine_rk29_init_irq(void) static void __init machine_rk29_board_init(void) { platform_add_devices(devices, ARRAY_SIZE(devices)); + rk29_board_iomux_init(); } static void __init machine_rk29_mapio(void) diff --git a/arch/arm/mach-rk29/devices.c b/arch/arm/mach-rk29/devices.c index 117d8891848d..b62ba8979ee1 100755 --- a/arch/arm/mach-rk29/devices.c +++ b/arch/arm/mach-rk29/devices.c @@ -19,9 +19,59 @@ #include #include #include - -#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, }, }; diff --git a/arch/arm/mach-rk29/devices.h b/arch/arm/mach-rk29/devices.h index 134f662e9bba..8d34b1f4e44f 100755 --- a/arch/arm/mach-rk29/devices.h +++ b/arch/arm/mach-rk29/devices.h @@ -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 diff --git a/arch/arm/mach-rk29/gpio.c b/arch/arm/mach-rk29/gpio.c index 3135b6d19077..b38b8fe37a7b 100644 --- a/arch/arm/mach-rk29/gpio.c +++ b/arch/arm/mach-rk29/gpio.c @@ -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; diff --git a/arch/arm/mach-rk29/include/mach/board.h b/arch/arm/mach-rk29/include/mach/board.h index 6598fc138fa5..bb575a0e2311 100755 --- a/arch/arm/mach-rk29/include/mach/board.h +++ b/arch/arm/mach-rk29/include/mach/board.h @@ -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); diff --git a/arch/arm/mach-rk29/include/mach/gpio.h b/arch/arm/mach-rk29/include/mach/gpio.h index ebcc601e8298..575f48f8594f 100644 --- a/arch/arm/mach-rk29/include/mach/gpio.h +++ b/arch/arm/mach-rk29/include/mach/gpio.h @@ -14,7 +14,8 @@ */ #ifndef __ARCH_ARM_MACH_RK29_GPIO_H #define __ARCH_ARM_MACH_RK29_GPIO_H - +#include + 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__ */ diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index a73fe94bb0d4..8d2bd242ac63 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -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; } diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 602b150163ee..bdb165f93046 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -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); } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 231439a961e2..fb25fd001f4a 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -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) { diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 33747f583df8..32af45c419f4 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -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; diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index c58ddc0eecc1..0aa0cf0dde24 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -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 diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index cf31850676a4..8230c5f949b1 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -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 diff --git a/drivers/mmc/host/rk2818-sdmmc.h b/drivers/mmc/host/rk2818-sdmmc.h index 15a12f4a5d55..2422958b6fe6 100755 --- a/drivers/mmc/host/rk2818-sdmmc.h +++ b/drivers/mmc/host/rk2818-sdmmc.h @@ -126,7 +126,7 @@ /* 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 index 000000000000..6e1339e0c5dd --- /dev/null +++ b/drivers/mmc/host/rk29_sdmmc.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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