[alsa-devel] [PATCH 0/5] ASoC: Intel: let machines configure SSP configuration

This series first add frame and data polarity to ssp config and then starts to use local values for ssp config and then eventually lets that be loaded by hw_params and updates by pcm format and tdm calls to allow machine t specify these parameters
Vinod Koul (5): ASoC: Intel: add frame and data polarity to ssp config ASoC: Intel: use local values for ssp configuration ASoC: Intel: load hw_defaults in hw_params of ssp be ASoC: intel: add support for specifying PCM format ASoC: Intel: add support for configuring TDM slots for SSP
sound/soc/intel/atom/sst-atom-controls.c | 167 +++++++++++++++++++++++---- sound/soc/intel/atom/sst-atom-controls.h | 7 ++ sound/soc/intel/atom/sst-mfld-platform-pcm.c | 47 +++++++- sound/soc/intel/atom/sst-mfld-platform.h | 2 + 4 files changed, 197 insertions(+), 26 deletions(-)

The current ssp configuration was not configuring the frame sync polarity and data polarity. Some codecs do need these different so add them in ssp configuration now
Signed-off-by: Praveen Diwakar praveen.diwakar@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- sound/soc/intel/atom/sst-atom-controls.c | 2 ++ sound/soc/intel/atom/sst-atom-controls.h | 2 ++ 2 files changed, 4 insertions(+)
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 90aa5c0476f3..59517b3fa04d 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -789,6 +789,8 @@ 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, };
int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable) diff --git a/sound/soc/intel/atom/sst-atom-controls.h b/sound/soc/intel/atom/sst-atom-controls.h index c55f76a535b3..eea715605130 100644 --- a/sound/soc/intel/atom/sst-atom-controls.h +++ b/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 {

So right now SSP configuration is statically coded in the driver. While we would like to keep this configuration intact for the users who are using these defaults, we need to provide a way for users to program it. So create a local value in driver structure which is populate with default value for now
Signed-off-by: Praveen Diwakar praveen.diwakar@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- sound/soc/intel/atom/sst-atom-controls.c | 53 ++++++++++++++++++-------------- sound/soc/intel/atom/sst-mfld-platform.h | 2 ++ 2 files changed, 32 insertions(+), 23 deletions(-)
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 59517b3fa04d..93c6c8b5fbc6 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -793,45 +793,52 @@ static const struct sst_ssp_config sst_ssp_configs = { .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, diff --git a/sound/soc/intel/atom/sst-mfld-platform.h b/sound/soc/intel/atom/sst-mfld-platform.h index 9094314be2b0..2409b23eeacf 100644 --- a/sound/soc/intel/atom/sst-mfld-platform.h +++ b/sound/soc/intel/atom/sst-mfld-platform.h @@ -22,6 +22,7 @@ #define __SST_PLATFORMDRV_H__
#include "sst-mfld-dsp.h" +#include "sst-atom-controls.h"
extern struct sst_device *sst;
@@ -175,6 +176,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);

We have the SSP defaults now and we need to load then in hw_params callback of BE SSP DAI ops.
Signed-off-by: Praveen Diwakar praveen.diwakar@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- sound/soc/intel/atom/sst-atom-controls.h | 2 ++ sound/soc/intel/atom/sst-mfld-platform-pcm.c | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/sound/soc/intel/atom/sst-atom-controls.h b/sound/soc/intel/atom/sst-atom-controls.h index eea715605130..da13f6fa7d1c 100644 --- a/sound/soc/intel/atom/sst-atom-controls.h +++ b/sound/soc/intel/atom/sst-atom-controls.h @@ -869,4 +869,6 @@ struct sst_enum { SOC_DAPM_ENUM(SST_MUX_CTL_NAME(xpname, xinstance), \ SST_SSP_MUX_ENUM(xreg, xshift, xtexts))
+void sst_fill_ssp_defaults(struct snd_soc_dai *dai); + #endif diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 2fbaf2c75d17..1fb2448e0fed 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -434,13 +434,22 @@ 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 void sst_disable_ssp(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -465,6 +474,7 @@ 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, .shutdown = sst_disable_ssp, };

With this machines can configure the PCM format applied on SSP port using the set_fmt API
Signed-off-by: Praveen Diwakar praveen.diwakar@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- sound/soc/intel/atom/sst-atom-controls.c | 99 ++++++++++++++++++++++++++++ sound/soc/intel/atom/sst-atom-controls.h | 1 + sound/soc/intel/atom/sst-mfld-platform-pcm.c | 15 +++++ 3 files changed, 115 insertions(+)
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 93c6c8b5fbc6..e024d98948fa 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -774,8 +774,107 @@ int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable) return ret; }
+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, diff --git a/sound/soc/intel/atom/sst-atom-controls.h b/sound/soc/intel/atom/sst-atom-controls.h index da13f6fa7d1c..53551a657b51 100644 --- a/sound/soc/intel/atom/sst-atom-controls.h +++ b/sound/soc/intel/atom/sst-atom-controls.h @@ -869,6 +869,7 @@ struct sst_enum { SOC_DAPM_ENUM(SST_MUX_CTL_NAME(xpname, xinstance), \ SST_SSP_MUX_ENUM(xreg, xshift, xtexts))
+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/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 1fb2448e0fed..580f5e92580e 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -450,6 +450,20 @@ static int sst_be_hw_params(struct snd_pcm_substream *substream, 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 void sst_disable_ssp(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -475,6 +489,7 @@ 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, .shutdown = sst_disable_ssp, };

With this machines can now configure TDM settings for SSP port using set_tdm_slot API
Signed-off-by: Praveen Diwakar praveen.diwakar@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- sound/soc/intel/atom/sst-atom-controls.c | 13 +++++++++++++ sound/soc/intel/atom/sst-atom-controls.h | 2 ++ sound/soc/intel/atom/sst-mfld-platform-pcm.c | 16 ++++++++++++++++ 3 files changed, 31 insertions(+)
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index e024d98948fa..61e240935451 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -774,6 +774,19 @@ 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) { diff --git a/sound/soc/intel/atom/sst-atom-controls.h b/sound/soc/intel/atom/sst-atom-controls.h index 53551a657b51..93de8045d4e1 100644 --- a/sound/soc/intel/atom/sst-atom-controls.h +++ b/sound/soc/intel/atom/sst-atom-controls.h @@ -869,6 +869,8 @@ 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);
diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 580f5e92580e..641ebe61dc08 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -464,6 +464,21 @@ static int sst_set_format(struct snd_soc_dai *dai, unsigned int fmt) 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) { @@ -490,6 +505,7 @@ 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, };

On Wed, May 06, 2015 at 10:06:39PM +0530, Vinod Koul wrote:
This series first add frame and data polarity to ssp config and then starts to use local values for ssp config and then eventually lets that be loaded by hw_params and updates by pcm format and tdm calls to allow machine t specify these parameters
Applied all, thanks.
participants (2)
-
Mark Brown
-
Vinod Koul