Example #1
0
static int msm_dai_q6_i2s_hw_params(struct snd_pcm_hw_params *params,
				    struct snd_soc_dai *dai, int stream)
{
	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
	struct msm_i2s_data *i2s_pdata =
			(struct msm_i2s_data *) dai->dev->platform_data;

	dai_data->channels = params_channels(params);
	if (num_of_bits_set(i2s_pdata->sd_lines) == 1) {
		switch (dai_data->channels) {
		case 2:
			dai_data->port_config.i2s.mono_stereo = MSM_AFE_STEREO;
			break;
		case 1:
			dai_data->port_config.i2s.mono_stereo = MSM_AFE_MONO;
			break;
		default:
			pr_warn("greater than stereo has not been validated");
			break;
		}
	}
	dai_data->rate = params_rate(params);
	dai_data->port_config.i2s.sample_rate = dai_data->rate;
	dai_data->port_config.i2s.i2s_cfg_minor_version =
						AFE_API_VERSION_I2S_CONFIG;
	dai_data->port_config.i2s.data_format =  AFE_LINEAR_PCM_DATA;
	/* Q6 only supports 16 as now */
	dai_data->port_config.i2s.bit_width = 16;
	dai_data->port_config.i2s.channel_mode = 1;

	return 0;
}
static int msm_dai_q6_mi2s_hw_params(struct snd_pcm_hw_params *params,
				    struct snd_soc_dai *dai, int stream)
{
	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
	struct msm_mi2s_data *mi2s_pdata =
			(struct msm_mi2s_data *) dai->dev->platform_data;

	dai_data->channels = params_channels(params);
	if (num_of_bits_set(mi2s_pdata->sd_lines) == 1) {
		switch (dai_data->channels) {
		case 2:
			dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
			break;
		case 1:
			dai_data->port_config.mi2s.channel = MSM_AFE_MONO;
			break;
		default:
			pr_warn("greater than stereo has not been validated");
			break;
		}
	}
	/* Q6 only supports 16 as now */
	dai_data->port_config.mi2s.bitwidth = 16;

	return 0;
}
bool mi2s_set_hdmi_input_path(uint8_t channels, uint8_t size,
		uint8_t sd_line_mask)
{
	bool ret_val = MI2S_TRUE;
	struct mi2s_state *mi2s = &the_mi2s_state;
	u8 sd_line, num_of_sd_lines = 0;
	void __iomem *baddr;
	uint32_t val;

	pr_debug("%s: channels = %u size = %u sd_line_mask = 0x%x\n", __func__,
		channels, size, sd_line_mask);

	if ((channels != 1) && (channels != MAX_NUM_CHANNELS_IN)) {

		pr_err("%s: invalid number of channels. channels = %u\n",
				__func__, channels);
		return  MI2S_FALSE;
	}

	if (size > WT_MAX) {

		pr_err("%s: mi2s word size can not be greater than 32 bits\n",
				__func__);
		return MI2S_FALSE;
	}

	sd_line_mask &=  MI2S_SD_LINE_MASK;

	if (!sd_line_mask) {
		pr_err("%s: Did not set any data lines to use "
			" sd_line_mask =0x%x\n", __func__, sd_line_mask);
		return  MI2S_FALSE;
	}

	num_of_sd_lines = num_of_bits_set(sd_line_mask);

	if (num_of_sd_lines != 1) {
		pr_err("%s: for two channel input only one SD lines is"
			" needed. num_of_sd_lines = %u sd_line_mask = 0x%x\n",
			__func__, num_of_sd_lines, sd_line_mask);
		return MI2S_FALSE;
	}

	/*Second argument to find_first_bit should be maximum number of
	bits interested*/
	sd_line = find_first_bit((unsigned long *)&sd_line_mask,
			sizeof(sd_line_mask) * 8);
	pr_debug("sd_line = %d\n", sd_line);

	/* Ensure sd_line parameter is valid (0-max) */
	if (sd_line > MAX_SD_LINES) {
		pr_err("%s: Line number can not be greater than = %u\n",
			__func__, MAX_SD_LINES);
		return MI2S_FALSE;
	}

	mutex_lock(&mi2s->mutex_lock);
	/* Put device in reset */
	mi2s_reset(mi2s, HDMI);

	mi2s_master(mi2s, HDMI, 1);

	/* Set word type */
	mi2s_set_word_type(mi2s, HDMI, size);

	/* Enable clock crossing synchronization of WR DMA ACK */
	mi2s_set_input_clk_synch(mi2s, HDMI);

	/* Ensure channels parameter is valid (non-zero, less than max,
	 * and even or mono)
	 */
	mi2s_set_input_num_channels(mi2s, HDMI, channels);

	mi2s_set_input_sd_line(mi2s, HDMI, sd_line);

	mi2s_set_sd(mi2s, HDMI, (MI2S_SD_0_EN_MAP << sd_line));

	baddr = get_base_addr(mi2s, HDMI);

	val = readl(baddr + MI2S_MODE_OFFSET);
	pr_debug("%s(): MI2S_MODE = 0x%x\n", __func__, val);

	val = readl(baddr + MI2S_RX_MODE_OFFSET);
	pr_debug("%s(): MI2S_RX_MODE = 0x%x\n", __func__, val);

	/* Release device from reset */
	mi2s_release(mi2s, HDMI);

	mutex_unlock(&mi2s->mutex_lock);
	mb();
	return ret_val;
}
bool mi2s_set_hdmi_output_path(uint8_t channels, uint8_t size,
		uint8_t sd_line_mask)
{
	bool ret_val = MI2S_TRUE;
	struct mi2s_state *mi2s = &the_mi2s_state;
	u8 sd_line, num_of_sd_lines = 0;
	void __iomem *baddr;
	uint32_t val;

	pr_debug("%s: channels = %u size = %u sd_line_mask = 0x%x\n", __func__,
		channels, size, sd_line_mask);

	if ((channels == 0) ||  (channels > MAX_NUM_CHANNELS_OUT) ||
		((channels != 1) && (channels % 2 != 0))) {

		pr_err("%s: invalid number of channels. channels = %u\n",
				__func__, channels);
		return  MI2S_FALSE;
	}

	sd_line_mask &=  MI2S_SD_LINE_MASK;

	if (!sd_line_mask) {
		pr_err("%s: Did not set any data lines to use "
			" sd_line_mask =0x%x\n", __func__, sd_line_mask);
		return  MI2S_FALSE;
	}

	mutex_lock(&mi2s->mutex_lock);
	/* Put device in reset */
	mi2s_reset(mi2s, HDMI);

	mi2s_master(mi2s, HDMI, 1);

	/* Set word type */
	if (size <= WT_MAX)
		mi2s_set_word_type(mi2s, HDMI, size);
	else
		ret_val = MI2S_FALSE;

	/* Enable clock crossing synchronization of RD DMA ACK */
	mi2s_set_output_clk_synch(mi2s, HDMI);

	mi2s_set_output_num_channels(mi2s, HDMI, channels);

	num_of_sd_lines = num_of_bits_set(sd_line_mask);
	/*Second argument to find_first_bit should be maximum number of
	bit*/

	sd_line = find_first_bit((unsigned long *)&sd_line_mask,
			sizeof(sd_line_mask) * 8);
	pr_debug("sd_line = %d\n", sd_line);

	if (channels == 1) {

		if (num_of_sd_lines != 1) {
			pr_err("%s: for one channel only one SD lines is"
				" needed. num_of_sd_lines = %u\n",
				__func__, num_of_sd_lines);

			ret_val = MI2S_FALSE;
			goto error;
		}

		if (sd_line != 0) {
			pr_err("%s: for one channel tx, need to use SD_0 "
					"sd_line = %u\n", __func__, sd_line);

			ret_val = MI2S_FALSE;
			goto error;
		}

		/* Enable SD line 0 for Tx (only option for
			 * mono audio)
		 */
		mi2s_set_sd(mi2s, HDMI, MI2S_SD_0_EN_MAP | MI2S_SD_0_TX_MAP);

	} else if (channels == 2) {

		if (num_of_sd_lines != 1) {
			pr_err("%s: for two channel only one SD lines is"
				" needed. num_of_sd_lines = %u\n",
				__func__, num_of_sd_lines);
			ret_val = MI2S_FALSE;
			goto error;
		}

		/* Enable single SD line for Tx */
		mi2s_set_sd(mi2s, HDMI, (MI2S_SD_0_EN_MAP << sd_line) |
				(MI2S_SD_0_TX_MAP << sd_line));

		/* Set 2-channel mapping */
		mi2s_set_output_2ch_map(mi2s, HDMI, sd_line);

	} else if (channels == 4) {

		if (num_of_sd_lines != 2) {
			pr_err("%s: for 4 channels two SD lines are"
				" needed. num_of_sd_lines = %u\\n",
				__func__, num_of_sd_lines);
			ret_val = MI2S_FALSE;
			goto error;
		}

		if ((sd_line_mask && MI2S_SD_0) &&
				(sd_line_mask && MI2S_SD_1)) {

			mi2s_set_sd(mi2s, HDMI, (MI2S_SD_0_EN_MAP |
				MI2S_SD_1_EN_MAP) | (MI2S_SD_0_TX_MAP |
				MI2S_SD_1_TX_MAP));
			mi2s_set_output_4ch_map(mi2s, HDMI, MI2S_FALSE);

		} else if ((sd_line_mask && MI2S_SD_2) &&
				(sd_line_mask && MI2S_SD_3)) {

			mi2s_set_sd(mi2s, HDMI, (MI2S_SD_2_EN_MAP |
				MI2S_SD_3_EN_MAP) | (MI2S_SD_2_TX_MAP |
				MI2S_SD_3_TX_MAP));

			mi2s_set_output_4ch_map(mi2s, HDMI, MI2S_TRUE);
		} else {

			pr_err("%s: for 4 channels invalid SD lines usage"
				" sd_line_mask = 0x%x\n",
				__func__, sd_line_mask);
			ret_val = MI2S_FALSE;
			goto error;
		}
	} else if (channels == 6) {

		if (num_of_sd_lines != 3) {
			pr_err("%s: for 6 channels three SD lines are"
				" needed. num_of_sd_lines = %u\n",
				__func__, num_of_sd_lines);
			ret_val = MI2S_FALSE;
			goto error;
		}

		if ((sd_line_mask && MI2S_SD_0) &&
			(sd_line_mask && MI2S_SD_1) &&
			(sd_line_mask && MI2S_SD_2)) {

			mi2s_set_sd(mi2s, HDMI, (MI2S_SD_0_EN_MAP |
				MI2S_SD_1_EN_MAP | MI2S_SD_2_EN_MAP) |
				(MI2S_SD_0_TX_MAP | MI2S_SD_1_TX_MAP |
				MI2S_SD_2_TX_MAP));

		} else if ((sd_line_mask && MI2S_SD_1) &&
				(sd_line_mask && MI2S_SD_2) &&
				(sd_line_mask && MI2S_SD_3)) {

			mi2s_set_sd(mi2s, HDMI, (MI2S_SD_1_EN_MAP |
				MI2S_SD_2_EN_MAP | MI2S_SD_3_EN_MAP) |
				(MI2S_SD_1_TX_MAP | MI2S_SD_2_TX_MAP |
				MI2S_SD_3_TX_MAP));

		} else {

			pr_err("%s: for 6 channels invalid SD lines usage"
				" sd_line_mask = 0x%x\n",
				__func__, sd_line_mask);
			ret_val = MI2S_FALSE;
			goto error;
		}
	} else if (channels == 8) {

		if (num_of_sd_lines != 4) {
			pr_err("%s: for 8 channels four SD lines are"
				" needed. num_of_sd_lines = %u\n",
				__func__, num_of_sd_lines);
			ret_val = MI2S_FALSE;
			goto error;
		}

		mi2s_set_sd(mi2s, HDMI, (MI2S_SD_0_EN_MAP |
			MI2S_SD_1_EN_MAP | MI2S_SD_2_EN_MAP |
			MI2S_SD_3_EN_MAP) | (MI2S_SD_0_TX_MAP |
			MI2S_SD_1_TX_MAP | MI2S_SD_2_TX_MAP |
			MI2S_SD_3_TX_MAP));
	} else {
		pr_err("%s: invalid number channels = %u\n",
				__func__, channels);
			ret_val = MI2S_FALSE;
			goto error;
	}

	baddr = get_base_addr(mi2s, HDMI);

	val = readl(baddr + MI2S_MODE_OFFSET);
	pr_debug("%s(): MI2S_MODE = 0x%x\n", __func__, val);

	val = readl(baddr + MI2S_TX_MODE_OFFSET);
	pr_debug("%s(): MI2S_TX_MODE = 0x%x\n", __func__, val);


error:
	/* Release device from reset */
	mi2s_release(mi2s, HDMI);

	mutex_unlock(&mi2s->mutex_lock);
	mb();
	return ret_val;
}
static int msm_dai_q6_mi2s_platform_data_validation(
					struct snd_soc_dai *dai)
{
	u8 num_of_sd_lines;
	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
	struct msm_mi2s_data *mi2s_pdata =
			(struct msm_mi2s_data *)dai->dev->platform_data;
	struct snd_soc_dai_driver *dai_driver =
			(struct snd_soc_dai_driver *)dai->driver;

	num_of_sd_lines = num_of_bits_set(mi2s_pdata->sd_lines);

	switch (num_of_sd_lines) {
	case 1:
		switch (mi2s_pdata->sd_lines) {
		case MSM_MI2S_SD0:
			dai_data->port_config.mi2s.line = AFE_I2S_SD0;
			break;
		case MSM_MI2S_SD1:
			dai_data->port_config.mi2s.line = AFE_I2S_SD1;
			break;
		case MSM_MI2S_SD2:
			dai_data->port_config.mi2s.line = AFE_I2S_SD2;
			break;
		case MSM_MI2S_SD3:
			dai_data->port_config.mi2s.line = AFE_I2S_SD3;
			break;
		default:
			pr_err("%s: invalid SD line\n",
				   __func__);
			goto error_invalid_data;
		}
		break;
	case 2:
		switch (mi2s_pdata->sd_lines) {
		case MSM_MI2S_SD0 | MSM_MI2S_SD1:
			dai_data->port_config.mi2s.line = AFE_I2S_QUAD01;
			break;
		case MSM_MI2S_SD2 | MSM_MI2S_SD3:
			dai_data->port_config.mi2s.line = AFE_I2S_QUAD23;
			break;
		default:
			pr_err("%s: invalid SD line\n",
				   __func__);
			goto error_invalid_data;
		}
		break;
	case 3:
		switch (mi2s_pdata->sd_lines) {
		case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2:
			dai_data->port_config.mi2s.line = AFE_I2S_6CHS;
			break;
		default:
			pr_err("%s: invalid SD lines\n",
				   __func__);
			goto error_invalid_data;
		}
		break;
	case 4:
		switch (mi2s_pdata->sd_lines) {
		case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2 | MSM_MI2S_SD3:
			dai_data->port_config.mi2s.line = AFE_I2S_8CHS;
			break;
		default:
			pr_err("%s: invalid SD lines\n",
				   __func__);
			goto error_invalid_data;
		}
		break;
	default:
		pr_err("%s: invalid SD lines\n", __func__);
		goto error_invalid_data;
	}
	if (mi2s_pdata->capability == MSM_MI2S_CAP_RX)
		dai_driver->playback.channels_max = num_of_sd_lines << 1;

	return 0;

error_invalid_data:
	return -EINVAL;
}
Example #6
0
static int snddev_mi2s_open(struct msm_snddev_info *dev_info)
{
	int rc = 0;
	union afe_port_config afe_config;
	u8 channels;
	u8 num_of_sd_lines = 0;
	struct snddev_mi2s_drv_state *drv = &snddev_mi2s_drv;
	struct snddev_mi2s_data *snddev_mi2s_data = dev_info->private_data;

	if (!dev_info) {
		pr_err("%s:  msm_snddev_info is null\n", __func__);
		return -EINVAL;
	}

	
	drv->tx_osrclk = clk_get_sys(NULL, "mi2s_osr_clk");
	if (IS_ERR(drv->tx_osrclk))
		pr_err("%s master clock Error\n", __func__);

	rc =  clk_set_rate(drv->tx_osrclk,
			 SNDDEV_MI2S_CLK_RATE(dev_info->sample_rate));
	if (IS_ERR_VALUE(rc)) {
		pr_err("ERROR setting osr clock\n");
		return -ENODEV;
	}
	clk_prepare_enable(drv->tx_osrclk);

	
	drv->tx_bitclk = clk_get_sys(NULL, "mi2s_bit_clk");
	if (IS_ERR(drv->tx_bitclk))
		pr_err("%s clock Error\n", __func__);

	rc =  clk_set_rate(drv->tx_bitclk, 8);
	if (IS_ERR_VALUE(rc)) {
		pr_err("ERROR setting bit clock\n");
		clk_disable_unprepare(drv->tx_osrclk);
		return -ENODEV;
	}
	clk_prepare_enable(drv->tx_bitclk);

	afe_config.mi2s.bitwidth = 16;

	if (snddev_mi2s_data->channel_mode == 1)
		channels = AFE_MI2S_MONO;
	else if (snddev_mi2s_data->channel_mode == 2)
		channels = AFE_MI2S_STEREO;
	else if (snddev_mi2s_data->channel_mode == 4)
		channels = AFE_MI2S_4CHANNELS;
	else if (snddev_mi2s_data->channel_mode == 6)
		channels = AFE_MI2S_6CHANNELS;
	else if (snddev_mi2s_data->channel_mode == 8)
		channels = AFE_MI2S_8CHANNELS;
	else {
		pr_err("ERROR: Invalid MI2S channel mode\n");
		goto error_invalid_data;
	}

	num_of_sd_lines = num_of_bits_set(snddev_mi2s_data->sd_lines);

	switch (num_of_sd_lines) {
	case 1:
		switch (snddev_mi2s_data->sd_lines) {
		case MI2S_SD0:
			afe_config.mi2s.line = AFE_I2S_SD0;
			break;
		case MI2S_SD1:
			afe_config.mi2s.line = AFE_I2S_SD1;
			break;
		case MI2S_SD2:
			afe_config.mi2s.line = AFE_I2S_SD2;
			break;
		case MI2S_SD3:
			afe_config.mi2s.line = AFE_I2S_SD3;
			break;
		default:
			pr_err("%s: invalid SD line\n",
			__func__);
			goto error_invalid_data;
		}
		if (channels != AFE_MI2S_STEREO &&
		channels != AFE_MI2S_MONO) {
			pr_err("%s: for one SD line, channel "
			"must be 1 or 2\n", __func__);
			goto error_invalid_data;
		}
		afe_config.mi2s.channel = channels;
		break;
	case 2:
		switch (snddev_mi2s_data->sd_lines) {
		case MI2S_SD0 | MI2S_SD1:
			afe_config.mi2s.line = AFE_I2S_QUAD01;
			break;
		case MI2S_SD2 | MI2S_SD3:
			afe_config.mi2s.line = AFE_I2S_QUAD23;
			break;
		default:
			pr_err("%s: invalid SD line\n",
			__func__);
			goto error_invalid_data;
		}
		if (channels != AFE_MI2S_4CHANNELS) {
			pr_err("%s: for two SD lines, channel "
			"must be 1 and 2 or 3 and 4\n", __func__);
			goto error_invalid_data;
		}
		break;
	case 3:
		switch (snddev_mi2s_data->sd_lines) {
		case MI2S_SD0 | MI2S_SD1 | MI2S_SD2:
			afe_config.mi2s.line = AFE_I2S_6CHS;
			break;
		default:
			pr_err("%s: invalid SD lines\n",
			__func__);
			goto error_invalid_data;
		}
		if (channels != AFE_MI2S_6CHANNELS) {
			pr_err("%s: for three SD lines, lines "
			"must be 1, 2, and 3\n", __func__);
			goto error_invalid_data;
		}
		break;
	case 4:
		switch (snddev_mi2s_data->sd_lines) {
		case MI2S_SD0 | MI2S_SD1 | MI2S_SD2 | MI2S_SD3:
			afe_config.mi2s.line = AFE_I2S_8CHS;
			break;
		default:
			pr_err("%s: invalid SD lines\n",
			__func__);
			goto error_invalid_data;
		}

		if (channels != AFE_MI2S_8CHANNELS) {
			pr_err("%s: for four SD lines, lines "
			"must be 1, 2, 3, and 4\n", __func__);
			goto error_invalid_data;
		}
		break;
	default:
		pr_err("%s: invalid SD lines\n", __func__);
		goto error_invalid_data;
	}
	afe_config.mi2s.ws = 1;
	afe_config.mi2s.format = MSM_AFE_I2S_FORMAT_LPCM;

	rc = afe_open(snddev_mi2s_data->copp_id, &afe_config,
		dev_info->sample_rate);

	if (rc < 0) {
		pr_err("%s:  afe_open failed\n", __func__);
		goto error_invalid_data;
	}

	
	rc = mi2s_gpios_request();
	if (rc < 0) {
		pr_err("%s: GPIO request failed\n", __func__);
		return rc;
	}

	pr_info("%s:  afe_open  done\n", __func__);

	return rc;

error_invalid_data:

	clk_disable_unprepare(drv->tx_bitclk);
	clk_disable_unprepare(drv->tx_osrclk);
	return -EINVAL;
}
static int msm_dai_q6_mi2s_get_lineconfig(u16 sd_lines, u16 *config_ptr,
	unsigned int *ch_cnt)
{
	u8 num_of_sd_lines;

	num_of_sd_lines = num_of_bits_set(sd_lines);

	switch (num_of_sd_lines) {
	case 0:
		pr_debug("%s: no line is assigned\n", __func__);
		break;
	case 1:
		switch (sd_lines) {
		case MSM_MI2S_SD0:
			*config_ptr = AFE_I2S_SD0;
			break;
		case MSM_MI2S_SD1:
			*config_ptr = AFE_I2S_SD1;
			break;
		case MSM_MI2S_SD2:
			*config_ptr = AFE_I2S_SD2;
			break;
		case MSM_MI2S_SD3:
			*config_ptr = AFE_I2S_SD3;
			break;
		default:
			pr_err("%s: invalid SD line\n",
				   __func__);
			goto error_invalid_data;
		}
		break;
	case 2:
		switch (sd_lines) {
		case MSM_MI2S_SD0 | MSM_MI2S_SD1:
			*config_ptr = AFE_I2S_QUAD01;
			break;
		case MSM_MI2S_SD2 | MSM_MI2S_SD3:
			*config_ptr = AFE_I2S_QUAD23;
			break;
		default:
			pr_err("%s: invalid SD line\n",
				   __func__);
			goto error_invalid_data;
		}
		break;
	case 3:
		switch (sd_lines) {
		case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2:
			*config_ptr = AFE_I2S_6CHS;
			break;
		default:
			pr_err("%s: invalid SD lines\n",
				   __func__);
			goto error_invalid_data;
		}
		break;
	case 4:
		switch (sd_lines) {
		case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2 | MSM_MI2S_SD3:
			*config_ptr = AFE_I2S_8CHS;
			break;
		default:
			pr_err("%s: invalid SD lines\n",
				   __func__);
			goto error_invalid_data;
		}
		break;
	default:
		pr_err("%s: invalid SD lines\n", __func__);
		goto error_invalid_data;
	}

	*ch_cnt = num_of_sd_lines;

	return 0;

error_invalid_data:
	return -EINVAL;
}