diff options
Diffstat (limited to 'kernel/sound/soc/intel/atom')
-rw-r--r-- | kernel/sound/soc/intel/atom/sst-atom-controls.c | 193 | ||||
-rw-r--r-- | kernel/sound/soc/intel/atom/sst-atom-controls.h | 9 | ||||
-rw-r--r-- | kernel/sound/soc/intel/atom/sst-mfld-platform-pcm.c | 67 | ||||
-rw-r--r-- | kernel/sound/soc/intel/atom/sst-mfld-platform.h | 3 | ||||
-rw-r--r-- | kernel/sound/soc/intel/atom/sst/sst_acpi.c | 4 | ||||
-rw-r--r-- | kernel/sound/soc/intel/atom/sst/sst_drv_interface.c | 11 | ||||
-rw-r--r-- | kernel/sound/soc/intel/atom/sst/sst_ipc.c | 3 |
7 files changed, 224 insertions, 66 deletions
diff --git a/kernel/sound/soc/intel/atom/sst-atom-controls.c b/kernel/sound/soc/intel/atom/sst-atom-controls.c index 90aa5c047..d55388e08 100644 --- a/kernel/sound/soc/intel/atom/sst-atom-controls.c +++ b/kernel/sound/soc/intel/atom/sst-atom-controls.c @@ -132,7 +132,7 @@ static int sst_send_slot_map(struct sst_data *drv) sizeof(cmd.header) + cmd.header.length); } -int sst_slot_enum_info(struct snd_kcontrol *kcontrol, +static int sst_slot_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct sst_enum *e = (struct sst_enum *)kcontrol->private_value; @@ -774,8 +774,120 @@ int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable) return ret; } +int sst_fill_ssp_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct sst_data *ctx = snd_soc_dai_get_drvdata(dai); + + ctx->ssp_cmd.nb_slots = slots; + ctx->ssp_cmd.active_tx_slot_map = tx_mask; + ctx->ssp_cmd.active_rx_slot_map = rx_mask; + ctx->ssp_cmd.nb_bits_per_slots = slot_width; + + return 0; +} + +static int sst_get_frame_sync_polarity(struct snd_soc_dai *dai, + unsigned int fmt) +{ + int format; + + format = fmt & SND_SOC_DAIFMT_INV_MASK; + dev_dbg(dai->dev, "Enter:%s, format=%x\n", __func__, format); + + switch (format) { + case SND_SOC_DAIFMT_NB_NF: + return SSP_FS_ACTIVE_LOW; + case SND_SOC_DAIFMT_NB_IF: + return SSP_FS_ACTIVE_HIGH; + case SND_SOC_DAIFMT_IB_IF: + return SSP_FS_ACTIVE_LOW; + case SND_SOC_DAIFMT_IB_NF: + return SSP_FS_ACTIVE_HIGH; + default: + dev_err(dai->dev, "Invalid frame sync polarity %d\n", format); + } + + return -EINVAL; +} + +static int sst_get_ssp_mode(struct snd_soc_dai *dai, unsigned int fmt) +{ + int format; + + format = (fmt & SND_SOC_DAIFMT_MASTER_MASK); + dev_dbg(dai->dev, "Enter:%s, format=%x\n", __func__, format); + + switch (format) { + case SND_SOC_DAIFMT_CBS_CFS: + return SSP_MODE_MASTER; + case SND_SOC_DAIFMT_CBM_CFM: + return SSP_MODE_SLAVE; + default: + dev_err(dai->dev, "Invalid ssp protocol: %d\n", format); + } + + return -EINVAL; +} + + +int sst_fill_ssp_config(struct snd_soc_dai *dai, unsigned int fmt) +{ + unsigned int mode; + int fs_polarity; + struct sst_data *ctx = snd_soc_dai_get_drvdata(dai); + + mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK; + + switch (mode) { + case SND_SOC_DAIFMT_DSP_B: + ctx->ssp_cmd.ssp_protocol = SSP_MODE_PCM; + ctx->ssp_cmd.mode = sst_get_ssp_mode(dai, fmt) | (SSP_PCM_MODE_NETWORK << 1); + ctx->ssp_cmd.start_delay = 0; + ctx->ssp_cmd.data_polarity = 1; + ctx->ssp_cmd.frame_sync_width = 1; + break; + + case SND_SOC_DAIFMT_DSP_A: + ctx->ssp_cmd.ssp_protocol = SSP_MODE_PCM; + ctx->ssp_cmd.mode = sst_get_ssp_mode(dai, fmt) | (SSP_PCM_MODE_NETWORK << 1); + ctx->ssp_cmd.start_delay = 1; + ctx->ssp_cmd.data_polarity = 1; + ctx->ssp_cmd.frame_sync_width = 1; + break; + + case SND_SOC_DAIFMT_I2S: + ctx->ssp_cmd.ssp_protocol = SSP_MODE_I2S; + ctx->ssp_cmd.mode = sst_get_ssp_mode(dai, fmt) | (SSP_PCM_MODE_NORMAL << 1); + ctx->ssp_cmd.start_delay = 1; + ctx->ssp_cmd.data_polarity = 0; + ctx->ssp_cmd.frame_sync_width = ctx->ssp_cmd.nb_bits_per_slots; + break; + + case SND_SOC_DAIFMT_LEFT_J: + ctx->ssp_cmd.ssp_protocol = SSP_MODE_I2S; + ctx->ssp_cmd.mode = sst_get_ssp_mode(dai, fmt) | (SSP_PCM_MODE_NORMAL << 1); + ctx->ssp_cmd.start_delay = 0; + ctx->ssp_cmd.data_polarity = 0; + ctx->ssp_cmd.frame_sync_width = ctx->ssp_cmd.nb_bits_per_slots; + break; + + default: + dev_dbg(dai->dev, "using default ssp configs\n"); + } + + fs_polarity = sst_get_frame_sync_polarity(dai, fmt); + if (fs_polarity < 0) + return fs_polarity; + + ctx->ssp_cmd.frame_sync_polarity = fs_polarity; + + return 0; +} + /** * sst_ssp_config - contains SSP configuration for media UC + * this can be overwritten by set_dai_xxx APIs */ static const struct sst_ssp_config sst_ssp_configs = { .ssp_id = SSP_CODEC, @@ -789,47 +901,56 @@ static const struct sst_ssp_config sst_ssp_configs = { .fs_frequency = SSP_FS_48_KHZ, .active_slot_map = 0xF, .start_delay = 0, + .frame_sync_polarity = SSP_FS_ACTIVE_HIGH, + .data_polarity = 1, }; +void sst_fill_ssp_defaults(struct snd_soc_dai *dai) +{ + const struct sst_ssp_config *config; + struct sst_data *ctx = snd_soc_dai_get_drvdata(dai); + + config = &sst_ssp_configs; + + ctx->ssp_cmd.selection = config->ssp_id; + ctx->ssp_cmd.nb_bits_per_slots = config->bits_per_slot; + ctx->ssp_cmd.nb_slots = config->slots; + ctx->ssp_cmd.mode = config->ssp_mode | (config->pcm_mode << 1); + ctx->ssp_cmd.duplex = config->duplex; + ctx->ssp_cmd.active_tx_slot_map = config->active_slot_map; + ctx->ssp_cmd.active_rx_slot_map = config->active_slot_map; + ctx->ssp_cmd.frame_sync_frequency = config->fs_frequency; + ctx->ssp_cmd.frame_sync_polarity = config->frame_sync_polarity; + ctx->ssp_cmd.data_polarity = config->data_polarity; + ctx->ssp_cmd.frame_sync_width = config->fs_width; + ctx->ssp_cmd.ssp_protocol = config->ssp_protocol; + ctx->ssp_cmd.start_delay = config->start_delay; + ctx->ssp_cmd.reserved1 = ctx->ssp_cmd.reserved2 = 0xFF; +} + int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable) { - struct sst_cmd_sba_hw_set_ssp cmd; struct sst_data *drv = snd_soc_dai_get_drvdata(dai); const struct sst_ssp_config *config; dev_info(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id); - SST_FILL_DEFAULT_DESTINATION(cmd.header.dst); - cmd.header.command_id = SBA_HW_SET_SSP; - cmd.header.length = sizeof(struct sst_cmd_sba_hw_set_ssp) + SST_FILL_DEFAULT_DESTINATION(drv->ssp_cmd.header.dst); + drv->ssp_cmd.header.command_id = SBA_HW_SET_SSP; + drv->ssp_cmd.header.length = sizeof(struct sst_cmd_sba_hw_set_ssp) - sizeof(struct sst_dsp_header); config = &sst_ssp_configs; dev_dbg(dai->dev, "ssp_id: %u\n", config->ssp_id); if (enable) - cmd.switch_state = SST_SWITCH_ON; + drv->ssp_cmd.switch_state = SST_SWITCH_ON; else - cmd.switch_state = SST_SWITCH_OFF; - - cmd.selection = config->ssp_id; - cmd.nb_bits_per_slots = config->bits_per_slot; - cmd.nb_slots = config->slots; - cmd.mode = config->ssp_mode | (config->pcm_mode << 1); - cmd.duplex = config->duplex; - cmd.active_tx_slot_map = config->active_slot_map; - cmd.active_rx_slot_map = config->active_slot_map; - cmd.frame_sync_frequency = config->fs_frequency; - cmd.frame_sync_polarity = SSP_FS_ACTIVE_HIGH; - cmd.data_polarity = 1; - cmd.frame_sync_width = config->fs_width; - cmd.ssp_protocol = config->ssp_protocol; - cmd.start_delay = config->start_delay; - cmd.reserved1 = cmd.reserved2 = 0xFF; + drv->ssp_cmd.switch_state = SST_SWITCH_OFF; return sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED, - SST_TASK_SBA, 0, &cmd, - sizeof(cmd.header) + cmd.header.length); + SST_TASK_SBA, 0, &drv->ssp_cmd, + sizeof(drv->ssp_cmd.header) + drv->ssp_cmd.header.length); } static int sst_set_be_modules(struct snd_soc_dapm_widget *w, @@ -1177,7 +1298,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute) dev_dbg(dai->dev, "Stream name=%s\n", dai->playback_widget->name); w = dai->playback_widget; - list_for_each_entry(p, &w->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(w, p) { if (p->connected && !p->connected(w, p->sink)) continue; @@ -1196,7 +1317,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute) dev_dbg(dai->dev, "Stream name=%s\n", dai->capture_widget->name); w = dai->capture_widget; - list_for_each_entry(p, &w->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(w, p) { if (p->connected && !p->connected(w, p->sink)) continue; @@ -1280,36 +1401,32 @@ static int sst_fill_widget_module_info(struct snd_soc_dapm_widget *w, down_read(&card->controls_rwsem); list_for_each_entry(kctl, &card->controls, list) { - idx = strstr(kctl->id.name, " "); + idx = strchr(kctl->id.name, ' '); if (idx == NULL) continue; - index = strlen(kctl->id.name) - strlen(idx); + index = idx - (char*)kctl->id.name; + if (strncmp(kctl->id.name, w->name, index)) + continue; - if (strstr(kctl->id.name, "Volume") && - !strncmp(kctl->id.name, w->name, index)) + if (strstr(kctl->id.name, "Volume")) ret = sst_fill_module_list(kctl, w, SST_MODULE_GAIN); - else if (strstr(kctl->id.name, "params") && - !strncmp(kctl->id.name, w->name, index)) + else if (strstr(kctl->id.name, "params")) ret = sst_fill_module_list(kctl, w, SST_MODULE_ALGO); else if (strstr(kctl->id.name, "Switch") && - !strncmp(kctl->id.name, w->name, index) && strstr(kctl->id.name, "Gain")) { struct sst_gain_mixer_control *mc = (void *)kctl->private_value; mc->w = w; - } else if (strstr(kctl->id.name, "interleaver") && - !strncmp(kctl->id.name, w->name, index)) { + } else if (strstr(kctl->id.name, "interleaver")) { struct sst_enum *e = (void *)kctl->private_value; e->w = w; - } else if (strstr(kctl->id.name, "deinterleaver") && - !strncmp(kctl->id.name, w->name, index)) { - + } else if (strstr(kctl->id.name, "deinterleaver")) { struct sst_enum *e = (void *)kctl->private_value; e->w = w; diff --git a/kernel/sound/soc/intel/atom/sst-atom-controls.h b/kernel/sound/soc/intel/atom/sst-atom-controls.h index daecc58f2..93de8045d 100644 --- a/kernel/sound/soc/intel/atom/sst-atom-controls.h +++ b/kernel/sound/soc/intel/atom/sst-atom-controls.h @@ -562,6 +562,8 @@ struct sst_ssp_config { u8 active_slot_map; u8 start_delay; u16 fs_width; + u8 frame_sync_polarity; + u8 data_polarity; }; struct sst_ssp_cfg { @@ -695,7 +697,7 @@ struct sst_gain_mixer_control { u16 module_id; u16 pipe_id; u16 task_id; - char pname[44]; + char pname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; struct snd_soc_dapm_widget *w; }; @@ -867,4 +869,9 @@ struct sst_enum { SOC_DAPM_ENUM(SST_MUX_CTL_NAME(xpname, xinstance), \ SST_SSP_MUX_ENUM(xreg, xshift, xtexts)) +int sst_fill_ssp_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width); +int sst_fill_ssp_config(struct snd_soc_dai *dai, unsigned int fmt); +void sst_fill_ssp_defaults(struct snd_soc_dai *dai); + #endif diff --git a/kernel/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/kernel/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 2fbaf2c75..0487cfaac 100644 --- a/kernel/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/kernel/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -33,7 +33,6 @@ struct sst_device *sst; static DEFINE_MUTEX(sst_lock); -extern struct snd_compr_ops sst_platform_compr_ops; int sst_register_dsp(struct sst_device *dev) { @@ -369,23 +368,6 @@ static void sst_media_close(struct snd_pcm_substream *substream, kfree(stream); } -static inline unsigned int get_current_pipe_id(struct snd_soc_dai *dai, - struct snd_pcm_substream *substream) -{ - struct sst_data *sst = snd_soc_dai_get_drvdata(dai); - struct sst_dev_stream_map *map = sst->pdata->pdev_strm_map; - struct sst_runtime_stream *stream = - substream->runtime->private_data; - u32 str_id = stream->stream_info.str_id; - unsigned int pipe_id; - - pipe_id = map[str_id].device_id; - - dev_dbg(dai->dev, "got pipe_id = %#x for str_id = %d\n", - pipe_id, str_id); - return pipe_id; -} - static int sst_media_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -434,13 +416,51 @@ static int sst_enable_ssp(struct snd_pcm_substream *substream, if (!dai->active) { ret = sst_handle_vb_timer(dai, true); - if (ret) - return ret; - ret = send_ssp_cmd(dai, dai->name, 1); + sst_fill_ssp_defaults(dai); } return ret; } +static int sst_be_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + int ret = 0; + + if (dai->active == 1) + ret = send_ssp_cmd(dai, dai->name, 1); + return ret; +} + +static int sst_set_format(struct snd_soc_dai *dai, unsigned int fmt) +{ + int ret = 0; + + if (!dai->active) + return 0; + + ret = sst_fill_ssp_config(dai, fmt); + if (ret < 0) + dev_err(dai->dev, "sst_set_format failed..\n"); + + return ret; +} + +static int sst_platform_set_ssp_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) { + int ret = 0; + + if (!dai->active) + return ret; + + ret = sst_fill_ssp_slot(dai, tx_mask, rx_mask, slots, slot_width); + if (ret < 0) + dev_err(dai->dev, "sst_fill_ssp_slot failed..%d\n", ret); + + return ret; +} + static void sst_disable_ssp(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -465,6 +485,9 @@ static struct snd_soc_dai_ops sst_compr_dai_ops = { static struct snd_soc_dai_ops sst_be_dai_ops = { .startup = sst_enable_ssp, + .hw_params = sst_be_hw_params, + .set_fmt = sst_set_format, + .set_tdm_slot = sst_platform_set_ssp_slot, .shutdown = sst_disable_ssp, }; @@ -489,7 +512,7 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { }, { .name = "compress-cpu-dai", - .compress_dai = 1, + .compress_new = snd_soc_new_compress, .ops = &sst_compr_dai_ops, .playback = { .stream_name = "Compress Playback", diff --git a/kernel/sound/soc/intel/atom/sst-mfld-platform.h b/kernel/sound/soc/intel/atom/sst-mfld-platform.h index 9094314be..cb32cc7e5 100644 --- a/kernel/sound/soc/intel/atom/sst-mfld-platform.h +++ b/kernel/sound/soc/intel/atom/sst-mfld-platform.h @@ -22,8 +22,10 @@ #define __SST_PLATFORMDRV_H__ #include "sst-mfld-dsp.h" +#include "sst-atom-controls.h" extern struct sst_device *sst; +extern struct snd_compr_ops sst_platform_compr_ops; #define SST_MONO 1 #define SST_STEREO 2 @@ -175,6 +177,7 @@ struct sst_data { struct snd_sst_bytes_v2 *byte_stream; struct mutex lock; struct snd_soc_card *soc_card; + struct sst_cmd_sba_hw_set_ssp ssp_cmd; }; int sst_register_dsp(struct sst_device *sst); int sst_unregister_dsp(struct sst_device *sst); diff --git a/kernel/sound/soc/intel/atom/sst/sst_acpi.c b/kernel/sound/soc/intel/atom/sst/sst_acpi.c index 05f693083..bb19b5801 100644 --- a/kernel/sound/soc/intel/atom/sst/sst_acpi.c +++ b/kernel/sound/soc/intel/atom/sst/sst_acpi.c @@ -354,6 +354,10 @@ static struct sst_machines sst_acpi_chv[] = { &chv_platform_data }, {"10EC5645", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin", &chv_platform_data }, + {"10EC5650", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin", + &chv_platform_data }, + {"193C9890", "cht-bsw", "cht-bsw-max98090", NULL, + "intel/fw_sst_22a8.bin", &chv_platform_data }, {}, }; diff --git a/kernel/sound/soc/intel/atom/sst/sst_drv_interface.c b/kernel/sound/soc/intel/atom/sst/sst_drv_interface.c index edc186908..ce689c5af 100644 --- a/kernel/sound/soc/intel/atom/sst/sst_drv_interface.c +++ b/kernel/sound/soc/intel/atom/sst/sst_drv_interface.c @@ -151,6 +151,7 @@ static int sst_power_control(struct device *dev, bool state) usage_count = GET_USAGE_COUNT(dev); dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", usage_count); if (ret < 0) { + pm_runtime_put_sync(dev); dev_err(ctx->dev, "Runtime get failed with err: %d\n", ret); return ret; } @@ -204,8 +205,10 @@ static int sst_cdev_open(struct device *dev, struct intel_sst_drv *ctx = dev_get_drvdata(dev); retval = pm_runtime_get_sync(ctx->dev); - if (retval < 0) + if (retval < 0) { + pm_runtime_put_sync(ctx->dev); return retval; + } str_id = sst_get_stream(ctx, str_params); if (str_id > 0) { @@ -533,7 +536,7 @@ static inline int sst_calc_tstamp(struct intel_sst_drv *ctx, info->buffer_ptr = pointer_samples / substream->runtime->channels; - info->pcm_delay = delay_frames / substream->runtime->channels; + info->pcm_delay = delay_frames; dev_dbg(ctx->dev, "buffer ptr %llu pcm_delay rep: %llu\n", info->buffer_ptr, info->pcm_delay); return 0; @@ -672,8 +675,10 @@ static int sst_send_byte_stream(struct device *dev, if (NULL == bytes) return -EINVAL; ret_val = pm_runtime_get_sync(ctx->dev); - if (ret_val < 0) + if (ret_val < 0) { + pm_runtime_put_sync(ctx->dev); return ret_val; + } ret_val = sst_send_byte_stream_mrfld(ctx, bytes); sst_pm_runtime_put(ctx); diff --git a/kernel/sound/soc/intel/atom/sst/sst_ipc.c b/kernel/sound/soc/intel/atom/sst/sst_ipc.c index 5a2786184..3dc735882 100644 --- a/kernel/sound/soc/intel/atom/sst/sst_ipc.c +++ b/kernel/sound/soc/intel/atom/sst/sst_ipc.c @@ -352,10 +352,9 @@ void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx, * copy from mailbox **/ if (msg_high.part.large) { - data = kzalloc(msg_low, GFP_KERNEL); + data = kmemdup((void *)msg->mailbox_data, msg_low, GFP_KERNEL); if (!data) return; - memcpy(data, (void *) msg->mailbox_data, msg_low); /* Copy command id so that we can use to put sst to reset */ dsp_hdr = (struct ipc_dsp_hdr *)data; cmd_id = dsp_hdr->cmd_id; |