*/
#ifndef __ARCH_ARM_MACH_RK29_GPIO_H
#define __ARCH_ARM_MACH_RK29_GPIO_H
-
+#include <asm/irq.h>
+
typedef enum eGPIOPinLevel
{
GPIO_LOW=0,
#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)
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__ */
--- /dev/null
+/* 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