static int hifDisableFunc(HIF_DEVICE *device, struct sdio_func *func) { int ret = 0; AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +hifDeviceRemoved\n")); device = getHifDevice(func); if (!IS_ERR(device->async_task)) { init_completion(&device->async_completion); device->async_shutdown = 1; up(&device->sem_async); wait_for_completion(&device->async_completion); device->async_task = NULL; } /* Disable the card */ sdio_claim_host(device->func); ret = sdio_disable_func(device->func); if (reset_sdio_on_unload) { /* reset the SDIO interface. This is useful in automated testing where the card * does not need to be removed at the end of the test. It is expected that the user will * also unload/reload the host controller driver to force the bus driver to re-enumerate the slot */ AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("AR6000: reseting SDIO card back to uninitialized state \n")); /* NOTE : sdio_f0_writeb() cannot be used here, that API only allows access * to undefined registers in the range of: 0xF0-0xFF */ ret = Func0_CMD52WriteByte(device->func->card, SDIO_CCCR_ABORT, (1 << 3)); if (ret) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("AR6000: reset failed : %d \n",ret)); } } sdio_release_host(device->func); return ret; }
static int hifDeviceInserted(struct sdio_func *func, const struct sdio_device_id *id) { int ret; HIF_DEVICE * device; int count; struct task_struct* startup_task_struct; AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: hifDeviceInserted, Function: 0x%X, Vendor ID: 0x%X, Device ID: 0x%X, block size: 0x%X/0x%X\n", func->num, func->vendor, func->device, func->max_blksize, func->cur_blksize)); addHifDevice(func); device = getHifDevice(func); spin_lock_init(&device->lock); spin_lock_init(&device->asynclock); DL_LIST_INIT(&device->ScatterReqHead); if (!nohifscattersupport) { /* try to allow scatter operation on all instances, * unless globally overridden */ device->scatter_enabled = TRUE; } /* enable the SDIO function */ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: claim\n")); sdio_claim_host(func); AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: enable\n")); if ((id->device & MANUFACTURER_ID_AR6K_BASE_MASK) >= MANUFACTURER_ID_AR6003_BASE) { /* enable 4-bit ASYNC interrupt on AR6003 or later devices */ ret = Func0_CMD52WriteByte(func->card, CCCR_SDIO_IRQ_MODE_REG, SDIO_IRQ_MODE_ASYNC_4BIT_IRQ); if (ret) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("AR6000: failed to enable 4-bit ASYNC IRQ mode %d \n",ret)); sdio_release_host(func); return ret; } AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: 4-bit ASYNC IRQ mode enabled\n")); } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) /* give us some time to enable, in ms */ func->enable_timeout = 100; #endif ret = sdio_enable_func(func); if (ret) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), Unable to enable AR6K: 0x%X\n", __FUNCTION__, ret)); sdio_release_host(func); return ret; } AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: set block size 0x%X\n", HIF_MBOX_BLOCK_SIZE)); ret = sdio_set_block_size(func, HIF_MBOX_BLOCK_SIZE); sdio_release_host(func); if (ret) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), Unable to set block size 0x%x AR6K: 0x%X\n", __FUNCTION__, HIF_MBOX_BLOCK_SIZE, ret)); return ret; } /* Initialize the bus requests to be used later */ A_MEMZERO(device->busRequest, sizeof(device->busRequest)); for (count = 0; count < BUS_REQUEST_MAX_NUM; count ++) { sema_init(&device->busRequest[count].sem_req, 0); hifFreeBusRequest(device, &device->busRequest[count]); } /* create async I/O thread */ device->async_shutdown = 0; device->async_task = kthread_create(async_task, (void *)device, "AR6K Async"); if (IS_ERR(device->async_task)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), to create async task\n", __FUNCTION__)); return A_ERROR; } AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: start async task\n")); sema_init(&device->sem_async, 0); wake_up_process(device->async_task ); /* create startup thread */ startup_task_struct = kthread_create(startup_task, (void *)device, "AR6K startup"); if (IS_ERR(startup_task_struct)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), to create startup task\n", __FUNCTION__)); return A_ERROR; } AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: start startup task\n")); wake_up_process(startup_task_struct); AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: return %d\n", ret)); return ret; }
int ReinitSDIO(struct hif_device *device) { s32 err; struct mmc_host *host; struct mmc_card *card; struct sdio_func *func; u8 cmd52_resp; u32 clock; func = device->func; card = func->card; host = card->host; AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +ReinitSDIO \n")); sdio_claim_host(func); do { if (!device->is_suspend) { u32 resp; u16 rca; u32 i; int bit = fls(host->ocr_avail) - 1; /* emulate the mmc_power_up(...) */ host->ios.vdd = bit; host->ios.chip_select = MMC_CS_DONTCARE; host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; host->ios.power_mode = MMC_POWER_UP; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; host->ops->set_ios(host, &host->ios); /* * This delay should be sufficient to allow the power supply * to reach the minimum voltage. */ msleep(2); host->ios.clock = host->f_min; host->ios.power_mode = MMC_POWER_ON; host->ops->set_ios(host, &host->ios); /* * This delay must be at least 74 clock sizes, or 1 ms, or the * time required to reach a stable voltage. */ msleep(2); /* Issue CMD0. Goto idle state */ host->ios.chip_select = MMC_CS_HIGH; host->ops->set_ios(host, &host->ios); msleep(1); err = IssueSDCommand(device, MMC_GO_IDLE_STATE, 0, (MMC_RSP_NONE | MMC_CMD_BC), NULL); host->ios.chip_select = MMC_CS_DONTCARE; host->ops->set_ios(host, &host->ios); msleep(1); host->use_spi_crc = 0; if (err) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD0 failed : %d \n",err)); break; } if (!host->ocr) { /* Issue CMD5, arg = 0 */ err = IssueSDCommand(device, SD_IO_SEND_OP_COND, 0, (MMC_RSP_R4 | MMC_CMD_BCR), &resp); if (err) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD5 failed : %d \n",err)); break; } host->ocr = resp; } /* Issue CMD5, arg = ocr. Wait till card is ready */ for (i=0;i<100;i++) { err = IssueSDCommand(device, SD_IO_SEND_OP_COND, host->ocr, (MMC_RSP_R4 | MMC_CMD_BCR), &resp); if (err) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD5 failed : %d \n",err)); break; } if (resp & MMC_CARD_BUSY) { break; } msleep(10); } if ((i == 100) || (err)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: card in not ready : %d %d \n",i,err)); break; } /* Issue CMD3, get RCA */ err = IssueSDCommand(device, SD_SEND_RELATIVE_ADDR, 0, MMC_RSP_R6 | MMC_CMD_BCR, &resp); if (err) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD3 failed : %d \n",err)); break; } rca = resp >> 16; host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; host->ops->set_ios(host, &host->ios); /* Issue CMD7, select card */ err = IssueSDCommand(device, MMC_SELECT_CARD, (rca << 16), MMC_RSP_R1 | MMC_CMD_AC, NULL); if (err) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD7 failed : %d \n",err)); break; } } /* Enable high speed */ if (card->host->caps & MMC_CAP_SD_HIGHSPEED) { AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("ReinitSDIO: Set high speed mode\n")); err = Func0_CMD52ReadByte(card, SDIO_CCCR_SPEED, &cmd52_resp); if (err) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD52 read to CCCR speed register failed : %d \n",err)); card->state &= ~MMC_STATE_HIGHSPEED; /* no need to break */ } else { err = Func0_CMD52WriteByte(card, SDIO_CCCR_SPEED, (cmd52_resp | SDIO_SPEED_EHS)); if (err) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD52 write to CCCR speed register failed : %d \n",err)); break; } mmc_card_set_highspeed(card); host->ios.timing = MMC_TIMING_SD_HS; host->ops->set_ios(host, &host->ios); } } /* Set clock */ if (mmc_card_highspeed(card)) { clock = 50000000; } else { clock = card->cis.max_dtr; } if (clock > host->f_max) { clock = host->f_max; } host->ios.clock = clock; host->ops->set_ios(host, &host->ios); if (card->host->caps & MMC_CAP_4_BIT_DATA) { /* CMD52: Set bus width & disable card detect resistor */ err = Func0_CMD52WriteByte(card, SDIO_CCCR_IF, SDIO_BUS_CD_DISABLE | SDIO_BUS_WIDTH_4BIT); if (err) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD52 to set bus mode failed : %d \n",err)); break; } host->ios.bus_width = MMC_BUS_WIDTH_4; host->ops->set_ios(host, &host->ios); } } while (0);