Example #1
0
int i2s_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
#endif
{
	int i ;
	unsigned long flags, data;
	i2s_config_type* ptri2s_config;
	    
	ptri2s_config = filp->private_data;
	switch (cmd) {
	case I2S_SRATE:
		spin_lock_irqsave(&ptri2s_config->lock, flags);
		{
			data = *(unsigned long*)(RALINK_SYSCTL_BASE+0x834);
			data |=(1<<17);
	    		*(unsigned long*)(RALINK_SYSCTL_BASE+0x834) = data;
	    		
	    		data = *(unsigned long*)(RALINK_SYSCTL_BASE+0x834);
			data &=~(1<<17);
	    		*(unsigned long*)(RALINK_SYSCTL_BASE+0x834) = data;
	    		
	    		audiohw_preinit();
		}	
		if((arg>MAX_SRATE_HZ)||(arg<MIN_SRATE_HZ))
		{
			MSG("audio sampling rate %u should be %d ~ %d Hz\n", (u32)arg, MIN_SRATE_HZ, MAX_SRATE_HZ);
			break;
		}	
		ptri2s_config->srate = arg;
		MSG("set audio sampling rate to %d Hz\n", ptri2s_config->srate);
		spin_unlock_irqrestore(&ptri2s_config->lock, flags);
		break;
	case I2S_TX_VOL:
		spin_lock_irqsave(&ptri2s_config->lock, flags);
		if((int)arg > 127)
		{
			ptri2s_config->txvol = 127;
		}
		else if((int)arg < 96)
		{
			ptri2s_config->txvol = 96;
		}	
		else
		ptri2s_config->txvol = arg;
		
		spin_unlock_irqrestore(&ptri2s_config->lock, flags);
		break;
	case I2S_RX_VOL:
		spin_lock_irqsave(&ptri2s_config->lock, flags);
		if((int)arg > 63)
		{
			ptri2s_config->rxvol = 63;
		}
		else if((int)arg < 0)
		{
			ptri2s_config->rxvol = 0;
		}	
		else
		ptri2s_config->rxvol = arg;

		spin_unlock_irqrestore(&ptri2s_config->lock, flags);
		break;	
	case I2S_TX_ENABLE:
		spin_lock_irqsave(&ptri2s_config->lock, flags);
		MSG("I2S_TXENABLE\n");

		/* allocate tx buffer */
		ptri2s_config->pPage0TxBuf8ptr = (u8*)pci_alloc_consistent(NULL, I2S_PAGE_SIZE*2 , &i2s_txdma_addr);
		if(ptri2s_config->pPage0TxBuf8ptr==NULL)
		{
			MSG("Allocate Tx Page Buffer Failed\n");
			return -1;
		}
		ptri2s_config->pPage1TxBuf8ptr = ptri2s_config->pPage0TxBuf8ptr + I2S_PAGE_SIZE;
		for( i = 0 ; i < MAX_I2S_PAGE ; i ++ )
		{
#if defined(CONFIG_I2S_MMAP)
			ptri2s_config->pMMAPTxBufPtr[i] = ptri2s_config->pMMAPBufPtr[i];
#else

			if(ptri2s_config->pMMAPTxBufPtr[i]==NULL)
				ptri2s_config->pMMAPTxBufPtr[i] = kmalloc(I2S_PAGE_SIZE, GFP_KERNEL);
#endif
		}
#if defined(I2S_FIFO_MODE)
#else
		GdmaI2sTx((u32)ptri2s_config->pPage0TxBuf8ptr, I2S_FIFO_WREG, 0, I2S_PAGE_SIZE, i2s_dma_tx_handler, i2s_unmask_handler);
		GdmaI2sTx((u32)ptri2s_config->pPage1TxBuf8ptr, I2S_FIFO_WREG, 1, I2S_PAGE_SIZE, i2s_dma_tx_handler, i2s_unmask_handler);
#endif	
		
		i2s_reset_tx_config(ptri2s_config);
		ptri2s_config->bTxDMAEnable = 1;
		i2s_tx_config(ptri2s_config);
		
		if(ptri2s_config->bRxDMAEnable==0)
			i2s_clock_enable(ptri2s_config);

		audiohw_set_lineout_vol(1, ptri2s_config->txvol, ptri2s_config->txvol);
		
		i2s_tx_enable(ptri2s_config);
#if defined(I2S_FIFO_MODE)
#else
		GdmaUnMaskChannel(GDMA_I2S_TX0);
#endif
		data = i2s_inw(RALINK_REG_INTENA);
		data |=0x0400;
	    	i2s_outw(RALINK_REG_INTENA, data);
	
	    	MSG("I2S_TXENABLE done\n");
		spin_unlock_irqrestore(&ptri2s_config->lock, flags);
		break;
	case I2S_TX_DISABLE:
		spin_lock_irqsave(&ptri2s_config->lock, flags);
		MSG("I2S_TXDISABLE\n");
		i2s_tx_disable(ptri2s_config);
		i2s_reset_tx_config(ptri2s_config);
		if(ptri2s_config->bRxDMAEnable==0)
			i2s_clock_disable(ptri2s_config);
		//i2s_tx_disable(ptri2s_config);
		if(ptri2s_config->bRxDMAEnable==0)
		{
			data = i2s_inw(RALINK_REG_INTENA);
			data &= 0xFFFFFBFF;
		    i2s_outw(RALINK_REG_INTENA, data);
		}
		
		for( i = 0 ; i < MAX_I2S_PAGE ; i ++ )
		{
			if(ptri2s_config->pMMAPTxBufPtr[i] != NULL)
			{
#if defined(CONFIG_I2S_MMAP)
				dma_unmap_single(NULL, i2s_mmap_addr[i], I2S_PAGE_SIZE, DMA_TO_DEVICE);
#endif
				kfree(ptri2s_config->pMMAPTxBufPtr[i]);		
				ptri2s_config->pMMAPTxBufPtr[i] = NULL;
			}
		}
		pci_free_consistent(NULL, I2S_PAGE_SIZE*2, ptri2s_config->pPage0TxBuf8ptr, i2s_txdma_addr);
		ptri2s_config->pPage0TxBuf8ptr = NULL;
		spin_unlock_irqrestore(&ptri2s_config->lock, flags);
		break;
	case I2S_RX_ENABLE:

		spin_lock_irqsave(&ptri2s_config->lock, flags);
		MSG("I2S_RXENABLE\n");
		
		/* allocate rx buffer */
		ptri2s_config->pPage0RxBuf8ptr = (u8*)pci_alloc_consistent(NULL, I2S_PAGE_SIZE*2 , &i2s_rxdma_addr);
		if(ptri2s_config->pPage0RxBuf8ptr==NULL)
		{
			MSG("Allocate Rx Page Buffer Failed\n");
			return -1;
		}
		ptri2s_config->pPage1RxBuf8ptr = ptri2s_config->pPage0RxBuf8ptr + I2S_PAGE_SIZE;
		
		for( i = 0 ; i < MAX_I2S_PAGE ; i ++ )
		{
			if(ptri2s_config->pMMAPRxBufPtr[i]==NULL)
				ptri2s_config->pMMAPRxBufPtr[i] = kmalloc(I2S_PAGE_SIZE, GFP_KERNEL);
		}
#if defined(I2S_FIFO_MODE)
#else		
		GdmaI2sRx(I2S_RX_FIFO_RREG, (u32)ptri2s_config->pPage0RxBuf8ptr, 0, I2S_PAGE_SIZE, i2s_dma_rx_handler, i2s_unmask_handler);
		GdmaI2sRx(I2S_RX_FIFO_RREG, (u32)ptri2s_config->pPage1RxBuf8ptr, 1, I2S_PAGE_SIZE, i2s_dma_rx_handler, i2s_unmask_handler);
#endif
		i2s_reset_rx_config(ptri2s_config);
		ptri2s_config->bRxDMAEnable = 1;
		i2s_rx_config(ptri2s_config);
#if defined(I2S_FIFO_MODE)
#else		
		GdmaUnMaskChannel(GDMA_I2S_RX0);
#endif
		if(ptri2s_config->bTxDMAEnable==0)
			i2s_clock_enable(ptri2s_config);
#if defined(CONFIG_I2S_TXRX)
		audiohw_set_linein_vol(ptri2s_config->rxvol,  ptri2s_config->rxvol);
#endif
		i2s_rx_enable(ptri2s_config);

		data = i2s_inw(RALINK_REG_INTENA);
		data |=0x0400;
	    	i2s_outw(RALINK_REG_INTENA, data);
		spin_unlock_irqrestore(&ptri2s_config->lock, flags);

		break;
	case I2S_RX_DISABLE:
		spin_lock_irqsave(&ptri2s_config->lock, flags);
		MSG("I2S_RXDISABLE\n");
		i2s_reset_rx_config(ptri2s_config);
		if(ptri2s_config->bTxDMAEnable==0)
			i2s_clock_disable(ptri2s_config);
		i2s_rx_disable(ptri2s_config);
		if(ptri2s_config->bRxDMAEnable==0)
		{
			data = i2s_inw(RALINK_REG_INTENA);
			data &= 0xFFFFFBFF;
	    	i2s_outw(RALINK_REG_INTENA, data);
		}
		
		for( i = 0 ; i < MAX_I2S_PAGE ; i ++ )
		{
			if(ptri2s_config->pMMAPRxBufPtr[i] != NULL)
				kfree(ptri2s_config->pMMAPRxBufPtr[i]);		
			ptri2s_config->pMMAPRxBufPtr[i] = NULL;
		}
		
		pci_free_consistent(NULL, I2S_PAGE_SIZE*2, ptri2s_config->pPage0RxBuf8ptr, i2s_rxdma_addr);
		ptri2s_config->pPage0RxBuf8ptr = NULL;
		spin_unlock_irqrestore(&ptri2s_config->lock, flags);
		break;
	case I2S_PUT_AUDIO:
		//MSG("I2S_PUT_AUDIO\n");	
#if defined(I2S_FIFO_MODE)		
		{
			
			long* pData ;
			//MSG("I2S_PUT_AUDIO FIFO\n");
			copy_from_user(ptri2s_config->pMMAPTxBufPtr[0], (char*)arg, I2S_PAGE_SIZE);
			pData = ptri2s_config->pMMAPTxBufPtr[0];
			for(i = 0 ; i < I2S_PAGE_SIZE>>2 ; i++ )	
			{
				int j;
				unsigned long status = i2s_inw(I2S_FF_STATUS);
				while((status&0x0F)==0)
				{
					for(j = 0 ; j < 50 ; j++);
					status = i2s_inw(I2S_FF_STATUS);
				}
				*((volatile uint32_t *)(I2S_TX_FIFO_WREG)) = cpu_to_le32(*pData);
				if(i==16)
					MSG("I2S_PUT_AUDIO FIFO[0x%08X]\n", *pData);
				pData++;
				
					
			}
		}
		break;
#else		
		do{
			spin_lock_irqsave(&ptri2s_config->lock, flags);
			
			if(((ptri2s_config->tx_w_idx+4)%MAX_I2S_PAGE)!=ptri2s_config->tx_r_idx)
			{
				ptri2s_config->tx_w_idx = (ptri2s_config->tx_w_idx+1)%MAX_I2S_PAGE;	
				//printk("put TB[%d] for user write\n",ptri2s_config->tx_w_idx);
#if defined(CONFIG_I2S_MMAP)
				put_user(ptri2s_config->tx_w_idx, (int*)arg);
#else
				copy_from_user(ptri2s_config->pMMAPTxBufPtr[ptri2s_config->tx_w_idx], (char*)arg, I2S_PAGE_SIZE);
#endif
				pi2s_status->txbuffer_len++;
				spin_unlock_irqrestore(&ptri2s_config->lock, flags);	
				break;
			}
			else
			{
				/* Buffer Full */
				//printk("TBF tr=%d, tw=%d\n", ptri2s_config->tx_r_idx, ptri2s_config->tx_w_idx);
				pi2s_status->txbuffer_ovrun++;
				spin_unlock_irqrestore(&ptri2s_config->lock, flags);
				interruptible_sleep_on(&(ptri2s_config->i2s_tx_qh));
				
			}
		}while(1);
		break;
#endif
	case I2S_GET_AUDIO:
#if defined(I2S_FIFO_MODE)			
		{
			
			long* pData ;
			
			
			pData = ptri2s_config->pMMAPRxBufPtr[0];
			for(i = 0 ; i < I2S_PAGE_SIZE>>2 ; i++ )	
			{
				int j;
				unsigned long status = i2s_inw(I2S_FF_STATUS);
				while((status&0x0F0)==0)
				{
					for(j = 0 ; j < 50 ; j++);
					status = i2s_inw(I2S_FF_STATUS);
				}
				
				*pData = i2s_inw(I2S_RX_FIFO_RREG);
				if(i==16)
					MSG("I2S_GET_AUDIO FIFO[0x%08X]\n", *pData);
				pData++;
			}
			
			copy_to_user((char*)arg, ptri2s_config->pMMAPRxBufPtr[0], I2S_PAGE_SIZE);
		}
		break;
#else		
		do{
			spin_lock_irqsave(&ptri2s_config->lock, flags);
			
			if(ptri2s_config->rx_r_idx!=ptri2s_config->rx_w_idx)
			{			
				copy_to_user((char*)arg, ptri2s_config->pMMAPRxBufPtr[ptri2s_config->rx_r_idx], I2S_PAGE_SIZE);
				ptri2s_config->rx_r_idx = (ptri2s_config->rx_r_idx+1)%MAX_I2S_PAGE;
				pi2s_status->rxbuffer_len--;
				spin_unlock_irqrestore(&ptri2s_config->lock, flags);	
				break;
			}
			else
			{
				/* Buffer Full */
				//printk("RBF rr=%d, rw=%d\n", ptri2s_config->rx_r_idx, ptri2s_config->rx_w_idx);
				pi2s_status->rxbuffer_ovrun++;
				spin_unlock_irqrestore(&ptri2s_config->lock, flags);
				interruptible_sleep_on(&(ptri2s_config->i2s_rx_qh));
				
			}
		}while(1);
		break;
#endif		
	case I2S_DEBUG_CLKGEN:
	case I2S_DEBUG_INLBK:
	case I2S_DEBUG_EXLBK:
	case I2S_DEBUG_CODECBYPASS:	
	case I2S_DEBUG_FMT:
	case I2S_DEBUG_RESET:
		i2s_debug_cmd(cmd, arg);
		break;							
	default :
		MSG("i2s_ioctl: command format error\n");
	}

	return 0;
}
int tegra_das_set_connection(enum tegra_das_port_con_id new_con_id)
{
	struct am_ch_info *ch1 = NULL, *ch2 = NULL;
	int dev_id1 = 0, dev_id2 = 0;
	int damch = 0;
	struct audio_dev_property dev1_prop, dev2_prop;
	int break_voicecall = 0, break_voicecallbt = 0;
	int make_voicecall = 0, make_voicecallbt = 0;

	AM_DEBUG_PRINT("%s++\n", __func__);

	if (new_con_id == tegra_das_port_con_id_voicecall_no_bt) {
		if (aud_manager->cur_conn ==
			tegra_das_port_con_id_voicecall_with_bt) {
			break_voicecallbt = 1;
		}
		make_voicecall = 1;
	} else if (new_con_id == tegra_das_port_con_id_voicecall_with_bt) {
		if (aud_manager->cur_conn ==
			tegra_das_port_con_id_voicecall_no_bt) {
			break_voicecall = 1;
		}
		make_voicecallbt = 1;
	} else if (new_con_id == tegra_das_port_con_id_hifi) {
		if (aud_manager->cur_conn ==
			tegra_das_port_con_id_voicecall_no_bt) {
			break_voicecall = 1;
		} else if (aud_manager->cur_conn ==
				tegra_das_port_con_id_voicecall_with_bt) {
				break_voicecallbt = 1;
		}
	} else if (new_con_id == tegra_das_port_con_id_bt_codec) {
		if (aud_manager->cur_conn ==
			tegra_das_port_con_id_voicecall_with_bt) {
			break_voicecallbt = 1;
		} else if (aud_manager->cur_conn ==
				tegra_das_port_con_id_voicecall_no_bt) {
				break_voicecall = 1;
		}
	}

	/*break old connections and make new connections*/
	if (break_voicecall == 1) {
		dev_id1 = aud_manager->hifi_port_idx;
		ch1 = &aud_manager->i2s_ch[dev_id1];

		AM_DEBUG_PRINT("devid1 %d\n", dev_id1);

		dev_id2 = aud_manager->bb_port_idx;
		ch2 = &aud_manager->i2s_ch[dev_id2];

		AM_DEBUG_PRINT("devid2 %d\n", dev_id2);

		i2s_fifo_enable(dev_id1, AUDIO_TX_MODE, 0);
		i2s_fifo_enable(dev_id2, AUDIO_TX_MODE, 0);
		i2s_fifo_enable(dev_id1, AUDIO_RX_MODE, 0);
		i2s_fifo_enable(dev_id2, AUDIO_RX_MODE, 0);
		dam_enable(ch1->damch[dam_ch_in0], 0, dam_ch_in0);
		dam_enable(ch2->damch[dam_ch_in0], 0, dam_ch_in0);

		audio_switch_clear_rx_port(dev_id2 + ahubrx_i2s0);
		audio_switch_clear_rx_port(ahubrx0_dam0 +
					(ch1->damch[dam_ch_in0] << 1));
		audio_switch_clear_rx_port(ahubrx0_dam0 +
					(ch2->damch[dam_ch_in0] << 1));


		dam_free_controller(ch1->damch[dam_ch_in0], dam_ch_in0);
		ch1->damch[dam_ch_in0] = -1;

		dam_free_controller(ch2->damch[dam_ch_in0], dam_ch_in0);
		ch2->damch[dam_ch_in0] = -1;

		i2s_clock_disable(dev_id1, 0);
		i2s_clock_disable(dev_id2, 0);
	} else if (break_voicecallbt == 1) {
		dev_id1 = aud_manager->bt_port_idx;
		ch1 = &aud_manager->i2s_ch[dev_id1];

		AM_DEBUG_PRINT("devid1 %d\n", dev_id1);

		dev_id2 = aud_manager->bb_port_idx;
		ch2 = &aud_manager->i2s_ch[dev_id2];

		AM_DEBUG_PRINT("devid2 %d\n", dev_id2);

		i2s_fifo_enable(dev_id1, AUDIO_TX_MODE, 0);
		i2s_fifo_enable(dev_id2, AUDIO_TX_MODE, 0);
		i2s_fifo_enable(dev_id1, AUDIO_RX_MODE, 0);
		i2s_fifo_enable(dev_id2, AUDIO_RX_MODE, 0);
		dam_enable(ch1->damch[dam_ch_in0], 0, dam_ch_in0);
		dam_enable(ch2->damch[dam_ch_in0], 0, dam_ch_in0);

		audio_switch_clear_rx_port(dev_id2 + ahubrx_i2s0);
		audio_switch_clear_rx_port(ahubrx0_dam0 +
					(ch1->damch[dam_ch_in0] << 1));
		audio_switch_clear_rx_port(ahubrx0_dam0 +
					(ch2->damch[dam_ch_in0] << 1));


		dam_free_controller(ch1->damch[dam_ch_in0], dam_ch_in0);
		ch1->damch[dam_ch_in0] = -1;

		dam_free_controller(ch2->damch[dam_ch_in0], dam_ch_in0);
		ch2->damch[dam_ch_in0] = -1;

		i2s_clock_disable(dev_id1, 0);
		i2s_clock_disable(dev_id2, 0);
	}


	if (make_voicecall == 1) {
		AM_DEBUG_PRINT("voice call connection\n");

		memset(&dev1_prop, 0,
			sizeof(struct audio_dev_property));
		memset(&dev2_prop, 0,
			sizeof(struct audio_dev_property));
		tegra_das_get_device_property(
			tegra_audio_codec_type_hifi,
			&dev1_prop);
		tegra_das_get_device_property(
			tegra_audio_codec_type_baseband,
			&dev2_prop);

		dev_id1 = aud_manager->hifi_port_idx;
		dev_id2 = aud_manager->bb_port_idx;

		i2s_clock_enable(dev_id1, 0);
		i2s_clock_enable(dev_id2, 0);

		ch1 = &aud_manager->i2s_ch[dev_id1];
		ch2 = &aud_manager->i2s_ch[dev_id2];

		AM_DEBUG_PRINT("devid1 %d devid2 %d\n",
			dev_id1, dev_id2);

		setup_baseband_connection(dev_id1, &dev1_prop);
		setup_baseband_connection(dev_id2, &dev2_prop);

		damch = ch1->damch[dam_ch_in0];
		dam_set_samplerate(damch, dam_ch_in0, dev2_prop.rate);

		/*i2s1_tx (48Khz) -> dam_ch0 rx (8k)*/
		audio_switch_set_rx_port(ahubrx0_dam0 + (damch << 1),
					dev_id2 + ahubtx_i2s0);

		/*get the properties of i2s and set to i2s and dam*/
		dam_set_acif(damch, dam_ch_in0, &ch2->outcif);
		dam_enable(damch, 1, dam_ch_in0);

		damch = ch2->damch[dam_ch_in0];
		dam_set_samplerate(damch, dam_ch_in0, dev1_prop.rate);

		/*get the properties of i2s and set to i2s and dam*/
		dam_set_acif(damch, dam_ch_in0, &ch1->outcif);
		audio_switch_set_rx_port(ahubrx0_dam0 + (damch << 1),
					dev_id1 + ahubtx_i2s0);

		/*enable the dap and i2s as well*/
		dam_enable(damch, 1, dam_ch_in0);
		i2s_fifo_enable(dev_id1, AUDIO_TX_MODE, 1);
		i2s_fifo_enable(dev_id2, AUDIO_TX_MODE, 1);
		i2s_fifo_enable(dev_id1, AUDIO_RX_MODE, 1);
		i2s_fifo_enable(dev_id2, AUDIO_RX_MODE, 1);
	} else if (make_voicecallbt == 1) {
		AM_DEBUG_PRINT("bt voice call connection\n");

		memset(&dev1_prop, 0,
			sizeof(struct audio_dev_property));
		memset(&dev2_prop, 0,
			sizeof(struct audio_dev_property));
		tegra_das_get_device_property(
			tegra_audio_codec_type_bluetooth,
			&dev1_prop);
		tegra_das_get_device_property(
			tegra_audio_codec_type_baseband,
			&dev2_prop);

		dev_id1 = aud_manager->bt_port_idx;
		dev_id2 = aud_manager->bb_port_idx;

		i2s_clock_enable(dev_id1, 0);
		i2s_clock_enable(dev_id2, 0);

		ch1 = &aud_manager->i2s_ch[dev_id1];
		ch2 = &aud_manager->i2s_ch[dev_id2];

		setup_baseband_connection(dev_id1, &dev1_prop);
		setup_baseband_connection(dev_id2, &dev2_prop);

		damch = ch1->damch[dam_ch_in0];
		dam_set_samplerate(damch, dam_ch_in0, dev2_prop.rate);

		/*i2s1_tx (48Khz) -> dam_ch0 rx (8k)*/
		audio_switch_set_rx_port(ahubrx0_dam0 + (damch << 1),
					dev_id2 + ahubtx_i2s0);

		/*get the properties of i2s and set to i2s and dam*/
		dam_set_acif(damch, dam_ch_in0, &ch2->outcif);
		dam_enable(damch, 1, dam_ch_in0);

		damch = ch2->damch[dam_ch_in0];
		dam_set_samplerate(damch, dam_ch_in0, dev1_prop.rate);

		/*get the properties of i2s and set to i2s and dam*/
		dam_set_acif(damch, dam_ch_in0, &ch1->outcif);
		audio_switch_set_rx_port(ahubrx0_dam0 + (damch << 1),
					dev_id1 + ahubtx_i2s0);

		/* enable the dap and i2s as well */
		dam_enable(damch, 1, dam_ch_in0);
		i2s_fifo_enable(dev_id1, AUDIO_TX_MODE, 1);
		i2s_fifo_enable(dev_id2, AUDIO_TX_MODE, 1);
		i2s_fifo_enable(dev_id1, AUDIO_RX_MODE, 1);
		i2s_fifo_enable(dev_id2, AUDIO_RX_MODE, 1);
	}

	aud_manager->cur_conn = new_con_id;
	AM_DEBUG_PRINT("%s--\n", __func__);
	return 0;
}