static void aic3008_tx_config(int mode)
{
	/* mode = 0 for initialisation */

	/* use default setting when tx table doesn't be updated*/
	if (aic3008_uplink == NULL) {
		AUD_DBG("[TX] use default setting since tx table doesn't be updated");
		if (mode == UPLINK_PATH_OFF)
			route_tx_enable(mode, 0); /* uploink off */
		else
			route_tx_enable(mode, 1); /* if no mem for aic3008_uplink + on */
		return;
	}

	/* if not uplink off or power off */
	if (mode != UPLINK_PATH_OFF && mode != POWER_OFF) {
		/* uplink_Wakeup */
		AUD_DBG("[TX] ----- uplink wakeup len(%d) -----\n",
				(aic3008_uplink[UPLINK_WAKEUP][0].data-1));

		aic3008_config(&aic3008_uplink[UPLINK_WAKEUP][1],
				aic3008_uplink[UPLINK_WAKEUP][0].data);
	}

	/* route tx device */
	AUD_INFO("[TX] ----- change i/o uplink TX %d len(%d) -----\n", mode,
			(aic3008_uplink[mode][0].data-1));

	aic3008_config(&aic3008_uplink[mode][1], aic3008_uplink[mode][0].data);
}
static void aic3008_rx_config(int mode)
{
	/* use default setting when rx table doesn't be updated*/
	if (aic3008_downlink == NULL) {
		AUD_DBG("[RX] use default setting since rx table doesn't be updated");
		if (mode == DOWNLINK_PATH_OFF)
			route_rx_enable(mode, 0);
		else
			route_rx_enable(mode, 1);
		return;
	}

	if (mode != DOWNLINK_PATH_OFF) {
		/* Downlink Wakeup */
		AUD_DBG("[RX] ----- downlink wakeup len(%d) -----\n",
				(aic3008_downlink[DOWNLINK_WAKEUP][0].data-1));
		aic3008_config(&aic3008_downlink[DOWNLINK_WAKEUP][1],
				aic3008_downlink[DOWNLINK_WAKEUP][0].data);
	}

	/* route rx device */
	AUD_INFO("[RX] ----- change i/o downlink RX %d len(%d) -----\n", mode,
			(aic3008_downlink[mode][0].data-1));

	aic3008_config(&aic3008_downlink[mode][1], aic3008_downlink[mode][0].data);
}
Esempio n. 3
0
static void tegra_audio_route(struct aic3008_priv *audio_data,
		int cmd, int idx)
{
	switch (cmd) {
	case AIC3008_IO_CONFIG_RX:
		AUD_DBG("tegra_audio_route, AIC3008_IO_CONFIG_RX, idx = %d, call mode %d \n",
				idx, audio_data->is_call_mode);
		aic3008_setMode(cmd, idx, audio_data->is_call_mode);
		break;

	case AIC3008_IO_CONFIG_TX:
		AUD_DBG("tegra_audio_route, AIC3008_IO_CONFIG_TX, idx = %d, call mode %d \n",
				idx, audio_data->is_call_mode);
		aic3008_setMode(cmd, idx, audio_data->is_call_mode);
		break;

	case AIC3008_IO_CONFIG_MEDIA:
		AUD_DBG("tegra_audio_route, AIC3008_IO_CONFIG_MEDIA, idx = %d, call mode %d \n",
				idx, audio_data->is_call_mode);
		aic3008_setMode(cmd, idx, audio_data->is_call_mode);
		break;
#if (defined(CONFIG_TEGRA_ES305))
	case ES305_SET_CONFIG:
		AUD_DBG("tegra_audio_route, ES305_SET_CONFIG, idx = %d, call mode %d \n",
				idx, audio_data->is_call_mode);
		es305_set_config(idx, ES305_CONFIG_FULL);
		break;
#endif
	}

}
Esempio n. 4
0
static int tegra_call_mode_put(struct snd_kcontrol *kcontrol,
				   struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
	struct aic3008_priv *audio_data = snd_soc_codec_get_drvdata(codec);
	int is_call_mode_new;

	if (audio_data) {
		is_call_mode_new = ucontrol->value.integer.value[0];

		if (is_call_mode_new == true)
		{
			AUD_DBG("in_call_mode.\n");
		}
		else
		{
#if (defined(CONFIG_TEGRA_ES305))
			if (audio_data->is_call_mode != is_call_mode_new) {
				AUD_DBG("not_in_call_mode. put es305 into sleep mode\n");
				es305_sleep();
				audio_data->es305_cfg_id = -1;
			}
#endif
		}

		audio_data->is_call_mode = is_call_mode_new;
		return 0;
	}
	return -EINVAL;
}
void aic3008_CodecInit()
{
	AUD_DBG("aic3008_CodecInit: start\n");
	pwr_up_time = ktime_to_ms(ktime_get());

	pr_device_power_on();

	// aic3008 power up
	aic3008_power_ctl->powerinit();

	// close mic
	aic3008_MicSwitch(0);

	spi_write_table_parsepage(POWER_UP_SEQ, ARRAY_SIZE(POWER_UP_SEQ));
	AUD_DBG("***** SPI CMD: Power Up Seq *****\n");

	AUD_DBG("Audio Codec Power Up takes %lld ms\n",
			ktime_to_ms(ktime_get()) - pwr_up_time);
#if AUDIO_DEBUG_BEEP
	mdelay(100);
	spi_write_table_parsepage(GENERATE_BEEP_LEFT_SPK, ARRAY_SIZE(GENERATE_BEEP_LEFT_SPK));

	AUD_DBG("***** SPI CMD: BEEP *****\n");
	mdelay(300);
	spi_write_table_parsepage(CODEC_SW_RESET, ARRAY_SIZE(CODEC_SW_RESET));
#endif

	aic3008_rx_mode = DOWNLINK_PATH_OFF;
	aic3008_tx_mode = UPLINK_PATH_OFF;
}
static int codec_spi_write(unsigned char addr, unsigned char data, bool flag)
{
	unsigned char buffer[2];
	int rc;

	if (!codec_spi_dev)
		return 0;

	if(addr == 0x00 && flag)
	{
		AUD_DBG("------ write page: 0x%02X ------\n", data);
	}
	else if(addr == 0x7F && flag)
	{
		AUD_DBG("------ write book: 0x%02X ------\n", data);
	}
	else if(flag)
	{
		AUD_DBG("write : reg: 0x%02X data: 0x%02X\n", addr, data);
	}

	codec_spi_dev->bits_per_word = 16;
	/* addr and data swapped around because 16bit word */
	buffer[1] = addr << 1;
	buffer[0] = data;
	rc = spi_write(codec_spi_dev, buffer, 2);

	return rc;
}
/* Access function pointed by ctl_ops to call control operations */
static int aic3008_config(CODEC_SPI_CMD *cmds, int size)
{
	int i, retry, ret;
	unsigned char data;
	if(!aic3008_power_ctl->isPowerOn)
	{
		AUD_INFO("aic3008_config: AIC3008 is power off now");
		return -EINVAL;
	}

	if (!codec_spi_dev) {
		AUD_ERR("no spi device\n");
		return -EFAULT;
	}

	if (cmds == NULL) {
		AUD_ERR("invalid spi parameters\n");
		return -EINVAL;
	}

	/* large dsp image use bulk mode to transfer */
	if (size < 1000) {
		for (i = 0; i < size; i++) {
			switch (cmds[i].act) {
			case 'w':
				codec_spi_write(cmds[i].reg, cmds[i].data, true);
				break;
			case 'r':
				for (retry = AIC3008_MAX_RETRY; retry > 0; retry--) {
					ret = codec_spi_read(cmds[i].reg, &data, true);
					if (ret < 0) {
						AUD_ERR("read fail %d, retry\n", ret);
						hr_msleep(1);
					} else if (data == cmds[i].data) {
						AUD_DBG("data == cmds\n");
						break;
					}
				}
				if (retry <= 0)
					AUD_DBG("3008 power down procedure,"
							" flag 0x%02X=0x%02X(0x%02X)\n",
							cmds[i].reg, ret, cmds[i].data);
				break;
			case 'd':
				msleep(cmds[i].data);
				break;
			default:
				break;
			}
		}
	} else {
		/* use bulk to transfer large data */
		spi_write_table_parsepage(cmds, size);
		AUD_DBG("Here is bulk mode\n");
	}
	return 0;
}
Esempio n. 8
0
static __devinit int tegra_aic3008_driver_probe(struct platform_device *pdev)
{
	struct snd_soc_card *card = &snd_soc_tegra_aic3008;
	struct tegra_aic3008 *machine;
	struct htc_asoc_platform_data *pdata;
	int ret;

	AUD_INFO("starting tegra_aic3008_driver_probe...\n");

	pdata = pdev->dev.platform_data;
	if (!pdata) {
		dev_err(&pdev->dev, "No platform data supplied\n");
		return -EINVAL;
	}
	AUD_INFO("starting tegra_aic3008_driver_probe...%p %p\n", &pdata->aic3008_power, &aic3008_power_ctl);
	aic3008_power_ctl = &pdata->aic3008_power;

	machine = kzalloc(sizeof(struct tegra_aic3008), GFP_KERNEL);
	if (!machine) {
		AUD_ERR("Can't allocate tegra_aic3008 struct\n");
		return -ENOMEM;
	}

	machine->pdata = pdata;

	ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card);
	util_data = &machine->util_data;
	if (ret)
		goto err_free_machine;
	AUD_DBG("DONE tegra_asoc_utils_init()\n");

	card->dev = &pdev->dev;
	platform_set_drvdata(pdev, card);
	snd_soc_card_set_drvdata(card, machine);

	ret = snd_soc_register_card(card);
	if (ret) {
		AUD_ERR("snd_soc_register_card failed %d\n",ret);
		goto err_unregister_switch;
	}
	AUD_DBG("DONE snd_soc_register_card()\n");

	return 0;

err_unregister_switch:

	tegra_asoc_utils_fini(&machine->util_data);
err_free_machine:
	kfree(machine);
	return ret;
}
/* write a register then read a register, compare them ! */
static int32_t spi_write_read_list(CODEC_SPI_CMD *cmds, int num)
{
	int i;
	int rc;
	unsigned char write_buffer[2];
	unsigned char read_result[2] = { 0, 0 };

	if (!codec_spi_dev)
		return 0;

	codec_spi_dev->bits_per_word = 16;
	for (i = 0; i < num; i++) {
		/*if writing page, then don't read its value */
		switch (cmds[i].act) {
		case 'w':
			write_buffer[1] = cmds[i].reg << 1;
			write_buffer[0] = cmds[i].data;
			if (cmds[i].reg == 0x00 || cmds[i].reg == 0x7F) {
				rc = spi_write(codec_spi_dev, write_buffer, sizeof(write_buffer));
				if (rc < 0)
					return rc;
				if(cmds[i].reg == 0x00)
				{
					AUD_DBG("------ write page: 0x%02X ------\n", cmds[i].data);
				}
				else if(cmds[i].reg == 0x7F)
				{
					AUD_DBG("------ write book: 0x%02X ------\n", cmds[i].data);
				}
			} else {
				rc = spi_write_then_read(codec_spi_dev, write_buffer, 2, read_result, 2);
				if (rc < 0)
					return rc;

				if (read_result[0] != cmds[i].data)
					AUD_INFO("incorrect value,reg 0x%02x, write 0x%02x, read 0x%02x",
						cmds[i].reg, cmds[i].data, read_result[0]);
			}
			break;
		case 'd':
			msleep(cmds[i].data);
			break;
		default:
			break;
		}
	}
	return 0;
}
static int __init aic3008_modinit(void)
{
	AUD_DBG("Start aic3008_modinit\n");
	drv_up_time = ktime_to_ms(ktime_get());
	spi_aic3008_init();
	return 0;
}
static inline void spi_aic3008_exit(void)
{
	AUD_DBG("exiting aic3008 spi driver...\n");

	spi_unregister_driver(&aic3008_spi_driver);
	misc_deregister(&aic3008_misc);
}
static int aic3008_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
	//AUD_DBG("call set_bias_level(SND_SOC_BIAS_OFF)\n");
	//aic3008_set_bias_level(codec, SND_SOC_BIAS_OFF);
	AUD_DBG("aic3008_suspend\n");
	return 0;
}
static int codec_spi_read(unsigned char addr, unsigned char *data, bool flag)
{
	int rc;
	u8 buffer[2] = { 0, 0 };
	u8 result[2] = { 0, 0 };

	codec_spi_dev->bits_per_word = 16;
	buffer[1] = addr << 1 | 1; /* high byte because 16bit word */

	/*AUD_DBG("before read: buf[1]:0x%02X buf[0]:0x%02X res[1]:0x%02X res[0]:0x%02X \n",
			buffer[1], buffer[0], result[1], result[0]);*/

	/* because aic3008 does symmetric SPI write and read */
	rc = spi_write_then_read(codec_spi_dev, buffer, 2, result, 2);
	if (rc < 0)
		return rc;

	if(flag)
	{
		AUD_DBG("read: reg: 0x%02X , data: 0x%02X \n", addr, result[0]);
	}

	*data = result[0]; /* seems address on high byte, data on low byte */
	return 0;
}
static int aic3008_resume(struct snd_soc_codec *codec)
{
	//AUD_DBG("call set_bias_level(SND_SOC_BIAS_STANDBY)\n");
	//aic3008_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
	AUD_DBG("aic3008_resume\n");
	return 0;
}
static int spi_aic3008_remove(struct spi_device *spi_aic3008)
{
	AUD_DBG("Remove the SPI driver for aic3008.\n");
	snd_soc_unregister_codec(&spi_aic3008->dev);
	kfree(spi_get_drvdata(spi_aic3008));
	return 0;
}
static void aic3008_i2s_control(int dsp_enum)
{
    AUD_DBG("%s %d\n", __func__, dsp_enum);
	switch (dsp_enum) {
	case Phone_Default:
	case Phone_BT:
	case VOIP_BT:
	case VOIP_BT_HW_AEC:
		if (pcbid >= PROJECT_PHASE_XB || board_get_sku_tag() == 0x34600) {
			power_config("AUD_BT_SEL", TEGRA_GPIO_PK5, GPIO_OUTPUT);
		}
		break;
	case FM_Headset:
	case FM_Speaker:
		power_config("AUD_FM_SEL", TEGRA_GPIO_PK6, GPIO_OUTPUT);
		break;
	default:
		if (pcbid >= PROJECT_PHASE_XB || board_get_sku_tag() == 0x34600) {
			power_deconfig("AUD_BT_SEL", TEGRA_GPIO_PK5, GPIO_OUTPUT);
		}
		power_deconfig("AUD_FM_SEL", TEGRA_GPIO_PK6, GPIO_OUTPUT);
		break;
	}
	return;
}
static int aic3008_dai_startup(struct snd_pcm_substream *substream,
		struct snd_soc_dai *dai)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_codec *codec = rtd->codec;
	struct aic3008_priv *aic3008 = snd_soc_codec_get_drvdata(codec);
	struct spi_device *spi = codec->control_data;
	struct snd_pcm_runtime *master_runtime;

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		aic3008->playback_active++;
	else
		aic3008->capture_active++;

	/* The DAI has shared clocks so if we already have a playback or
	 * capture going then constrain this substream to match it.
	 */
	if (aic3008->master_substream) {
		master_runtime = aic3008->master_substream->runtime;

		/* dev_dbg(&spi->dev, "Constraining to %d bits\n",
		 master_runtime->sample_bits); */
		AUD_DBG("%p Constraining to %d bits\n", &spi->dev,
				master_runtime->sample_bits);

		snd_pcm_hw_constraint_minmax(substream->runtime,
				SNDRV_PCM_HW_PARAM_SAMPLE_BITS, master_runtime->sample_bits,
				master_runtime->sample_bits);

		aic3008->slave_substream = substream;
	} else
		aic3008->master_substream = substream;

	return 0;
}
int route_tx_enable(int path, int en)
{
	AUD_DBG("[TX] (%d, %d) uses aic3008 default TX setting\n", path, en);
	if (en) {
		/* Uplink_Wakeup */
		AUD_INFO("[TX] route_tx_enable call Uplink_Wakeup");
		aic3008_config(CODEC_UPLINK_ON, ARRAY_SIZE(CODEC_UPLINK_ON));
		/* Path switching */
		switch (path) {
		case CALL_UPLINK_IMIC_RECEIVER:
		case CALL_UPLINK_IMIC_HEADPHONE:
		case CALL_UPLINK_IMIC_SPEAKER:
		case VOICERECORD_IMIC:
			/* By pass */
			AUD_INFO("[TX] route_tx_enable call MECHA_UPLINK_IMIC");
			aic3008_config(MECHA_UPLINK_IMIC, ARRAY_SIZE(MECHA_UPLINK_IMIC));
			break;
		case CALL_UPLINK_EMIC_HEADPHONE:
		case VOICERECORD_EMIC:
			AUD_INFO("[TX] route_tx_enable call UPLINK_EMIC,");
			aic3008_config(UPLINK_EMIC, ARRAY_SIZE(UPLINK_EMIC));
			break;
		}
	} else {
		/* Uplink_Off */
		AUD_INFO("[TX] route_tx_enable call CODEC_UPLINK_OFF");
		aic3008_config(CODEC_UPLINK_OFF, ARRAY_SIZE(CODEC_UPLINK_OFF));
	}
	return 0;
}
/* This fn is very important!!!. We need to control the audio codec
   according to the different bias levels. i.e. to turn on/off essential
   audio components for different bias level */
static int aic3008_set_bias_level(struct snd_soc_codec *codec,
		enum snd_soc_bias_level level)
{
	/* struct i2c_client *i2c = codec->control_data; */
	/* u16 reg, reg2; */

	switch (level) {
	case SND_SOC_BIAS_ON:
	case SND_SOC_BIAS_PREPARE: /* Preparing to playback */

		/* FIXME: more actions here before playback or recording */
		break;

	case SND_SOC_BIAS_STANDBY: /* when done playback / recording */
		/* bias_level is set to SND_SOC_BIAS_OFF when powering down */
		/* So will run this if-block only once when powering up */
		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
			/* first time powering up the audio codec */
			/*AUD_DBG("First time STANDBY block\n");*/
			/*aic3008_CodecInit();*/
		}
		/* FIXME: should return to HEADPHONE if Headphone is plugged */
		AUD_DBG("common STANDBY block\n");
		break;

	case SND_SOC_BIAS_OFF: /* power down the audio codec */
		/*AUD_DBG("SND_SOC_BIAS_OFF\n");*/
		/* power down the audio codec */
		/*aic3008_powerdown();*/
		break;
	}

	codec->dapm.bias_level = level;
	return 0;
}
int aic3008_setMode(int cmd, int idx, int is_call_mode)
{
	int ret;
	AUD_DBG("setMode: cmd:%d, idx:%d, call_mode:%d\n", cmd, idx, is_call_mode);
	if (aic3008_power_ctl->mic_switch)
	{
		// set int/ext mic power off
		aic3008_MicSwitch(0);
		if (cmd == AIC3008_IO_CONFIG_TX && (idx == VOICERECORD_IMIC || idx == VOIP_DOWNLINK_IMIC_SPEAKER)) {
			AUD_DBG("[PWR] aic3008_setMode aic3008_MicSwitch");
			aic3008_MicSwitch(1);
		}
	}

	ret = aic3008_set_config(cmd, idx, 1);
	return ret;
}
void power_config(const char *name, int pin, int method)
{
	int ret = 0;

	switch (method) {
	case REGULATOR_METHOD:
		audio_regulator = regulator_get(NULL, name);
		if (IS_ERR_OR_NULL(audio_regulator)) {
			AUD_ERR("[PWR] couldn't get regulator %s, pin = %d, addr = %p.\n", name, pin, &audio_regulator);
			return;
		}

		ret = regulator_is_enabled(audio_regulator);
		if (ret > 0) {
			AUD_DBG("[PWR] regulator %s was enabled, pin = %d.\n", name, pin);
			return;
		} else if (ret < 0) {
			AUD_ERR("[PWR] regulator_is_enable error.\n");
			return;
		}

		ret = regulator_enable(audio_regulator);
		if (ret < 0) {
			AUD_ERR("[PWR] couldn't enable regulator %s, pin = %d, ret = %d.\n", name, pin, ret);
		}

		AUD_INFO("[PWR] ***** regulator %s %d enable *****\n", name, pin);
		break;
	case GPIO_OUTPUT:
		gpio_direction_output(pin, 1);
		tegra_gpio_enable(pin);
		gpio_set_value(pin, 1);
		AUD_INFO("[PWR] ***** gpio %s %d output enable *****\n", name, pin);
		break;
	case GPIO_INPUT:
		gpio_direction_input(pin);
		tegra_gpio_enable(pin);
		AUD_INFO("[PWR] ***** gpio %s %d input enable *****\n", name, pin);
		break;
	case INIT_OUTPUT_LOW:
		gpio_request(pin, name);
		gpio_direction_output(pin, 0);
		break;
	case INIT_OUTPUT_HIGH:
		gpio_request(pin, name);
		gpio_direction_output(pin, 1);
		break;
	case INIT_INPUT:
		gpio_request(pin, name);
		gpio_direction_input(pin);
		break;
	default:
		AUD_ERR("[PWR] ***** power_configure nothing *****\n");
	}

	return;
}
static int aic3008_release(struct inode *inode, struct file *pfile)
{
	mutex_lock(&lock);

	aic3008_opened = 0;

	mutex_unlock(&lock);
	AUD_DBG("IOCTL release\n");
	return 0;
}
Esempio n. 23
0
void power_deconfig(const char *name, int pin, int method)
{
	int ret = 0;

	switch (method) {
	case REGULATOR_METHOD:
		audio_regulator = regulator_get(NULL, name);
		if (IS_ERR_OR_NULL(audio_regulator)) {
			AUD_ERR("[PWR] couldn't get regulator %s %d, addr =  %p.\n", name, pin, &audio_regulator);
			return;
		}

		ret = regulator_is_enabled(audio_regulator);
		if (ret == 0)	{
			AUD_DBG("[PWR] regulator %s was disabled, pin = %d.\n", name, pin);
			return;
		} else if (ret < 0) {
			AUD_ERR("[PWR] regulator_is_enable error.\n");
			return;
		}

		ret = regulator_disable(audio_regulator);
		if (ret < 0) {
			AUD_ERR("[PWR] couldn't enable regulator %s %d, ret = %d.\n", name, pin, ret);
		}

		AUD_DBG("[PWR] ***** regulator %s %d disable *****\n", name, pin);
		break;
	case GPIO_OUTPUT:
		gpio_set_value(pin, 0);
		AUD_DBG("[PWR] ***** gpio %s %d disable *****\n", name, pin);
		break;
	default:
		AUD_ERR("[PWR] ***** power_deconfig nothing *****\n");
	}

	return;
}
Esempio n. 24
0
void dock_config(const char *name, int pin, bool output, bool out_val)
{
	int ret = 0;

	if (output) {
		ret = gpio_direction_output(pin, out_val);
		if (ret < 0) {
			AUD_ERR("[PWR] set %s %d output direction failed\n", name, pin);
			return;
		}
		tegra_gpio_enable(pin);
		AUD_DBG("[PWR] ***** gpio %s %d enable *****\n", name, pin);
	} else {
		ret = gpio_direction_input(pin);
		if (ret < 0) {
			AUD_ERR("[PWR] set %s %d input direction failed\n", name, pin);
			return;
		}
		tegra_gpio_enable(pin);
		AUD_DBG("[PWR] ***** gpio %s %d disable *****\n", name, pin);
	}
	return;
}
static inline int spi_aic3008_init(void)
{
	int ret = 0;

	AUD_DBG("starting aic3008 spi driver init...\n");
	mutex_init(&lock);

	ret = spi_register_driver(&aic3008_spi_driver);
	AUD_DBG("DONE spi_register_driver(&aic3008_spi_driver).\n");
	if (ret < 0) {
		AUD_ERR("failed to register spi driver(%d)\n", ret);
		return ret;
	}
	ret = misc_register(&aic3008_misc);
	AUD_DBG("DONE misc_register(&aic3008_misc).\n");
	if (ret < 0) {
		AUD_ERR("failed to register misc device(%d)\n", ret);
		spi_unregister_driver(&aic3008_spi_driver);
		return ret;
	}

	return 0;
}
Esempio n. 26
0
static int tegra_aic3008_init(struct snd_soc_pcm_runtime *rtd)
{
	struct snd_soc_codec *codec = rtd->codec;

	int err = 0;
	AUD_DBG("tegra_codec_init().\n");

	/* calls tegra_controls_init() in tegra_soc_controls.c
	* to set up playback, capture, mode, i2s loop back
	* routes controls. tegra_soc_controls handles the ALSA
	* IOCTL calls issued from ALSA HAL
	*/
	// Add controls
	err = snd_soc_add_controls(codec, tegra_controls,
			ARRAY_SIZE(tegra_controls));
	if (err < 0)
		return err;

	aic3008_CodecInit();
	AUD_DBG("DONE aic3008_CodecInit().\n");

	return err;
}
static int aic3008_open(struct inode *inode, struct file *pfile)
{
	int ret = 0;
	AUD_DBG("IOCTL open\n");
	mutex_lock(&lock);

	if (aic3008_opened) {
		AUD_ERR("busy\n");
		ret = -EBUSY;
	} else
		aic3008_opened = 1;

	mutex_unlock(&lock);
	return ret;
}
static void aic3008_powerdown(void)
{
	int64_t t1, t2;

	t1 = ktime_to_ms(ktime_get());

	if (aic3008_uplink != NULL) {
		AUD_DBG("[PWR] power off AIC3008 by table len(%d)\n",
				(aic3008_uplink[POWER_OFF][0].data-1));
		aic3008_config(&aic3008_uplink[POWER_OFF][1],
				aic3008_uplink[POWER_OFF][0].data);
	} else {
		AUD_DBG("[PWR] power off AIC3008 by default len(%d)\n",
				(ARRAY_SIZE(CODEC_POWER_OFF)));
		aic3008_config(CODEC_POWER_OFF, ARRAY_SIZE(CODEC_POWER_OFF));
	}

	aic3008_power_ctl->suspend();

	t2 = ktime_to_ms(ktime_get()) - t1;
	AUD_INFO("[PWR] power down AIC3008 %lldms\n", t2);

	return;
}
Esempio n. 29
0
static int tegra_config_es305_put(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
	struct aic3008_priv *audio_data = snd_soc_codec_get_drvdata(codec);
	int new_es305_cfg_id;
	if (audio_data) {
		new_es305_cfg_id = ucontrol->value.integer.value[0];
		if (audio_data->es305_cfg_id != new_es305_cfg_id) {
			AUD_DBG("tegra_config_es305_put, %d", new_es305_cfg_id);
			tegra_audio_route(audio_data, ES305_SET_CONFIG, new_es305_cfg_id);
			audio_data->es305_cfg_id = new_es305_cfg_id;
		}
		return 0;
	}
	return -EINVAL;
}
Esempio n. 30
0
static int tegra_capture_route_put(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
	struct aic3008_priv *audio_data = snd_soc_codec_get_drvdata(codec);
	int uplink;

	AUD_DBG("tegra_capture_route_put\n");

	if (audio_data) {
		uplink = ucontrol->value.integer.value[0];

		if (audio_data->uplink_id != uplink)
			audio_data->uplink_id = uplink;

		tegra_audio_route(audio_data, AIC3008_IO_CONFIG_TX, uplink);
		return 0;
	}
	return -EINVAL;
}