Register dai ops for two controller instances.
Signed-off-by: Vijendar Mukunda Vijendar.Mukunda@amd.com --- drivers/soundwire/amd_master.c | 186 ++++++++++++++++++++++++++++++ include/linux/soundwire/sdw_amd.h | 21 ++++ 2 files changed, 207 insertions(+)
diff --git a/drivers/soundwire/amd_master.c b/drivers/soundwire/amd_master.c index 7e1f618254ac..93bffe6ff9e2 100644 --- a/drivers/soundwire/amd_master.c +++ b/drivers/soundwire/amd_master.c @@ -952,6 +952,186 @@ static const struct sdw_master_ops amd_sdwc_ops = { .read_ping_status = amd_sdwc_read_ping_status, };
+static int amd_sdwc_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct amd_sdwc_ctrl *ctrl = snd_soc_dai_get_drvdata(dai); + struct sdw_amd_dma_data *dma; + struct sdw_stream_config sconfig; + struct sdw_port_config *pconfig; + int ch, dir; + int ret; + + dma = snd_soc_dai_get_dma_data(dai, substream); + if (!dma) + return -EIO; + + ch = params_channels(params); + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + dir = SDW_DATA_DIR_RX; + else + dir = SDW_DATA_DIR_TX; + dev_dbg(ctrl->dev, "%s: dir:%d dai->id:0x%x\n", __func__, dir, dai->id); + dma->hw_params = params; + + sconfig.direction = dir; + sconfig.ch_count = ch; + sconfig.frame_rate = params_rate(params); + sconfig.type = dma->stream_type; + + sconfig.bps = snd_pcm_format_width(params_format(params)); + + /* Port configuration */ + pconfig = kzalloc(sizeof(*pconfig), GFP_KERNEL); + if (!pconfig) { + ret = -ENOMEM; + goto error; + } + + pconfig->num = dai->id; + pconfig->ch_mask = (1 << ch) - 1; + ret = sdw_stream_add_master(&ctrl->bus, &sconfig, + pconfig, 1, dma->stream); + if (ret) + dev_err(ctrl->dev, "add master to stream failed:%d\n", ret); + + kfree(pconfig); +error: + return ret; +} + +static int amd_sdwc_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct amd_sdwc_ctrl *ctrl = snd_soc_dai_get_drvdata(dai); + struct sdw_amd_dma_data *dma; + int ret; + + dma = snd_soc_dai_get_dma_data(dai, substream); + if (!dma) + return -EIO; + + ret = sdw_stream_remove_master(&ctrl->bus, dma->stream); + if (ret < 0) { + dev_err(dai->dev, "remove master from stream %s failed: %d\n", + dma->stream->name, ret); + return ret; + } + dma->hw_params = NULL; + return 0; +} + +static int amd_set_sdw_stream(struct snd_soc_dai *dai, void *stream, int direction) +{ + struct amd_sdwc_ctrl *ctrl = snd_soc_dai_get_drvdata(dai); + struct sdw_amd_dma_data *dma; + + if (stream) { + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + dma = dai->playback_dma_data; + else + dma = dai->capture_dma_data; + + if (dma) { + dev_err(dai->dev, + "dma_data already allocated for dai %s\n", + dai->name); + return -EINVAL; + } + + /* allocate and set dma info */ + dma = kzalloc(sizeof(*dma), GFP_KERNEL); + if (!dma) + return -ENOMEM; + dma->stream_type = SDW_STREAM_PCM; + dma->bus = &ctrl->bus; + dma->link_id = ctrl->instance; + dma->stream = stream; + + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + dai->playback_dma_data = dma; + else + dai->capture_dma_data = dma; + } else { + if (direction == SNDRV_PCM_STREAM_PLAYBACK) { + kfree(dai->playback_dma_data); + dai->playback_dma_data = NULL; + } else { + kfree(dai->capture_dma_data); + dai->capture_dma_data = NULL; + } + } + return 0; +} + +static int amd_pcm_set_sdw_stream(struct snd_soc_dai *dai, void *stream, int direction) +{ + return amd_set_sdw_stream(dai, stream, direction); +} + +static void *amd_get_sdw_stream(struct snd_soc_dai *dai, int direction) +{ + struct sdw_amd_dma_data *dma; + + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + dma = dai->playback_dma_data; + else + dma = dai->capture_dma_data; + + if (!dma) + return ERR_PTR(-EINVAL); + + return dma->stream; +} + +static const struct snd_soc_dai_ops amd_sdwc_dai_ops = { + .hw_params = amd_sdwc_hw_params, + .hw_free = amd_sdwc_hw_free, + .set_stream = amd_pcm_set_sdw_stream, + .get_stream = amd_get_sdw_stream, +}; + +static const struct snd_soc_component_driver amd_sdwc_dai_component = { + .name = "soundwire", +}; + +static int amd_sdwc_register_dais(struct amd_sdwc_ctrl *ctrl) +{ + struct snd_soc_dai_driver *dais; + struct snd_soc_pcm_stream *stream; + struct device *dev; + int i, num_dais; + + dev = ctrl->dev; + num_dais = ctrl->num_dout_ports + ctrl->num_din_ports; + dais = devm_kcalloc(dev, num_dais, sizeof(*dais), GFP_KERNEL); + if (!dais) + return -ENOMEM; + for (i = 0; i < num_dais; i++) { + dais[i].name = devm_kasprintf(dev, GFP_KERNEL, "SDW%d Pin%d", ctrl->instance, i); + if (!dais[i].name) { + dev_err(ctrl->dev, "-ENOMEM dai name allocation failed\n"); + return -ENOMEM; + } + + if (i < ctrl->num_dout_ports) + stream = &dais[i].playback; + else + stream = &dais[i].capture; + + stream->channels_min = 2; + stream->channels_max = 2; + stream->rates = SNDRV_PCM_RATE_48000; + stream->formats = SNDRV_PCM_FMTBIT_S16_LE; + + dais[i].ops = &amd_sdwc_dai_ops; + dais[i].id = i; + } + + return devm_snd_soc_register_component(ctrl->dev, &amd_sdwc_dai_component, + dais, num_dais); +} + static void amd_sdwc_probe_work(struct work_struct *work) { struct amd_sdwc_ctrl *ctrl = container_of(work, struct amd_sdwc_ctrl, probe_work); @@ -1043,6 +1223,12 @@ static int amd_sdwc_probe(struct platform_device *pdev) ret); return ret; } + ret = amd_sdwc_register_dais(ctrl); + if (ret) { + dev_err(dev, "CPU DAI registration failed\n"); + sdw_bus_master_delete(&ctrl->bus); + return ret; + } INIT_WORK(&ctrl->probe_work, amd_sdwc_probe_work); schedule_work(&ctrl->probe_work); return 0; diff --git a/include/linux/soundwire/sdw_amd.h b/include/linux/soundwire/sdw_amd.h index 5ec39f8c2f2e..7a99d782969f 100644 --- a/include/linux/soundwire/sdw_amd.h +++ b/include/linux/soundwire/sdw_amd.h @@ -13,6 +13,7 @@ #define ACP_SDW0 0 #define ACP_SDW1 1 #define ACP_SDW0_MAX_DAI 6 +#define AMD_SDW_MAX_DAIS 8
struct acp_sdw_pdata { u16 instance; @@ -25,6 +26,7 @@ struct amd_sdwc_ctrl { void __iomem *mmio; struct work_struct probe_work; struct mutex *sdw_lock; + struct sdw_stream_runtime *sruntime[AMD_SDW_MAX_DAIS]; int num_din_ports; int num_dout_ports; int cols_index; @@ -36,4 +38,23 @@ struct amd_sdwc_ctrl { bool startup_done; u32 power_mode_mask; }; + +/** + * struct sdw_amd_dma_data: AMD DMA data + * + * @name: SoundWire stream name + * @stream: stream runtime + * @bus: Bus handle + * @stream_type: Stream type + * @link_id: Master link id + * @hw_params: hw_params to be applied in .prepare step + */ +struct sdw_amd_dma_data { + char *name; + struct sdw_stream_runtime *stream; + struct sdw_bus *bus; + enum sdw_stream_type stream_type; + int link_id; + struct snd_pcm_hw_params *hw_params; +}; #endif