From fd5d3907197c60464672c8a32edeea66e01f6222 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 20 Sep 2019 11:01:42 +0900 Subject: ASoC: soc-component.h: remove GPL explanation from header soc-component.h already has SPDX License, thus, GPL explanation is not needed. This patch removes it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/8736grafp5.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'include') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 5d80b2eef525..1a832695f69c 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -3,10 +3,6 @@ * soc-component.h * * Copyright (c) 2019 Kuninori Morimoto - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __SOC_COMPONENT_H #define __SOC_COMPONENT_H -- cgit v1.2.3 From b7c5bc45ee94a03a0dc45a862180e17db8ea8e9d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 12 Sep 2019 13:41:01 +0900 Subject: ASoC: soc-core: merge soc_free_pcm_runtime() and soc_rtd_free() "rtd" is handled by soc_xxx_pcm_runtime(), and "rtd->dev" is handled by soc_rtd_xxx(). There is no reason to separate these, and it makes code complex. We can free these in the same time. Here soc_rtd_free() (A) which frees rtd->dev is called from soc_remove_link_dais() many times (1). Then, it is using dev_registered flags to avoid multi kfree() (2). This is no longer needed if we can merge these functions. static void soc_remove_link_dais(...) { ... (1) for_each_comp_order(order) { (1) for_each_card_rtds(card, rtd) { (A) soc_rtd_free(rtd); ... } } } (A) static void soc_rtd_free(...) { (2) if (rtd->dev_registered) { /* we don't need to call kfree() for rtd->dev */ device_unregister(rtd->dev); (2) rtd->dev_registered = 0; } } This patch merges soc_rtd_free() into soc_free_pcm_runtime(). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/878squf7oi.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 1 - sound/soc/soc-core.c | 24 ++++++++---------------- 2 files changed, 8 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/include/sound/soc.h b/include/sound/soc.h index f264c6509f00..d93cb46c536d 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1148,7 +1148,6 @@ struct snd_soc_pcm_runtime { struct list_head component_list; /* list of connected components */ /* bit field */ - unsigned int dev_registered:1; unsigned int pop_wait:1; unsigned int fe_compr:1; /* for Dynamic PCM */ }; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6abc1bc9a236..8a37850291bd 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -369,6 +369,14 @@ static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd) kfree(rtd->codec_dais); snd_soc_rtdcom_del_all(rtd); list_del(&rtd->list); + + /* + * we don't need to call kfree() for rtd->dev + * see + * soc_release_rtd_dev() + */ + if (rtd->dev) + device_unregister(rtd->dev); kfree(rtd); } @@ -434,8 +442,6 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( rtd->num = card->num_rtd; card->num_rtd++; - rtd->dev_registered = 1; - return rtd; free_rtd: @@ -1169,7 +1175,6 @@ static int soc_probe_dai(struct snd_soc_dai *dai, int order) return 0; } -static void soc_rtd_free(struct snd_soc_pcm_runtime *rtd); /* remove me */ static void soc_remove_link_dais(struct snd_soc_card *card) { int i; @@ -1179,10 +1184,6 @@ static void soc_remove_link_dais(struct snd_soc_card *card) for_each_comp_order(order) { for_each_card_rtds(card, rtd) { - - /* finalize rtd device */ - soc_rtd_free(rtd); - /* remove the CODEC DAI */ for_each_rtd_codec_dai(rtd, i, codec_dai) soc_remove_dai(codec_dai, order); @@ -1460,15 +1461,6 @@ void snd_soc_remove_dai_link(struct snd_soc_card *card, } EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link); -static void soc_rtd_free(struct snd_soc_pcm_runtime *rtd) -{ - if (rtd->dev_registered) { - /* we don't need to call kfree() for rtd->dev */ - device_unregister(rtd->dev); - rtd->dev_registered = 0; - } -} - static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, struct snd_soc_pcm_runtime *rtd) { -- cgit v1.2.3 From e957204e732bc2916a241dc61dd7dd14e9a98350 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 27 Sep 2019 09:46:11 +0800 Subject: ASoC: pcm_dmaengine: Extract snd_dmaengine_pcm_refine_runtime_hwparams When set the runtime hardware parameters, we may need to query the capability of DMA to complete the parameters. This patch is to Extract this operation from dmaengine_pcm_set_runtime_hwparams function to a separate function snd_dmaengine_pcm_refine_runtime_hwparams, that other components which need this feature can call this function. Signed-off-by: Shengjiu Wang Reviewed-by: Nicolin Chen Link: https://lore.kernel.org/r/d728f65194e9978cbec4132b522d4fed420d704a.1569493933.git.shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- include/sound/dmaengine_pcm.h | 5 +++ sound/core/pcm_dmaengine.c | 83 +++++++++++++++++++++++++++++++++++ sound/soc/soc-generic-dmaengine-pcm.c | 61 +++---------------------- 3 files changed, 94 insertions(+), 55 deletions(-) (limited to 'include') diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index c679f6116580..b65220685920 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -83,6 +83,11 @@ void snd_dmaengine_pcm_set_config_from_dai_data( const struct snd_dmaengine_dai_dma_data *dma_data, struct dma_slave_config *config); +int snd_dmaengine_pcm_refine_runtime_hwparams( + struct snd_pcm_substream *substream, + struct snd_dmaengine_dai_dma_data *dma_data, + struct snd_pcm_hardware *hw, + struct dma_chan *chan); /* * Try to request the DMA channel using compat_request_channel or diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c index 89a05926ac73..5749a8a49784 100644 --- a/sound/core/pcm_dmaengine.c +++ b/sound/core/pcm_dmaengine.c @@ -369,4 +369,87 @@ int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream) } EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan); +/** + * snd_dmaengine_pcm_refine_runtime_hwparams - Refine runtime hw params + * @substream: PCM substream + * @dma_data: DAI DMA data + * @hw: PCM hw params + * @chan: DMA channel to use for data transfers + * + * Returns 0 on success, a negative error code otherwise. + * + * This function will query DMA capability, then refine the pcm hardware + * parameters. + */ +int snd_dmaengine_pcm_refine_runtime_hwparams( + struct snd_pcm_substream *substream, + struct snd_dmaengine_dai_dma_data *dma_data, + struct snd_pcm_hardware *hw, + struct dma_chan *chan) +{ + struct dma_slave_caps dma_caps; + u32 addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); + snd_pcm_format_t i; + int ret = 0; + + if (!hw || !chan || !dma_data) + return -EINVAL; + + ret = dma_get_slave_caps(chan, &dma_caps); + if (ret == 0) { + if (dma_caps.cmd_pause && dma_caps.cmd_resume) + hw->info |= SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME; + if (dma_caps.residue_granularity <= DMA_RESIDUE_GRANULARITY_SEGMENT) + hw->info |= SNDRV_PCM_INFO_BATCH; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + addr_widths = dma_caps.dst_addr_widths; + else + addr_widths = dma_caps.src_addr_widths; + } + + /* + * If SND_DMAENGINE_PCM_DAI_FLAG_PACK is set keep + * hw.formats set to 0, meaning no restrictions are in place. + * In this case it's the responsibility of the DAI driver to + * provide the supported format information. + */ + if (!(dma_data->flags & SND_DMAENGINE_PCM_DAI_FLAG_PACK)) + /* + * Prepare formats mask for valid/allowed sample types. If the + * dma does not have support for the given physical word size, + * it needs to be masked out so user space can not use the + * format which produces corrupted audio. + * In case the dma driver does not implement the slave_caps the + * default assumption is that it supports 1, 2 and 4 bytes + * widths. + */ + for (i = SNDRV_PCM_FORMAT_FIRST; i <= SNDRV_PCM_FORMAT_LAST; i++) { + int bits = snd_pcm_format_physical_width(i); + + /* + * Enable only samples with DMA supported physical + * widths + */ + switch (bits) { + case 8: + case 16: + case 24: + case 32: + case 64: + if (addr_widths & (1 << (bits / 8))) + hw->formats |= pcm_format_to_bits(i); + break; + default: + /* Unsupported types */ + break; + } + } + + return ret; +} +EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_refine_runtime_hwparams); + MODULE_LICENSE("GPL"); diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 5552c66ca642..f2c98a9cbf75 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -118,12 +118,7 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea struct device *dma_dev = dmaengine_dma_dev(pcm, substream); struct dma_chan *chan = pcm->chan[substream->stream]; struct snd_dmaengine_dai_dma_data *dma_data; - struct dma_slave_caps dma_caps; struct snd_pcm_hardware hw; - u32 addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | - BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | - BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); - snd_pcm_format_t i; int ret; if (pcm->config && pcm->config->pcm_hardware) @@ -145,56 +140,12 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea if (pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE) hw.info |= SNDRV_PCM_INFO_BATCH; - ret = dma_get_slave_caps(chan, &dma_caps); - if (ret == 0) { - if (dma_caps.cmd_pause && dma_caps.cmd_resume) - hw.info |= SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME; - if (dma_caps.residue_granularity <= DMA_RESIDUE_GRANULARITY_SEGMENT) - hw.info |= SNDRV_PCM_INFO_BATCH; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - addr_widths = dma_caps.dst_addr_widths; - else - addr_widths = dma_caps.src_addr_widths; - } - - /* - * If SND_DMAENGINE_PCM_DAI_FLAG_PACK is set keep - * hw.formats set to 0, meaning no restrictions are in place. - * In this case it's the responsibility of the DAI driver to - * provide the supported format information. - */ - if (!(dma_data->flags & SND_DMAENGINE_PCM_DAI_FLAG_PACK)) - /* - * Prepare formats mask for valid/allowed sample types. If the - * dma does not have support for the given physical word size, - * it needs to be masked out so user space can not use the - * format which produces corrupted audio. - * In case the dma driver does not implement the slave_caps the - * default assumption is that it supports 1, 2 and 4 bytes - * widths. - */ - for (i = SNDRV_PCM_FORMAT_FIRST; i <= SNDRV_PCM_FORMAT_LAST; i++) { - int bits = snd_pcm_format_physical_width(i); - - /* - * Enable only samples with DMA supported physical - * widths - */ - switch (bits) { - case 8: - case 16: - case 24: - case 32: - case 64: - if (addr_widths & (1 << (bits / 8))) - hw.formats |= pcm_format_to_bits(i); - break; - default: - /* Unsupported types */ - break; - } - } + ret = snd_dmaengine_pcm_refine_runtime_hwparams(substream, + dma_data, + &hw, + chan); + if (ret) + return ret; return snd_soc_set_runtime_hwparams(substream, &hw); } -- cgit v1.2.3 From e3ebfd0ab5b4880bfb6a9f32614c2e389cc3da56 Mon Sep 17 00:00:00 2001 From: Marcin Rajwa Date: Fri, 27 Sep 2019 15:05:33 -0500 Subject: ASoC: SOF: ipc: introduce no_stream_position in sof_ipc_stream_params struct The host period bytes value needs to be passed to firmware. However current implementation uses this field for different purpose - to indicate whether FW should send stream position to the host. Therefore this patch introduces another field "no_stream_position", a boolean value aimed to store information about position tracking. This way host_period_bytes preserves its original value. Signed-off-by: Marcin Rajwa Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190927200538.660-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/stream.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/sound/sof/stream.h b/include/sound/sof/stream.h index 0b71b381b952..7facefb541b3 100644 --- a/include/sound/sof/stream.h +++ b/include/sound/sof/stream.h @@ -83,10 +83,10 @@ struct sof_ipc_stream_params { uint16_t sample_valid_bytes; uint16_t sample_container_bytes; - /* for notifying host period has completed - 0 means no period IRQ */ uint32_t host_period_bytes; + uint16_t no_stream_position; /**< 1 means don't send stream position */ - uint32_t reserved[2]; + uint16_t reserved[3]; uint16_t chmap[SOF_IPC_MAX_CHANNELS]; /**< channel map - SOF_CHMAP_ */ } __packed; -- cgit v1.2.3 From af78cec45f2d01be9d14c177e403c8021ebfd40e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 16 Sep 2019 16:42:40 -0500 Subject: ASoC: soc-acpi: add link_mask field When interfaces can be pin-muxed, static information from ACPI might not be enough. Add information on which links needs to be enabled by hardware/firmware for a specific machine driver to be selected. When walking through the list of possible machines, links will be checked, which implies that configurations where multiple links are required need to be checked first. Additional criteria will be needed later, such as which SoundWire Slave devices are actually enabled, but for now this helps detect between basic configurations. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190916214251.13130-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/soc-acpi.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 35b38e41e5b2..c0fb71c7b3ad 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -75,6 +75,7 @@ struct snd_soc_acpi_mach_params { * all firmware/topology related fields. * * @id: ACPI ID (usually the codec's) used to find a matching machine driver. + * @link_mask: describes required board layout, e.g. for SoundWire. * @drv_name: machine driver name * @fw_filename: firmware file name. Used when SOF is not enabled. * @board: board name @@ -90,6 +91,7 @@ struct snd_soc_acpi_mach_params { /* Descriptor for SST ASoC machine driver */ struct snd_soc_acpi_mach { const u8 id[ACPI_ID_LEN]; + const u32 link_mask; const char *drv_name; const char *fw_filename; const char *board; -- cgit v1.2.3 From 1466327e8eb3e59ae8e65e5c728055102fe0a60e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 16 Sep 2019 16:42:41 -0500 Subject: ASoC: SOF: support alternate list of machines For cases where an interface can be pin-muxed, we need to assess at probe time which configuration should be used. In cases such as SoundWire, we need to maintain an alternate list of machines and walk through them when the primary detection based on ACPI _HID fails. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20190916214251.13130-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/sound/sof.h b/include/sound/sof.h index 4640566b54fe..479101736ee0 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -61,6 +61,9 @@ struct sof_dev_desc { /* list of machines using this configuration */ struct snd_soc_acpi_mach *machines; + /* alternate list of machines using this configuration */ + struct snd_soc_acpi_mach *alt_machines; + /* Platform resource indexes in BAR / ACPI resources. */ /* Must set to -1 if not used - add new items to end */ int resindex_lpe_base; -- cgit v1.2.3 From e2cb4a14541dba3587bb78e0f62da27a0e1ad399 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:30:48 +0900 Subject: ASoC: soc-core: merge snd_pcm_ops member to component driver Current snd_soc_component_driver has snd_pcm_ops, and each driver can have callback via it (1). But, it is mainly created for ALSA, thus, it doesn't have "component" as parameter for ALSA SoC (1)(2). Thus, each callback can't know it is called for which component. Thus, each callback currently is getting "component" by using snd_soc_rtdcom_lookup() with driver name (3). --- ALSA SoC --- ... if (component->driver->ops && component->driver->ops->open) (1) return component->driver->ops->open(substream); ... --- driver --- (2) static int xxx_open(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; (3) struct snd_soc_component *component = snd_soc_rtdcom_lookup(..); ... } It works today, but, will not work in the future if we support multi CPU/Codec/Platform, because 1 rtd might have multiple components which have same driver name. To solve this issue, each callback needs to be called with component. We already have many component driver callback. This patch copies each snd_pcm_ops member under component driver, and having "component" as parameter. --- ALSA SoC --- ... if (component->driver->open) => return component->driver->open(component, substream); ... --- driver --- => static int xxx_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { ... } *Note* Only Intel skl-pcm has .get_time_info implementation, but ALSA SoC framework doesn't call it so far. To keep its implementation, this patch keeps .get_time_info, but it is still not called. Intel guy need to support it in the future. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87tv8raf3r.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 34 ++++++++++++++++++++++++++++ sound/soc/soc-component.c | 52 +++++++++++++++++++++++++++++++++++++++++++ sound/soc/soc-pcm.c | 9 ++++---- 3 files changed, 91 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 1a832695f69c..a6a3b696d5b0 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -70,6 +70,40 @@ struct snd_soc_component_driver { int (*set_bias_level)(struct snd_soc_component *component, enum snd_soc_bias_level level); + int (*open)(struct snd_soc_component *component, + struct snd_pcm_substream *substream); + int (*close)(struct snd_soc_component *component, + struct snd_pcm_substream *substream); + int (*ioctl)(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + unsigned int cmd, void *arg); + int (*hw_params)(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); + int (*hw_free)(struct snd_soc_component *component, + struct snd_pcm_substream *substream); + int (*prepare)(struct snd_soc_component *component, + struct snd_pcm_substream *substream); + int (*trigger)(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd); + snd_pcm_uframes_t (*pointer)(struct snd_soc_component *component, + struct snd_pcm_substream *substream); + int (*get_time_info)(struct snd_soc_component *component, + struct snd_pcm_substream *substream, struct timespec *system_ts, + struct timespec *audio_ts, + struct snd_pcm_audio_tstamp_config *audio_tstamp_config, + struct snd_pcm_audio_tstamp_report *audio_tstamp_report); + int (*copy_user)(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int channel, + unsigned long pos, void __user *buf, + unsigned long bytes); + struct page *(*page)(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + unsigned long offset); + int (*mmap)(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct vm_area_struct *vma); + const struct snd_pcm_ops *ops; const struct snd_compr_ops *compr_ops; diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 79ffc2820ba9..2d9cb763e63a 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -314,6 +314,10 @@ void snd_soc_component_module_put(struct snd_soc_component *component, int snd_soc_component_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { + if (component->driver->open) + return component->driver->open(component, substream); + + /* remove me */ if (component->driver->ops && component->driver->ops->open) return component->driver->ops->open(substream); @@ -324,6 +328,10 @@ int snd_soc_component_open(struct snd_soc_component *component, int snd_soc_component_close(struct snd_soc_component *component, struct snd_pcm_substream *substream) { + if (component->driver->close) + return component->driver->close(component, substream); + + /* remove me */ if (component->driver->ops && component->driver->ops->close) return component->driver->ops->close(substream); @@ -334,6 +342,10 @@ int snd_soc_component_close(struct snd_soc_component *component, int snd_soc_component_prepare(struct snd_soc_component *component, struct snd_pcm_substream *substream) { + if (component->driver->prepare) + return component->driver->prepare(component, substream); + + /* remove me */ if (component->driver->ops && component->driver->ops->prepare) return component->driver->ops->prepare(substream); @@ -345,6 +357,11 @@ int snd_soc_component_hw_params(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { + if (component->driver->hw_params) + return component->driver->hw_params(component, + substream, params); + + /* remove me */ if (component->driver->ops && component->driver->ops->hw_params) return component->driver->ops->hw_params(substream, params); @@ -355,6 +372,10 @@ int snd_soc_component_hw_params(struct snd_soc_component *component, int snd_soc_component_hw_free(struct snd_soc_component *component, struct snd_pcm_substream *substream) { + if (component->driver->hw_free) + return component->driver->hw_free(component, substream); + + /* remove me */ if (component->driver->ops && component->driver->ops->hw_free) return component->driver->ops->hw_free(substream); @@ -366,6 +387,10 @@ int snd_soc_component_trigger(struct snd_soc_component *component, struct snd_pcm_substream *substream, int cmd) { + if (component->driver->trigger) + return component->driver->trigger(component, substream, cmd); + + /* remove me */ if (component->driver->ops && component->driver->ops->trigger) return component->driver->ops->trigger(substream, cmd); @@ -435,6 +460,10 @@ int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream) component = rtdcom->component; /* FIXME: use 1st pointer */ + if (component->driver->pointer) + return component->driver->pointer(component, substream); + + /* remove me */ if (component->driver->ops && component->driver->ops->pointer) return component->driver->ops->pointer(substream); @@ -454,6 +483,11 @@ int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, component = rtdcom->component; /* FIXME: use 1st ioctl */ + if (component->driver->ioctl) + return component->driver->ioctl(component, substream, + cmd, arg); + + /* remove me */ if (component->driver->ops && component->driver->ops->ioctl) return component->driver->ops->ioctl(substream, @@ -475,6 +509,11 @@ int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream, component = rtdcom->component; /* FIXME. it returns 1st copy now */ + if (component->driver->copy_user) + return component->driver->copy_user( + component, substream, channel, pos, buf, bytes); + + /* remove me */ if (component->driver->ops && component->driver->ops->copy_user) return component->driver->ops->copy_user( @@ -496,6 +535,14 @@ struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, component = rtdcom->component; /* FIXME. it returns 1st page now */ + if (component->driver->page) { + page = component->driver->page(component, + substream, offset); + if (page) + return page; + } + + /* remove me */ if (component->driver->ops && component->driver->ops->page) { page = component->driver->ops->page(substream, offset); @@ -518,6 +565,11 @@ int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, component = rtdcom->component; /* FIXME. it returns 1st mmap now */ + if (component->driver->mmap) + return component->driver->mmap(component, + substream, vma); + + /* remove me */ if (component->driver->ops && component->driver->ops->mmap) return component->driver->ops->mmap(substream, vma); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 66910500e3b6..dbf67d8a5411 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2987,16 +2987,17 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) } for_each_rtdcom(rtd, rtdcom) { - const struct snd_pcm_ops *ops = rtdcom->component->driver->ops; + const struct snd_soc_component_driver *drv = rtdcom->component->driver; + const struct snd_pcm_ops *ops = drv->ops; if (!ops) continue; - if (ops->copy_user) + if (ops->copy_user || drv->copy_user) rtd->ops.copy_user = snd_soc_pcm_component_copy_user; - if (ops->page) + if (ops->page || drv->page) rtd->ops.page = snd_soc_pcm_component_page; - if (ops->mmap) + if (ops->mmap || drv->mmap) rtd->ops.mmap = snd_soc_pcm_component_mmap; } -- cgit v1.2.3 From c64bfc9066007962fca1b9b2d426b1efc171cac9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:30:59 +0900 Subject: ASoC: soc-core: add new pcm_construct/pcm_destruct Current snd_soc_component_driver has pcm_new/pcm_free, but, it doesn't have "component" at parameter. Thus, each callback can't know it is called for which component. Each callback currently is getting "component" by using snd_soc_rtdcom_lookup() with driver name. It works today, but, will not work in the future if we support multi CPU/Codec/Platform, because 1 rtd might have multiple same driver name component. To solve this issue, each callback need to be called with component. This patch adds new pcm_construct/pcm_destruct with "component" parameter. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87sgobaf3g.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 6 ++++++ sound/soc/soc-component.c | 11 +++++++++++ 2 files changed, 17 insertions(+) (limited to 'include') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index a6a3b696d5b0..aa2e2cbc1ee5 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -46,10 +46,16 @@ struct snd_soc_component_driver { int (*write)(struct snd_soc_component *component, unsigned int reg, unsigned int val); + /* remove me */ /* pcm creation and destruction */ int (*pcm_new)(struct snd_soc_pcm_runtime *rtd); void (*pcm_free)(struct snd_pcm *pcm); + int (*pcm_construct)(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd); + void (*pcm_destruct)(struct snd_soc_component *component, + struct snd_pcm *pcm); + /* component wide operations */ int (*set_sysclk)(struct snd_soc_component *component, int clk_id, int source, unsigned int freq, int dir); diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 2d9cb763e63a..d2b052ac88cd 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -588,6 +588,13 @@ int snd_soc_pcm_component_new(struct snd_pcm *pcm) for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; + if (component->driver->pcm_construct) { + ret = component->driver->pcm_construct(component, rtd); + if (ret < 0) + return ret; + } + + /* remove me */ if (component->driver->pcm_new) { ret = component->driver->pcm_new(rtd); if (ret < 0) @@ -607,6 +614,10 @@ void snd_soc_pcm_component_free(struct snd_pcm *pcm) for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; + if (component->driver->pcm_destruct) + component->driver->pcm_destruct(component, pcm); + + /* remove me */ if (component->driver->pcm_free) component->driver->pcm_free(pcm); } -- cgit v1.2.3 From 8ec241c495dde3d19a0459304298c2468c60182b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:31:06 +0900 Subject: ASoC: soc-core: add snd_soc_pcm_lib_ioctl() add snd_soc_pcm_lib_ioctl() to bypass to snd_pcm_lib_ioctl() Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r23vaf39.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 5 +++++ sound/soc/soc-core.c | 12 ++++++++++++ 2 files changed, 17 insertions(+) (limited to 'include') diff --git a/include/sound/soc.h b/include/sound/soc.h index d93cb46c536d..32748f78060a 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1390,6 +1390,11 @@ static inline void snd_soc_dapm_mutex_unlock(struct snd_soc_dapm_context *dapm) mutex_unlock(&dapm->card->dapm_mutex); } +/* bypass */ +int snd_soc_pcm_lib_ioctl(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + unsigned int cmd, void *arg); + #include #endif diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d39d908f3204..bd2ac1912466 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -277,6 +277,18 @@ static inline void snd_soc_debugfs_exit(void) #endif +/* + * This is glue code between snd_pcm_lib_ioctl() and + * snd_soc_component_driver :: ioctl + */ +int snd_soc_pcm_lib_ioctl(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + unsigned int cmd, void *arg) +{ + return snd_pcm_lib_ioctl(substream, cmd, arg); +} +EXPORT_SYMBOL_GPL(snd_soc_pcm_lib_ioctl); + static int snd_soc_rtdcom_add(struct snd_soc_pcm_runtime *rtd, struct snd_soc_component *component) { -- cgit v1.2.3 From f8772e17def20470f94bd1d6e1cf24badb2611de Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:33:50 +0900 Subject: ASoC: pxa: remove snd_pcm_ops snd_pcm_ops is no longer needed. Let's use component driver callback. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87o8yz90e9.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/pxa2xx-lib.h | 26 +++++++++++++-- sound/arm/pxa2xx-pcm-lib.c | 80 +++++++++++++++++++++++++++++++++++++-------- sound/soc/pxa/pxa-ssp.c | 14 ++++++-- sound/soc/pxa/pxa2xx-ac97.c | 14 ++++++-- sound/soc/pxa/pxa2xx-i2s.c | 14 ++++++-- sound/soc/pxa/pxa2xx-pcm.c | 14 ++++++-- 6 files changed, 135 insertions(+), 27 deletions(-) (limited to 'include') diff --git a/include/sound/pxa2xx-lib.h b/include/sound/pxa2xx-lib.h index 6758fc12fa84..0feaf16e6ac0 100644 --- a/include/sound/pxa2xx-lib.h +++ b/include/sound/pxa2xx-lib.h @@ -10,6 +10,7 @@ struct snd_pcm_substream; struct snd_pcm_hw_params; struct snd_soc_pcm_runtime; struct snd_pcm; +struct snd_soc_component; extern int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); @@ -23,8 +24,29 @@ extern int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma); extern int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream); extern void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm); -extern int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd); -extern const struct snd_pcm_ops pxa2xx_pcm_ops; +extern void pxa2xx_soc_pcm_free(struct snd_soc_component *component, + struct snd_pcm *pcm); +extern int pxa2xx_soc_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd); +extern int pxa2xx_soc_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream); +extern int pxa2xx_soc_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream); +extern int pxa2xx_soc_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); +extern int pxa2xx_soc_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream); +extern int pxa2xx_soc_pcm_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream); +extern int pxa2xx_soc_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd); +extern snd_pcm_uframes_t +pxa2xx_soc_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream); +extern int pxa2xx_soc_pcm_mmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct vm_area_struct *vma); /* AC97 */ diff --git a/sound/arm/pxa2xx-pcm-lib.c b/sound/arm/pxa2xx-pcm-lib.c index 54500bd098f9..a86c95d89824 100644 --- a/sound/arm/pxa2xx-pcm-lib.c +++ b/sound/arm/pxa2xx-pcm-lib.c @@ -175,7 +175,15 @@ void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm) } EXPORT_SYMBOL(pxa2xx_pcm_free_dma_buffers); -int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd) +void pxa2xx_soc_pcm_free(struct snd_soc_component *component, + struct snd_pcm *pcm) +{ + pxa2xx_pcm_free_dma_buffers(pcm); +} +EXPORT_SYMBOL(pxa2xx_soc_pcm_free); + +int pxa2xx_soc_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; struct snd_pcm *pcm = rtd->pcm; @@ -203,18 +211,64 @@ int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd) } EXPORT_SYMBOL(pxa2xx_soc_pcm_new); -const struct snd_pcm_ops pxa2xx_pcm_ops = { - .open = pxa2xx_pcm_open, - .close = pxa2xx_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = pxa2xx_pcm_hw_params, - .hw_free = pxa2xx_pcm_hw_free, - .prepare = pxa2xx_pcm_prepare, - .trigger = pxa2xx_pcm_trigger, - .pointer = pxa2xx_pcm_pointer, - .mmap = pxa2xx_pcm_mmap, -}; -EXPORT_SYMBOL(pxa2xx_pcm_ops); +int pxa2xx_soc_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + return pxa2xx_pcm_open(substream); +} +EXPORT_SYMBOL(pxa2xx_soc_pcm_open); + +int pxa2xx_soc_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + return pxa2xx_pcm_close(substream); +} +EXPORT_SYMBOL(pxa2xx_soc_pcm_close); + +int pxa2xx_soc_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + return pxa2xx_pcm_hw_params(substream, params); +} +EXPORT_SYMBOL(pxa2xx_soc_pcm_hw_params); + +int pxa2xx_soc_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + return pxa2xx_pcm_hw_free(substream); +} +EXPORT_SYMBOL(pxa2xx_soc_pcm_hw_free); + +int pxa2xx_soc_pcm_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + return pxa2xx_pcm_prepare(substream); +} +EXPORT_SYMBOL(pxa2xx_soc_pcm_prepare); + +int pxa2xx_soc_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) +{ + return pxa2xx_pcm_trigger(substream, cmd); +} +EXPORT_SYMBOL(pxa2xx_soc_pcm_trigger); + +snd_pcm_uframes_t +pxa2xx_soc_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + return pxa2xx_pcm_pointer(substream); +} +EXPORT_SYMBOL(pxa2xx_soc_pcm_pointer); + +int pxa2xx_soc_pcm_mmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + return pxa2xx_pcm_mmap(substream, vma); +} +EXPORT_SYMBOL(pxa2xx_soc_pcm_mmap); MODULE_AUTHOR("Nicolas Pitre"); MODULE_DESCRIPTION("Intel PXA2xx sound library"); diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 5fdd1a24c232..49cb3ba1519f 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -869,9 +869,17 @@ static struct snd_soc_dai_driver pxa_ssp_dai = { static const struct snd_soc_component_driver pxa_ssp_component = { .name = "pxa-ssp", - .ops = &pxa2xx_pcm_ops, - .pcm_new = pxa2xx_soc_pcm_new, - .pcm_free = pxa2xx_pcm_free_dma_buffers, + .pcm_construct = pxa2xx_soc_pcm_new, + .pcm_destruct = pxa2xx_soc_pcm_free, + .open = pxa2xx_soc_pcm_open, + .close = pxa2xx_soc_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = pxa2xx_soc_pcm_hw_params, + .hw_free = pxa2xx_soc_pcm_hw_free, + .prepare = pxa2xx_soc_pcm_prepare, + .trigger = pxa2xx_soc_pcm_trigger, + .pointer = pxa2xx_soc_pcm_pointer, + .mmap = pxa2xx_soc_pcm_mmap, }; #ifdef CONFIG_OF diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index bf28187315db..31e81a6f616f 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -204,9 +204,17 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = { static const struct snd_soc_component_driver pxa_ac97_component = { .name = "pxa-ac97", - .ops = &pxa2xx_pcm_ops, - .pcm_new = pxa2xx_soc_pcm_new, - .pcm_free = pxa2xx_pcm_free_dma_buffers, + .pcm_construct = pxa2xx_soc_pcm_new, + .pcm_destruct = pxa2xx_soc_pcm_free, + .open = pxa2xx_soc_pcm_open, + .close = pxa2xx_soc_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = pxa2xx_soc_pcm_hw_params, + .hw_free = pxa2xx_soc_pcm_hw_free, + .prepare = pxa2xx_soc_pcm_prepare, + .trigger = pxa2xx_soc_pcm_trigger, + .pointer = pxa2xx_soc_pcm_pointer, + .mmap = pxa2xx_soc_pcm_mmap, }; #ifdef CONFIG_OF diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 9f7fb7335ac0..e77d707efde7 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -360,9 +360,17 @@ static struct snd_soc_dai_driver pxa_i2s_dai = { static const struct snd_soc_component_driver pxa_i2s_component = { .name = "pxa-i2s", - .ops = &pxa2xx_pcm_ops, - .pcm_new = pxa2xx_soc_pcm_new, - .pcm_free = pxa2xx_pcm_free_dma_buffers, + .pcm_construct = pxa2xx_soc_pcm_new, + .pcm_destruct = pxa2xx_soc_pcm_free, + .open = pxa2xx_soc_pcm_open, + .close = pxa2xx_soc_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = pxa2xx_soc_pcm_hw_params, + .hw_free = pxa2xx_soc_pcm_hw_free, + .prepare = pxa2xx_soc_pcm_prepare, + .trigger = pxa2xx_soc_pcm_trigger, + .pointer = pxa2xx_soc_pcm_pointer, + .mmap = pxa2xx_soc_pcm_mmap, }; static int pxa2xx_i2s_drv_probe(struct platform_device *pdev) diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index 74b56fa0870f..07b3455a6f23 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c @@ -18,9 +18,17 @@ #include static const struct snd_soc_component_driver pxa2xx_soc_platform = { - .ops = &pxa2xx_pcm_ops, - .pcm_new = pxa2xx_soc_pcm_new, - .pcm_free = pxa2xx_pcm_free_dma_buffers, + .pcm_construct = pxa2xx_soc_pcm_new, + .pcm_destruct = pxa2xx_soc_pcm_free, + .open = pxa2xx_soc_pcm_open, + .close = pxa2xx_soc_pcm_close, + .ioctl = snd_soc_pcm_lib_ioctl, + .hw_params = pxa2xx_soc_pcm_hw_params, + .hw_free = pxa2xx_soc_pcm_hw_free, + .prepare = pxa2xx_soc_pcm_prepare, + .trigger = pxa2xx_soc_pcm_trigger, + .pointer = pxa2xx_soc_pcm_pointer, + .mmap = pxa2xx_soc_pcm_mmap, }; static int pxa2xx_soc_platform_probe(struct platform_device *pdev) -- cgit v1.2.3 From e9067bb502787869dabe385727baff233024097b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 2 Oct 2019 14:35:13 +0900 Subject: ASoC: soc-component: remove snd_pcm_ops from component driver No driver is using snd_pcm_ops on component driver. This patch removes it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/8736gb90by.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 5 --- sound/soc/soc-component.c | 77 ------------------------------------------- sound/soc/soc-pcm.c | 10 ++---- 3 files changed, 3 insertions(+), 89 deletions(-) (limited to 'include') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index aa2e2cbc1ee5..6aa3ecb7b6d3 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -46,11 +46,7 @@ struct snd_soc_component_driver { int (*write)(struct snd_soc_component *component, unsigned int reg, unsigned int val); - /* remove me */ /* pcm creation and destruction */ - int (*pcm_new)(struct snd_soc_pcm_runtime *rtd); - void (*pcm_free)(struct snd_pcm *pcm); - int (*pcm_construct)(struct snd_soc_component *component, struct snd_soc_pcm_runtime *rtd); void (*pcm_destruct)(struct snd_soc_component *component, @@ -110,7 +106,6 @@ struct snd_soc_component_driver { struct snd_pcm_substream *substream, struct vm_area_struct *vma); - const struct snd_pcm_ops *ops; const struct snd_compr_ops *compr_ops; /* probe ordering - for components with runtime dependencies */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index d2b052ac88cd..debaf1f6f403 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -316,12 +316,6 @@ int snd_soc_component_open(struct snd_soc_component *component, { if (component->driver->open) return component->driver->open(component, substream); - - /* remove me */ - if (component->driver->ops && - component->driver->ops->open) - return component->driver->ops->open(substream); - return 0; } @@ -330,12 +324,6 @@ int snd_soc_component_close(struct snd_soc_component *component, { if (component->driver->close) return component->driver->close(component, substream); - - /* remove me */ - if (component->driver->ops && - component->driver->ops->close) - return component->driver->ops->close(substream); - return 0; } @@ -344,12 +332,6 @@ int snd_soc_component_prepare(struct snd_soc_component *component, { if (component->driver->prepare) return component->driver->prepare(component, substream); - - /* remove me */ - if (component->driver->ops && - component->driver->ops->prepare) - return component->driver->ops->prepare(substream); - return 0; } @@ -360,12 +342,6 @@ int snd_soc_component_hw_params(struct snd_soc_component *component, if (component->driver->hw_params) return component->driver->hw_params(component, substream, params); - - /* remove me */ - if (component->driver->ops && - component->driver->ops->hw_params) - return component->driver->ops->hw_params(substream, params); - return 0; } @@ -374,12 +350,6 @@ int snd_soc_component_hw_free(struct snd_soc_component *component, { if (component->driver->hw_free) return component->driver->hw_free(component, substream); - - /* remove me */ - if (component->driver->ops && - component->driver->ops->hw_free) - return component->driver->ops->hw_free(substream); - return 0; } @@ -389,12 +359,6 @@ int snd_soc_component_trigger(struct snd_soc_component *component, { if (component->driver->trigger) return component->driver->trigger(component, substream, cmd); - - /* remove me */ - if (component->driver->ops && - component->driver->ops->trigger) - return component->driver->ops->trigger(substream, cmd); - return 0; } @@ -462,11 +426,6 @@ int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream) /* FIXME: use 1st pointer */ if (component->driver->pointer) return component->driver->pointer(component, substream); - - /* remove me */ - if (component->driver->ops && - component->driver->ops->pointer) - return component->driver->ops->pointer(substream); } return 0; @@ -486,12 +445,6 @@ int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, if (component->driver->ioctl) return component->driver->ioctl(component, substream, cmd, arg); - - /* remove me */ - if (component->driver->ops && - component->driver->ops->ioctl) - return component->driver->ops->ioctl(substream, - cmd, arg); } return snd_pcm_lib_ioctl(substream, cmd, arg); @@ -512,12 +465,6 @@ int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream, if (component->driver->copy_user) return component->driver->copy_user( component, substream, channel, pos, buf, bytes); - - /* remove me */ - if (component->driver->ops && - component->driver->ops->copy_user) - return component->driver->ops->copy_user( - substream, channel, pos, buf, bytes); } return -EINVAL; @@ -541,14 +488,6 @@ struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, if (page) return page; } - - /* remove me */ - if (component->driver->ops && - component->driver->ops->page) { - page = component->driver->ops->page(substream, offset); - if (page) - return page; - } } return NULL; @@ -568,11 +507,6 @@ int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, if (component->driver->mmap) return component->driver->mmap(component, substream, vma); - - /* remove me */ - if (component->driver->ops && - component->driver->ops->mmap) - return component->driver->ops->mmap(substream, vma); } return -EINVAL; @@ -593,13 +527,6 @@ int snd_soc_pcm_component_new(struct snd_pcm *pcm) if (ret < 0) return ret; } - - /* remove me */ - if (component->driver->pcm_new) { - ret = component->driver->pcm_new(rtd); - if (ret < 0) - return ret; - } } return 0; @@ -616,9 +543,5 @@ void snd_soc_pcm_component_free(struct snd_pcm *pcm) if (component->driver->pcm_destruct) component->driver->pcm_destruct(component, pcm); - - /* remove me */ - if (component->driver->pcm_free) - component->driver->pcm_free(pcm); } } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index dbf67d8a5411..f462947a5d27 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2988,16 +2988,12 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) for_each_rtdcom(rtd, rtdcom) { const struct snd_soc_component_driver *drv = rtdcom->component->driver; - const struct snd_pcm_ops *ops = drv->ops; - if (!ops) - continue; - - if (ops->copy_user || drv->copy_user) + if (drv->copy_user) rtd->ops.copy_user = snd_soc_pcm_component_copy_user; - if (ops->page || drv->page) + if (drv->page) rtd->ops.page = snd_soc_pcm_component_page; - if (ops->mmap || drv->mmap) + if (drv->mmap) rtd->ops.mmap = snd_soc_pcm_component_mmap; } -- cgit v1.2.3 From 4bbee14d8e5487e3d2662138e3767cf4678cdf57 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 9 Oct 2019 18:36:14 +0300 Subject: ASoC: simple_card_utils.h: Add missing include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When debug is enabled compiler cannot find the definition of clk_get_rate resulting in the following error: ./include/sound/simple_card_utils.h:168:40: note: previous implicit declaration of ‘clk_get_rate’ was here dev_dbg(dev, "%s clk %luHz\n", name, clk_get_rate(dai->clk)); ./include/sound/simple_card_utils.h:168:3: note: in expansion of macro ‘dev_dbg’ dev_dbg(dev, "%s clk %luHz\n", name, clk_get_rate(dai->clk)); Fix this by including the appropriate header. Fixes: 0580dde59438686d ("ASoC: simple-card-utils: add asoc_simple_debug_info()") Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20191009153615.32105-2-daniel.baluta@nxp.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 985a5f583de4..293ff8115960 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -8,6 +8,7 @@ #ifndef __SIMPLE_CARD_UTILS_H #define __SIMPLE_CARD_UTILS_H +#include #include #define asoc_simple_init_hp(card, sjack, prefix) \ -- cgit v1.2.3 From b4be427683cf6debda331a5d6a4af34885851d19 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 8 Oct 2019 11:44:39 -0500 Subject: ASoC: SOF: imx: Describe ESAI parameters to be sent to DSP Introduce sof_ipc_dai_esai_params to keep information that we get from topology and we send to DSP FW. Also bump the ABI minor to reflect the changes on DSP FW. Signed-off-by: Daniel Baluta Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191008164443.1358-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/dai-imx.h | 34 ++++++++++++++++++++++++++++++++++ include/sound/sof/dai.h | 2 ++ include/uapi/sound/sof/abi.h | 2 +- include/uapi/sound/sof/tokens.h | 3 +-- 4 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 include/sound/sof/dai-imx.h (limited to 'include') diff --git a/include/sound/sof/dai-imx.h b/include/sound/sof/dai-imx.h new file mode 100644 index 000000000000..e02fb0b0fae1 --- /dev/null +++ b/include/sound/sof/dai-imx.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Copyright 2019 NXP + * + * Author: Daniel Baluta + */ + +#ifndef __INCLUDE_SOUND_SOF_DAI_IMX_H__ +#define __INCLUDE_SOUND_SOF_DAI_IMX_H__ + +#include + +/* ESAI Configuration Request - SOF_IPC_DAI_ESAI_CONFIG */ +struct sof_ipc_dai_esai_params { + struct sof_ipc_hdr hdr; + + /* MCLK */ + uint16_t reserved1; + uint16_t mclk_id; + uint32_t mclk_direction; + + uint32_t mclk_rate; /* MCLK frequency in Hz */ + uint32_t fsync_rate; /* FSYNC frequency in Hz */ + uint32_t bclk_rate; /* BCLK frequency in Hz */ + + /* TDM */ + uint32_t tdm_slots; + uint32_t rx_slots; + uint32_t tx_slots; + uint16_t tdm_slot_width; + uint16_t reserved2; /* alignment */ +} __packed; + +#endif diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 0f1235022146..c229565767e5 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -11,6 +11,7 @@ #include #include +#include /* * DAI Configuration. @@ -73,6 +74,7 @@ struct sof_ipc_dai_config { struct sof_ipc_dai_dmic_params dmic; struct sof_ipc_dai_hda_params hda; struct sof_ipc_dai_alh_params alh; + struct sof_ipc_dai_esai_params esai; }; } __packed; diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index a0fe0d4c4b66..ebfdc20ca081 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -26,7 +26,7 @@ /* SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 10 +#define SOF_ABI_MINOR 11 #define SOF_ABI_PATCH 0 /* SOF ABI version number. Format within 32bit word is MMmmmppp */ diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 8f996857fb24..da18c9de1056 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -111,7 +111,6 @@ /* TODO: Add SAI tokens */ /* ESAI */ -#define SOF_TKN_IMX_ESAI_FIRST_TOKEN 1100 -/* TODO: Add ESAI tokens */ +#define SOF_TKN_IMX_ESAI_MCLK_ID 1100 #endif -- cgit v1.2.3 From 5d43001ae43606dc525f55c482c545afba01bb55 Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Tue, 8 Oct 2019 11:44:43 -0500 Subject: ASoC: SOF: acpi led support for switch controls Currently sof doesn't support acpi leds with mute switches. So implement acpi leds following quite shamelessly existing HDA implementation by Takashi Iwai. Mute leds can be enabled in topology by adding led and direction token in switch control private data. Signed-off-by: Jaska Uimonen Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191008164443.1358-10-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/uapi/sound/sof/tokens.h | 4 ++++ sound/soc/sof/control.c | 32 ++++++++++++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 9 +++++++++ sound/soc/sof/topology.c | 13 +++++++++++++ 4 files changed, 58 insertions(+) (limited to 'include') diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index da18c9de1056..d65406f34361 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -113,4 +113,8 @@ /* ESAI */ #define SOF_TKN_IMX_ESAI_MCLK_ID 1100 +/* Led control for mute switches */ +#define SOF_TKN_MUTE_LED_USE 1300 +#define SOF_TKN_MUTE_LED_DIRECTION 1301 + #endif diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index a4983f90ff5b..41551e8f6ac3 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -11,8 +11,37 @@ /* Mixer Controls */ #include +#include #include "sof-priv.h" +static void update_mute_led(struct snd_sof_control *scontrol, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + unsigned int temp = 0; + unsigned int mask; + int i; + + mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + + for (i = 0; i < scontrol->num_channels; i++) { + if (ucontrol->value.integer.value[i]) { + temp |= mask; + break; + } + } + + if (temp == scontrol->led_ctl.led_value) + return; + + scontrol->led_ctl.led_value = temp; + + if (!scontrol->led_ctl.direction) + ledtrig_audio_set(LED_AUDIO_MUTE, temp ? LED_OFF : LED_ON); + else + ledtrig_audio_set(LED_AUDIO_MICMUTE, temp ? LED_OFF : LED_ON); +} + static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size) { if (value >= size) @@ -112,6 +141,9 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, cdata->chanv[i].channel = i; } + if (scontrol->led_ctl.use_led) + update_mute_led(scontrol, kcontrol, ucontrol); + /* notify DSP of mixer updates */ if (pm_runtime_active(sdev->dev)) snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 44f789bf7fb0..5a11a8517fa5 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -15,6 +15,7 @@ #include #include +#include #include #include /* needs to be included before control.h */ @@ -310,6 +311,12 @@ struct snd_sof_pcm { bool prepared[2]; /* PCM_PARAMS set successfully */ }; +struct snd_sof_led_control { + unsigned int use_led; + unsigned int direction; + unsigned int led_value; +}; + /* ALSA SOF Kcontrol device */ struct snd_sof_control { struct snd_sof_dev *sdev; @@ -324,6 +331,8 @@ struct snd_sof_control { u32 *volume_table; /* volume table computed from tlv data*/ struct list_head list; /* list in sdev control list */ + + struct snd_sof_led_control led_ctl; }; /* ASoC SOF DAPM widget */ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 3918301c573b..2e5fab1cfbb4 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -682,6 +682,14 @@ static const struct sof_topology_token dmic_pdm_tokens[] = { static const struct sof_topology_token hda_tokens[] = { }; +/* Leds */ +static const struct sof_topology_token led_tokens[] = { + {SOF_TKN_MUTE_LED_USE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct snd_sof_led_control, use_led), 0}, + {SOF_TKN_MUTE_LED_DIRECTION, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_u32, offsetof(struct snd_sof_led_control, direction), 0}, +}; + static void sof_parse_uuid_tokens(struct snd_soc_component *scomp, void *object, const struct sof_topology_token *tokens, @@ -944,6 +952,11 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, } out: + /* set up possible led control from mixer private data */ + ret = sof_parse_tokens(scomp, &scontrol->led_ctl, led_tokens, + ARRAY_SIZE(led_tokens), mc->priv.array, + le32_to_cpu(mc->priv.size)); + dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", scontrol->comp_id, scontrol->num_channels); -- cgit v1.2.3 From 03048217624a9472c1c7a205c8ea9bf8d4026e59 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 15 Oct 2019 14:44:09 +0900 Subject: ASoC: sof: include types.h at header.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Content-Transfer-Encoding: 8bit Without we will get these error linux/include/sound/sof/header.h:125:2: error: unknown type name ‘uint32_t’uint32_t size; linux/include/sound/sof/header.h:136:2: error: unknown type name ‘uint32_t’uint32_t size; linux/include/sound/sof/header.h:137:2: error: unknown type name ‘uint32_t’uint32_t cmd; ... linux/include/sound/sof/dai-imx.h:18:2: error: unknown type name ‘uint16_t’uint16_t reserved1; linux/include/sound/sof/dai-imx.h:30:2: error: unknown type name ‘uint16_t’uint16_t tdm_slot_width; linux/include/sound/sof/dai-imx.h:31:2: error: unknown type name ‘uint16_t’uint16_t reserved2; Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87a7a24l7r.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/sof/header.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h index 10f00c08dbb7..332143ff7278 100644 --- a/include/sound/sof/header.h +++ b/include/sound/sof/header.h @@ -9,6 +9,7 @@ #ifndef __INCLUDE_SOUND_SOF_HEADER_H__ #define __INCLUDE_SOUND_SOF_HEADER_H__ +#include #include /** \addtogroup sof_uapi uAPI -- cgit v1.2.3 From 036beb0e85f8772acb635c30df573876103b0c21 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 14 Oct 2019 18:20:13 +0800 Subject: platform/chrome: cros_ec: remove unused EC feature Remove unused EC_FEATURE_AUDIO_CODEC. Signed-off-by: Tzung-Bi Shih Acked-By: Benson Leung Link: https://lore.kernel.org/r/20191014180059.01.I374c311eaca0d47944a37b07acbe48fdb74f734d@changeid Signed-off-by: Mark Brown --- include/linux/platform_data/cros_ec_commands.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index 98415686cbfa..43b8f7dae4cc 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -1277,8 +1277,6 @@ enum ec_feature_code { * MOTIONSENSE_CMD_TABLET_MODE_LID_ANGLE. */ EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS = 37, - /* EC supports audio codec. */ - EC_FEATURE_AUDIO_CODEC = 38, /* The MCU is a System Companion Processor (SCP). */ EC_FEATURE_SCP = 39, /* The MCU is an Integrated Sensor Hub */ -- cgit v1.2.3 From 727f1c71c780789aeb8f3da2596c65ae008d5d6c Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 14 Oct 2019 18:20:14 +0800 Subject: ASoC: cros_ec_codec: refactor I2S RX Refactor by the following items: - reformat copyright declaration - use more specific name "i2s rx" - use verbose symbol names to separate namespaces - make some short functions inline - remove unused TDM-related code Signed-off-by: Tzung-Bi Shih Acked-By: Benson Leung Link: https://lore.kernel.org/r/20191014180059.02.I43373b9a66dbb70196b3f216b3aa86111c410836@changeid Signed-off-by: Mark Brown --- drivers/platform/chrome/cros_ec_trace.c | 2 +- include/linux/platform_data/cros_ec_commands.h | 120 +++--- sound/soc/codecs/cros_ec_codec.c | 502 ++++++++++--------------- 3 files changed, 251 insertions(+), 373 deletions(-) (limited to 'include') diff --git a/drivers/platform/chrome/cros_ec_trace.c b/drivers/platform/chrome/cros_ec_trace.c index 6f80ff4532ae..901850004b2b 100644 --- a/drivers/platform/chrome/cros_ec_trace.c +++ b/drivers/platform/chrome/cros_ec_trace.c @@ -98,7 +98,7 @@ TRACE_SYMBOL(EC_CMD_SB_READ_BLOCK), \ TRACE_SYMBOL(EC_CMD_SB_WRITE_BLOCK), \ TRACE_SYMBOL(EC_CMD_BATTERY_VENDOR_PARAM), \ - TRACE_SYMBOL(EC_CMD_CODEC_I2S), \ + TRACE_SYMBOL(EC_CMD_EC_CODEC_I2S_RX), \ TRACE_SYMBOL(EC_CMD_REBOOT_EC), \ TRACE_SYMBOL(EC_CMD_GET_PANIC_INFO), \ TRACE_SYMBOL(EC_CMD_ACPI_READ), \ diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index 43b8f7dae4cc..261ac83bd007 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -4466,92 +4466,74 @@ enum mkbp_cec_event { /*****************************************************************************/ -/* Commands for I2S recording on audio codec. */ - -#define EC_CMD_CODEC_I2S 0x00BC -#define EC_WOV_I2S_SAMPLE_RATE 48000 - -enum ec_codec_i2s_subcmd { - EC_CODEC_SET_SAMPLE_DEPTH = 0x0, - EC_CODEC_SET_GAIN = 0x1, - EC_CODEC_GET_GAIN = 0x2, - EC_CODEC_I2S_ENABLE = 0x3, - EC_CODEC_I2S_SET_CONFIG = 0x4, - EC_CODEC_I2S_SET_TDM_CONFIG = 0x5, - EC_CODEC_I2S_SET_BCLK = 0x6, - EC_CODEC_I2S_SUBCMD_COUNT = 0x7, +/* Commands for I2S RX on audio codec. */ + +#define EC_CMD_EC_CODEC_I2S_RX 0x00BC + +enum ec_codec_i2s_rx_subcmd { + EC_CODEC_I2S_RX_ENABLE = 0x0, + EC_CODEC_I2S_RX_DISABLE = 0x1, + EC_CODEC_I2S_RX_SET_GAIN = 0x2, + EC_CODEC_I2S_RX_GET_GAIN = 0x3, + EC_CODEC_I2S_RX_SET_SAMPLE_DEPTH = 0x4, + EC_CODEC_I2S_RX_SET_DAIFMT = 0x5, + EC_CODEC_I2S_RX_SET_BCLK = 0x6, + EC_CODEC_I2S_RX_SUBCMD_COUNT, }; -enum ec_sample_depth_value { - EC_CODEC_SAMPLE_DEPTH_16 = 0, - EC_CODEC_SAMPLE_DEPTH_24 = 1, +enum ec_codec_i2s_rx_sample_depth { + EC_CODEC_I2S_RX_SAMPLE_DEPTH_16 = 0x0, + EC_CODEC_I2S_RX_SAMPLE_DEPTH_24 = 0x1, + EC_CODEC_I2S_RX_SAMPLE_DEPTH_COUNT, }; -enum ec_i2s_config { - EC_DAI_FMT_I2S = 0, - EC_DAI_FMT_RIGHT_J = 1, - EC_DAI_FMT_LEFT_J = 2, - EC_DAI_FMT_PCM_A = 3, - EC_DAI_FMT_PCM_B = 4, - EC_DAI_FMT_PCM_TDM = 5, +enum ec_codec_i2s_rx_daifmt { + EC_CODEC_I2S_RX_DAIFMT_I2S = 0x0, + EC_CODEC_I2S_RX_DAIFMT_RIGHT_J = 0x1, + EC_CODEC_I2S_RX_DAIFMT_LEFT_J = 0x2, + EC_CODEC_I2S_RX_DAIFMT_COUNT, }; -/* - * For subcommand EC_CODEC_GET_GAIN. - */ -struct __ec_align1 ec_codec_i2s_gain { +struct __ec_align1 ec_param_ec_codec_i2s_rx_set_sample_depth { + uint8_t depth; + uint8_t reserved[3]; +}; + +struct __ec_align1 ec_param_ec_codec_i2s_rx_set_gain { uint8_t left; uint8_t right; + uint8_t reserved[2]; }; -struct __ec_todo_unpacked ec_param_codec_i2s_tdm { - int16_t ch0_delay; /* 0 to 496 */ - int16_t ch1_delay; /* -1 to 496 */ - uint8_t adjacent_to_ch0; - uint8_t adjacent_to_ch1; +struct __ec_align1 ec_param_ec_codec_i2s_rx_set_daifmt { + uint8_t daifmt; + uint8_t reserved[3]; }; -struct __ec_todo_packed ec_param_codec_i2s { - /* enum ec_codec_i2s_subcmd */ - uint8_t cmd; - union { - /* - * EC_CODEC_SET_SAMPLE_DEPTH - * Value should be one of ec_sample_depth_value. - */ - uint8_t depth; - - /* - * EC_CODEC_SET_GAIN - * Value should be 0~43 for both channels. - */ - struct ec_codec_i2s_gain gain; - - /* - * EC_CODEC_I2S_ENABLE - * 1 to enable, 0 to disable. - */ - uint8_t i2s_enable; - - /* - * EC_CODEC_I2S_SET_CONFIG - * Value should be one of ec_i2s_config. - */ - uint8_t i2s_config; +struct __ec_align4 ec_param_ec_codec_i2s_rx_set_bclk { + uint32_t bclk; +}; - /* - * EC_CODEC_I2S_SET_TDM_CONFIG - * Value should be one of ec_i2s_config. - */ - struct ec_param_codec_i2s_tdm tdm_param; +struct __ec_align4 ec_param_ec_codec_i2s_rx { + uint8_t cmd; /* enum ec_codec_i2s_rx_subcmd */ + uint8_t reserved[3]; - /* - * EC_CODEC_I2S_SET_BCLK - */ - uint32_t bclk; + union { + struct ec_param_ec_codec_i2s_rx_set_sample_depth + set_sample_depth_param; + struct ec_param_ec_codec_i2s_rx_set_gain + set_gain_param; + struct ec_param_ec_codec_i2s_rx_set_daifmt + set_daifmt_param; + struct ec_param_ec_codec_i2s_rx_set_bclk + set_bclk_param; }; }; +struct __ec_align1 ec_response_ec_codec_i2s_rx_get_gain { + uint8_t left; + uint8_t right; +}; /*****************************************************************************/ /* System commands */ diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c index 3c1bd24a1057..179fa77291cd 100644 --- a/sound/soc/codecs/cros_ec_codec.c +++ b/sound/soc/codecs/cros_ec_codec.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Driver for ChromeOS Embedded Controller codec. + * Copyright 2019 Google, Inc. + * + * ChromeOS Embedded Controller codec driver. * * This driver uses the cros-ec interface to communicate with the ChromeOS * EC for audio function. @@ -18,403 +20,297 @@ #include #include -#define DRV_NAME "cros-ec-codec" - -/** - * struct cros_ec_codec_data - ChromeOS EC codec driver data. - * @dev: Device structure used in sysfs. - * @ec_device: cros_ec_device structure to talk to the physical device. - * @component: Pointer to the component. - * @max_dmic_gain: Maximum gain in dB supported by EC codec. - */ -struct cros_ec_codec_data { +struct cros_ec_codec_priv { struct device *dev; struct cros_ec_device *ec_device; - struct snd_soc_component *component; - unsigned int max_dmic_gain; }; -static const DECLARE_TLV_DB_SCALE(ec_mic_gain_tlv, 0, 100, 0); - -static int ec_command_get_gain(struct snd_soc_component *component, - struct ec_param_codec_i2s *param, - struct ec_codec_i2s_gain *resp) +static int send_ec_host_command(struct cros_ec_device *ec_dev, uint32_t cmd, + uint8_t *out, size_t outsize, + uint8_t *in, size_t insize) { - struct cros_ec_codec_data *codec_data = - snd_soc_component_get_drvdata(component); - struct cros_ec_device *ec_device = codec_data->ec_device; - u8 buffer[sizeof(struct cros_ec_command) + - max(sizeof(struct ec_param_codec_i2s), - sizeof(struct ec_codec_i2s_gain))]; - struct cros_ec_command *msg = (struct cros_ec_command *)&buffer; int ret; + struct cros_ec_command *msg; + + msg = kmalloc(sizeof(*msg) + max(outsize, insize), GFP_KERNEL); + if (!msg) + return -ENOMEM; msg->version = 0; - msg->command = EC_CMD_CODEC_I2S; - msg->outsize = sizeof(struct ec_param_codec_i2s); - msg->insize = sizeof(struct ec_codec_i2s_gain); + msg->command = cmd; + msg->outsize = outsize; + msg->insize = insize; + + if (outsize) + memcpy(msg->data, out, outsize); - memcpy(msg->data, param, msg->outsize); + ret = cros_ec_cmd_xfer_status(ec_dev, msg); + if (ret < 0) + goto error; - ret = cros_ec_cmd_xfer_status(ec_device, msg); - if (ret > 0) - memcpy(resp, msg->data, msg->insize); + if (insize) + memcpy(in, msg->data, insize); + ret = 0; +error: + kfree(msg); return ret; } -/* - * Wrapper for EC command without response. - */ -static int ec_command_no_resp(struct snd_soc_component *component, - struct ec_param_codec_i2s *param) +static int dmic_get_gain(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct cros_ec_codec_data *codec_data = + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(component); - struct cros_ec_device *ec_device = codec_data->ec_device; - u8 buffer[sizeof(struct cros_ec_command) + - sizeof(struct ec_param_codec_i2s)]; - struct cros_ec_command *msg = (struct cros_ec_command *)&buffer; - - msg->version = 0; - msg->command = EC_CMD_CODEC_I2S; - msg->outsize = sizeof(struct ec_param_codec_i2s); - msg->insize = 0; - - memcpy(msg->data, param, msg->outsize); - - return cros_ec_cmd_xfer_status(ec_device, msg); -} - -static int set_i2s_config(struct snd_soc_component *component, - enum ec_i2s_config i2s_config) -{ - struct ec_param_codec_i2s param; + struct ec_param_ec_codec_i2s_rx p; + struct ec_response_ec_codec_i2s_rx_get_gain r; + int ret; - dev_dbg(component->dev, "%s set I2S format to %u\n", __func__, - i2s_config); + p.cmd = EC_CODEC_I2S_RX_GET_GAIN; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, + (uint8_t *)&p, sizeof(p), + (uint8_t *)&r, sizeof(r)); + if (ret < 0) + return ret; - param.cmd = EC_CODEC_I2S_SET_CONFIG; - param.i2s_config = i2s_config; + ucontrol->value.integer.value[0] = r.left; + ucontrol->value.integer.value[1] = r.right; - return ec_command_no_resp(component, ¶m); + return 0; } -static int cros_ec_i2s_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +static int dmic_put_gain(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component = dai->component; - enum ec_i2s_config i2s_config; - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - i2s_config = EC_DAI_FMT_I2S; - break; - - case SND_SOC_DAIFMT_RIGHT_J: - i2s_config = EC_DAI_FMT_RIGHT_J; - break; - - case SND_SOC_DAIFMT_LEFT_J: - i2s_config = EC_DAI_FMT_LEFT_J; - break; - - case SND_SOC_DAIFMT_DSP_A: - i2s_config = EC_DAI_FMT_PCM_A; - break; - - case SND_SOC_DAIFMT_DSP_B: - i2s_config = EC_DAI_FMT_PCM_B; - break; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + struct soc_mixer_control *control = + (struct soc_mixer_control *)kcontrol->private_value; + int max_dmic_gain = control->max; + int left = ucontrol->value.integer.value[0]; + int right = ucontrol->value.integer.value[1]; + struct ec_param_ec_codec_i2s_rx p; - default: + if (left > max_dmic_gain || right > max_dmic_gain) return -EINVAL; - } - return set_i2s_config(component, i2s_config); -} - -static int set_i2s_sample_depth(struct snd_soc_component *component, - enum ec_sample_depth_value depth) -{ - struct ec_param_codec_i2s param; - - dev_dbg(component->dev, "%s set depth to %u\n", __func__, depth); - - param.cmd = EC_CODEC_SET_SAMPLE_DEPTH; - param.depth = depth; + dev_dbg(component->dev, "set mic gain to %u, %u\n", left, right); - return ec_command_no_resp(component, ¶m); + p.cmd = EC_CODEC_I2S_RX_SET_GAIN; + p.set_gain_param.left = left; + p.set_gain_param.right = right; + return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, + (uint8_t *)&p, sizeof(p), NULL, 0); } -static int set_i2s_bclk(struct snd_soc_component *component, uint32_t bclk) -{ - struct ec_param_codec_i2s param; - - dev_dbg(component->dev, "%s set i2s bclk to %u\n", __func__, bclk); +static const DECLARE_TLV_DB_SCALE(dmic_gain_tlv, 0, 100, 0); - param.cmd = EC_CODEC_I2S_SET_BCLK; - param.bclk = bclk; +enum { + DMIC_CTL_GAIN = 0, +}; - return ec_command_no_resp(component, ¶m); -} +static struct snd_kcontrol_new dmic_controls[] = { + [DMIC_CTL_GAIN] = + SOC_DOUBLE_EXT_TLV("EC Mic Gain", SND_SOC_NOPM, SND_SOC_NOPM, + 0, 0, 0, dmic_get_gain, dmic_put_gain, + dmic_gain_tlv), +}; -static int cros_ec_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) +static int i2s_rx_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; - unsigned int rate, bclk; + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + struct ec_param_ec_codec_i2s_rx p; + enum ec_codec_i2s_rx_sample_depth depth; int ret; - rate = params_rate(params); - if (rate != 48000) + if (params_rate(params) != 48000) return -EINVAL; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: - ret = set_i2s_sample_depth(component, EC_CODEC_SAMPLE_DEPTH_16); + depth = EC_CODEC_I2S_RX_SAMPLE_DEPTH_16; break; case SNDRV_PCM_FORMAT_S24_LE: - ret = set_i2s_sample_depth(component, EC_CODEC_SAMPLE_DEPTH_24); + depth = EC_CODEC_I2S_RX_SAMPLE_DEPTH_24; break; default: return -EINVAL; } - if (ret < 0) - return ret; - - bclk = snd_soc_params_to_bclk(params); - return set_i2s_bclk(component, bclk); -} -static const struct snd_soc_dai_ops cros_ec_i2s_dai_ops = { - .hw_params = cros_ec_i2s_hw_params, - .set_fmt = cros_ec_i2s_set_dai_fmt, -}; + dev_dbg(component->dev, "set depth to %u\n", depth); -static struct snd_soc_dai_driver cros_ec_dai[] = { - { - .name = "cros_ec_codec I2S", - .id = 0, - .capture = { - .stream_name = "I2S Capture", - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE, - }, - .ops = &cros_ec_i2s_dai_ops, - } -}; - -static int get_ec_mic_gain(struct snd_soc_component *component, - u8 *left, u8 *right) -{ - struct ec_param_codec_i2s param; - struct ec_codec_i2s_gain resp; - int ret; - - param.cmd = EC_CODEC_GET_GAIN; - - ret = ec_command_get_gain(component, ¶m, &resp); + p.cmd = EC_CODEC_I2S_RX_SET_SAMPLE_DEPTH; + p.set_sample_depth_param.depth = depth; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, + (uint8_t *)&p, sizeof(p), NULL, 0); if (ret < 0) return ret; - *left = resp.left; - *right = resp.right; - - return 0; -} - -static int mic_gain_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = - snd_soc_kcontrol_component(kcontrol); - u8 left, right; - int ret; - - ret = get_ec_mic_gain(component, &left, &right); - if (ret) - return ret; - - ucontrol->value.integer.value[0] = left; - ucontrol->value.integer.value[1] = right; - - return 0; -} - -static int set_ec_mic_gain(struct snd_soc_component *component, - u8 left, u8 right) -{ - struct ec_param_codec_i2s param; - - dev_dbg(component->dev, "%s set mic gain to %u, %u\n", - __func__, left, right); + dev_dbg(component->dev, "set bclk to %u\n", + snd_soc_params_to_bclk(params)); - param.cmd = EC_CODEC_SET_GAIN; - param.gain.left = left; - param.gain.right = right; - - return ec_command_no_resp(component, ¶m); + p.cmd = EC_CODEC_I2S_RX_SET_BCLK; + p.set_bclk_param.bclk = snd_soc_params_to_bclk(params); + return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, + (uint8_t *)&p, sizeof(p), NULL, 0); } -static int mic_gain_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int i2s_rx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - struct snd_soc_component *component = - snd_soc_kcontrol_component(kcontrol); - struct cros_ec_codec_data *codec_data = + struct snd_soc_component *component = dai->component; + struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(component); - int left = ucontrol->value.integer.value[0]; - int right = ucontrol->value.integer.value[1]; - unsigned int max_dmic_gain = codec_data->max_dmic_gain; + struct ec_param_ec_codec_i2s_rx p; + enum ec_codec_i2s_rx_daifmt daifmt; - if (left > max_dmic_gain || right > max_dmic_gain) + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: return -EINVAL; + } - return set_ec_mic_gain(component, (u8)left, (u8)right); -} - -static struct snd_kcontrol_new mic_gain_control = - SOC_DOUBLE_EXT_TLV("EC Mic Gain", SND_SOC_NOPM, SND_SOC_NOPM, 0, 0, 0, - mic_gain_get, mic_gain_put, ec_mic_gain_tlv); - -static int enable_i2s(struct snd_soc_component *component, int enable) -{ - struct ec_param_codec_i2s param; + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + default: + return -EINVAL; + } - dev_dbg(component->dev, "%s set i2s to %u\n", __func__, enable); + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + daifmt = EC_CODEC_I2S_RX_DAIFMT_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + daifmt = EC_CODEC_I2S_RX_DAIFMT_RIGHT_J; + break; + case SND_SOC_DAIFMT_LEFT_J: + daifmt = EC_CODEC_I2S_RX_DAIFMT_LEFT_J; + break; + default: + return -EINVAL; + } - param.cmd = EC_CODEC_I2S_ENABLE; - param.i2s_enable = enable; + dev_dbg(component->dev, "set format to %u\n", daifmt); - return ec_command_no_resp(component, ¶m); + p.cmd = EC_CODEC_I2S_RX_SET_DAIFMT; + p.set_daifmt_param.daifmt = daifmt; + return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, + (uint8_t *)&p, sizeof(p), NULL, 0); } -static int cros_ec_i2s_enable_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +static const struct snd_soc_dai_ops i2s_rx_dai_ops = { + .hw_params = i2s_rx_hw_params, + .set_fmt = i2s_rx_set_fmt, +}; + +static int i2s_rx_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + struct ec_param_ec_codec_i2s_rx p; switch (event) { case SND_SOC_DAPM_PRE_PMU: - dev_dbg(component->dev, - "%s got SND_SOC_DAPM_PRE_PMU event\n", __func__); - return enable_i2s(component, 1); - + dev_dbg(component->dev, "enable I2S RX\n"); + p.cmd = EC_CODEC_I2S_RX_ENABLE; + break; case SND_SOC_DAPM_PRE_PMD: - dev_dbg(component->dev, - "%s got SND_SOC_DAPM_PRE_PMD event\n", __func__); - return enable_i2s(component, 0); + dev_dbg(component->dev, "disable I2S RX\n"); + p.cmd = EC_CODEC_I2S_RX_DISABLE; + break; + default: + return 0; } - return 0; + return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, + (uint8_t *)&p, sizeof(p), NULL, 0); } -/* - * The goal of this DAPM route is to turn on/off I2S using EC - * host command when capture stream is started/stopped. - */ -static const struct snd_soc_dapm_widget cros_ec_codec_dapm_widgets[] = { +static struct snd_soc_dapm_widget i2s_rx_dapm_widgets[] = { SND_SOC_DAPM_INPUT("DMIC"), - - /* - * Control EC to enable/disable I2S. - */ - SND_SOC_DAPM_SUPPLY("I2S Enable", SND_SOC_NOPM, - 0, 0, cros_ec_i2s_enable_event, + SND_SOC_DAPM_SUPPLY("I2S RX Enable", SND_SOC_NOPM, 0, 0, i2s_rx_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_AIF_OUT("I2S RX", "I2S Capture", 0, SND_SOC_NOPM, 0, 0), +}; - SND_SOC_DAPM_AIF_OUT("I2STX", "I2S Capture", 0, SND_SOC_NOPM, 0, 0), +static struct snd_soc_dapm_route i2s_rx_dapm_routes[] = { + {"I2S RX", NULL, "DMIC"}, + {"I2S RX", NULL, "I2S RX Enable"}, }; -static const struct snd_soc_dapm_route cros_ec_codec_dapm_routes[] = { - { "I2STX", NULL, "DMIC" }, - { "I2STX", NULL, "I2S Enable" }, +static struct snd_soc_dai_driver i2s_rx_dai_driver = { + .name = "EC Codec I2S RX", + .capture = { + .stream_name = "I2S Capture", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &i2s_rx_dai_ops, }; -/* - * Read maximum gain from device property and set it to mixer control. - */ -static int cros_ec_set_gain_range(struct device *dev) +static int i2s_rx_probe(struct snd_soc_component *component) { + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + struct device *dev = priv->dev; + int ret, val; struct soc_mixer_control *control; - struct cros_ec_codec_data *codec_data = dev_get_drvdata(dev); - int rc; - rc = device_property_read_u32(dev, "max-dmic-gain", - &codec_data->max_dmic_gain); - if (rc) - return rc; + ret = device_property_read_u32(dev, "max-dmic-gain", &val); + if (ret) { + dev_err(dev, "Failed to read 'max-dmic-gain'\n"); + return ret; + } control = (struct soc_mixer_control *) - mic_gain_control.private_value; - control->max = codec_data->max_dmic_gain; - control->platform_max = codec_data->max_dmic_gain; + dmic_controls[DMIC_CTL_GAIN].private_value; + control->max = val; + control->platform_max = val; - return 0; -} - -static int cros_ec_codec_probe(struct snd_soc_component *component) -{ - int rc; - - struct cros_ec_codec_data *codec_data = - snd_soc_component_get_drvdata(component); - - rc = cros_ec_set_gain_range(codec_data->dev); - if (rc) - return rc; - - return snd_soc_add_component_controls(component, &mic_gain_control, 1); + return snd_soc_add_component_controls(component, + &dmic_controls[DMIC_CTL_GAIN], 1); } -static const struct snd_soc_component_driver cros_ec_component_driver = { - .probe = cros_ec_codec_probe, - .dapm_widgets = cros_ec_codec_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(cros_ec_codec_dapm_widgets), - .dapm_routes = cros_ec_codec_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(cros_ec_codec_dapm_routes), +static const struct snd_soc_component_driver i2s_rx_component_driver = { + .probe = i2s_rx_probe, + .dapm_widgets = i2s_rx_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(i2s_rx_dapm_widgets), + .dapm_routes = i2s_rx_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(i2s_rx_dapm_routes), }; -/* - * Platform device and platform driver fro cros-ec-codec. - */ -static int cros_ec_codec_platform_probe(struct platform_device *pd) +static int cros_ec_codec_platform_probe(struct platform_device *pdev) { - struct device *dev = &pd->dev; - struct cros_ec_device *ec_device = dev_get_drvdata(pd->dev.parent); - struct cros_ec_codec_data *codec_data; + struct device *dev = &pdev->dev; + struct cros_ec_device *ec_device = dev_get_drvdata(pdev->dev.parent); + struct cros_ec_codec_priv *priv; - codec_data = devm_kzalloc(dev, sizeof(struct cros_ec_codec_data), - GFP_KERNEL); - if (!codec_data) + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) return -ENOMEM; - codec_data->dev = dev; - codec_data->ec_device = ec_device; + priv->dev = dev; + priv->ec_device = ec_device; - platform_set_drvdata(pd, codec_data); + platform_set_drvdata(pdev, priv); - return devm_snd_soc_register_component(dev, &cros_ec_component_driver, - cros_ec_dai, ARRAY_SIZE(cros_ec_dai)); + return devm_snd_soc_register_component(dev, &i2s_rx_component_driver, + &i2s_rx_dai_driver, 1); } #ifdef CONFIG_OF @@ -427,7 +323,7 @@ MODULE_DEVICE_TABLE(of, cros_ec_codec_of_match); static struct platform_driver cros_ec_codec_platform_driver = { .driver = { - .name = DRV_NAME, + .name = "cros-ec-codec", .of_match_table = of_match_ptr(cros_ec_codec_of_match), }, .probe = cros_ec_codec_platform_probe, @@ -438,4 +334,4 @@ module_platform_driver(cros_ec_codec_platform_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("ChromeOS EC codec driver"); MODULE_AUTHOR("Cheng-Yi Chiang "); -MODULE_ALIAS("platform:" DRV_NAME); +MODULE_ALIAS("platform:cros-ec-codec"); -- cgit v1.2.3 From 8f731d4c92c2ef9434d4d7f84882c6429754164b Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 14 Oct 2019 18:20:15 +0800 Subject: ASoC: cros_ec_codec: extract DMIC EC command from I2S RX Extract DMIC EC command from I2S RX. Setting and getting microphone gains is common features. Signed-off-by: Tzung-Bi Shih Acked-By: Benson Leung Link: https://lore.kernel.org/r/20191014180059.03.I93d9c65964f3c30f85a36d228e31150ff1917706@changeid Signed-off-by: Mark Brown --- drivers/platform/chrome/cros_ec_trace.c | 1 + include/linux/platform_data/cros_ec_commands.h | 49 ++++++++++++++++------ sound/soc/codecs/cros_ec_codec.c | 57 ++++++++++++++------------ 3 files changed, 68 insertions(+), 39 deletions(-) (limited to 'include') diff --git a/drivers/platform/chrome/cros_ec_trace.c b/drivers/platform/chrome/cros_ec_trace.c index 901850004b2b..e73bb6a8b00e 100644 --- a/drivers/platform/chrome/cros_ec_trace.c +++ b/drivers/platform/chrome/cros_ec_trace.c @@ -98,6 +98,7 @@ TRACE_SYMBOL(EC_CMD_SB_READ_BLOCK), \ TRACE_SYMBOL(EC_CMD_SB_WRITE_BLOCK), \ TRACE_SYMBOL(EC_CMD_BATTERY_VENDOR_PARAM), \ + TRACE_SYMBOL(EC_CMD_EC_CODEC_DMIC), \ TRACE_SYMBOL(EC_CMD_EC_CODEC_I2S_RX), \ TRACE_SYMBOL(EC_CMD_REBOOT_EC), \ TRACE_SYMBOL(EC_CMD_GET_PANIC_INFO), \ diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index 261ac83bd007..58e460c015ef 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -4466,18 +4466,48 @@ enum mkbp_cec_event { /*****************************************************************************/ +/* Commands for DMIC on audio codec. */ +#define EC_CMD_EC_CODEC_DMIC 0x00BC + +enum ec_codec_dmic_subcmd { + EC_CODEC_DMIC_SET_GAIN = 0x0, + EC_CODEC_DMIC_GET_GAIN = 0x1, + EC_CODEC_DMIC_SUBCMD_COUNT, +}; + +struct __ec_align1 ec_param_ec_codec_dmic_set_gain { + uint8_t left; + uint8_t right; + uint8_t reserved[2]; +}; + +struct __ec_align4 ec_param_ec_codec_dmic { + uint8_t cmd; /* enum ec_codec_dmic_subcmd */ + uint8_t reserved[3]; + + union { + struct ec_param_ec_codec_dmic_set_gain + set_gain_param; + }; +}; + +struct __ec_align1 ec_response_ec_codec_dmic_get_gain { + uint8_t left; + uint8_t right; +}; + +/*****************************************************************************/ + /* Commands for I2S RX on audio codec. */ -#define EC_CMD_EC_CODEC_I2S_RX 0x00BC +#define EC_CMD_EC_CODEC_I2S_RX 0x00BD enum ec_codec_i2s_rx_subcmd { EC_CODEC_I2S_RX_ENABLE = 0x0, EC_CODEC_I2S_RX_DISABLE = 0x1, - EC_CODEC_I2S_RX_SET_GAIN = 0x2, - EC_CODEC_I2S_RX_GET_GAIN = 0x3, - EC_CODEC_I2S_RX_SET_SAMPLE_DEPTH = 0x4, - EC_CODEC_I2S_RX_SET_DAIFMT = 0x5, - EC_CODEC_I2S_RX_SET_BCLK = 0x6, + EC_CODEC_I2S_RX_SET_SAMPLE_DEPTH = 0x2, + EC_CODEC_I2S_RX_SET_DAIFMT = 0x3, + EC_CODEC_I2S_RX_SET_BCLK = 0x4, EC_CODEC_I2S_RX_SUBCMD_COUNT, }; @@ -4521,8 +4551,6 @@ struct __ec_align4 ec_param_ec_codec_i2s_rx { union { struct ec_param_ec_codec_i2s_rx_set_sample_depth set_sample_depth_param; - struct ec_param_ec_codec_i2s_rx_set_gain - set_gain_param; struct ec_param_ec_codec_i2s_rx_set_daifmt set_daifmt_param; struct ec_param_ec_codec_i2s_rx_set_bclk @@ -4530,11 +4558,6 @@ struct __ec_align4 ec_param_ec_codec_i2s_rx { }; }; -struct __ec_align1 ec_response_ec_codec_i2s_rx_get_gain { - uint8_t left; - uint8_t right; -}; - /*****************************************************************************/ /* System commands */ diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c index 179fa77291cd..c19c7fe42e2e 100644 --- a/sound/soc/codecs/cros_ec_codec.c +++ b/sound/soc/codecs/cros_ec_codec.c @@ -64,12 +64,12 @@ static int dmic_get_gain(struct snd_kcontrol *kcontrol, snd_soc_kcontrol_component(kcontrol); struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(component); - struct ec_param_ec_codec_i2s_rx p; - struct ec_response_ec_codec_i2s_rx_get_gain r; + struct ec_param_ec_codec_dmic p; + struct ec_response_ec_codec_dmic_get_gain r; int ret; - p.cmd = EC_CODEC_I2S_RX_GET_GAIN; - ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, + p.cmd = EC_CODEC_DMIC_GET_GAIN; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, (uint8_t *)&p, sizeof(p), (uint8_t *)&r, sizeof(r)); if (ret < 0) @@ -93,17 +93,17 @@ static int dmic_put_gain(struct snd_kcontrol *kcontrol, int max_dmic_gain = control->max; int left = ucontrol->value.integer.value[0]; int right = ucontrol->value.integer.value[1]; - struct ec_param_ec_codec_i2s_rx p; + struct ec_param_ec_codec_dmic p; if (left > max_dmic_gain || right > max_dmic_gain) return -EINVAL; dev_dbg(component->dev, "set mic gain to %u, %u\n", left, right); - p.cmd = EC_CODEC_I2S_RX_SET_GAIN; + p.cmd = EC_CODEC_DMIC_SET_GAIN; p.set_gain_param.left = left; p.set_gain_param.right = right; - return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_I2S_RX, + return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, (uint8_t *)&p, sizeof(p), NULL, 0); } @@ -120,6 +120,29 @@ static struct snd_kcontrol_new dmic_controls[] = { dmic_gain_tlv), }; +static int dmic_probe(struct snd_soc_component *component) +{ + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + struct device *dev = priv->dev; + int ret, val; + struct soc_mixer_control *control; + + ret = device_property_read_u32(dev, "max-dmic-gain", &val); + if (ret) { + dev_err(dev, "Failed to read 'max-dmic-gain'\n"); + return ret; + } + + control = (struct soc_mixer_control *) + dmic_controls[DMIC_CTL_GAIN].private_value; + control->max = val; + control->platform_max = val; + + return snd_soc_add_component_controls(component, + &dmic_controls[DMIC_CTL_GAIN], 1); +} + static int i2s_rx_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -265,25 +288,7 @@ static struct snd_soc_dai_driver i2s_rx_dai_driver = { static int i2s_rx_probe(struct snd_soc_component *component) { - struct cros_ec_codec_priv *priv = - snd_soc_component_get_drvdata(component); - struct device *dev = priv->dev; - int ret, val; - struct soc_mixer_control *control; - - ret = device_property_read_u32(dev, "max-dmic-gain", &val); - if (ret) { - dev_err(dev, "Failed to read 'max-dmic-gain'\n"); - return ret; - } - - control = (struct soc_mixer_control *) - dmic_controls[DMIC_CTL_GAIN].private_value; - control->max = val; - control->platform_max = val; - - return snd_soc_add_component_controls(component, - &dmic_controls[DMIC_CTL_GAIN], 1); + return dmic_probe(component); } static const struct snd_soc_component_driver i2s_rx_component_driver = { -- cgit v1.2.3 From 104c6f8f7ff859ddd53b69c4af11e83f2971f0c4 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 17 Oct 2019 22:00:09 +0800 Subject: platform/chrome: cros_ec: add common commands for EC codec Add the following common commands: - GET_CAPABILITIES - GET_SHM_ADDR - SET_SHM_ADDR Acked-by: Benson Leung Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20191017213539.04.Idc3c6e1cd94b70bf010249928d4a93c6c90495b7@changeid Signed-off-by: Mark Brown --- drivers/platform/chrome/cros_ec_trace.c | 1 + include/linux/platform_data/cros_ec_commands.h | 64 +++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/platform/chrome/cros_ec_trace.c b/drivers/platform/chrome/cros_ec_trace.c index e73bb6a8b00e..2ea0d4e0d54d 100644 --- a/drivers/platform/chrome/cros_ec_trace.c +++ b/drivers/platform/chrome/cros_ec_trace.c @@ -98,6 +98,7 @@ TRACE_SYMBOL(EC_CMD_SB_READ_BLOCK), \ TRACE_SYMBOL(EC_CMD_SB_WRITE_BLOCK), \ TRACE_SYMBOL(EC_CMD_BATTERY_VENDOR_PARAM), \ + TRACE_SYMBOL(EC_CMD_EC_CODEC), \ TRACE_SYMBOL(EC_CMD_EC_CODEC_DMIC), \ TRACE_SYMBOL(EC_CMD_EC_CODEC_I2S_RX), \ TRACE_SYMBOL(EC_CMD_REBOOT_EC), \ diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index 58e460c015ef..3ca0fa9e92a7 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -4466,8 +4466,68 @@ enum mkbp_cec_event { /*****************************************************************************/ +/* Commands for audio codec. */ +#define EC_CMD_EC_CODEC 0x00BC + +enum ec_codec_subcmd { + EC_CODEC_GET_CAPABILITIES = 0x0, + EC_CODEC_GET_SHM_ADDR = 0x1, + EC_CODEC_SET_SHM_ADDR = 0x2, + EC_CODEC_SUBCMD_COUNT, +}; + +enum ec_codec_cap { + EC_CODEC_CAP_LAST = 32, +}; + +enum ec_codec_shm_id { + EC_CODEC_SHM_ID_LAST, +}; + +enum ec_codec_shm_type { + EC_CODEC_SHM_TYPE_EC_RAM = 0x0, + EC_CODEC_SHM_TYPE_SYSTEM_RAM = 0x1, +}; + +struct __ec_align1 ec_param_ec_codec_get_shm_addr { + uint8_t shm_id; + uint8_t reserved[3]; +}; + +struct __ec_align4 ec_param_ec_codec_set_shm_addr { + uint64_t phys_addr; + uint32_t len; + uint8_t shm_id; + uint8_t reserved[3]; +}; + +struct __ec_align4 ec_param_ec_codec { + uint8_t cmd; /* enum ec_codec_subcmd */ + uint8_t reserved[3]; + + union { + struct ec_param_ec_codec_get_shm_addr + get_shm_addr_param; + struct ec_param_ec_codec_set_shm_addr + set_shm_addr_param; + }; +}; + +struct __ec_align4 ec_response_ec_codec_get_capabilities { + uint32_t capabilities; +}; + +struct __ec_align4 ec_response_ec_codec_get_shm_addr { + uint64_t phys_addr; + uint32_t len; + uint8_t type; + uint8_t reserved[3]; +}; + +/*****************************************************************************/ + /* Commands for DMIC on audio codec. */ -#define EC_CMD_EC_CODEC_DMIC 0x00BC +#define EC_CMD_EC_CODEC_DMIC 0x00BD enum ec_codec_dmic_subcmd { EC_CODEC_DMIC_SET_GAIN = 0x0, @@ -4500,7 +4560,7 @@ struct __ec_align1 ec_response_ec_codec_dmic_get_gain { /* Commands for I2S RX on audio codec. */ -#define EC_CMD_EC_CODEC_I2S_RX 0x00BD +#define EC_CMD_EC_CODEC_I2S_RX 0x00BE enum ec_codec_i2s_rx_subcmd { EC_CODEC_I2S_RX_ENABLE = 0x0, -- cgit v1.2.3 From f3e82ad43ca538a7e0db0f310e26c5e75db6ba18 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 17 Oct 2019 22:00:10 +0800 Subject: ASoC: cros_ec_codec: read max DMIC gain from EC codec Read max DMIC gain from EC codec instead of DTS. Also removes the dt-binding of max-dmic-gain. Acked-by: Rob Herring Acked-by: Benson Leung Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20191017213539.05.Id4657c864d544634f2b5c1c9b34fa8232ecba44d@changeid Signed-off-by: Mark Brown --- .../bindings/sound/google,cros-ec-codec.txt | 4 +- include/linux/platform_data/cros_ec_commands.h | 43 ++++++++++++++---- sound/soc/codecs/cros_ec_codec.c | 53 ++++++++++++++++------ 3 files changed, 73 insertions(+), 27 deletions(-) (limited to 'include') diff --git a/Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt b/Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt index 1084f7f22eea..0ce9fafc78e2 100644 --- a/Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt +++ b/Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt @@ -1,4 +1,4 @@ -* Audio codec controlled by ChromeOS EC +Audio codec controlled by ChromeOS EC Google's ChromeOS EC codec is a digital mic codec provided by the Embedded Controller (EC) and is controlled via a host-command interface. @@ -9,7 +9,6 @@ Documentation/devicetree/bindings/mfd/cros-ec.txt). Required properties: - compatible: Must contain "google,cros-ec-codec" - #sound-dai-cells: Should be 1. The cell specifies number of DAIs. -- max-dmic-gain: A number for maximum gain in dB on digital microphone. Example: @@ -21,6 +20,5 @@ cros-ec@0 { cros_ec_codec: ec-codec { compatible = "google,cros-ec-codec"; #sound-dai-cells = <1>; - max-dmic-gain = <43>; }; }; diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index 3ca0fa9e92a7..21db0d4d4025 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -4530,30 +4530,53 @@ struct __ec_align4 ec_response_ec_codec_get_shm_addr { #define EC_CMD_EC_CODEC_DMIC 0x00BD enum ec_codec_dmic_subcmd { - EC_CODEC_DMIC_SET_GAIN = 0x0, - EC_CODEC_DMIC_GET_GAIN = 0x1, + EC_CODEC_DMIC_GET_MAX_GAIN = 0x0, + EC_CODEC_DMIC_SET_GAIN_IDX = 0x1, + EC_CODEC_DMIC_GET_GAIN_IDX = 0x2, EC_CODEC_DMIC_SUBCMD_COUNT, }; -struct __ec_align1 ec_param_ec_codec_dmic_set_gain { - uint8_t left; - uint8_t right; +enum ec_codec_dmic_channel { + EC_CODEC_DMIC_CHANNEL_0 = 0x0, + EC_CODEC_DMIC_CHANNEL_1 = 0x1, + EC_CODEC_DMIC_CHANNEL_2 = 0x2, + EC_CODEC_DMIC_CHANNEL_3 = 0x3, + EC_CODEC_DMIC_CHANNEL_4 = 0x4, + EC_CODEC_DMIC_CHANNEL_5 = 0x5, + EC_CODEC_DMIC_CHANNEL_6 = 0x6, + EC_CODEC_DMIC_CHANNEL_7 = 0x7, + EC_CODEC_DMIC_CHANNEL_COUNT, +}; + +struct __ec_align1 ec_param_ec_codec_dmic_set_gain_idx { + uint8_t channel; /* enum ec_codec_dmic_channel */ + uint8_t gain; uint8_t reserved[2]; }; +struct __ec_align1 ec_param_ec_codec_dmic_get_gain_idx { + uint8_t channel; /* enum ec_codec_dmic_channel */ + uint8_t reserved[3]; +}; + struct __ec_align4 ec_param_ec_codec_dmic { uint8_t cmd; /* enum ec_codec_dmic_subcmd */ uint8_t reserved[3]; union { - struct ec_param_ec_codec_dmic_set_gain - set_gain_param; + struct ec_param_ec_codec_dmic_set_gain_idx + set_gain_idx_param; + struct ec_param_ec_codec_dmic_get_gain_idx + get_gain_idx_param; }; }; -struct __ec_align1 ec_response_ec_codec_dmic_get_gain { - uint8_t left; - uint8_t right; +struct __ec_align1 ec_response_ec_codec_dmic_get_max_gain { + uint8_t max_gain; +}; + +struct __ec_align1 ec_response_ec_codec_dmic_get_gain_idx { + uint8_t gain; }; /*****************************************************************************/ diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c index c19c7fe42e2e..3d4f9e82d6e9 100644 --- a/sound/soc/codecs/cros_ec_codec.c +++ b/sound/soc/codecs/cros_ec_codec.c @@ -65,18 +65,26 @@ static int dmic_get_gain(struct snd_kcontrol *kcontrol, struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(component); struct ec_param_ec_codec_dmic p; - struct ec_response_ec_codec_dmic_get_gain r; + struct ec_response_ec_codec_dmic_get_gain_idx r; int ret; - p.cmd = EC_CODEC_DMIC_GET_GAIN; + p.cmd = EC_CODEC_DMIC_GET_GAIN_IDX; + p.get_gain_idx_param.channel = EC_CODEC_DMIC_CHANNEL_0; ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, (uint8_t *)&p, sizeof(p), (uint8_t *)&r, sizeof(r)); if (ret < 0) return ret; + ucontrol->value.integer.value[0] = r.gain; - ucontrol->value.integer.value[0] = r.left; - ucontrol->value.integer.value[1] = r.right; + p.cmd = EC_CODEC_DMIC_GET_GAIN_IDX; + p.get_gain_idx_param.channel = EC_CODEC_DMIC_CHANNEL_1; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, + (uint8_t *)&p, sizeof(p), + (uint8_t *)&r, sizeof(r)); + if (ret < 0) + return ret; + ucontrol->value.integer.value[1] = r.gain; return 0; } @@ -94,15 +102,24 @@ static int dmic_put_gain(struct snd_kcontrol *kcontrol, int left = ucontrol->value.integer.value[0]; int right = ucontrol->value.integer.value[1]; struct ec_param_ec_codec_dmic p; + int ret; if (left > max_dmic_gain || right > max_dmic_gain) return -EINVAL; dev_dbg(component->dev, "set mic gain to %u, %u\n", left, right); - p.cmd = EC_CODEC_DMIC_SET_GAIN; - p.set_gain_param.left = left; - p.set_gain_param.right = right; + p.cmd = EC_CODEC_DMIC_SET_GAIN_IDX; + p.set_gain_idx_param.channel = EC_CODEC_DMIC_CHANNEL_0; + p.set_gain_idx_param.gain = left; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, + (uint8_t *)&p, sizeof(p), NULL, 0); + if (ret < 0) + return ret; + + p.cmd = EC_CODEC_DMIC_SET_GAIN_IDX; + p.set_gain_idx_param.channel = EC_CODEC_DMIC_CHANNEL_1; + p.set_gain_idx_param.gain = right; return send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, (uint8_t *)&p, sizeof(p), NULL, 0); } @@ -125,19 +142,27 @@ static int dmic_probe(struct snd_soc_component *component) struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(component); struct device *dev = priv->dev; - int ret, val; struct soc_mixer_control *control; + struct ec_param_ec_codec_dmic p; + struct ec_response_ec_codec_dmic_get_max_gain r; + int ret; - ret = device_property_read_u32(dev, "max-dmic-gain", &val); - if (ret) { - dev_err(dev, "Failed to read 'max-dmic-gain'\n"); - return ret; + p.cmd = EC_CODEC_DMIC_GET_MAX_GAIN; + + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, + (uint8_t *)&p, sizeof(p), + (uint8_t *)&r, sizeof(r)); + if (ret < 0) { + dev_warn(dev, "get_max_gain() unsupported\n"); + return 0; } + dev_dbg(dev, "max gain = %d\n", r.max_gain); + control = (struct soc_mixer_control *) dmic_controls[DMIC_CTL_GAIN].private_value; - control->max = val; - control->platform_max = val; + control->max = r.max_gain; + control->platform_max = r.max_gain; return snd_soc_add_component_controls(component, &dmic_controls[DMIC_CTL_GAIN], 1); -- cgit v1.2.3 From 6cc23ed2ceab880e96ad287d9c85b53659050510 Mon Sep 17 00:00:00 2001 From: Maciej Falkowski Date: Thu, 26 Sep 2019 13:02:19 +0200 Subject: ASoC: samsung: i2s: Document clocks macros Document clocks macros with their description from 'Documentation/devicetree/bindings/sound/samsung-i2s.txt' Signed-off-by: Maciej Falkowski Signed-off-by: Marek Szyprowski Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20190926110219.6144-1-m.szyprowski@samsung.com Signed-off-by: Mark Brown --- include/dt-bindings/sound/samsung-i2s.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/dt-bindings/sound/samsung-i2s.h b/include/dt-bindings/sound/samsung-i2s.h index 77545f14c379..250de0d6c734 100644 --- a/include/dt-bindings/sound/samsung-i2s.h +++ b/include/dt-bindings/sound/samsung-i2s.h @@ -2,8 +2,14 @@ #ifndef _DT_BINDINGS_SAMSUNG_I2S_H #define _DT_BINDINGS_SAMSUNG_I2S_H -#define CLK_I2S_CDCLK 0 -#define CLK_I2S_RCLK_SRC 1 -#define CLK_I2S_RCLK_PSR 2 +#define CLK_I2S_CDCLK 0 /* the CDCLK (CODECLKO) gate clock */ + +#define CLK_I2S_RCLK_SRC 1 /* the RCLKSRC mux clock (corresponding to + * RCLKSRC bit in IISMOD register) + */ + +#define CLK_I2S_RCLK_PSR 2 /* the RCLK prescaler divider clock + * (corresponding to the IISPSR register) + */ #endif /* _DT_BINDINGS_SAMSUNG_I2S_H */ -- cgit v1.2.3 From b6bc07d4360dbf766e551f18e43c67fff6784955 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Sat, 19 Oct 2019 15:02:51 +0800 Subject: ASoC: cros_ec_codec: support WoV 1. Get EC codec's capabilities. 2. Get and set SHM address if any. 3. Transmit language model to EC codec if needed. 4. Start to read audio data from EC codec if receives host event. Signed-off-by: Tzung-Bi Shih Acked-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20191019143504.1.I5388b69a7a9c551078fed216a77440cee6dedf49@changeid Signed-off-by: Mark Brown --- drivers/platform/chrome/cros_ec_trace.c | 1 + include/linux/platform_data/cros_ec_commands.h | 69 +++ sound/soc/codecs/Kconfig | 2 + sound/soc/codecs/cros_ec_codec.c | 700 ++++++++++++++++++++++++- 4 files changed, 770 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/platform/chrome/cros_ec_trace.c b/drivers/platform/chrome/cros_ec_trace.c index 2ea0d4e0d54d..5af1d66d9eca 100644 --- a/drivers/platform/chrome/cros_ec_trace.c +++ b/drivers/platform/chrome/cros_ec_trace.c @@ -101,6 +101,7 @@ TRACE_SYMBOL(EC_CMD_EC_CODEC), \ TRACE_SYMBOL(EC_CMD_EC_CODEC_DMIC), \ TRACE_SYMBOL(EC_CMD_EC_CODEC_I2S_RX), \ + TRACE_SYMBOL(EC_CMD_EC_CODEC_WOV), \ TRACE_SYMBOL(EC_CMD_REBOOT_EC), \ TRACE_SYMBOL(EC_CMD_GET_PANIC_INFO), \ TRACE_SYMBOL(EC_CMD_ACPI_READ), \ diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index 21db0d4d4025..69210881ebac 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -556,6 +556,9 @@ enum host_event_code { /* Keyboard recovery combo with hardware reinitialization */ EC_HOST_EVENT_KEYBOARD_RECOVERY_HW_REINIT = 30, + /* WoV */ + EC_HOST_EVENT_WOV = 31, + /* * The high bit of the event mask is not used as a host event code. If * it reads back as set, then the entire event mask should be @@ -4477,10 +4480,14 @@ enum ec_codec_subcmd { }; enum ec_codec_cap { + EC_CODEC_CAP_WOV_AUDIO_SHM = 0, + EC_CODEC_CAP_WOV_LANG_SHM = 1, EC_CODEC_CAP_LAST = 32, }; enum ec_codec_shm_id { + EC_CODEC_SHM_ID_WOV_AUDIO = 0x0, + EC_CODEC_SHM_ID_WOV_LANG = 0x1, EC_CODEC_SHM_ID_LAST, }; @@ -4641,6 +4648,68 @@ struct __ec_align4 ec_param_ec_codec_i2s_rx { }; }; +/*****************************************************************************/ +/* Commands for WoV on audio codec. */ + +#define EC_CMD_EC_CODEC_WOV 0x00BF + +enum ec_codec_wov_subcmd { + EC_CODEC_WOV_SET_LANG = 0x0, + EC_CODEC_WOV_SET_LANG_SHM = 0x1, + EC_CODEC_WOV_GET_LANG = 0x2, + EC_CODEC_WOV_ENABLE = 0x3, + EC_CODEC_WOV_DISABLE = 0x4, + EC_CODEC_WOV_READ_AUDIO = 0x5, + EC_CODEC_WOV_READ_AUDIO_SHM = 0x6, + EC_CODEC_WOV_SUBCMD_COUNT, +}; + +/* + * @hash is SHA256 of the whole language model. + * @total_len indicates the length of whole language model. + * @offset is the cursor from the beginning of the model. + * @buf is the packet buffer. + * @len denotes how many bytes in the buf. + */ +struct __ec_align4 ec_param_ec_codec_wov_set_lang { + uint8_t hash[32]; + uint32_t total_len; + uint32_t offset; + uint8_t buf[128]; + uint32_t len; +}; + +struct __ec_align4 ec_param_ec_codec_wov_set_lang_shm { + uint8_t hash[32]; + uint32_t total_len; +}; + +struct __ec_align4 ec_param_ec_codec_wov { + uint8_t cmd; /* enum ec_codec_wov_subcmd */ + uint8_t reserved[3]; + + union { + struct ec_param_ec_codec_wov_set_lang + set_lang_param; + struct ec_param_ec_codec_wov_set_lang_shm + set_lang_shm_param; + }; +}; + +struct __ec_align4 ec_response_ec_codec_wov_get_lang { + uint8_t hash[32]; +}; + +struct __ec_align4 ec_response_ec_codec_wov_read_audio { + uint8_t buf[128]; + uint32_t len; +}; + +struct __ec_align4 ec_response_ec_codec_wov_read_audio_shm { + uint32_t offset; + uint32_t len; +}; + /*****************************************************************************/ /* System commands */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 5a706102db04..1a4b084cc90d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -509,6 +509,8 @@ config SND_SOC_CQ0093VC config SND_SOC_CROS_EC_CODEC tristate "codec driver for ChromeOS EC" depends on CROS_EC + select CRYPTO + select CRYPTO_SHA256 help If you say yes here you will get support for the ChromeOS Embedded Controller's Audio Codec. diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c index 3d4f9e82d6e9..dd14caf9091a 100644 --- a/sound/soc/codecs/cros_ec_codec.c +++ b/sound/soc/codecs/cros_ec_codec.c @@ -8,10 +8,16 @@ * EC for audio function. */ +#include +#include #include #include +#include +#include #include #include +#include +#include #include #include #include @@ -23,8 +29,45 @@ struct cros_ec_codec_priv { struct device *dev; struct cros_ec_device *ec_device; + + /* common */ + uint32_t ec_capabilities; + + uint64_t ec_shm_addr; + uint32_t ec_shm_len; + + uint64_t ap_shm_phys_addr; + uint32_t ap_shm_len; + uint64_t ap_shm_addr; + uint64_t ap_shm_last_alloc; + + /* DMIC */ + atomic_t dmic_probed; + + /* WoV */ + bool wov_enabled; + uint8_t *wov_audio_shm_p; + uint32_t wov_audio_shm_len; + uint8_t wov_audio_shm_type; + uint8_t *wov_lang_shm_p; + uint32_t wov_lang_shm_len; + uint8_t wov_lang_shm_type; + + struct mutex wov_dma_lock; + uint8_t wov_buf[64000]; + uint32_t wov_rp, wov_wp; + size_t wov_dma_offset; + bool wov_burst_read; + struct snd_pcm_substream *wov_substream; + struct delayed_work wov_copy_work; + struct notifier_block wov_notifier; }; +static int ec_codec_capable(struct cros_ec_codec_priv *priv, uint8_t cap) +{ + return priv->ec_capabilities & BIT(cap); +} + static int send_ec_host_command(struct cros_ec_device *ec_dev, uint32_t cmd, uint8_t *out, size_t outsize, uint8_t *in, size_t insize) @@ -57,6 +100,41 @@ error: return ret; } +static int calculate_sha256(struct cros_ec_codec_priv *priv, + uint8_t *buf, uint32_t size, uint8_t *digest) +{ + struct crypto_shash *tfm; + + tfm = crypto_alloc_shash("sha256", CRYPTO_ALG_TYPE_SHASH, 0); + if (IS_ERR(tfm)) { + dev_err(priv->dev, "can't alloc shash\n"); + return PTR_ERR(tfm); + } + + { + SHASH_DESC_ON_STACK(desc, tfm); + + desc->tfm = tfm; + + crypto_shash_digest(desc, buf, size, digest); + shash_desc_zero(desc); + } + + crypto_free_shash(tfm); + +#ifdef DEBUG + { + char digest_str[65]; + + bin2hex(digest_str, digest, 32); + digest_str[64] = 0; + dev_dbg(priv->dev, "hash=%s\n", digest_str); + } +#endif + + return 0; +} + static int dmic_get_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -147,6 +225,9 @@ static int dmic_probe(struct snd_soc_component *component) struct ec_response_ec_codec_dmic_get_max_gain r; int ret; + if (!atomic_add_unless(&priv->dmic_probed, 1, 1)) + return 0; + p.cmd = EC_CODEC_DMIC_GET_MAX_GAIN; ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_DMIC, @@ -324,23 +405,638 @@ static const struct snd_soc_component_driver i2s_rx_component_driver = { .num_dapm_routes = ARRAY_SIZE(i2s_rx_dapm_routes), }; +static void *wov_map_shm(struct cros_ec_codec_priv *priv, + uint8_t shm_id, uint32_t *len, uint8_t *type) +{ + struct ec_param_ec_codec p; + struct ec_response_ec_codec_get_shm_addr r; + uint32_t req, offset; + + p.cmd = EC_CODEC_GET_SHM_ADDR; + p.get_shm_addr_param.shm_id = shm_id; + if (send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC, + (uint8_t *)&p, sizeof(p), + (uint8_t *)&r, sizeof(r)) < 0) { + dev_err(priv->dev, "failed to EC_CODEC_GET_SHM_ADDR\n"); + return NULL; + } + + dev_dbg(priv->dev, "phys_addr=%#llx, len=%#x\n", r.phys_addr, r.len); + + *len = r.len; + *type = r.type; + + switch (r.type) { + case EC_CODEC_SHM_TYPE_EC_RAM: + return (void __force *)devm_ioremap_wc(priv->dev, + r.phys_addr + priv->ec_shm_addr, r.len); + case EC_CODEC_SHM_TYPE_SYSTEM_RAM: + if (r.phys_addr) { + dev_err(priv->dev, "unknown status\n"); + return NULL; + } + + req = round_up(r.len, PAGE_SIZE); + dev_dbg(priv->dev, "round up from %u to %u\n", r.len, req); + + if (priv->ap_shm_last_alloc + req > + priv->ap_shm_phys_addr + priv->ap_shm_len) { + dev_err(priv->dev, "insufficient space for AP SHM\n"); + return NULL; + } + + dev_dbg(priv->dev, "alloc AP SHM addr=%#llx, len=%#x\n", + priv->ap_shm_last_alloc, req); + + p.cmd = EC_CODEC_SET_SHM_ADDR; + p.set_shm_addr_param.phys_addr = priv->ap_shm_last_alloc; + p.set_shm_addr_param.len = req; + p.set_shm_addr_param.shm_id = shm_id; + if (send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC, + (uint8_t *)&p, sizeof(p), + NULL, 0) < 0) { + dev_err(priv->dev, "failed to EC_CODEC_SET_SHM_ADDR\n"); + return NULL; + } + + /* + * Note: EC codec only requests for `r.len' but we allocate + * round up PAGE_SIZE `req'. + */ + offset = priv->ap_shm_last_alloc - priv->ap_shm_phys_addr; + priv->ap_shm_last_alloc += req; + + return (void *)(uintptr_t)(priv->ap_shm_addr + offset); + default: + return NULL; + } +} + +static bool wov_queue_full(struct cros_ec_codec_priv *priv) +{ + return ((priv->wov_wp + 1) % sizeof(priv->wov_buf)) == priv->wov_rp; +} + +static size_t wov_queue_size(struct cros_ec_codec_priv *priv) +{ + if (priv->wov_wp >= priv->wov_rp) + return priv->wov_wp - priv->wov_rp; + else + return sizeof(priv->wov_buf) - priv->wov_rp + priv->wov_wp; +} + +static void wov_queue_dequeue(struct cros_ec_codec_priv *priv, size_t len) +{ + struct snd_pcm_runtime *runtime = priv->wov_substream->runtime; + size_t req; + + while (len) { + req = min(len, runtime->dma_bytes - priv->wov_dma_offset); + if (priv->wov_wp >= priv->wov_rp) + req = min(req, (size_t)priv->wov_wp - priv->wov_rp); + else + req = min(req, sizeof(priv->wov_buf) - priv->wov_rp); + + memcpy(runtime->dma_area + priv->wov_dma_offset, + priv->wov_buf + priv->wov_rp, req); + + priv->wov_dma_offset += req; + if (priv->wov_dma_offset == runtime->dma_bytes) + priv->wov_dma_offset = 0; + + priv->wov_rp += req; + if (priv->wov_rp == sizeof(priv->wov_buf)) + priv->wov_rp = 0; + + len -= req; + } + + snd_pcm_period_elapsed(priv->wov_substream); +} + +static void wov_queue_try_dequeue(struct cros_ec_codec_priv *priv) +{ + size_t period_bytes = snd_pcm_lib_period_bytes(priv->wov_substream); + + while (period_bytes && wov_queue_size(priv) >= period_bytes) { + wov_queue_dequeue(priv, period_bytes); + period_bytes = snd_pcm_lib_period_bytes(priv->wov_substream); + } +} + +static void wov_queue_enqueue(struct cros_ec_codec_priv *priv, + uint8_t *addr, size_t len, bool iomem) +{ + size_t req; + + while (len) { + if (wov_queue_full(priv)) { + wov_queue_try_dequeue(priv); + + if (wov_queue_full(priv)) { + dev_err(priv->dev, "overrun detected\n"); + return; + } + } + + if (priv->wov_wp >= priv->wov_rp) + req = sizeof(priv->wov_buf) - priv->wov_wp; + else + /* Note: waste 1-byte to differentiate full and empty */ + req = priv->wov_rp - priv->wov_wp - 1; + req = min(req, len); + + if (iomem) + memcpy_fromio(priv->wov_buf + priv->wov_wp, + (void __force __iomem *)addr, req); + else + memcpy(priv->wov_buf + priv->wov_wp, addr, req); + + priv->wov_wp += req; + if (priv->wov_wp == sizeof(priv->wov_buf)) + priv->wov_wp = 0; + + addr += req; + len -= req; + } + + wov_queue_try_dequeue(priv); +} + +static int wov_read_audio_shm(struct cros_ec_codec_priv *priv) +{ + struct ec_param_ec_codec_wov p; + struct ec_response_ec_codec_wov_read_audio_shm r; + int ret; + + p.cmd = EC_CODEC_WOV_READ_AUDIO_SHM; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, + (uint8_t *)&p, sizeof(p), + (uint8_t *)&r, sizeof(r)); + if (ret) { + dev_err(priv->dev, "failed to EC_CODEC_WOV_READ_AUDIO_SHM\n"); + return ret; + } + + if (!r.len) + dev_dbg(priv->dev, "no data, sleep\n"); + else + wov_queue_enqueue(priv, priv->wov_audio_shm_p + r.offset, r.len, + priv->wov_audio_shm_type == EC_CODEC_SHM_TYPE_EC_RAM); + return -EAGAIN; +} + +static int wov_read_audio(struct cros_ec_codec_priv *priv) +{ + struct ec_param_ec_codec_wov p; + struct ec_response_ec_codec_wov_read_audio r; + int remain = priv->wov_burst_read ? 16000 : 320; + int ret; + + while (remain >= 0) { + p.cmd = EC_CODEC_WOV_READ_AUDIO; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, + (uint8_t *)&p, sizeof(p), + (uint8_t *)&r, sizeof(r)); + if (ret) { + dev_err(priv->dev, + "failed to EC_CODEC_WOV_READ_AUDIO\n"); + return ret; + } + + if (!r.len) { + dev_dbg(priv->dev, "no data, sleep\n"); + priv->wov_burst_read = false; + break; + } + + wov_queue_enqueue(priv, r.buf, r.len, false); + remain -= r.len; + } + + return -EAGAIN; +} + +static void wov_copy_work(struct work_struct *w) +{ + struct cros_ec_codec_priv *priv = + container_of(w, struct cros_ec_codec_priv, wov_copy_work.work); + int ret; + + mutex_lock(&priv->wov_dma_lock); + if (!priv->wov_substream) { + dev_warn(priv->dev, "no pcm substream\n"); + goto leave; + } + + if (ec_codec_capable(priv, EC_CODEC_CAP_WOV_AUDIO_SHM)) + ret = wov_read_audio_shm(priv); + else + ret = wov_read_audio(priv); + + if (ret == -EAGAIN) + schedule_delayed_work(&priv->wov_copy_work, + msecs_to_jiffies(10)); + else if (ret) + dev_err(priv->dev, "failed to read audio data\n"); +leave: + mutex_unlock(&priv->wov_dma_lock); +} + +static int wov_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol); + struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(c); + + ucontrol->value.integer.value[0] = priv->wov_enabled; + return 0; +} + +static int wov_enable_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol); + struct cros_ec_codec_priv *priv = snd_soc_component_get_drvdata(c); + int enabled = ucontrol->value.integer.value[0]; + struct ec_param_ec_codec_wov p; + int ret; + + if (priv->wov_enabled != enabled) { + if (enabled) + p.cmd = EC_CODEC_WOV_ENABLE; + else + p.cmd = EC_CODEC_WOV_DISABLE; + + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, + (uint8_t *)&p, sizeof(p), NULL, 0); + if (ret) { + dev_err(priv->dev, "failed to %s wov\n", + enabled ? "enable" : "disable"); + return ret; + } + + priv->wov_enabled = enabled; + } + + return 0; +} + +static int wov_set_lang_shm(struct cros_ec_codec_priv *priv, + uint8_t *buf, size_t size, uint8_t *digest) +{ + struct ec_param_ec_codec_wov p; + struct ec_param_ec_codec_wov_set_lang_shm *pp = &p.set_lang_shm_param; + int ret; + + if (size > priv->wov_lang_shm_len) { + dev_err(priv->dev, "no enough SHM size: %d\n", + priv->wov_lang_shm_len); + return -EIO; + } + + switch (priv->wov_lang_shm_type) { + case EC_CODEC_SHM_TYPE_EC_RAM: + memcpy_toio((void __force __iomem *)priv->wov_lang_shm_p, + buf, size); + memset_io((void __force __iomem *)priv->wov_lang_shm_p + size, + 0, priv->wov_lang_shm_len - size); + break; + case EC_CODEC_SHM_TYPE_SYSTEM_RAM: + memcpy(priv->wov_lang_shm_p, buf, size); + memset(priv->wov_lang_shm_p + size, 0, + priv->wov_lang_shm_len - size); + + /* make sure write to memory before calling host command */ + wmb(); + break; + } + + p.cmd = EC_CODEC_WOV_SET_LANG_SHM; + memcpy(pp->hash, digest, SHA256_DIGEST_SIZE); + pp->total_len = size; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, + (uint8_t *)&p, sizeof(p), NULL, 0); + if (ret) { + dev_err(priv->dev, "failed to EC_CODEC_WOV_SET_LANG_SHM\n"); + return ret; + } + + return 0; +} + +static int wov_set_lang(struct cros_ec_codec_priv *priv, + uint8_t *buf, size_t size, uint8_t *digest) +{ + struct ec_param_ec_codec_wov p; + struct ec_param_ec_codec_wov_set_lang *pp = &p.set_lang_param; + size_t i, req; + int ret; + + for (i = 0; i < size; i += req) { + req = min(size - i, ARRAY_SIZE(pp->buf)); + + p.cmd = EC_CODEC_WOV_SET_LANG; + memcpy(pp->hash, digest, SHA256_DIGEST_SIZE); + pp->total_len = size; + pp->offset = i; + memcpy(pp->buf, buf + i, req); + pp->len = req; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, + (uint8_t *)&p, sizeof(p), NULL, 0); + if (ret) { + dev_err(priv->dev, "failed to EC_CODEC_WOV_SET_LANG\n"); + return ret; + } + } + + return 0; +} + +static int wov_hotword_model_put(struct snd_kcontrol *kcontrol, + const unsigned int __user *bytes, + unsigned int size) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + struct ec_param_ec_codec_wov p; + struct ec_response_ec_codec_wov_get_lang r; + uint8_t digest[SHA256_DIGEST_SIZE]; + uint8_t *buf; + int ret; + + /* Skips the TLV header. */ + bytes += 2; + size -= 8; + + dev_dbg(priv->dev, "%s: size=%d\n", __func__, size); + + buf = memdup_user(bytes, size); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + ret = calculate_sha256(priv, buf, size, digest); + if (ret) + goto leave; + + p.cmd = EC_CODEC_WOV_GET_LANG; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC_WOV, + (uint8_t *)&p, sizeof(p), + (uint8_t *)&r, sizeof(r)); + if (ret) + goto leave; + + if (memcmp(digest, r.hash, SHA256_DIGEST_SIZE) == 0) { + dev_dbg(priv->dev, "not updated"); + goto leave; + } + + if (ec_codec_capable(priv, EC_CODEC_CAP_WOV_LANG_SHM)) + ret = wov_set_lang_shm(priv, buf, size, digest); + else + ret = wov_set_lang(priv, buf, size, digest); + +leave: + kfree(buf); + return ret; +} + +static struct snd_kcontrol_new wov_controls[] = { + SOC_SINGLE_BOOL_EXT("Wake-on-Voice Switch", 0, + wov_enable_get, wov_enable_put), + SND_SOC_BYTES_TLV("Hotword Model", 0x11000, NULL, + wov_hotword_model_put), +}; + +static struct snd_soc_dai_driver wov_dai_driver = { + .name = "Wake on Voice", + .capture = { + .stream_name = "WoV Capture", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}; + +static int wov_host_event(struct notifier_block *nb, + unsigned long queued_during_suspend, void *notify) +{ + struct cros_ec_codec_priv *priv = + container_of(nb, struct cros_ec_codec_priv, wov_notifier); + u32 host_event; + + dev_dbg(priv->dev, "%s\n", __func__); + + host_event = cros_ec_get_host_event(priv->ec_device); + if (host_event & EC_HOST_EVENT_MASK(EC_HOST_EVENT_WOV)) { + schedule_delayed_work(&priv->wov_copy_work, 0); + return NOTIFY_OK; + } else { + return NOTIFY_DONE; + } +} + +static int wov_probe(struct snd_soc_component *component) +{ + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + int ret; + + mutex_init(&priv->wov_dma_lock); + INIT_DELAYED_WORK(&priv->wov_copy_work, wov_copy_work); + + priv->wov_notifier.notifier_call = wov_host_event; + ret = blocking_notifier_chain_register( + &priv->ec_device->event_notifier, &priv->wov_notifier); + if (ret) + return ret; + + if (ec_codec_capable(priv, EC_CODEC_CAP_WOV_LANG_SHM)) { + priv->wov_lang_shm_p = wov_map_shm(priv, + EC_CODEC_SHM_ID_WOV_LANG, + &priv->wov_lang_shm_len, + &priv->wov_lang_shm_type); + if (!priv->wov_lang_shm_p) + return -EFAULT; + } + + if (ec_codec_capable(priv, EC_CODEC_CAP_WOV_AUDIO_SHM)) { + priv->wov_audio_shm_p = wov_map_shm(priv, + EC_CODEC_SHM_ID_WOV_AUDIO, + &priv->wov_audio_shm_len, + &priv->wov_audio_shm_type); + if (!priv->wov_audio_shm_p) + return -EFAULT; + } + + return dmic_probe(component); +} + +static void wov_remove(struct snd_soc_component *component) +{ + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + + blocking_notifier_chain_unregister( + &priv->ec_device->event_notifier, &priv->wov_notifier); +} + +static int wov_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + static const struct snd_pcm_hardware hw_param = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_16000, + .channels_min = 1, + .channels_max = 1, + .period_bytes_min = PAGE_SIZE, + .period_bytes_max = 0x20000 / 8, + .periods_min = 8, + .periods_max = 8, + .buffer_bytes_max = 0x20000, + }; + + return snd_soc_set_runtime_hwparams(substream, &hw_param); +} + +static int wov_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + + mutex_lock(&priv->wov_dma_lock); + priv->wov_substream = substream; + priv->wov_rp = priv->wov_wp = 0; + priv->wov_dma_offset = 0; + priv->wov_burst_read = true; + mutex_unlock(&priv->wov_dma_lock); + + return snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); +} + +static int wov_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + + mutex_lock(&priv->wov_dma_lock); + wov_queue_dequeue(priv, wov_queue_size(priv)); + priv->wov_substream = NULL; + mutex_unlock(&priv->wov_dma_lock); + + cancel_delayed_work_sync(&priv->wov_copy_work); + + return snd_pcm_lib_free_vmalloc_buffer(substream); +} + +static snd_pcm_uframes_t wov_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct cros_ec_codec_priv *priv = + snd_soc_component_get_drvdata(component); + + return bytes_to_frames(runtime, priv->wov_dma_offset); +} + +static struct page *wov_pcm_page(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + unsigned long offset) +{ + return snd_pcm_lib_get_vmalloc_page(substream, offset); +} + +static const struct snd_soc_component_driver wov_component_driver = { + .probe = wov_probe, + .remove = wov_remove, + .controls = wov_controls, + .num_controls = ARRAY_SIZE(wov_controls), + .open = wov_pcm_open, + .hw_params = wov_pcm_hw_params, + .hw_free = wov_pcm_hw_free, + .pointer = wov_pcm_pointer, + .page = wov_pcm_page, +}; + static int cros_ec_codec_platform_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct cros_ec_device *ec_device = dev_get_drvdata(pdev->dev.parent); struct cros_ec_codec_priv *priv; + struct ec_param_ec_codec p; + struct ec_response_ec_codec_get_capabilities r; + int ret; +#ifdef CONFIG_OF + struct device_node *node; + struct resource res; + u64 ec_shm_size; + const __be32 *regaddr_p; +#endif priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; +#ifdef CONFIG_OF + regaddr_p = of_get_address(dev->of_node, 0, &ec_shm_size, NULL); + if (regaddr_p) { + priv->ec_shm_addr = of_read_number(regaddr_p, 2); + priv->ec_shm_len = ec_shm_size; + + dev_dbg(dev, "ec_shm_addr=%#llx len=%#x\n", + priv->ec_shm_addr, priv->ec_shm_len); + } + + node = of_parse_phandle(dev->of_node, "memory-region", 0); + if (node) { + ret = of_address_to_resource(node, 0, &res); + if (!ret) { + priv->ap_shm_phys_addr = res.start; + priv->ap_shm_len = resource_size(&res); + priv->ap_shm_addr = + (uint64_t)(uintptr_t)devm_ioremap_wc( + dev, priv->ap_shm_phys_addr, + priv->ap_shm_len); + priv->ap_shm_last_alloc = priv->ap_shm_phys_addr; + + dev_dbg(dev, "ap_shm_phys_addr=%#llx len=%#x\n", + priv->ap_shm_phys_addr, priv->ap_shm_len); + } + } +#endif + priv->dev = dev; priv->ec_device = ec_device; + atomic_set(&priv->dmic_probed, 0); + + p.cmd = EC_CODEC_GET_CAPABILITIES; + ret = send_ec_host_command(priv->ec_device, EC_CMD_EC_CODEC, + (uint8_t *)&p, sizeof(p), + (uint8_t *)&r, sizeof(r)); + if (ret) { + dev_err(dev, "failed to EC_CODEC_GET_CAPABILITIES\n"); + return ret; + } + priv->ec_capabilities = r.capabilities; platform_set_drvdata(pdev, priv); - return devm_snd_soc_register_component(dev, &i2s_rx_component_driver, - &i2s_rx_dai_driver, 1); + ret = devm_snd_soc_register_component(dev, &i2s_rx_component_driver, + &i2s_rx_dai_driver, 1); + if (ret) + return ret; + + return devm_snd_soc_register_component(dev, &wov_component_driver, + &wov_dai_driver, 1); } #ifdef CONFIG_OF -- cgit v1.2.3 From 33536a14879515949b065721cdb7fedb276d8e8a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 15 Oct 2019 12:59:44 +0900 Subject: ASoC: soc-core: remove for_each_rtdcom_safe() There is no user of for_each_rtdcom(). Let's remove it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87a7a264m9.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/sound/soc.h b/include/sound/soc.h index 32748f78060a..d730883626dc 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -741,8 +741,6 @@ snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, const char *driver_name); #define for_each_rtdcom(rtd, rtdcom) \ list_for_each_entry(rtdcom, &(rtd)->component_list, list) -#define for_each_rtdcom_safe(rtd, rtdcom1, rtdcom2) \ - list_for_each_entry_safe(rtdcom1, rtdcom2, &(rtd)->component_list, list) struct snd_soc_dai_link_component { const char *name; -- cgit v1.2.3 From 2b544dd7b43b19fb55ea4fbb3e30b60eb20b7828 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 15 Oct 2019 12:59:31 +0900 Subject: ASoC: soc-core: add for_each_rtd_components() and replace ALSA SoC has for_each_rtdcom() which is link list for rtd-component which is called as rtdcom. The relationship image is like below rtdcom rtdcom rtdcom component component component rtd->component_list -> list -> list -> list ... Here, the pointer get via normal link list is rtdcom, Thus, current for_each loop is like below, and need to get component via rtdcom->component for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; ... } but usually, user want to get pointer from for_each_xxx is component directly, like below. for_each_rtd_component(rtd, rtdcom, component) { ... } This patch expands list_for_each_entry manually, and enable to get component directly from for_each macro. Because of it, the macro becoming difficult to read, but macro itself becoming useful. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/878spm64m4.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 8 ++++++-- sound/soc/soc-component.c | 43 +++++++++++---------------------------- sound/soc/soc-compress.c | 52 ++++++++++++----------------------------------- sound/soc/soc-core.c | 22 ++++++++------------ sound/soc/soc-pcm.c | 49 +++++++++++++------------------------------- 5 files changed, 54 insertions(+), 120 deletions(-) (limited to 'include') diff --git a/include/sound/soc.h b/include/sound/soc.h index d730883626dc..320dcd440dab 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -739,8 +739,12 @@ struct snd_soc_rtdcom_list { struct snd_soc_component* snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, const char *driver_name); -#define for_each_rtdcom(rtd, rtdcom) \ - list_for_each_entry(rtdcom, &(rtd)->component_list, list) +#define for_each_rtd_components(rtd, rtdcom, _component) \ + for (rtdcom = list_first_entry(&(rtd)->component_list, \ + typeof(*rtdcom), list); \ + (&rtdcom->list != &(rtd)->component_list) && \ + (_component = rtdcom->component); \ + rtdcom = list_next_entry(rtdcom, list)) struct snd_soc_dai_link_component { const char *name; diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index debaf1f6f403..98ef0666add2 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -420,13 +420,10 @@ int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream) struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - /* FIXME: use 1st pointer */ + /* FIXME: use 1st pointer */ + for_each_rtd_components(rtd, rtdcom, component) if (component->driver->pointer) return component->driver->pointer(component, substream); - } return 0; } @@ -438,14 +435,11 @@ int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - /* FIXME: use 1st ioctl */ + /* FIXME: use 1st ioctl */ + for_each_rtd_components(rtd, rtdcom, component) if (component->driver->ioctl) return component->driver->ioctl(component, substream, cmd, arg); - } return snd_pcm_lib_ioctl(substream, cmd, arg); } @@ -458,14 +452,11 @@ int snd_soc_pcm_component_copy_user(struct snd_pcm_substream *substream, struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_component *component; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - /* FIXME. it returns 1st copy now */ + /* FIXME. it returns 1st copy now */ + for_each_rtd_components(rtd, rtdcom, component) if (component->driver->copy_user) return component->driver->copy_user( component, substream, channel, pos, buf, bytes); - } return -EINVAL; } @@ -478,10 +469,8 @@ struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, struct snd_soc_component *component; struct page *page; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - /* FIXME. it returns 1st page now */ + /* FIXME. it returns 1st page now */ + for_each_rtd_components(rtd, rtdcom, component) { if (component->driver->page) { page = component->driver->page(component, substream, offset); @@ -500,14 +489,11 @@ int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_component *component; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - /* FIXME. it returns 1st mmap now */ + /* FIXME. it returns 1st mmap now */ + for_each_rtd_components(rtd, rtdcom, component) if (component->driver->mmap) return component->driver->mmap(component, substream, vma); - } return -EINVAL; } @@ -519,9 +505,7 @@ int snd_soc_pcm_component_new(struct snd_pcm *pcm) struct snd_soc_component *component; int ret; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (component->driver->pcm_construct) { ret = component->driver->pcm_construct(component, rtd); if (ret < 0) @@ -538,10 +522,7 @@ void snd_soc_pcm_component_free(struct snd_pcm *pcm) struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_component *component; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) if (component->driver->pcm_destruct) component->driver->pcm_destruct(component, pcm); - } } diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 9e54d8ae6d2c..61f230324164 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -28,9 +28,7 @@ static int soc_compr_components_open(struct snd_compr_stream *cstream, struct snd_soc_rtdcom_list *rtdcom; int ret; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->open) continue; @@ -57,9 +55,7 @@ static int soc_compr_components_free(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (component == last) break; @@ -353,9 +349,7 @@ static int soc_compr_components_trigger(struct snd_compr_stream *cstream, struct snd_soc_rtdcom_list *rtdcom; int ret; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->trigger) continue; @@ -458,9 +452,7 @@ static int soc_compr_components_set_params(struct snd_compr_stream *cstream, struct snd_soc_rtdcom_list *rtdcom; int ret; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->set_params) continue; @@ -601,9 +593,7 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream, goto err; } - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->get_params) continue; @@ -627,9 +617,7 @@ static int soc_compr_get_caps(struct snd_compr_stream *cstream, mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->get_caps) continue; @@ -652,9 +640,7 @@ static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->get_codec_caps) continue; @@ -684,9 +670,7 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) goto err; } - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->ack) continue; @@ -715,9 +699,7 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, if (cpu_dai->driver->cops && cpu_dai->driver->cops->pointer) cpu_dai->driver->cops->pointer(cstream, tstamp, cpu_dai); - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->pointer) continue; @@ -740,9 +722,7 @@ static int soc_compr_copy(struct snd_compr_stream *cstream, mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass); - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->copy) continue; @@ -770,9 +750,7 @@ static int soc_compr_set_metadata(struct snd_compr_stream *cstream, return ret; } - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->set_metadata) continue; @@ -801,9 +779,7 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream, return ret; } - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->get_metadata) continue; @@ -932,9 +908,7 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops)); } - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->compr_ops || !component->driver->compr_ops->copy) continue; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f028a6938ee8..f1b41b0391ed 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -293,10 +293,11 @@ static int snd_soc_rtdcom_add(struct snd_soc_pcm_runtime *rtd, struct snd_soc_component *component) { struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *comp; - for_each_rtdcom(rtd, rtdcom) { + for_each_rtd_components(rtd, rtdcom, comp) { /* already connected */ - if (rtdcom->component == component) + if (comp == component) return 0; } @@ -327,6 +328,7 @@ struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, const char *driver_name) { struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; if (!driver_name) return NULL; @@ -339,8 +341,8 @@ struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, * But, if many components which have same driver name are connected * to 1 rtd, this function will return 1st found component. */ - for_each_rtdcom(rtd, rtdcom) { - const char *component_name = rtdcom->component->driver->name; + for_each_rtd_components(rtd, rtdcom, component) { + const char *component_name = component->driver->name; if (!component_name) continue; @@ -1248,9 +1250,7 @@ static void soc_remove_link_components(struct snd_soc_card *card) for_each_comp_order(order) { for_each_card_rtds(card, rtd) { - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (component->driver->remove_order != order) continue; @@ -1269,9 +1269,7 @@ static int soc_probe_link_components(struct snd_soc_card *card) for_each_comp_order(order) { for_each_card_rtds(card, rtd) { - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (component->driver->probe_order != order) continue; @@ -1520,9 +1518,7 @@ static int soc_link_init(struct snd_soc_card *card, * topology based drivers can use the DAI link id field to set PCM * device number and then use rtd + a base offset of the BEs. */ - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (!component->driver->use_dai_pcm_id) continue; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 600d9bf3b076..8655df6a6089 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -118,11 +118,8 @@ bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd) if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time) return true; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) ignore &= !component->driver->use_pmdown_time; - } return ignore; } @@ -435,8 +432,7 @@ static int soc_pcm_components_open(struct snd_pcm_substream *substream, struct snd_soc_component *component; int ret = 0; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; + for_each_rtd_components(rtd, rtdcom, component) { *last = component; ret = snd_soc_component_module_get_when_open(component); @@ -467,9 +463,7 @@ static int soc_pcm_components_close(struct snd_pcm_substream *substream, struct snd_soc_component *component; int ret = 0; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (component == last) break; @@ -500,9 +494,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) for_each_rtd_codec_dai(rtd, i, codec_dai) pinctrl_pm_select_default_state(codec_dai->dev); - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { pm_runtime_get_sync(component->dev); } @@ -625,9 +617,7 @@ component_err: out: mutex_unlock(&rtd->card->pcm_mutex); - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { pm_runtime_mark_last_busy(component->dev); pm_runtime_put_autosuspend(component->dev); } @@ -740,9 +730,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) mutex_unlock(&rtd->card->pcm_mutex); - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { pm_runtime_mark_last_busy(component->dev); pm_runtime_put_autosuspend(component->dev); } @@ -782,9 +770,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } } - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { ret = snd_soc_component_prepare(component, substream); if (ret < 0) { dev_err(component->dev, @@ -849,9 +835,7 @@ static int soc_pcm_components_hw_free(struct snd_pcm_substream *substream, struct snd_soc_component *component; int ret = 0; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { if (component == last) break; @@ -945,9 +929,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, snd_soc_dapm_update_dai(substream, params, cpu_dai); - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { ret = snd_soc_component_hw_params(component, substream, params); if (ret < 0) { dev_err(component->dev, @@ -1062,9 +1044,7 @@ static int soc_pcm_trigger_start(struct snd_pcm_substream *substream, int cmd) return ret; } - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { ret = snd_soc_component_trigger(component, substream, cmd); if (ret < 0) return ret; @@ -1102,9 +1082,7 @@ static int soc_pcm_trigger_stop(struct snd_pcm_substream *substream, int cmd) if (ret < 0) return ret; - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - + for_each_rtd_components(rtd, rtdcom, component) { ret = snd_soc_component_trigger(component, substream, cmd); if (ret < 0) return ret; @@ -2879,6 +2857,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) struct snd_soc_dai *codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; struct snd_pcm *pcm; char new_name[64]; int ret = 0, playback = 0, capture = 0; @@ -2990,8 +2969,8 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) rtd->ops.ioctl = snd_soc_pcm_component_ioctl; } - for_each_rtdcom(rtd, rtdcom) { - const struct snd_soc_component_driver *drv = rtdcom->component->driver; + for_each_rtd_components(rtd, rtdcom, component) { + const struct snd_soc_component_driver *drv = component->driver; if (drv->copy_user) rtd->ops.copy_user = snd_soc_pcm_component_copy_user; -- cgit v1.2.3 From 4f0637eae56f02ef648de5ed839d572259d396e9 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Tue, 22 Oct 2019 14:47:04 -0500 Subject: ASoC: Intel: common: add ACPI matching tables for JSL There are no upstream machine drivers just yet so just add dummy table for compilation in nocodec-mode. Signed-off-by: Pan Xiuli Link: https://lore.kernel.org/r/20191022194705.23347-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/soc-acpi-intel-match.h | 1 + sound/soc/intel/common/Makefile | 1 + sound/soc/intel/common/soc-acpi-intel-jsl-match.c | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+) create mode 100644 sound/soc/intel/common/soc-acpi-intel-jsl-match.c (limited to 'include') diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index 6c9929abd90b..4e44782862df 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -27,6 +27,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[]; /* * generic table used for HDA codec-based platforms, possibly with diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 18d9630ae9a2..eafe95ead49b 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -9,6 +9,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \ soc-acpi-intel-cnl-match.o soc-acpi-intel-icl-match.o \ soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \ + soc-acpi-intel-jsl-match.o \ soc-acpi-intel-hda-match.o obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o diff --git a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c new file mode 100644 index 000000000000..1c68a04f0c6e --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * soc-apci-intel-jsl-match.c - tables and support for JSL ACPI enumeration. + * + * Copyright (c) 2019, Intel Corporation. + * + */ + +#include +#include + +struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = { + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_jsl_machines); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); -- cgit v1.2.3 From 4baabbf932ed4f97df8e18cf546d39b7c2138020 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 25 Oct 2019 09:56:10 +0900 Subject: ASoC: soc-dpcm: tidyup for_each_dpcm_xx() macro for_each_dpcm_xx() macro is using "dpcm" as parameter (1), but, it is also struct member (2). #define for_each_dpcm_fe(be, stream, dpcm) \ list_for_each_entry(dpcm, &(be)->dpcm[stream]...) ^^^^(1) ^^^^(2) Thus, it will be compile error if user not used "dpcm" as parameter for_each_dpcm_fe(be, stream, dp) ^^ This patch fixup it. Reported-by: Pavel Machek Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87tv7x7idx.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dpcm.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h index e55aeb00ce2d..b654ebfc8766 100644 --- a/include/sound/soc-dpcm.h +++ b/include/sound/soc-dpcm.h @@ -103,15 +103,15 @@ struct snd_soc_dpcm_runtime { int trigger_pending; /* trigger cmd + 1 if pending, 0 if not */ }; -#define for_each_dpcm_fe(be, stream, dpcm) \ - list_for_each_entry(dpcm, &(be)->dpcm[stream].fe_clients, list_fe) - -#define for_each_dpcm_be(fe, stream, dpcm) \ - list_for_each_entry(dpcm, &(fe)->dpcm[stream].be_clients, list_be) -#define for_each_dpcm_be_safe(fe, stream, dpcm, _dpcm) \ - list_for_each_entry_safe(dpcm, _dpcm, &(fe)->dpcm[stream].be_clients, list_be) -#define for_each_dpcm_be_rollback(fe, stream, dpcm) \ - list_for_each_entry_continue_reverse(dpcm, &(fe)->dpcm[stream].be_clients, list_be) +#define for_each_dpcm_fe(be, stream, _dpcm) \ + list_for_each_entry(_dpcm, &(be)->dpcm[stream].fe_clients, list_fe) + +#define for_each_dpcm_be(fe, stream, _dpcm) \ + list_for_each_entry(_dpcm, &(fe)->dpcm[stream].be_clients, list_be) +#define for_each_dpcm_be_safe(fe, stream, _dpcm, __dpcm) \ + list_for_each_entry_safe(_dpcm, __dpcm, &(fe)->dpcm[stream].be_clients, list_be) +#define for_each_dpcm_be_rollback(fe, stream, _dpcm) \ + list_for_each_entry_continue_reverse(_dpcm, &(fe)->dpcm[stream].be_clients, list_be) /* can this BE stop and free */ int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe, -- cgit v1.2.3 From c19255659b6ed952948ce54a260efb2ad950cc54 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 24 Oct 2019 17:16:03 +0200 Subject: ASoC: Spelling s/configr/configur/ Fix misspellings of "configuration" and "configure". Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20191024151603.29043-1-geert+renesas@glider.be Signed-off-by: Mark Brown --- include/sound/wm8904.h | 2 +- sound/soc/codecs/cx2072x.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/sound/wm8904.h b/include/sound/wm8904.h index 14074405f501..88ac1870510e 100644 --- a/include/sound/wm8904.h +++ b/include/sound/wm8904.h @@ -120,7 +120,7 @@ * DRC configurations are specified with a label and a set of register * values to write (the enable bits will be ignored). At runtime an * enumerated control will be presented for each DRC block allowing - * the user to choose the configration to use. + * the user to choose the configuration to use. * * Configurations may be generated by hand or by using the DRC control * panel provided by the WISCE - see http://www.wolfsonmicro.com/wisce/ diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c index 1c1ba7bea4d8..2ad00ed21bec 100644 --- a/sound/soc/codecs/cx2072x.c +++ b/sound/soc/codecs/cx2072x.c @@ -1507,7 +1507,7 @@ static int cx2072x_probe(struct snd_soc_component *codec) regmap_multi_reg_write(cx2072x->regmap, cx2072x_reg_init, ARRAY_SIZE(cx2072x_reg_init)); - /* configre PortC as input device */ + /* configure PortC as input device */ regmap_update_bits(cx2072x->regmap, CX2072X_PORTC_PIN_CTRL, 0x20, 0x20); -- cgit v1.2.3 From 4a94940988cc44adeb383401dea0beeac4abbe63 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:04 -0500 Subject: ASoC: SOF: token: add tokens for PCM compatible with D0i3 substate Add stream token SOF_TKN_STREAM_PLAYBACK_COMPATIBLE_D0I3 and SOF_TKN_STREAM_CAPTURE_COMPATIBLE_D0I3 to denote if the stream can be opened at low power d0i3 status or not. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/uapi/sound/sof/tokens.h | 4 ++++ sound/soc/sof/topology.c | 10 ++++++++++ 2 files changed, 14 insertions(+) (limited to 'include') diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index d65406f34361..76883e6fb750 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -113,6 +113,10 @@ /* ESAI */ #define SOF_TKN_IMX_ESAI_MCLK_ID 1100 +/* Stream */ +#define SOF_TKN_STREAM_PLAYBACK_COMPATIBLE_D0I3 1200 +#define SOF_TKN_STREAM_CAPTURE_COMPATIBLE_D0I3 1201 + /* Led control for mute switches */ #define SOF_TKN_MUTE_LED_USE 1300 #define SOF_TKN_MUTE_LED_DIRECTION 1301 diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index b3ab6f23fc93..121e5d6f8477 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -567,6 +567,16 @@ static const struct sof_topology_token pcm_tokens[] = { offsetof(struct sof_ipc_comp_host, dmac_config), 0}, }; +/* PCM */ +static const struct sof_topology_token stream_tokens[] = { + {SOF_TKN_STREAM_PLAYBACK_COMPATIBLE_D0I3, + SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, + offsetof(struct snd_sof_pcm, stream[0].d0i3_compatible), 0}, + {SOF_TKN_STREAM_CAPTURE_COMPATIBLE_D0I3, + SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, + offsetof(struct snd_sof_pcm, stream[1].d0i3_compatible), 0}, +}; + /* Generic components */ static const struct sof_topology_token comp_tokens[] = { {SOF_TKN_COMP_PERIOD_SINK_COUNT, -- cgit v1.2.3 From 10992004e1e960c7e256ec70c7ab22895a7003d7 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:09 -0500 Subject: ASoC: SOF: ipc: introduce message for DSP power gating Add new ipc messages which will be sent from driver to FW, to ask FW to enter specific power saving state. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-14-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof/header.h | 1 + include/sound/sof/pm.h | 8 ++++++++ 2 files changed, 9 insertions(+) (limited to 'include') diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h index 332143ff7278..bf3edd9c08b4 100644 --- a/include/sound/sof/header.h +++ b/include/sound/sof/header.h @@ -75,6 +75,7 @@ #define SOF_IPC_PM_CLK_GET SOF_CMD_TYPE(0x005) #define SOF_IPC_PM_CLK_REQ SOF_CMD_TYPE(0x006) #define SOF_IPC_PM_CORE_ENABLE SOF_CMD_TYPE(0x007) +#define SOF_IPC_PM_GATE SOF_CMD_TYPE(0x008) /* component runtime config - multiple different types */ #define SOF_IPC_COMP_SET_VALUE SOF_CMD_TYPE(0x001) diff --git a/include/sound/sof/pm.h b/include/sound/sof/pm.h index 003879401d63..3cf2e0f39d94 100644 --- a/include/sound/sof/pm.h +++ b/include/sound/sof/pm.h @@ -45,4 +45,12 @@ struct sof_ipc_pm_core_config { uint32_t enable_mask; } __packed; +struct sof_ipc_pm_gate { + struct sof_ipc_cmd_hdr hdr; + uint32_t flags; /* platform specific */ + + /* reserved for future use */ + uint32_t reserved[5]; +} __packed; + #endif -- cgit v1.2.3 From a9c82d63ca4819d3d03964dbf4aa427b36c5a67f Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Mon, 28 Oct 2019 15:19:25 +0800 Subject: drm: bridge: dw-hdmi: Report connector status using callback Allow codec driver register callback function for plug event. The callback registration flow: dw-hdmi <--- hw-hdmi-i2s-audio <--- hdmi-codec dw-hdmi-i2s-audio implements hook_plugged_cb op so codec driver can register the callback. dw-hdmi exports a function dw_hdmi_set_plugged_cb so platform device can register the callback. When connector plug/unplug event happens, report this event using the callback. Make sure that audio and drm are using the single source of truth for connector status. Signed-off-by: Cheng-Yi Chiang Link: https://lore.kernel.org/r/20191028071930.145899-2-cychiang@chromium.org Signed-off-by: Mark Brown --- .../gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 11 ++++++ drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 41 +++++++++++++++++++++- include/drm/bridge/dw_hdmi.h | 4 +++ 3 files changed, 55 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c index 1d15cf9b6821..6c2c44d0bdee 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c @@ -151,11 +151,22 @@ static int dw_hdmi_i2s_get_dai_id(struct snd_soc_component *component, return -EINVAL; } +static int dw_hdmi_i2s_hook_plugged_cb(struct device *dev, void *data, + hdmi_codec_plugged_cb fn, + struct device *codec_dev) +{ + struct dw_hdmi_i2s_audio_data *audio = data; + struct dw_hdmi *hdmi = audio->hdmi; + + return dw_hdmi_set_plugged_cb(hdmi, fn, codec_dev); +} + static struct hdmi_codec_ops dw_hdmi_i2s_ops = { .hw_params = dw_hdmi_i2s_hw_params, .audio_shutdown = dw_hdmi_i2s_audio_shutdown, .get_eld = dw_hdmi_i2s_get_eld, .get_dai_id = dw_hdmi_i2s_get_dai_id, + .hook_plugged_cb = dw_hdmi_i2s_hook_plugged_cb, }; static int snd_dw_hdmi_probe(struct platform_device *pdev) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 521d689413c8..2102872bf43c 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -191,6 +191,10 @@ struct dw_hdmi { struct mutex cec_notifier_mutex; struct cec_notifier *cec_notifier; + + hdmi_codec_plugged_cb plugged_cb; + struct device *codec_dev; + enum drm_connector_status last_connector_result; }; #define HDMI_IH_PHY_STAT0_RX_SENSE \ @@ -215,6 +219,28 @@ static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset) return val; } +static void handle_plugged_change(struct dw_hdmi *hdmi, bool plugged) +{ + if (hdmi->plugged_cb && hdmi->codec_dev) + hdmi->plugged_cb(hdmi->codec_dev, plugged); +} + +int dw_hdmi_set_plugged_cb(struct dw_hdmi *hdmi, hdmi_codec_plugged_cb fn, + struct device *codec_dev) +{ + bool plugged; + + mutex_lock(&hdmi->mutex); + hdmi->plugged_cb = fn; + hdmi->codec_dev = codec_dev; + plugged = hdmi->last_connector_result == connector_status_connected; + handle_plugged_change(hdmi, plugged); + mutex_unlock(&hdmi->mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(dw_hdmi_set_plugged_cb); + static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg) { regmap_update_bits(hdmi->regm, reg << hdmi->reg_shift, mask, data); @@ -2161,6 +2187,7 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force) { struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, connector); + enum drm_connector_status result; mutex_lock(&hdmi->mutex); hdmi->force = DRM_FORCE_UNSPECIFIED; @@ -2168,7 +2195,18 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force) dw_hdmi_update_phy_mask(hdmi); mutex_unlock(&hdmi->mutex); - return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); + result = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); + + mutex_lock(&hdmi->mutex); + if (result != hdmi->last_connector_result) { + dev_dbg(hdmi->dev, "read_hpd result: %d", result); + handle_plugged_change(hdmi, + result == connector_status_connected); + hdmi->last_connector_result = result; + } + mutex_unlock(&hdmi->mutex); + + return result; } static int dw_hdmi_connector_get_modes(struct drm_connector *connector) @@ -2619,6 +2657,7 @@ __dw_hdmi_probe(struct platform_device *pdev, hdmi->rxsense = true; hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE); hdmi->mc_clkdis = 0x7f; + hdmi->last_connector_result = connector_status_disconnected; mutex_init(&hdmi->mutex); mutex_init(&hdmi->audio_mutex); diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index cf528c289857..9a0c8381a069 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -6,6 +6,8 @@ #ifndef __DW_HDMI__ #define __DW_HDMI__ +#include + struct drm_connector; struct drm_display_mode; struct drm_encoder; @@ -154,6 +156,8 @@ void dw_hdmi_resume(struct dw_hdmi *hdmi); void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense); +int dw_hdmi_set_plugged_cb(struct dw_hdmi *hdmi, hdmi_codec_plugged_cb fn, + struct device *codec_dev); void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate); void dw_hdmi_set_channel_count(struct dw_hdmi *hdmi, unsigned int cnt); void dw_hdmi_set_channel_allocation(struct dw_hdmi *hdmi, unsigned int ca); -- cgit v1.2.3 From 2a2edfbbfee47947dd05f5860c66c0e80ee5e09d Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 29 Oct 2019 15:40:09 +0200 Subject: ALSA: hda/hdmi - implement mst_no_extra_pcms flag To support the DP-MST multiple streams via single connector feature, the HDMI driver was extended with the concept of backup PCMs. See commit 9152085defb6 ("ALSA: hda - add DP MST audio support"). This implementation works fine with snd_hda_intel.c as PCM topology is fully managed within the single driver. When the HDA codec driver is used from ASoC components, the concept of backup PCMs no longer fits. For ASoC topologies, the physical HDMI converters are presented as backend DAIs and these should match with hardware capabilities. The ASoC topology may define arbitrary PCMs (i.e. frontend DAIs) and have processing elements before eventual routing to the HDMI BE DAIs. With backup PCMs, the link between FE and BE DAIs would become dynamic and change when monitors are (un)plugged. This would lead to modifying the topology every time hotplug events happen, which is not currently possible in ASoC and there does not seem to be any obvious benefits from this design. To overcome above problems and enable the HDMI driver to be used from ASoC, this patch adds a new mode (mst_no_extra_pcms flags) to patch_hdmi.c. In this mode, the codec driver does not assume the backup PCMs to be created. Signed-off-by: Kai Vehmanen Reviewed-by: Takashi Iwai Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191029134017.18901-2-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- include/sound/hda_codec.h | 1 + sound/pci/hda/patch_hdmi.c | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h index 9a0393cf024c..ac18f428eda6 100644 --- a/include/sound/hda_codec.h +++ b/include/sound/hda_codec.h @@ -254,6 +254,7 @@ struct hda_codec { unsigned int force_pin_prefix:1; /* Add location prefix */ unsigned int link_down_at_suspend:1; /* link down at runtime suspend */ unsigned int relaxed_resume:1; /* don't resume forcibly for jack */ + unsigned int mst_no_extra_pcms:1; /* no backup PCMs for DP-MST */ #ifdef CONFIG_PM unsigned long power_on_acct; diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index bca5de78e9ad..59aaee4a40fd 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2072,15 +2072,24 @@ static bool is_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) static int generic_hdmi_build_pcms(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; - int idx; + int idx, pcm_num; /* * for non-mst mode, pcm number is the same as before - * for DP MST mode, pcm number is (nid number + dev_num - 1) - * dev_num is the device entry number in a pin - * + * for DP MST mode without extra PCM, pcm number is same + * for DP MST mode with extra PCMs, pcm number is + * (nid number + dev_num - 1) + * dev_num is the device entry number in a pin */ - for (idx = 0; idx < spec->num_nids + spec->dev_num - 1; idx++) { + + if (codec->mst_no_extra_pcms) + pcm_num = spec->num_nids; + else + pcm_num = spec->num_nids + spec->dev_num - 1; + + codec_dbg(codec, "hdmi: pcm_num set to %d\n", pcm_num); + + for (idx = 0; idx < pcm_num; idx++) { struct hda_pcm *info; struct hda_pcm_stream *pstr; -- cgit v1.2.3 From 7de9a47c8971bdec07cc9a62e948382003c5908f Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 29 Oct 2019 15:40:11 +0200 Subject: ASoC: Intel: skl-hda-dsp-generic: use snd-hda-codec-hdmi Add support for using snd-hda-codec-hdmi driver for HDMI/DP instead of ASoC hdac-hdmi. This is aligned with how other HDA codecs are already handled. When snd-hda-codec-hdmi is used, the PCM device numbers are parsed from card topology and passed to the codec driver. This needs to be done at runtime as topology changes may affect PCM device allocation. Signed-off-by: Kai Vehmanen Reviewed-by: Takashi Iwai Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191029134017.18901-4-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- include/sound/soc-acpi.h | 2 + sound/soc/intel/boards/Makefile | 2 +- sound/soc/intel/boards/hda_dsp_common.c | 85 ++++++++++++++++++++++++++++ sound/soc/intel/boards/hda_dsp_common.h | 32 +++++++++++ sound/soc/intel/boards/skl_hda_dsp_common.c | 6 ++ sound/soc/intel/boards/skl_hda_dsp_common.h | 23 ++++++++ sound/soc/intel/boards/skl_hda_dsp_generic.c | 1 + 7 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/boards/hda_dsp_common.c create mode 100644 sound/soc/intel/boards/hda_dsp_common.h (limited to 'include') diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index c0fb71c7b3ad..c4c997bd0379 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -60,12 +60,14 @@ static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) * @acpi_ipc_irq_index: used for BYT-CR detection * @platform: string used for HDaudio codec support * @codec_mask: used for HDAudio support + * @common_hdmi_codec_drv: use commom HDAudio HDMI codec driver */ struct snd_soc_acpi_mach_params { u32 acpi_ipc_irq_index; const char *platform; u32 codec_mask; u32 dmic_num; + bool common_hdmi_codec_drv; }; /** diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 6445f90ea542..52e990b16b0d 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -24,7 +24,7 @@ snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o snd-soc-kbl_rt5660-objs := kbl_rt5660.o snd-soc-skl_rt286-objs := skl_rt286.o -snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o +snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o hda_dsp_common.o snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o diff --git a/sound/soc/intel/boards/hda_dsp_common.c b/sound/soc/intel/boards/hda_dsp_common.c new file mode 100644 index 000000000000..ed36b68d6705 --- /dev/null +++ b/sound/soc/intel/boards/hda_dsp_common.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright(c) 2019 Intel Corporation. All rights reserved. + +#include +#include +#include +#include +#include "../../codecs/hdac_hda.h" + +#include "hda_dsp_common.h" + +/* + * Search card topology and return PCM device number + * matching Nth HDMI device (zero-based index). + */ +struct snd_pcm *hda_dsp_hdmi_pcm_handle(struct snd_soc_card *card, + int hdmi_idx) +{ + struct snd_soc_pcm_runtime *rtd; + struct snd_pcm *spcm; + int i = 0; + + for_each_card_rtds(card, rtd) { + spcm = rtd->pcm ? + rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].pcm : NULL; + if (spcm && strstr(spcm->id, "HDMI")) { + if (i == hdmi_idx) + return rtd->pcm; + ++i; + } + } + + return NULL; +} + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) +/* + * Search card topology and register HDMI PCM related controls + * to codec driver. + */ +int hda_dsp_hdmi_build_controls(struct snd_soc_card *card, + struct snd_soc_component *comp) +{ + struct hdac_hda_priv *hda_pvt; + struct hda_codec *hcodec; + struct snd_pcm *spcm; + struct hda_pcm *hpcm; + int err = 0, i = 0; + + if (!comp) + return -EINVAL; + + hda_pvt = snd_soc_component_get_drvdata(comp); + hcodec = &hda_pvt->codec; + + list_for_each_entry(hpcm, &hcodec->pcm_list_head, list) { + spcm = hda_dsp_hdmi_pcm_handle(card, i); + if (spcm) { + hpcm->pcm = spcm; + hpcm->device = spcm->device; + dev_dbg(card->dev, + "%s: mapping HDMI converter %d to PCM %d (%p)\n", + __func__, i, hpcm->device, spcm); + } else { + hpcm->pcm = 0; + hpcm->device = SNDRV_PCM_INVALID_DEVICE; + dev_warn(card->dev, + "%s: no PCM in topology for HDMI converter %d\n\n", + __func__, i); + } + i++; + } + snd_hdac_display_power(hcodec->core.bus, + HDA_CODEC_IDX_CONTROLLER, true); + err = snd_hda_codec_build_controls(hcodec); + if (err < 0) + dev_err(card->dev, "unable to create controls %d\n", err); + snd_hdac_display_power(hcodec->core.bus, + HDA_CODEC_IDX_CONTROLLER, false); + + return err; +} + +#endif diff --git a/sound/soc/intel/boards/hda_dsp_common.h b/sound/soc/intel/boards/hda_dsp_common.h new file mode 100644 index 000000000000..431f7f09dccb --- /dev/null +++ b/sound/soc/intel/boards/hda_dsp_common.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(c) 2019 Intel Corporation. + */ + +/* + * This file defines helper functions used by multiple + * Intel HDA based machine drivers. + */ + +#ifndef __HDA_DSP_COMMON_H +#define __HDA_DSP_COMMON_H + +#include +#include +#include "../../codecs/hdac_hda.h" + +struct snd_pcm *hda_dsp_hdmi_pcm_handle(struct snd_soc_card *card, + int hdmi_idx); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) +int hda_dsp_hdmi_build_controls(struct snd_soc_card *card, + struct snd_soc_component *comp); +#else +static inline int hda_dsp_hdmi_build_controls(struct snd_soc_card *card, + struct snd_soc_component *comp) +{ + return -EINVAL; +} +#endif + +#endif /* __HDA_DSP_COMMON_H */ diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.c b/sound/soc/intel/boards/skl_hda_dsp_common.c index 58409b6e476e..eb419e1ec42b 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_common.c +++ b/sound/soc/intel/boards/skl_hda_dsp_common.c @@ -14,6 +14,9 @@ #include "../../codecs/hdac_hdmi.h" #include "skl_hda_dsp_common.h" +#include +#include "../../codecs/hdac_hda.h" + #define NAME_SIZE 32 int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device) @@ -136,6 +139,9 @@ int skl_hda_hdmi_jack_init(struct snd_soc_card *card) char jack_name[NAME_SIZE]; int err; + if (ctx->common_hdmi_codec_drv) + return skl_hda_hdmi_build_controls(card); + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { component = pcm->codec_dai->component; snprintf(jack_name, sizeof(jack_name), diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.h b/sound/soc/intel/boards/skl_hda_dsp_common.h index daa582e513b2..bbe6e2acfda3 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_common.h +++ b/sound/soc/intel/boards/skl_hda_dsp_common.h @@ -14,6 +14,9 @@ #include #include #include +#include +#include "../../codecs/hdac_hda.h" +#include "hda_dsp_common.h" #define HDA_DSP_MAX_BE_DAI_LINKS 7 @@ -29,10 +32,30 @@ struct skl_hda_private { int pcm_count; int dai_index; const char *platform_name; + bool common_hdmi_codec_drv; }; extern struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS]; int skl_hda_hdmi_jack_init(struct snd_soc_card *card); int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device); +/* + * Search card topology and register HDMI PCM related controls + * to codec driver. + */ +static inline int skl_hda_hdmi_build_controls(struct snd_soc_card *card) +{ + struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_component *component; + struct skl_hda_hdmi_pcm *pcm; + + pcm = list_first_entry(&ctx->hdmi_pcm_list, struct skl_hda_hdmi_pcm, + head); + component = pcm->codec_dai->component; + if (!component) + return -EINVAL; + + return hda_dsp_hdmi_build_controls(card, component); +} + #endif /* __SOUND_SOC_HDA_DSP_COMMON_H */ diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index e8d676c192f6..4e45901e3a2f 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -178,6 +178,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev) ctx->pcm_count = hda_soc_card.num_links; ctx->dai_index = 1; /* hdmi codec dai name starts from index 1 */ ctx->platform_name = mach->mach_params.platform; + ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; hda_soc_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&hda_soc_card, ctx); -- cgit v1.2.3 From e226445802cb2a51c3cb127fac31fba0a4330e87 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 30 Oct 2019 16:55:33 +0800 Subject: ASoC: rt5682: improve the sensitivity of push button The sensitivity could improve by decreasing the HW debounce time and reduce the delay time of workequeue. This patch added a device property for HW debounce time control. We could change this value to tune the sensitivity of push button. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20191030085533.14299-1-shumingf@realtek.com Signed-off-by: Mark Brown --- include/sound/rt5682.h | 1 + sound/soc/codecs/rt5682.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+) (limited to 'include') diff --git a/include/sound/rt5682.h b/include/sound/rt5682.h index bf2ee75aabb1..bc2c31734df1 100644 --- a/include/sound/rt5682.h +++ b/include/sound/rt5682.h @@ -31,6 +31,7 @@ struct rt5682_platform_data { enum rt5682_dmic1_data_pin dmic1_data_pin; enum rt5682_dmic1_clk_pin dmic1_clk_pin; enum rt5682_jd_src jd_src; + unsigned int btndet_delay; }; #endif diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index c50b75ce82e0..35dcec135c8a 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -44,6 +44,7 @@ static const struct rt5682_platform_data i2s_default_platform_data = { .dmic1_data_pin = RT5682_DMIC1_DATA_GPIO2, .dmic1_clk_pin = RT5682_DMIC1_CLK_GPIO3, .jd_src = RT5682_JD1, + .btndet_delay = 16, }; struct rt5682_priv { @@ -1026,6 +1027,18 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component, regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2, RT5682_JD1_EN_MASK | RT5682_JD1_POL_MASK, RT5682_JD1_EN | RT5682_JD1_POL_NOR); + regmap_update_bits(rt5682->regmap, RT5682_4BTN_IL_CMD_4, + 0x7f7f, (rt5682->pdata.btndet_delay << 8 | + rt5682->pdata.btndet_delay)); + regmap_update_bits(rt5682->regmap, RT5682_4BTN_IL_CMD_5, + 0x7f7f, (rt5682->pdata.btndet_delay << 8 | + rt5682->pdata.btndet_delay)); + regmap_update_bits(rt5682->regmap, RT5682_4BTN_IL_CMD_6, + 0x7f7f, (rt5682->pdata.btndet_delay << 8 | + rt5682->pdata.btndet_delay)); + regmap_update_bits(rt5682->regmap, RT5682_4BTN_IL_CMD_7, + 0x7f7f, (rt5682->pdata.btndet_delay << 8 | + rt5682->pdata.btndet_delay)); mod_delayed_work(system_power_efficient_wq, &rt5682->jack_detect_work, msecs_to_jiffies(250)); break; @@ -2467,6 +2480,8 @@ static int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev) &rt5682->pdata.dmic1_clk_pin); device_property_read_u32(dev, "realtek,jd-src", &rt5682->pdata.jd_src); + device_property_read_u32(dev, "realtek,btndet-delay", + &rt5682->pdata.btndet_delay); rt5682->pdata.ldo1_en = of_get_named_gpio(dev->of_node, "realtek,ldo1-en-gpios", 0); -- cgit v1.2.3 From e11381f38f34789b374880c4a149e25e8d7f0cfd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:47:04 +0900 Subject: ASoC: soc-core: add snd_soc_unregister_dai() It is easy to read code if it is cleanly using paired function/naming, like start <-> stop, register <-> unregister, etc, etc. But, current ALSA SoC code is very random, unbalance, not paired, etc. It is easy to create bug at the such code, and is difficult to debug. This patch adds missing soc_del_dai() and snd_soc_unregister_dai(). Signed-off-by: Kuninori Morimoto Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87v9ry251z.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 1 + sound/soc/soc-core.c | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/sound/soc.h b/include/sound/soc.h index 320dcd440dab..daa0e100ecd9 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1328,6 +1328,7 @@ struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card, int snd_soc_register_dai(struct snd_soc_component *component, struct snd_soc_dai_driver *dai_drv); +void snd_soc_unregister_dai(struct snd_soc_dai *dai); struct snd_soc_dai *snd_soc_find_dai( const struct snd_soc_dai_link_component *dlc); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c803447fe639..38199cd7ce97 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2532,6 +2532,12 @@ static inline char *fmt_multiple_name(struct device *dev, return devm_kstrdup(dev, dai_drv->name, GFP_KERNEL); } +static void soc_del_dai(struct snd_soc_dai *dai) +{ + dev_dbg(dai->dev, "ASoC: Unregistered DAI '%s'\n", dai->name); + list_del(&dai->list); +} + /* Create a DAI and add it to the component's DAI list */ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, struct snd_soc_dai_driver *dai_drv, @@ -2581,6 +2587,12 @@ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, return dai; } +void snd_soc_unregister_dai(struct snd_soc_dai *dai) +{ + soc_del_dai(dai); +} +EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); + /** * snd_soc_register_dai - Register a DAI dynamically & create its widgets * @@ -2633,11 +2645,8 @@ static void snd_soc_unregister_dais(struct snd_soc_component *component) { struct snd_soc_dai *dai, *_dai; - for_each_component_dais_safe(component, dai, _dai) { - dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n", - dai->name); - list_del(&dai->list); - } + for_each_component_dais_safe(component, dai, _dai) + snd_soc_unregister_dai(dai); } /** -- cgit v1.2.3 From 5d07519703bc2f0bf19d33652401552a480d68b8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:47:09 +0900 Subject: ASoC: soc-core: have legacy_dai_naming at snd_soc_register_dai() ALSA SoC has 2 functions. snd_soc_register_dai() is used from topology snd_soc_register_dais() is used from snd_soc_add_component() In general, people think like _dai() is called from _dais() with for loop. But in reality, these are very similar but different implementation. We shouldn't have duplicated and confusing implementation. snd_soc_register_dai() is now used from topology. But to reduce duplicated code, it should be used from _dais(), too. To prepare it, this patch adds missing parameter legacy_dai_naming to snd_soc_register_dai(). Signed-off-by: Kuninori Morimoto Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87tv7i251u.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 3 ++- sound/soc/soc-core.c | 5 +++-- sound/soc/soc-topology.c | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/sound/soc.h b/include/sound/soc.h index daa0e100ecd9..766fa81494c3 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1327,7 +1327,8 @@ struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card, const char *stream_name); int snd_soc_register_dai(struct snd_soc_component *component, - struct snd_soc_dai_driver *dai_drv); + struct snd_soc_dai_driver *dai_drv, + bool legacy_dai_naming); void snd_soc_unregister_dai(struct snd_soc_dai *dai); struct snd_soc_dai *snd_soc_find_dai( diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 38199cd7ce97..6f4933f13b08 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2604,7 +2604,8 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); * will be freed in the component cleanup. */ int snd_soc_register_dai(struct snd_soc_component *component, - struct snd_soc_dai_driver *dai_drv) + struct snd_soc_dai_driver *dai_drv, + bool legacy_dai_naming) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); @@ -2618,7 +2619,7 @@ int snd_soc_register_dai(struct snd_soc_component *component, } lockdep_assert_held(&client_mutex); - dai = soc_add_dai(component, dai_drv, false); + dai = soc_add_dai(component, dai_drv, legacy_dai_naming); if (!dai) return -ENOMEM; diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 0fd032914a31..b6e145627ab4 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1842,7 +1842,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, list_add(&dai_drv->dobj.list, &tplg->comp->dobj_list); /* register the DAI to the component */ - return snd_soc_register_dai(tplg->comp, dai_drv); + return snd_soc_register_dai(tplg->comp, dai_drv, false); } static void set_link_flags(struct snd_soc_dai_link *link, -- cgit v1.2.3 From e443c20593de9f8efd9b2935ed40eb0bbacce30b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:47:14 +0900 Subject: ASoC: soc-core: don't call snd_soc_dapm_new_dai_widgets() at snd_soc_register_dai() ALSA SoC has 2 functions. snd_soc_register_dai() is used from topology snd_soc_register_dais() is used from snd_soc_add_component() In general, people think like _dai() is called from _dais() with for loop. But in reality, these are very similar but different implementation. We shouldn't have duplicated and confusing implementation. snd_soc_register_dai() is now used from topology. But to reduce duplicated code, it should be used from _dais(), too. Because of topology side specific reason, it is calling snd_soc_dapm_new_dai_widgets(), but it is not needed _dais() side. This patch factorizes snd_soc_register_dai() to topology / _dais() common part, and topology specific part. And do topology specific part at soc-topology. Signed-off-by: Kuninori Morimoto Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87sgn2251p.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 6 +++--- sound/soc/soc-core.c | 29 +++++------------------------ sound/soc/soc-topology.c | 17 ++++++++++++++++- 3 files changed, 24 insertions(+), 28 deletions(-) (limited to 'include') diff --git a/include/sound/soc.h b/include/sound/soc.h index 766fa81494c3..4e38ee656c4b 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1326,9 +1326,9 @@ struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card, int id, const char *name, const char *stream_name); -int snd_soc_register_dai(struct snd_soc_component *component, - struct snd_soc_dai_driver *dai_drv, - bool legacy_dai_naming); +struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, + struct snd_soc_dai_driver *dai_drv, + bool legacy_dai_naming); void snd_soc_unregister_dai(struct snd_soc_dai *dai); struct snd_soc_dai *snd_soc_find_dai( diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6f4933f13b08..55b13c0037d2 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2603,37 +2603,18 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); * These DAIs's widgets will be freed in the card cleanup and the DAIs * will be freed in the component cleanup. */ -int snd_soc_register_dai(struct snd_soc_component *component, - struct snd_soc_dai_driver *dai_drv, - bool legacy_dai_naming) +struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, + struct snd_soc_dai_driver *dai_drv, + bool legacy_dai_naming) { - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - struct snd_soc_dai *dai; - int ret; - if (dai_drv->dobj.type != SND_SOC_DOBJ_PCM) { dev_err(component->dev, "Invalid dai type %d\n", dai_drv->dobj.type); - return -EINVAL; + return NULL; } lockdep_assert_held(&client_mutex); - dai = soc_add_dai(component, dai_drv, legacy_dai_naming); - if (!dai) - return -ENOMEM; - - /* - * Create the DAI widgets here. After adding DAIs, topology may - * also add routes that need these widgets as source or sink. - */ - ret = snd_soc_dapm_new_dai_widgets(dapm, dai); - if (ret != 0) { - dev_err(component->dev, - "Failed to create DAI widgets %d\n", ret); - } - - return ret; + return soc_add_dai(component, dai_drv, legacy_dai_naming); } EXPORT_SYMBOL_GPL(snd_soc_register_dai); diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index b6e145627ab4..81d2af000a5c 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1800,6 +1800,9 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, struct snd_soc_dai_driver *dai_drv; struct snd_soc_pcm_stream *stream; struct snd_soc_tplg_stream_caps *caps; + struct snd_soc_dai *dai; + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(tplg->comp); int ret; dai_drv = kzalloc(sizeof(struct snd_soc_dai_driver), GFP_KERNEL); @@ -1842,7 +1845,19 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, list_add(&dai_drv->dobj.list, &tplg->comp->dobj_list); /* register the DAI to the component */ - return snd_soc_register_dai(tplg->comp, dai_drv, false); + dai = snd_soc_register_dai(tplg->comp, dai_drv, false); + if (!dai) + return -ENOMEM; + + /* Create the DAI widgets here */ + ret = snd_soc_dapm_new_dai_widgets(dapm, dai); + if (ret != 0) { + dev_err(dai->dev, "Failed to create DAI widgets %d\n", ret); + snd_soc_unregister_dai(dai); + return ret; + } + + return ret; } static void set_link_flags(struct snd_soc_dai_link *link, -- cgit v1.2.3 From 509ba54fcfd1e45bceebe8ccea59dc496312f1a0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 5 Nov 2019 15:47:26 +0900 Subject: ASoC: soc.h: dobj is used only when SND_SOC_TOPOLOGY snd_soc_dobj is used only when SND_SOC_TOPOLOGY was selected. Let's enable it under SND_SOC_TOPOLOGY. Signed-off-by: Kuninori Morimoto Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://lore.kernel.org/r/87o8xq251d.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/sound/soc.h b/include/sound/soc.h index 4e38ee656c4b..e0855dc08d30 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -847,7 +847,9 @@ struct snd_soc_dai_link { unsigned int ignore:1; struct list_head list; /* DAI link list of the soc card */ +#ifdef CONFIG_SND_SOC_TOPOLOGY struct snd_soc_dobj dobj; /* For topology */ +#endif }; #define for_each_link_codecs(link, i, codec) \ for ((i) = 0; \ @@ -1169,7 +1171,9 @@ struct soc_mixer_control { unsigned int sign_bit; unsigned int invert:1; unsigned int autodisable:1; +#ifdef CONFIG_SND_SOC_TOPOLOGY struct snd_soc_dobj dobj; +#endif }; struct soc_bytes { @@ -1180,8 +1184,9 @@ struct soc_bytes { struct soc_bytes_ext { int max; +#ifdef CONFIG_SND_SOC_TOPOLOGY struct snd_soc_dobj dobj; - +#endif /* used for TLV byte control */ int (*get)(struct snd_kcontrol *kcontrol, unsigned int __user *bytes, unsigned int size); @@ -1205,7 +1210,9 @@ struct soc_enum { const char * const *texts; const unsigned int *values; unsigned int autodisable:1; +#ifdef CONFIG_SND_SOC_TOPOLOGY struct snd_soc_dobj dobj; +#endif }; /* device driver data */ -- cgit v1.2.3 From 1f24d93c4f4ec0bb0b73c5b020060aa2d9faa756 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 11 Nov 2019 16:28:59 -0600 Subject: ASoC: Intel: acpi-match: split CNL tables in three Due to firmware manifest/signature differences, we have to use different firmware names, so split CNL machine table in three (CNL, CFL, CML). The CFL table is currently empty since all known platforms use HDaudio, but let's plan ahead. Reviewed-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191111222901.19892-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- include/sound/soc-acpi-intel-match.h | 2 + sound/soc/intel/common/Makefile | 3 +- sound/soc/intel/common/soc-acpi-intel-cfl-match.c | 18 ++++++++ sound/soc/intel/common/soc-acpi-intel-cml-match.c | 56 +++++++++++++++++++++++ sound/soc/intel/common/soc-acpi-intel-cnl-match.c | 38 --------------- 5 files changed, 78 insertions(+), 39 deletions(-) create mode 100644 sound/soc/intel/common/soc-acpi-intel-cfl-match.c create mode 100644 sound/soc/intel/common/soc-acpi-intel-cml-match.c (limited to 'include') diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index 4e44782862df..20c0bee3b959 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -24,6 +24,8 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[]; diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index eafe95ead49b..bd352878f89a 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -7,7 +7,8 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-hsw-bdw-match.o \ soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \ soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \ - soc-acpi-intel-cnl-match.o soc-acpi-intel-icl-match.o \ + soc-acpi-intel-cnl-match.o soc-acpi-intel-cfl-match.o \ + soc-acpi-intel-cml-match.o soc-acpi-intel-icl-match.o \ soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \ soc-acpi-intel-jsl-match.o \ soc-acpi-intel-hda-match.o diff --git a/sound/soc/intel/common/soc-acpi-intel-cfl-match.c b/sound/soc/intel/common/soc-acpi-intel-cfl-match.c new file mode 100644 index 000000000000..d6fd2026d0b8 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-cfl-match.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * soc-apci-intel-cfl-match.c - tables and support for CFL ACPI enumeration. + * + * Copyright (c) 2019, Intel Corporation. + * + */ + +#include +#include + +struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_machines[] = { + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cfl_machines); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); diff --git a/sound/soc/intel/common/soc-acpi-intel-cml-match.c b/sound/soc/intel/common/soc-acpi-intel-cml-match.c new file mode 100644 index 000000000000..5d08ae066738 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * soc-acpi-intel-cml-match.c - tables and support for CML ACPI enumeration. + * + * Copyright (c) 2019, Intel Corporation. + * + */ + +#include +#include + +static struct snd_soc_acpi_codecs cml_codecs = { + .num_codecs = 1, + .codecs = {"10EC5682"} +}; + +static struct snd_soc_acpi_codecs cml_spk_codecs = { + .num_codecs = 1, + .codecs = {"MX98357A"} +}; + +struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[] = { + { + .id = "DLGS7219", + .drv_name = "cml_da7219_max98357a", + .quirk_data = &cml_spk_codecs, + .sof_fw_filename = "sof-cml.ri", + .sof_tplg_filename = "sof-cml-da7219-max98357a.tplg", + }, + { + .id = "MX98357A", + .drv_name = "sof_rt5682", + .quirk_data = &cml_codecs, + .sof_fw_filename = "sof-cml.ri", + .sof_tplg_filename = "sof-cml-rt5682-max98357a.tplg", + }, + { + .id = "10EC1011", + .drv_name = "cml_rt1011_rt5682", + .quirk_data = &cml_codecs, + .sof_fw_filename = "sof-cml.ri", + .sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg", + }, + { + .id = "10EC5682", + .drv_name = "sof_rt5682", + .sof_fw_filename = "sof-cml.ri", + .sof_tplg_filename = "sof-cml-rt5682.tplg", + }, + + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cml_machines); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index 16d0bae8b316..27588841c8b0 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -14,16 +14,6 @@ static struct skl_machine_pdata cnl_pdata = { .use_tplg_pcm = true, }; -static struct snd_soc_acpi_codecs cml_codecs = { - .num_codecs = 1, - .codecs = {"10EC5682"} -}; - -static struct snd_soc_acpi_codecs cml_spk_codecs = { - .num_codecs = 1, - .codecs = {"MX98357A"} -}; - struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { { .id = "INT34C2", @@ -33,34 +23,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .sof_fw_filename = "sof-cnl.ri", .sof_tplg_filename = "sof-cnl-rt274.tplg", }, - { - .id = "DLGS7219", - .drv_name = "cml_da7219_max98357a", - .quirk_data = &cml_spk_codecs, - .sof_fw_filename = "sof-cnl.ri", - .sof_tplg_filename = "sof-cml-da7219-max98357a.tplg", - }, - { - .id = "MX98357A", - .drv_name = "sof_rt5682", - .quirk_data = &cml_codecs, - .sof_fw_filename = "sof-cnl.ri", - .sof_tplg_filename = "sof-cml-rt5682-max98357a.tplg", - }, - { - .id = "10EC1011", - .drv_name = "cml_rt1011_rt5682", - .quirk_data = &cml_codecs, - .sof_fw_filename = "sof-cnl.ri", - .sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg", - }, - { - .id = "10EC5682", - .drv_name = "sof_rt5682", - .sof_fw_filename = "sof-cnl.ri", - .sof_tplg_filename = "sof-cml-rt5682.tplg", - }, - {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cnl_machines); -- cgit v1.2.3 From d2522335c92c090bf58531a2b696d7fe80ab2a7a Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 15 Nov 2019 15:57:03 +0530 Subject: ALSA: compress: add flac decoder params The current design of sending codec parameters assumes that decoders will have parsers so they can parse the encoded stream for parameters and configure the decoder. But this assumption may not be universally true and we know some DSPs which do not contain the parsers so additional parameters are required to be passed. So add these parameters starting with FLAC decoder. The size of snd_codec_options is still 120 bytes after this change (due to this being a union) Co-developed-by: Srinivas Kandagatla Signed-off-by: Srinivas Kandagatla Signed-off-by: Vinod Koul Link: https://lore.kernel.org/r/20191115102705.649976-2-vkoul@kernel.org Acked-by: Takashi Iwai Signed-off-by: Mark Brown --- include/uapi/sound/compress_params.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'include') diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h index 3d4d6de66a17..9c96fb0e4d90 100644 --- a/include/uapi/sound/compress_params.h +++ b/include/uapi/sound/compress_params.h @@ -317,12 +317,22 @@ struct snd_enc_generic { __s32 reserved[15]; /* Can be used for SND_AUDIOCODEC_BESPOKE */ } __attribute__((packed, aligned(4))); +struct snd_dec_flac { + __u16 sample_size; + __u16 min_blk_size; + __u16 max_blk_size; + __u16 min_frame_size; + __u16 max_frame_size; + __u16 reserved; +} __attribute__((packed, aligned(4))); + union snd_codec_options { struct snd_enc_wma wma; struct snd_enc_vorbis vorbis; struct snd_enc_real real; struct snd_enc_flac flac; struct snd_enc_generic generic; + struct snd_dec_flac flac_d; } __attribute__((packed, aligned(4))); /** struct snd_codec_desc - description of codec capabilities -- cgit v1.2.3 From b2b2afbb48eac7215f951a8a462aa6837e0d495f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 18 Nov 2019 10:50:32 +0900 Subject: ASoC: soc-component: tidyup snd_soc_pcm_component_new/free() parameter This patch uses rtd instead of pcm at snd_soc_pcm_component_new/free() parameter. This is prepare for dai_link remove bug fix on topology. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pnhqx89j.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 4 ++-- sound/soc/soc-component.c | 8 +++----- sound/soc/soc-pcm.c | 4 ++-- 3 files changed, 7 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 6aa3ecb7b6d3..f8fadf0e696a 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -412,7 +412,7 @@ struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, unsigned long offset); int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma); -int snd_soc_pcm_component_new(struct snd_pcm *pcm); -void snd_soc_pcm_component_free(struct snd_pcm *pcm); +int snd_soc_pcm_component_new(struct snd_soc_pcm_runtime *rtd); +void snd_soc_pcm_component_free(struct snd_soc_pcm_runtime *rtd); #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 98ef0666add2..1590e805d016 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -498,9 +498,8 @@ int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, return -EINVAL; } -int snd_soc_pcm_component_new(struct snd_pcm *pcm) +int snd_soc_pcm_component_new(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_pcm_runtime *rtd = pcm->private_data; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_component *component; int ret; @@ -516,13 +515,12 @@ int snd_soc_pcm_component_new(struct snd_pcm *pcm) return 0; } -void snd_soc_pcm_component_free(struct snd_pcm *pcm) +void snd_soc_pcm_component_free(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_pcm_runtime *rtd = pcm->private_data; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_component *component; for_each_rtd_components(rtd, rtdcom, component) if (component->driver->pcm_destruct) - component->driver->pcm_destruct(component, pcm); + component->driver->pcm_destruct(component, rtd->pcm); } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 4bf71e3211d8..c624d30bfa3c 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2898,7 +2898,7 @@ static void soc_pcm_private_free(struct snd_pcm *pcm) /* need to sync the delayed work before releasing resources */ flush_delayed_work(&rtd->delayed_work); - snd_soc_pcm_component_free(pcm); + snd_soc_pcm_component_free(rtd); } /* create a new pcm */ @@ -3036,7 +3036,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) if (capture) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops); - ret = snd_soc_pcm_component_new(pcm); + ret = snd_soc_pcm_component_new(rtd); if (ret < 0) { dev_err(rtd->dev, "ASoC: pcm constructor failed: %d\n", ret); return ret; -- cgit v1.2.3 From dc73d73aa7145f55412611f3eead1e85ae026785 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 19 Nov 2019 18:49:32 +0100 Subject: ASoC: add control components management This ASCII string can carry additional information about soundcard components or configuration. Add the possibility to set this string via the ASoC card. Signed-off-by: Jaroslav Kysela Cc: Mark Brown Link: https://lore.kernel.org/r/20191119174933.25526-1-perex@perex.cz Signed-off-by: Mark Brown --- include/sound/soc.h | 1 + sound/soc/soc-core.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) (limited to 'include') diff --git a/include/sound/soc.h b/include/sound/soc.h index e0855dc08d30..bd943b5d7d45 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -982,6 +982,7 @@ struct snd_soc_card { const char *name; const char *long_name; const char *driver_name; + const char *components; char dmi_longname[80]; char topology_shortname[32]; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e3a53ef1db04..cc0ef0fcc005 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2108,6 +2108,19 @@ static int snd_soc_bind_card(struct snd_soc_card *card) soc_setup_card_name(card->snd_card->driver, card->driver_name, card->name, 1); + if (card->components) { + /* the current implementation of snd_component_add() accepts */ + /* multiple components in the string separated by space, */ + /* but the string collision (identical string) check might */ + /* not work correctly */ + ret = snd_component_add(card->snd_card, card->components); + if (ret < 0) { + dev_err(card->dev, "ASoC: %s snd_component_add() failed: %d\n", + card->name, ret); + goto probe_end; + } + } + if (card->late_probe) { ret = card->late_probe(card); if (ret < 0) { -- cgit v1.2.3 From fb5126778333d289b2623a7e6260beeb1ac1b819 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Wed, 20 Nov 2019 14:08:43 +0800 Subject: ASoC: core: add SND_SOC_BYTES_E Add SND_SOC_BYTES_E to accept getter and putter. Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20191120060844.224607-2-tzungbi@google.com Signed-off-by: Mark Brown --- include/sound/soc.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'include') diff --git a/include/sound/soc.h b/include/sound/soc.h index bd943b5d7d45..c28a1ed5e8df 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -299,6 +299,12 @@ .put = snd_soc_bytes_put, .private_value = \ ((unsigned long)&(struct soc_bytes) \ {.base = xbase, .num_regs = xregs }) } +#define SND_SOC_BYTES_E(xname, xbase, xregs, xhandler_get, xhandler_put) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_bytes_info, .get = xhandler_get, \ + .put = xhandler_put, .private_value = \ + ((unsigned long)&(struct soc_bytes) \ + {.base = xbase, .num_regs = xregs }) } #define SND_SOC_BYTES_MASK(xname, xbase, xregs, xmask) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ -- cgit v1.2.3