u32 rda_hif_sdio_irq(MTK_WCN_HIF_SDIO_CLTCTX cltCtx) { int ret = 0; struct if_sdio_card *card; struct rda5890_private *priv; u8 status; RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG, "%s >>>\n", __func__); if(!gCard) { return -EIO; } card = gCard; priv = card->priv; ret = mtk_wcn_hif_sdio_readb(priv->cltCtx, IF_SDIO_FUN1_INT_STAT, &status); if (ret) goto out; RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_VERB, "if_sdio_interrupt, status = 0x%02x\n", status); if (status & IF_SDIO_INT_AHB2SDIO) if_sdio_card_to_host(card); if (status & IF_SDIO_INT_ERROR) { ret = mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_FUN1_INT_PEND ,IF_SDIO_INT_ERROR); if (ret) { RDA5890_ERRP("write FUN1_INT_STAT reg fail\n"); goto out; } RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE, "%s, INT_ERROR\n", __func__); } #ifdef WIFI_CLOCK_ALWAYS_ON export_msdc_clk_always_on_off(); #endif out: RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG, "%s <<< ret=%d \n", __func__, ret); return ret; }
int if_sdio_card_to_host(struct if_sdio_card *card) { int ret = 0; struct rda5890_private *priv = card->priv; u8 size_l = 0, size_h = 0; u16 size, chunk; RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG, "%s <<< \n", __func__); ret = mtk_wcn_hif_sdio_readb(priv->cltCtx, IF_SDIO_AHB2SDIO_PKTLEN_L, &size_l); if (ret) { RDA5890_ERRP("read PKTLEN_L reg fail\n"); goto out; } else RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_NORM,"read PKTLEN_L reg size_l:%d \n", size_l); ret = mtk_wcn_hif_sdio_readb(priv->cltCtx, IF_SDIO_AHB2SDIO_PKTLEN_H, &size_h); if (ret) { RDA5890_ERRP("read PKTLEN_H reg fail\n"); goto out; } else RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_NORM,"read PKTLEN_H reg size_h:%d\n",size_h); size = (size_l | ((size_h & 0x7f) << 8)) * 4; if (size < 4) { RDA5890_ERRP("invalid packet size (%d bytes) from firmware\n", size); ret = -EINVAL; goto out; } /* alignment is handled on firmside */ //chunk = sdio_align_size(card->func, size); chunk = size; RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_NORM, "if_sdio_card_to_host, size = %d, aligned size = %d\n", size, chunk); /* TODO: handle multiple packets here */ ret = mtk_wcn_hif_sdio_read_buf(priv->cltCtx, IF_SDIO_FUN1_FIFO_RD, (u32)card->buffer, chunk); if (ret) { RDA5890_ERRP("sdio_readsb fail, ret = %d, size = %d, aligned size = %d\n", ret, size, chunk); goto out; } #if 1 if(priv->version == 7) { mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_FUN1_INT_PEND, 0x20); if(ret) { RDA5890_ERRP("clear SDIO Tx Complete flag failed\n"); goto out; } } #endif RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_VERB, "if_sdio_card_to_host, read done\n"); if(ret) { RDA5890_ERRP("clear SDIO Tx Complete flag failed\n"); goto out; } if (sdio_test_flag) { rda5890_sdio_test_card_to_host(card->buffer, chunk); goto out; } /* TODO: this chunk size need to be handled here */ rda5890_card_to_host(priv, card->buffer, chunk); out: RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG, "if_sdio_card_to_host >>>\n"); return ret; }
static void if_sdio_host_to_card_worker(struct work_struct *work) { struct if_sdio_card *card = NULL; struct rda5890_private *priv = NULL; struct if_sdio_packet *packet = NULL; int ret; unsigned long flags; u16 size; u32 retries = 500; u8 size_l, size_h, write_status = 0; #define SDIO_HOST_WRITE_BATCH_SIZE 512 u16 bytes_left, offset, batch; card = container_of(work, struct if_sdio_card, packet_worker); priv = card->priv; //mask_all_sdio_irq(priv->cltCtx); #ifdef WIFI_POWER_MANAGER if(is_sdio_init_complete()) { if(atomic_read(&card->sleep_work_is_active)) { cancel_delayed_work(&card->sleep_work); #ifdef WIFI_UNLOCK_SYSTEM rda5990_wakeUnlock(); #endif atomic_set(&card->sleep_work_is_active, 0); } } #endif while (1) { retries = 500; spin_lock_irqsave(&card->lock, flags); packet = card->packets; if (packet) card->packets = packet->next; spin_unlock_irqrestore(&card->lock, flags); if (!packet) break; #ifdef WIFI_POWER_MANAGER if (atomic_read(&priv->sleep_flag)) { /* Deivce maybe sleep, wakeup it. */ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_NORM, "Wakeup\n"); ret = if_sdio_wakeup_card(card); if (ret) { RDA5890_ERRP("wakeup card fail\n"); goto out; } } #endif while(retries && is_sdio_patch_complete()) //check write flow ctrl { ret = mtk_wcn_hif_sdio_readb(priv->cltCtx, IF_SDIO_FUN1_INT_PEND, &write_status); if(ret) { RDA5890_ERRP("read IF_SDIO_FUN1_INT_PEND failed\n"); goto release; } if((write_status & IF_SDIO_INT_RXCMPL) == 0) { //RDA5890_ERRP("**** sdio is busy retry next time \n "); retries --; schedule(); } else { ret = mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_FUN1_INT_PEND, IF_SDIO_INT_RXCMPL); if(ret) { RDA5890_ERRP("write IF_SDIO_FUN1_INT_PEND failed\n"); goto release; } break; } } RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG, "if_sdio_host_to_card_worker, send one packet, size = %d\n", packet->nb); /* write length */ size = packet->nb/4; size_l = (u8)(size & 0xff); size_h = (u8)((size >> 8) & 0x7f); size_h |= 0x80; ret = mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_SDIO2AHB_PKTLEN_L, size_l); if (ret) { RDA5890_ERRP("write PKTLEN_L reg fail\n"); goto release; } ret = mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_SDIO2AHB_PKTLEN_H, size_h); if (ret) { RDA5890_ERRP("write PKTLEN_H reg fail\n"); goto release; } /* write data */ bytes_left = packet->nb; offset = 0; while(bytes_left) { batch = (bytes_left < SDIO_HOST_WRITE_BATCH_SIZE)? bytes_left:SDIO_HOST_WRITE_BATCH_SIZE; ret = mtk_wcn_hif_sdio_write_buf(priv->cltCtx, IF_SDIO_FUN1_FIFO_WR, packet->buffer + offset, batch); if (ret) { RDA5890_ERRP("sdio_writesb fail, ret = %d\n", ret); goto release; } RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG, "write batch %d, offset = %d\n", batch, offset); offset += batch; bytes_left -= batch; } RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG, "if_sdio_host_to_card_worker, send one packet done\n"); release: kfree(packet); packet = NULL; } out: if(is_sdio_init_complete()) //init complete should start sleep_work { #ifdef WIFI_UNLOCK_SYSTEM rda5990_wakeLock(); #endif #ifdef WIFI_POWER_MANAGER #ifdef WIFI_TEST_MODE if(rda_5990_wifi_in_test_mode()) return; #endif //end WIFI_TEST_MODE atomic_set(&card->sleep_work_is_active, 1); queue_delayed_work(priv->work_thread, &card->sleep_work, rda5890_assoc_in_progress ? 30 * HZ : HZ/5); // 100ms //queue_delayed_work(priv->work_thread, &card->sleep_work, HZ/5); // 100ms #endif } }
static long mt6620_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int err = 0; int retval = 0; u8 data; unsigned int tmp; if(_IOC_TYPE(cmd) != MT6620_IOC_MAGIC) return -ENOTTY; else if(_IOC_NR(cmd) > MT6620_IOC_MAXNR) return -ENOTTY; if(_IOC_DIR(cmd) & _IOC_READ) err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) & _IOC_WRITE) err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); if (err) return -EFAULT; switch(cmd) { case MT6620_IOC_GET_FUNC_FOCUS: case MT6620_IOC_SET_FUNC_FOCUS: case MT6620_IOC_GET_SDBUS_WIDTH: case MT6620_IOC_SET_SDBUS_WIDTH: case MT6620_IOC_GET_BUS_CLOCK: case MT6620_IOC_SET_BUS_CLOCK: retval = -EINVAL; break; case MT6620_IOC_READ_DIRECT: if(down_interruptible(&mt6620_sem)) { return -ERESTARTSYS; } retval = mtk_wcn_hif_sdio_readb(mt6620_t.cltCtx, mt6620_t.addr, &data); up(&mt6620_sem); if(retval == 0) retval = __put_user(data, (u8 __user *)arg); break; case MT6620_IOC_WRITE_DIRECT: __get_user(data, (u8 __user *)arg); if(down_interruptible(&mt6620_sem)) { return -ERESTARTSYS; } retval = mtk_wcn_hif_sdio_writeb(mt6620_t.cltCtx, mt6620_t.addr, data); up(&mt6620_sem); break; case MT6620_IOC_GET_ADDR: tmp = mt6620_t.addr; __put_user(tmp, (u32 __user *)arg); break; case MT6620_IOC_SET_ADDR: __get_user(tmp, (u32 __user *)arg); if(tmp <= 0xFF) mt6620_t.addr = tmp; else retval = -EINVAL; break; case MT6620_IOC_SET_FIFO_MODE: case MT6620_IOC_SET_INCR_MODE: case MT6620_IOC_GET_BLOCK_SIZE: case MT6620_IOC_SET_BLOCK_SIZE: retval = -EINVAL; break; case MT6620_IOC_QUERY_IRQ_LEVEL: if(down_interruptible(&mt6620_sem)) retval = -ERESTARTSYS; else if(mt6620_t.irq.irq == 1) { unsigned char buffer[88]; if(mt6620_t.enhance_int.totalBytes != 0) { int i, offset = 0; if(mtk_wcn_hif_sdio_read_buf(mt6620_t.cltCtx, MCR_WHISR, (PUINT32)(buffer), mt6620_t.enhance_int.totalBytes + sizeof(unsigned int))) { /* I/O error */ up(&mt6620_sem); return -EIO; } mt6620_t.irq.u4HISR |= *(uint32_t *)(&(buffer[offset])); offset += sizeof(uint32_t); // WTSR0/WTSR1 if(mt6620_t.enhance_int.totalBytes >= (12)) { int tqStatus[2]; memcpy(&(tqStatus[0]), &(buffer[offset]), 8); // increase mt6620_t.irq.rTxInfo.u.ucTQ0Cnt += ((tqStatus[0] >> 0) & 0xff); mt6620_t.irq.rTxInfo.u.ucTQ1Cnt += ((tqStatus[0] >> 8) & 0xff); mt6620_t.irq.rTxInfo.u.ucTQ2Cnt += ((tqStatus[0] >> 16) & 0xff); mt6620_t.irq.rTxInfo.u.ucTQ3Cnt += ((tqStatus[0] >> 24) & 0xff); mt6620_t.irq.rTxInfo.u.ucTQ4Cnt += ((tqStatus[1] >> 0) & 0xff); mt6620_t.irq.rTxInfo.u.ucTQ5Cnt += ((tqStatus[1] >> 8) & 0xff); offset += 8; } // RX0NUM/RX1NUM if(mt6620_t.enhance_int.totalBytes >= (16)) { memcpy(&(mt6620_t.irq.rRxInfo.au4RxStatusRaw[0]), &(buffer[offset]), 4); offset += 4; } // RX0 LEN0-15 / RX1 LEN0-15 if(mt6620_t.enhance_int.totalBytes >= (16 + mt6620_t.enhance_int.rxNum * 4)) { for(i = 0 ; i < mt6620_t.enhance_int.rxNum ; i++) { mt6620_t.irq.rRxInfo.u.au2Rx0Len[i] = *(uint16_t *)(&(buffer[offset])); offset += sizeof(uint16_t); } for(i = 0 ; i < mt6620_t.enhance_int.rxNum ; i++) { mt6620_t.irq.rRxInfo.u.au2Rx1Len[i] = *(uint16_t *)(&(buffer[offset])); offset += sizeof(uint16_t); } } // D2HRM0R / D2HRM1R if(mt6620_t.enhance_int.totalBytes >= (16 + mt6620_t.enhance_int.rxNum * 4 + 8)) { memcpy(&(mt6620_t.irq.u4RcvMailbox0), &(buffer[offset]), 4); offset += 4; memcpy(&(mt6620_t.irq.u4RcvMailbox1), &(buffer[offset]), 4); offset += 4; } //@FIXME: WHISR could be configured as write-1-clear .... //if so, we need to clear WHISR here .. }