/** * @brief ドライバwrite関数 * * @param[in] *file : ファイル * @param[in] *buffer : 書き込みパラメータ * @param[in] count : 書き込みサイズ * @param[in] *f_pos : ファイルのRW位置 * @retval write_size : 正常終了 書き込みサイズ * @retval EFAULT : 異常終了 アドレス不正 * @retval ENOENT : 異常終了 ファイルorディレクトリがない * @retval ENOSPC : 異常終了 デバイスに空領域がない * @retval EINVAL : 異常終了 引数なし * @retval D_SHDMA_RET_NG : 異常終了 エラー * @exception なし * @see なし */ static ssize_t shdma_write( struct file *file, const char __user *buffer, size_t count, loff_t *f_pos ) { int ret = D_SHDMA_RET_OK; unsigned int i,j; int err = D_SHDMA_RET_OK; int result_chk = D_SHDMA_RET_OK; struct vm_area_struct *vma; unsigned long pfn = 0; ion_phys_addr_t src_phys = 0; unsigned long dst_phys = 0; size_t src_len; unsigned long trans_size = 0; unsigned long shdma_trans_num_rows = 0; unsigned long dma_trans_num_rows = 0; unsigned long dma_trans_num_rows_rem = 0; unsigned addr_offset = 0; struct ion_handle *shdma_src_handle; struct shdma_dmov_exec_cmdptr_cmd cmd[3]; struct shdma_command_t shdma_cmd[D_SHDMA_CHANNEL_MAX]; unsigned int id[D_SHDMA_CHANNEL_MAX] = { DMOV_SHDMA_CH1, DMOV_SHDMA_CH2, DMOV_SHDMA_CH3 }; unsigned long width_yuv = 0; unsigned long height_y = 0; unsigned long height_uv = 0; unsigned long ysize_align = 0; unsigned long uvsize_align = 0; int ion_ret = 0; /** <ol><li>処理開始 */ SHDMA_DEBUG_MSG_ENTER(0, 0, 0); /** <li> ドライバwriteセマフォ獲得*/ down( &write_sem ); /** <li>初期化処理 */ /** <ol><li>引数NULLチェック */ if( file == NULL || buffer == NULL || count <= 0 || f_pos == NULL ){ printk("***ERROR: argument NULL file = %p buffer = %p count = 0x%x f_pos = %p\n", file, buffer, count, f_pos ); up( &write_sem ); return -EINVAL; } /** <li>上位からのパラメータをコピーする */ if (copy_from_user(&tci, buffer, sizeof(tci))){ printk("***ERROR: fault copy write data parameter.\n" ); up( &write_sem ); return -EFAULT; } /** <li>転送元、転送先アドレスNULLチェック */ if( tci[0].dst_handle == NULL || tci[0].src_handle == NULL ){ printk("***ERROR: fault transfer address NULL src = %p dst = %p\n", tci[0].src_handle, tci[0].dst_handle ); up( &write_sem ); return -EINVAL; } /** <li>転送幅、高さチェック */ if(( tci[0].height < D_SHDMA_CHANNEL_MAX ) || ( tci[0].src_stride == 0 )){ printk("***ERROR: argument ERROR height = %d width = %ld\n", tci[0].height, tci[0].src_stride ); up( &write_sem ); return -EINVAL; } if(( tci[0].src_stride % D_SHDMA_ODD_CHECK ) != 0 ){ /* widthが奇数の場合はありえないためNGを返す */ printk("***ERROR: argument ERROR width is odd number width = %ld\n", tci[0].src_stride ); up( &write_sem ); return -EINVAL; } /** <li>内部変数の初期化をする */ memset( &cmd, 0, sizeof(struct shdma_dmov_exec_cmdptr_cmd) * 3 ); for( i = 0; i < D_SHDMA_CHANNEL_MAX; i++ ){ memset( &shdma_cmd[i], 0, sizeof(struct shdma_command_t)); } /** </ol>*/ /** <li>物理アドレス取得 */ /** <ol><li>転送元物理アドレス取得 */ shdma_src_handle = (struct ion_handle *)tci[0].src_handle; ion_ret = ion_phys( shdma_src_handle->client, shdma_src_handle, &src_phys, &src_len); if( src_phys == 0 || src_len < 1 || ion_ret < 0 ){ printk("***ERROR: get src_phys falut.\n"); up( &write_sem ); return -EFAULT; } /** <li>転送先物理アドレス取得 */ vma = find_vma( current->mm, (unsigned int )tci[0].dst_handle ); if( vma == NULL ){ printk("***ERROR: get vma falut.\n"); up( &write_sem ); return -ENOENT; } follow_pfn( vma, (unsigned int)tci[0].dst_handle, &pfn ); dst_phys = __pfn_to_phys( pfn ); /** </ol> */ /** <li>DMA転送用パラメータバッファ獲得 */ for( i = 0; i < D_SHDMA_CHANNEL_MAX; i++ ){ /** <ol><li>DMAチャネル分獲得する */ /** <ol><li>DMA転送用パラメータ領域獲得 */ shdma_cmd[i].cmd_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA); if( shdma_cmd[i].cmd_ptr == NULL ){ printk("***ERROR: falut allocate buffer cmd_ptr num = 0x%x .\n" , i); if( i != 0 ){ for( j = 0; j < (i - 1); j++ ){ kfree(shdma_cmd[j].cmd_ptr); } } up( &write_sem ); return -ENOSPC; } } for( i = 0; i < D_SHDMA_CHANNEL_MAX; i++ ){ /** <li>DMA転送用パラメータ先頭アドレス領域獲得 */ shdma_cmd[i].cmd_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA); if( shdma_cmd[i].cmd_ptr_ptr == NULL ){ printk("***ERROR: falut allocate buffer cmd_ptr_ptr num = 0x%x .\n" , i); if( i != 0 ){ for( j = 0; j < (i - 1); j++ ){ kfree(shdma_cmd[j].cmd_ptr_ptr); } } for( j = 0; j < D_SHDMA_CHANNEL_MAX; j++ ){ kfree(shdma_cmd[j].cmd_ptr); } up( &write_sem ); return -ENOSPC; } } /** </ol></ol> */ /** <li>転送サイズ計算 */ /** <li>アライメント調整 */ if(( tci[0].src_stride % D_SHDMA_ALIGN_128 ) != 0 ){ /*Y領域、UV領域幅アライメント調整*/ width_yuv = ((( tci[0].src_stride / D_SHDMA_ALIGN_128 ) + D_SHDMA_ALIGN_ADJUST ) * D_SHDMA_ALIGN_128 ); /*128バイトでアライメント*/ } else { width_yuv = tci[0].src_stride; } if(( tci[0].height % D_SHDMA_ALIGN_32 ) != 0 ){ /*Y領域高さアライメント調整*/ height_y = ((( tci[0].height / D_SHDMA_ALIGN_32 ) + D_SHDMA_ALIGN_ADJUST ) * D_SHDMA_ALIGN_32 ); /*32バイトでアライメント*/ } else { height_y = tci[0].height; } if((( tci[0].height / D_SHDMA_ALIGN_HEIGHT_UV ) % D_SHDMA_ALIGN_32 ) != 0 ){ /*UV領域高さアライメント調整*/ height_uv = (((( tci[0].height / D_SHDMA_ALIGN_HEIGHT_UV ) / D_SHDMA_ALIGN_32 ) + D_SHDMA_ALIGN_ADJUST ) * D_SHDMA_ALIGN_32 ); /*32バイトでアライメント*/ } else { height_uv = tci[0].height / D_SHDMA_ALIGN_HEIGHT_UV; } if(( width_yuv * height_y ) % D_SHDMA_ALIGN_8192 ){ /*Y領域のアライメント調整*/ ysize_align = ((( width_yuv * height_y / D_SHDMA_ALIGN_8192 ) + D_SHDMA_ALIGN_ADJUST ) * D_SHDMA_ALIGN_8192 ); /*8Kバイトでアライメント*/ } else { ysize_align = width_yuv * height_y; } if(( width_yuv * height_uv ) % D_SHDMA_ALIGN_8192 ){ /*YU領域のアライメント調整*/ uvsize_align = ((( width_yuv * height_uv / D_SHDMA_ALIGN_8192 ) + D_SHDMA_ALIGN_ADJUST ) * D_SHDMA_ALIGN_8192 ); /*8Kバイトでアライメント*/ } else { uvsize_align = width_yuv * height_uv; } shdma_trans_num_rows = (( ysize_align + uvsize_align ) / D_SHDMA_ALIGN_8192 ); /** <li>DMAbox転送回数はYUV領域を8Kで割った値*/ trans_size = D_SHDMA_ALIGN_8192; /** <li>DMA転送1boxサイズは8Kサイズを指定*/ dma_trans_num_rows = shdma_trans_num_rows / D_SHDMA_CHANNEL_MAX; /** <li>DMA1面あたりのbox転送回数算出 */ dma_trans_num_rows_rem = shdma_trans_num_rows % D_SHDMA_CHANNEL_MAX; /** <li>DMA1面あたりのbox転送回数の余り算出 */ if( trans_size > D_SHDMA_TRANS_MAX_SIZE ){ /** <li>DMA転送1boxサイズが65535より大きい場合はハード制約で転送できないため、NGを返す */ printk("***ERROR: Size over for DMA transfer.\n"); for( i = 0; i < D_SHDMA_CHANNEL_MAX; i++ ){ kfree(shdma_cmd[i].cmd_ptr); kfree(shdma_cmd[i].cmd_ptr_ptr); } up( &write_sem ); return -EINVAL; } /** </ol> */ /** <li>DMA転送用パラメータ設定 */ for( i = 0; i < D_SHDMA_CHANNEL_MAX; i++ ){ /** <ol><li>DMAチャネル分設定する */ if( i == D_SHDMA_CHANNEL_MAX - 1){ /** <ol><li>最後のDMAチャネルの場合転送box数の余りも転送する */ dma_trans_num_rows += dma_trans_num_rows_rem; } shdma_cmd[i].cmd_ptr->cmd = CMD_PTR_LP | CMD_MODE_BOX; /** <li>boxモード転送 */ shdma_cmd[i].cmd_ptr->src_row_addr = (unsigned int)src_phys + addr_offset; /** <li>転送元アドレス設定 */ shdma_cmd[i].cmd_ptr->dst_row_addr = (unsigned int)dst_phys + addr_offset; /** <li>転送先アドレス設定 */ shdma_cmd[i].cmd_ptr->src_dst_len = /** <li>1box転送サイズ設定 */ (( trans_size & D_SHDMA_PARAM_MASK ) << D_SHDMA_SRC_PARAM_SHIFT ) | ( trans_size & D_SHDMA_PARAM_MASK ); shdma_cmd[i].cmd_ptr->num_rows = /** <li>転送box数設定 */ (( dma_trans_num_rows & D_SHDMA_PARAM_MASK ) << D_SHDMA_SRC_PARAM_SHIFT ) | ( dma_trans_num_rows & D_SHDMA_PARAM_MASK ); shdma_cmd[i].cmd_ptr->row_offset = /** <li>転送オフセット設定 */ (( trans_size & D_SHDMA_PARAM_MASK ) << D_SHDMA_SRC_PARAM_SHIFT ) | ( trans_size & D_SHDMA_PARAM_MASK ); /** <li>転送アドレスオフセット加算 */ addr_offset += trans_size * dma_trans_num_rows; } /** </ol></ol> */ /** <li>DMA転送用パラメータをマッピングする */ for( i = 0; i < D_SHDMA_CHANNEL_MAX; i++ ){ /** <ol><li>DMAチャネル分マッピングする */ /** <ol><li>DMA転送用パラメータ領域の物理アドレスを獲得する */ shdma_cmd[i].map_cmd = dma_map_single( NULL, shdma_cmd[i].cmd_ptr, sizeof(*shdma_cmd[i].cmd_ptr), DMA_TO_DEVICE ); if( shdma_cmd[i].map_cmd == 0 ){ printk("***ERROR: falut cmd_ptr mapping. num = 0x%x\n", i); if( i != 0 ){ for( j = 0; j < (i - 1); j++ ){ dma_unmap_single( NULL, shdma_cmd[j].map_cmd, sizeof(*shdma_cmd[j].cmd_ptr), DMA_TO_DEVICE ); } } for( j = 0; j < D_SHDMA_CHANNEL_MAX; j++ ){ kfree(shdma_cmd[j].cmd_ptr_ptr); kfree(shdma_cmd[j].cmd_ptr); } up( &write_sem ); return -EFAULT; } /** <li>DMA転送用パラメータの物理アドレスをDMA転送用パラメータ先頭領域に格納する */ *shdma_cmd[i].cmd_ptr_ptr = CMD_PTR_ADDR(shdma_cmd[i].map_cmd) | CMD_PTR_LP; } for( i = 0; i < D_SHDMA_CHANNEL_MAX; i++ ){ /** <li>DMA転送用パラメータ先頭領域の物理アドレスを獲得する */ err = shdma_cmd[i].map_cmd_ptr = dma_map_single( NULL, shdma_cmd[i].cmd_ptr_ptr, sizeof(*shdma_cmd[i].cmd_ptr_ptr), DMA_TO_DEVICE ); if( err == 0 ){ printk("***ERROR: falut cmd_ptr_ptr mapping. num = 0x%x\n", i); if( i != 0 ){ for( j = 0; j < (i - 1); j++ ){ dma_unmap_single( NULL, shdma_cmd[j].map_cmd_ptr, sizeof(*shdma_cmd[j].cmd_ptr_ptr), DMA_TO_DEVICE ); } } for( j = 0; j < D_SHDMA_CHANNEL_MAX; j++ ){ dma_unmap_single( NULL, shdma_cmd[j].map_cmd, sizeof(*shdma_cmd[j].cmd_ptr), DMA_TO_DEVICE ); kfree(shdma_cmd[j].cmd_ptr_ptr); kfree(shdma_cmd[j].cmd_ptr); } up( &write_sem ); return -EFAULT; } } /** </ol></ol> */ /** <li>DMA転送構造体にパラメータを設定する */ for( i = 0; i < D_SHDMA_CHANNEL_MAX; i++ ){ /** <ol><li>DMAチャネル分設定する */ cmd[i].dmov_cmd.cmdptr = DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(shdma_cmd[i].map_cmd_ptr); cmd[i].dmov_cmd.complete_func = shdma_complete_func; cmd[i].dmov_cmd.exec_func = NULL; cmd[i].id = id[i]; cmd[i].result = 0; } /** </ol> */ /** <li>DMA転送完了資源をチャネル数分に設定する */ atomic_set( &atomic_shdma, D_SHDMA_CHANNEL_MAX ); /** <li>DMA転送開始関数をコールする */ for( i = 0; i < D_SHDMA_CHANNEL_MAX; i++ ){ msm_dmov_enqueue_cmd( cmd[i].id, &cmd[i].dmov_cmd ); } /** <li>DMA転送完了資源が0以下になるまでWaitする */ wait_event( wq, ( atomic_read( &atomic_shdma ) <= 0 )); /** <li>DMA転送結果を確認する*/ for( i = 0; i < D_SHDMA_CHANNEL_MAX; i++){ /** <ol><li>DMAチャネル分確認する */ if( cmd[i].result != D_SHDMA_DMOV_RESULT_OK ){ /** <li>DMA転送結果がNGの場合、ログを出力する */ result_chk = D_SHDMA_RET_NG; printk("***ERROR: dma id:%d result:0x%08x \n***flush: 0x%08x 0x%08x 0x%08x 0x%08x\n", id[i], cmd[i].result, cmd[i].err.flush[0], cmd[i].err.flush[1], cmd[i].err.flush[2], cmd[i].err.flush[3]); } } /** </ol>*/ /** <li>獲得したメモリを解放する */ for( i = 0; i < D_SHDMA_CHANNEL_MAX; i++ ){ dma_unmap_single( NULL, (dma_addr_t)shdma_cmd[i].map_cmd_ptr, sizeof(*shdma_cmd[i].cmd_ptr_ptr), DMA_TO_DEVICE ); dma_unmap_single( NULL, shdma_cmd[i].map_cmd, sizeof(*shdma_cmd[i].cmd_ptr), DMA_TO_DEVICE ); kfree(shdma_cmd[i].cmd_ptr_ptr); kfree(shdma_cmd[i].cmd_ptr); } /** <li>DMA転送結果を返す */ if( result_chk == 0 ){ ret = count; } else { ret = result_chk; } /** <li>ドライバwriteセマフォ解放 */ up( &write_sem ); SHDMA_DEBUG_MSG_EXIT(); /** <li>処理終了</ol>*/ return ret; }
static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) { struct msmsdcc_nc_dmadata *nc; dmov_box *box; uint32_t rows; uint32_t crci; unsigned int n; int i, rc; struct scatterlist *sg = data->sg; rc = validate_dma(host, data); if (rc) return rc; host->dma.sg = data->sg; host->dma.num_ents = data->sg_len; nc = host->dma.nc; if (host->pdev_id == 1) crci = MSMSDCC_CRCI_SDC1; else if (host->pdev_id == 2) crci = MSMSDCC_CRCI_SDC2; else if (host->pdev_id == 3) crci = MSMSDCC_CRCI_SDC3; else if (host->pdev_id == 4) crci = MSMSDCC_CRCI_SDC4; else { host->dma.sg = NULL; host->dma.num_ents = 0; return -ENOENT; } if (data->flags & MMC_DATA_READ) host->dma.dir = DMA_FROM_DEVICE; else host->dma.dir = DMA_TO_DEVICE; /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */ host->curr.user_pages = 0; n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, host->dma.dir); if (n != host->dma.num_ents) { printk(KERN_ERR "%s: Unable to map in all sg elements\n", mmc_hostname(host->mmc)); host->dma.sg = NULL; host->dma.num_ents = 0; return -ENOMEM; } box = &nc->cmd[0]; for (i = 0; i < host->dma.num_ents; i++) { box->cmd = CMD_MODE_BOX; if (i == (host->dma.num_ents - 1)) box->cmd |= CMD_LC; rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ? (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 : (sg_dma_len(sg) / MCI_FIFOSIZE) ; if (data->flags & MMC_DATA_READ) { box->src_row_addr = msmsdcc_fifo_addr(host); box->dst_row_addr = sg_dma_address(sg); box->src_dst_len = (MCI_FIFOSIZE << 16) | (MCI_FIFOSIZE); box->row_offset = MCI_FIFOSIZE; box->num_rows = rows * ((1 << 16) + 1); box->cmd |= CMD_SRC_CRCI(crci); } else { box->src_row_addr = sg_dma_address(sg); box->dst_row_addr = msmsdcc_fifo_addr(host); box->src_dst_len = (MCI_FIFOSIZE << 16) | (MCI_FIFOSIZE); box->row_offset = (MCI_FIFOSIZE << 16); box->num_rows = rows * ((1 << 16) + 1); box->cmd |= CMD_DST_CRCI(crci); } box++; sg++; } /* location of command block must be 64 bit aligned */ BUG_ON(host->dma.cmd_busaddr & 0x07); nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP; host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(host->dma.cmdptr_busaddr); host->dma.hdr.complete_func = msmsdcc_dma_complete_func; return 0; }
static int irda_uart_open(struct inode *inode, struct file *file) { int ret; u8 misc = 0x0; down(&irc->sem); printk(KERN_INFO DRV_NAME ": %s\n", __func__); /* Check refcount */ if (irc->refcount > 0) { irc->refcount++; printk(KERN_INFO DRV_NAME ": refirence counter count up(%d).\n", irc->refcount); up(&irc->sem); return 0; } /* PM8058-NFC Request */ irc->nfcdev = pm8058_nfc_request(); if (irc->nfcdev == NULL) { printk(KERN_ERR DRV_NAME ": pm8058 nfc not found.\n"); ret = -ENODEV; goto error_pm_nfc_request; } /* PM8058 UART MUX setting */ ret = pm8058_read(irc->nfcdev->pm_chip, SSBI_REG_ADDR_MISC, &misc, 1); if (ret) printk(KERN_ERR DRV_NAME ": cannot read pm8058 UART MUX reg.\n"); else printk(KERN_INFO DRV_NAME ": misc register = %x\n", misc); misc &= PM8058_UART_MUX_MASK; switch (misc) { case PM8058_UART_MUX_NO: pm8058_misc_control(irc->nfcdev->pm_chip, PM8058_UART_MUX_MASK, PM8058_UART_MUX_3); printk(KERN_INFO DRV_NAME ": OK. UART MUX = neutral --> IrDA.\n"); break; case PM8058_UART_MUX_1: printk(KERN_ERR DRV_NAME ": Now, uart_mux = 1 (FeliCa)\n"); ret = -EBUSY; goto err_set_uart_mux; case PM8058_UART_MUX_2: printk(KERN_ERR DRV_NAME ": Now, uart_mux = 2 (unknown)\n"); ret = -EBUSY; goto err_set_uart_mux; default: printk(KERN_ERR DRV_NAME ": UART MUX unavaible.\n"); ret = -EIO; goto err_set_uart_mux; } /* init IMR value */ irc->imr_reg = 0x0; /* init wait queue */ init_waitqueue_head(&irc->wait_tx); init_waitqueue_head(&irc->wait_rx); /* init tasklet */ tasklet_init(&irc->tasklet_rxfer_s, irda_uart_rxfer_start, 0); tasklet_init(&irc->tasklet_rxfer_e, irda_uart_rxfer_end, 0); tasklet_init(&irc->tasklet_txfer, irda_uart_txfer_exec, 0); /* Register UARTDM IRQ */ ret = request_irq(irc->pfdata->irq_uartdm, irda_uart_irq_handler, IRQF_TRIGGER_HIGH, "irda_uart", irc); if (ret) { printk(KERN_ERR DRV_NAME ": request IRQ failed. (UARTDM)\n"); goto err_request_irq_uart; } /* UARTDM ioremap */ /* memory protection */ irc->iores_uartdm = request_mem_region((u32) irc->pfdata->paddr_uartdm, UARTDM_SIZE, "irda_uart"); if (!irc->iores_uartdm) { printk(KERN_ERR DRV_NAME ": UARTDM request_mem_region failed.\n"); ret = -EBUSY; goto err_request_mem_region; } irc->vaddr_uartdm = ioremap_nocache((u32) irc->pfdata->paddr_uartdm, UARTDM_SIZE); if (!irc->vaddr_uartdm) { printk(KERN_ERR DRV_NAME ": UARTDM ioremap failed.\n"); ret = -ENOMEM; goto err_ioremap_uartdm; } /* UARTDM clock set and start */ /* default 9600 bps */ irc->bps = 9600; clk_set_rate(irc->clk_uartdm, IRUART_UARTDM_CLK(9600)); clk_enable(irc->clk_uartdm); msm_uartdm_write(UARTDM_CSR, IRUART_DEF_BAUDRATE_CSR); /* UARTDM register setting */ /* Data-stop-parity setting (MR2) */ msm_uartdm_write(UARTDM_MR2, IRUART_DATA_STOP_PARITY); /* RX&TX wartermark setting */ msm_uartdm_write(UARTDM_TFWR, 0x0); msm_uartdm_write(UARTDM_RFWR, 0x0); /* Stale time-out setting */ msm_uartdm_write(UARTDM_IPR, (IRUART_DEF_RXSTALE & BIT_STALE_TIMEOUT_LSB) | ((IRUART_DEF_RXSTALE << 2) & BIT_STALE_TIMEOUT_MSB)); /* Enable TXDM and RXDM mode */ msm_uartdm_write(UARTDM_DMEN, BIT_RX_DM_EN|BIT_TX_DM_EN); /* Enable the IRDA transceiver */ msm_uartdm_write(UARTDM_IRDA, IRUART_IRDA_EN); /* TX DMOV mapping */ irc->txbox = dma_alloc_coherent(NULL, sizeof(dmov_box), &irc->mapped_txbox, GFP_KERNEL); if (!irc->txbox) { printk(KERN_ERR DRV_NAME ": no enough mem for TX DMOV(1).\n"); ret = -ENOMEM; goto err_alloc_txbox; } irc->txbox_ptr = dma_alloc_coherent(NULL, sizeof(u32 *), &irc->mapped_txbox_ptr, GFP_KERNEL); if (!irc->txbox_ptr) { printk(KERN_ERR DRV_NAME ": no enough mem for TX DMOV(2).\n"); ret = -ENOMEM; goto err_alloc_txbox_ptr; } *irc->txbox_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(irc->mapped_txbox); irc->txdmov_cmd.cmdptr = DMOV_CMD_ADDR(irc->mapped_txbox_ptr); irc->txdmov_cmd.complete_func = irda_txdmov_callback; irc->txdmov_cmd.cmdptr = DMOV_CMD_ADDR(irc->mapped_txbox_ptr); irc->txbox->cmd = CMD_LC | CMD_DST_CRCI(irc->pfdata->crci_uartdm_tx) | CMD_MODE_BOX; /* TX DMOV BOX command */ irc->txbox->src_row_addr = 0x0; irc->txbox->dst_row_addr = (u32)irc->pfdata->paddr_uartdm + UARTDM_TF; irc->txbox->src_dst_len = (UARTDM_BURST_SIZE<<16)|UARTDM_BURST_SIZE; irc->txbox->num_rows = 0x0; irc->txbox->row_offset = (UARTDM_BURST_SIZE<<16); /* RX DMOV mapping */ irc->rxbox = dma_alloc_coherent(NULL, sizeof(dmov_box), &irc->mapped_rxbox, GFP_KERNEL); if (!irc->rxbox) { printk(KERN_ERR DRV_NAME ": no enough mem for RX DMOV(1).\n"); ret = -ENOMEM; goto err_alloc_rxbox; } irc->rxbox_ptr = dma_alloc_coherent(NULL, sizeof(u32 *), &irc->mapped_rxbox_ptr, GFP_KERNEL); if (!irc->rxbox_ptr) { printk(KERN_ERR DRV_NAME ": no enough mem for RX DMOV(2).\n"); ret = -ENOMEM; goto err_alloc_rxbox_ptr; } *irc->rxbox_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(irc->mapped_rxbox); irc->rxdmov_cmd.cmdptr = DMOV_CMD_ADDR(irc->mapped_rxbox_ptr); irc->rxdmov_cmd.complete_func = irda_rxdmov_callback; irc->rxdmov_cmd.cmdptr = DMOV_CMD_ADDR(irc->mapped_rxbox_ptr); irc->rxbox->cmd = CMD_LC | CMD_SRC_CRCI(irc->pfdata->crci_uartdm_rx) | CMD_MODE_BOX; /* RX DMOV BOX command */ irc->rxbox->src_row_addr = (u32)irc->pfdata->paddr_uartdm + UARTDM_RF; irc->rxbox->dst_row_addr = 0x0; irc->rxbox->src_dst_len = (UARTDM_BURST_SIZE<<16)|UARTDM_BURST_SIZE; irc->rxbox->num_rows = (IRUART_SW_RXBUF_SIZE >> 4 << 16) | IRUART_SW_RXBUF_SIZE >> 4; irc->rxbox->row_offset = UARTDM_BURST_SIZE; /* Enable Command Register Protection */ msm_uartdm_write(UARTDM_CR, GCMD_CR_PROTECTION_ENABLE); /* Reset TX and RX */ msm_uartdm_write(UARTDM_CR, CCMD_RESET_RECEIVER); msm_uartdm_write(UARTDM_CR, CCMD_RESET_TRANSMITTER); msm_uartdm_write(UARTDM_CR, CCMD_RESET_ERROR_STATUS); msm_uartdm_write(UARTDM_CR, CCMD_RESET_STALE_INTERRUPT); /* Setting PM power on (Low) */ ret = pm8058_gpio_config(irc->pfdata->gpio_pow, irc->pfdata->gpio_pwcfg_low); if (ret) { printk(KERN_ERR DRV_NAME ": pmic gpio write failed\n"); goto err_gpio_config; } /* Wait 200usec */ udelay(200); /* Enable Transmitter and Receiver */ msm_uartdm_write(UARTDM_CR, BIT_UART_TX_EN); msm_uartdm_write(UARTDM_CR, BIT_UART_RX_EN); /* Clear UART SW buffer */ irda_txbuf_clear(&irc->txbuf); irda_rxbuf_clear(&irc->rxbuf); /* init Overflow flag */ irc->rx_overflow = IRDA_NORMAL; /* Increment refcount */ irc->refcount++; /* (state change)--> IRDA_UART_OPEN */ irc->state = IRDA_UART_OPEN; irc->rx_state = IRDA_RX_IDLE; printk(KERN_INFO DRV_NAME ": succecssfly opened, refcount = %d\n", irc->refcount); /* Activate RXLEV IRQ */ irc->imr_reg |= BIT_RXLEV; msm_uartdm_write(UARTDM_IMR, irc->imr_reg); up(&irc->sem); return 0; /* Error handling */ err_gpio_config: dma_free_coherent(NULL, sizeof(u32 *), irc->rxbox_ptr, irc->mapped_txbox_ptr); err_alloc_rxbox_ptr: dma_free_coherent(NULL, sizeof(dmov_box), irc->rxbox, irc->mapped_rxbox); err_alloc_rxbox: dma_free_coherent(NULL, sizeof(u32 *), irc->txbox_ptr, irc->mapped_txbox_ptr); err_alloc_txbox_ptr: dma_free_coherent(NULL, sizeof(dmov_box), irc->txbox, irc->mapped_txbox); err_alloc_txbox: msm_uartdm_write(UARTDM_IRDA, IRUART_IRDA_DISABLE); clk_disable(irc->clk_uartdm); iounmap(irc->vaddr_uartdm); err_ioremap_uartdm: release_mem_region((u32) irc->pfdata->paddr_uartdm, UARTDM_SIZE); err_request_mem_region: free_irq(irc->pfdata->irq_uartdm, irc); err_request_irq_uart: tasklet_kill(&irc->tasklet_rxfer_s); tasklet_kill(&irc->tasklet_rxfer_e); tasklet_kill(&irc->tasklet_txfer); pm8058_misc_control(irc->nfcdev->pm_chip, PM8058_UART_MUX_MASK, PM8058_UART_MUX_NO); err_set_uart_mux: error_pm_nfc_request: up(&irc->sem); return ret; }