Ejemplo n.º 1
0
/**
 * @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;
}