--- 2.6_kernel/drivers/mmc/mmc.c 2006-09-05 17:48:50.000000000 -0500 +++ 2.6_kernel-sdio/drivers/mmc/mmc.c 2006-09-05 17:57:06.000000000 -0500 @@ -709,6 +709,23 @@ mmc_alloc_card(struct mmc_host *host, u3 } /* + * Allocate a new SDIO card, and assign a RCA. + */ +static struct mmc_card * +sdio_alloc_card(struct mmc_host *host, int io_rca) +{ + struct mmc_card *card; + + card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL); + if (!card) + return ERR_PTR(-ENOMEM); + mmc_init_card(card, host); + card->rca = io_rca; + + return card; +} + +/* * Tell attached cards to go to IDLE state */ static void mmc_idle_cards(struct mmc_host *host) @@ -796,6 +813,121 @@ static int mmc_send_op_cond(struct mmc_h return err; } +static int io_send_op_cond(struct mmc_host *host, u32 ocr, u32 * rocr) +{ + struct mmc_command cmd; + int i, err = 0; + + cmd.opcode = IO_SEND_OP_COND; + cmd.arg = ocr; + cmd.flags = MMC_RSP_R4; + + for (i = 100; i; i--) { + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err != MMC_ERR_NONE) + break; + + if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) + break; + mmc_delay(1); + err = MMC_ERR_TIMEOUT; + + mmc_delay(10); + } + + if (rocr) + *rocr = cmd.resp[0]; + + return err; +} + +struct mmc_card *sdiocard; +static int io_select_card(struct mmc_host *host){ + struct mmc_command cmd; + int err = 0; + + cmd.opcode = MMC_SELECT_CARD; + cmd.arg = sdiocard->rca; + cmd.flags = MMC_RSP_R1; + + err = mmc_wait_for_cmd(host, &cmd,0); + return err; +} + +static int read_cia,sdioresp; +/* +* Read/Write one byte of data from an SDIO card register of the given function on the resp line. +*/ +int io_rw_direct(int rwFlag,int funcNum,int rawFlag, unsigned long regAddr,int value){ + struct mmc_command cmd; + int err = 0,trans_err = 1; + + if (!sdiocard) + return trans_err; + + if (sdioresp) + return trans_err; + + cmd.opcode = IO_RW_DIRECT; + if(rwFlag) + cmd.arg = ((rwFlag<<31) | (funcNum << 28) | (rawFlag<<27) | (regAddr << 9) | value); + else + cmd.arg = ((rwFlag<<31) | (funcNum << 28) | (rawFlag<<27) | (regAddr << 9)); + cmd.flags = MMC_RSP_R5; + + if (read_cia == 0) + mmc_claim_host(sdiocard->host); + + if (sdiocard->host->ios.clock == 0){ + printk(KERN_ERR"CMD52 when the host is suspended\n"); + mmc_release_host(sdiocard->host); + return trans_err; + } + + err = mmc_wait_for_cmd(sdiocard->host, &cmd,0); + + if (err!= MMC_ERR_NONE) + return err; + + if (read_cia == 0) + mmc_release_host(sdiocard->host); + + if (rwFlag) + return err; + else + return cmd.resp[0] & 0xFF; +} +EXPORT_SYMBOL(io_rw_direct); +/* +* Read/Write bytec number of bytes from SDIO card registers of a given function on the data lines. +*/ +int io_rw_extended(struct mmc_request *mrq,int rwFlag,int funcNum,int blkMode,int opcode, unsigned long regAddr, int bytec){ + struct mmc_command cmd; + int err = 0,trans_err = 1; + + if (!sdiocard) + return trans_err; + + mrq->cmd = &cmd; + cmd.opcode = IO_RW_EXTENDED; + cmd.arg = ((rwFlag<<31) | (funcNum << 28) | (blkMode<<27) | (opcode << 26) | (regAddr << 9) | bytec); + cmd.flags = MMC_RSP_R5; + + mmc_claim_host(sdiocard->host); + + if (sdiocard->host->ios.clock == 0){ + printk(KERN_ERR"CMD53 when the host is suspended\n"); + mmc_release_host(sdiocard->host); + return trans_err; + } + + err = mmc_wait_for_req(sdiocard->host, mrq); + + mmc_release_host(sdiocard->host); + + return err; +} +EXPORT_SYMBOL(io_rw_extended); static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) { struct mmc_command cmd; @@ -835,11 +967,27 @@ static int mmc_send_app_op_cond(struct m static void mmc_discover_cards(struct mmc_host *host) { struct mmc_card *card; - unsigned int first_rca = 1, err; + unsigned int first_rca = 1,io_rca, err; while (1) { struct mmc_command cmd; + if (host->mode == MMC_MODE_SDIO){ + /* Read the rca of an SDIO card. + * */ + cmd.opcode = SDIO_SEND_RELATIVE_ADDR; + cmd.arg = 0x0; + cmd.flags = MMC_RSP_R6; + + err = mmc_wait_for_cmd(host, &cmd,0); + + if (err == MMC_ERR_NONE){ + io_rca = cmd.resp[0] & 0xFFFF0000; + sdiocard = sdio_alloc_card(host, io_rca); + break; + } + } + cmd.opcode = MMC_ALL_SEND_CID; cmd.arg = 0; cmd.flags = MMC_RSP_R2; @@ -1052,6 +1200,70 @@ static unsigned int mmc_read_ext_csd(str return err; } + +/* + * Read the CCCR register contents of an I/O card. + */ +static void io_read_cia(struct mmc_host *host) +{ + int sdio_rev,io_cardType,io_busWidth,io_cardCap; + + read_cia = 1; + sdioresp = io_select_card(host); + + host->ios.bus_width = MMC_BUS_WIDTH_1; + if (sdioresp == 0){ + if (host->caps & MMC_CAP_4_BIT_DATA) { + io_cardCap = io_rw_direct(READ,FUNCTION_0,0,CCCR_CARD_CAPACITY,0x0); + if (io_cardCap & (1<<6)){ + host->ios.clock = host->f_min; + host->ops->set_ios(host, &host->ios); + if (io_cardCap & (1<<7)){ + io_busWidth = io_rw_direct(READ,FUNCTION_0,0,CCCR_BUS_INTF_CONTROL,0x0); + io_busWidth |= 0x2; + io_rw_direct(WRITE,FUNCTION_0,0,CCCR_BUS_INTF_CONTROL,io_busWidth); + host->ios.bus_width = MMC_BUS_WIDTH_4; + } + } else { + host->ios.clock = 25000000; + host->ios.bus_width = MMC_BUS_WIDTH_4; + host->ops->set_ios(host, &host->ios); + io_busWidth = io_rw_direct(READ,FUNCTION_0,0,CCCR_BUS_INTF_CONTROL,0x0); + io_busWidth |= 0x2; + io_rw_direct(WRITE,FUNCTION_0,0,CCCR_BUS_INTF_CONTROL,io_busWidth); + + } + + } + + sdio_rev = io_rw_direct(READ,FUNCTION_0,0,CCCR_SDIO_REVISION,0x0); + /* + * Enable all the functions in the card. + */ + io_rw_direct(WRITE,FUNCTION_0,0,CCCR_IO_ENABLE,0xFF); + io_rw_direct(WRITE,FUNCTION_0,0,CCCR_FUNCTION_SELECT,io_rw_direct(READ,FUNCTION_0,0,CCCR_FUNCTION_SELECT,0x0) | 0x1); + + io_cardType = io_rw_direct(READ,FUNCTION_1,0,FBR1,0x0); + if (io_cardType == 0x0) + printk(KERN_INFO"SDIO WLAN card detected\n"); + else if (io_cardType == 0x1) + printk(KERN_INFO"SDIO UART interface detected\n"); + else if (io_cardType == 0x2) + printk(KERN_INFO"SDIO thin bluetooth interface detected\n"); + else if (io_cardType == 0x3) + printk(KERN_INFO"SDIO complete bluetooth interface detected\n"); + else if (io_cardType == 0x4) + printk(KERN_INFO"SDIO GPS standard interface detected\n"); + else if (io_cardType == 0x5) + printk(KERN_INFO"SDIO Camera standard interface detected\n"); + else if (io_cardType == 0x6) + printk(KERN_INFO"SDIO PHS Radio standard interface detected\n"); + if (sdio_rev == 0x00) + printk(KERN_INFO"SDIO revision 1.00\n"); + + } + read_cia = 0; +} static unsigned int mmc_calculate_clock(struct mmc_host *host) { struct mmc_card *card; @@ -1453,18 +1665,24 @@ static void mmc_setup(struct mmc_host *h int err; u32 ocr; - host->mode = MMC_MODE_SD; + host->mode = MMC_MODE_SDIO; mmc_power_up(host); mmc_idle_cards(host); + err = io_send_op_cond(host, 0, &ocr); + /* + * * If we fail to detect any SDIO cards then try + * * searching for SD cards. + */ + if (err != MMC_ERR_NONE) { err = mmc_send_app_op_cond(host, 0, &ocr); /* * * If we fail to detect any SD cards then try * * searching for MMC cards. */ - if (err != MMC_ERR_NONE){ + if (err != MMC_ERR_NONE){ host->mode = MMC_MODE_MMC; err = mmc_send_op_cond(host, 0, &ocr); if (err != MMC_ERR_NONE) @@ -1473,6 +1691,7 @@ static void mmc_setup(struct mmc_host *h else { host->mode = MMC_MODE_SD; } + } host->ocr = mmc_select_voltage(host, ocr); /* @@ -1511,7 +1730,10 @@ static void mmc_setup(struct mmc_host *h * all get the idea that they should be ready for CMD2. * (My SanDisk card seems to need this.) */ - if (host->mode == MMC_MODE_SD) + if (host->mode == MMC_MODE_SDIO){ + io_send_op_cond(host, host->ocr, NULL); + } + else if (host->mode == MMC_MODE_SD) mmc_send_app_op_cond(host, host->ocr, NULL); else mmc_send_op_cond(host, host->ocr, NULL); @@ -1523,7 +1745,10 @@ static void mmc_setup(struct mmc_host *h */ host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; host->ops->set_ios(host, &host->ios); - mmc_read_csds(host); + if (host->mode == MMC_MODE_MMC || host->mode == MMC_MODE_SD) + mmc_read_csds(host); + else + io_read_cia(host); if (host->mode == MMC_MODE_SD) mmc_read_scrs(host); @@ -1600,8 +1825,16 @@ static void mmc_rescan(void *data) * If we discover that there are no cards on the * bus, turn off the clock and power down. */ + if (host->mode == MMC_MODE_SDIO ){ + if (sdioresp == 1){ + kfree(sdiocard); + mmc_power_off(host); + } + } + else { if (list_empty(&host->cards)) mmc_power_off(host); + } }