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; }
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; }